// IntersectTriangle find whether there's an intersection point between the ray and the triangle // using barycentric coordinates and calculate the distance func IntersectTriangle(ray *ray.Ray, A, B, C *maths.Vec3) (bool, float64) { AB := maths.MinusVectors(B, A) AC := maths.MinusVectors(C, A) reverseDirection := ray.Direction.Negative() distToA := maths.MinusVectors(&ray.Start, A) ABxAC := maths.CrossProduct(AB, AC) det := maths.DotProduct(ABxAC, reverseDirection) reverseDet := 1 / det if math.Abs(det) < maths.Epsilon { return false, maths.Inf } lambda2 := maths.MixedProduct(distToA, AC, reverseDirection) * reverseDet lambda3 := maths.MixedProduct(AB, distToA, reverseDirection) * reverseDet gamma := maths.DotProduct(ABxAC, distToA) * reverseDet if gamma < 0 { return false, maths.Inf } if lambda2 < 0 || lambda2 > 1 || lambda3 < 0 || lambda3 > 1 || lambda2+lambda3 > 1 { return false, maths.Inf } return true, gamma }
// IntersectTriangle returns whether there's an intersection between the ray and the triangle, // using barycentric coordinates and takes the point only if it's closer to the // previously found intersection and the point is within the bounding box func (m *Mesh) intersectTriangle(ray *ray.Ray, triangle *Triangle, intersection *ray.Intersection, boundingBox *BoundingBox) bool { // lambda2 * AB + lambda3 * AC - intersectDist*rayDir = distToA // If the triangle is ABC, this gives you A A := &m.Vertices[triangle.Vertices[0]].Coordinates distToA := maths.MinusVectors(&ray.Start, A) rayDir := ray.Direction ABxAC := triangle.ABxAC // We will find the barycentric coordinates using Cramer's formula, so we'll need the determinant // det is (AB^AC)*dir of the ray, but we're gonna use 1/det, so we find the recerse: det := -maths.DotProduct(ABxAC, &rayDir) if math.Abs(det) < maths.Epsilon { return false } reverseDet := 1 / det intersectDist := maths.DotProduct(ABxAC, distToA) * reverseDet if intersectDist < 0 || intersectDist > intersection.Distance { return false } // lambda2 = (dist^dir)*AC / det // lambda3 = -(dist^dir)*AB / det lambda2 := maths.MixedProduct(distToA, &rayDir, triangle.AC) * reverseDet lambda3 := -maths.MixedProduct(distToA, &rayDir, triangle.AB) * reverseDet if lambda2 < 0 || lambda2 > 1 || lambda3 < 0 || lambda3 > 1 || lambda2+lambda3 > 1 { return false } ip := maths.AddVectors(&ray.Start, (&rayDir).Scaled(intersectDist)) // If we aren't inside the bounding box, there could be a closer intersection // within the bounding box if boundingBox != nil && !boundingBox.Inside(ip) { return false } intersection.Point = ip intersection.Distance = intersectDist if triangle.Normal != nil { intersection.Normal = triangle.Normal } else { // We solve intersection.normal = Anormal + AB normal * lambda2 + ACnormal * lambda 3 Anormal := &m.Vertices[triangle.Vertices[0]].Normal Bnormal := &m.Vertices[triangle.Vertices[1]].Normal Cnormal := &m.Vertices[triangle.Vertices[2]].Normal ABxlambda2 := maths.MinusVectors(Bnormal, Anormal).Scaled(lambda2) ACxlambda3 := maths.MinusVectors(Cnormal, Anormal).Scaled(lambda3) intersection.Normal = maths.AddVectors(Anormal, maths.AddVectors(ABxlambda2, ACxlambda3)) } uvA := &m.Vertices[triangle.Vertices[0]].UV uvB := &m.Vertices[triangle.Vertices[1]].UV uvC := &m.Vertices[triangle.Vertices[2]].UV // We solve intersection.uv = uvA + uvAB * lambda2 + uvAC * lambda 3 uvABxlambda2 := maths.MinusVectors(uvB, uvA).Scaled(lambda2) uvACxlambda3 := maths.MinusVectors(uvC, uvA).Scaled(lambda3) uv := maths.AddVectors(uvA, maths.AddVectors(uvABxlambda2, uvACxlambda3)) intersection.U = uv.X intersection.V = uv.Y intersection.SurfaceOx = triangle.surfaceOx intersection.SurfaceOy = triangle.surfaceOy intersection.Incoming = ray intersection.Material = triangle.Material return true }