Пример #1
0
// 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
}
Пример #2
0
// 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
}