Esempio n. 1
0
// Vec3HemiCos returns a random unit vector chosen on a
// cosine-weighed hemisphere defined by normal
func (r *Random) Vec3HemiCos(normal *maths.Vec3) *maths.Vec3 {
	ox := maths.CrossProduct(maths.NewVec3(42, 56, -15), normal)
	for math.Abs(ox.Length()) < maths.Epsilon {
		ox = maths.CrossProduct(r.Vec3Sphere(), normal)
	}

	oy := maths.CrossProduct(ox, normal)
	ox.Normalise()
	oy.Normalise()

	u := r.Float01()
	radius := math.Sqrt(u)
	theta := r.Float02Pi()

	vec := normal.Scaled(math.Sqrt(math.Max(0, 1-u)))
	vec.Add(ox.Scaled(radius * math.Cos(theta)))
	vec.Add(oy.Scaled(radius * math.Sin(theta)))

	return vec
}
Esempio n. 2
0
// Init  of Mesh sets the Triangle indices in the Faces array, calculates the bounding box
// and KD tree, sets the surfaceOx and Oy and Cross Products of the sides of each triangle
func (m *Mesh) Init() {
	allIndices := make([]int, len(m.Faces))
	for i := range allIndices {
		allIndices[i] = i
	}

	m.BoundingBox = m.GetBoundingBox()
	m.tree = m.newKDtree(m.BoundingBox, allIndices, 0)
	for i := range m.Faces {
		triangle := &m.Faces[i]

		A := &m.Vertices[triangle.Vertices[0]].Coordinates
		B := &m.Vertices[triangle.Vertices[1]].Coordinates
		C := &m.Vertices[triangle.Vertices[2]].Coordinates

		AB := maths.MinusVectors(B, A)
		AC := maths.MinusVectors(C, A)

		triangle.AB = AB
		triangle.AC = AC
		triangle.ABxAC = maths.CrossProduct(AB, AC)

		surfaceA := &m.Vertices[triangle.Vertices[0]].UV
		surfaceB := &m.Vertices[triangle.Vertices[1]].UV
		surfaceC := &m.Vertices[triangle.Vertices[2]].UV

		surfaceAB := maths.MinusVectors(surfaceB, surfaceA)
		surfaceAC := maths.MinusVectors(surfaceC, surfaceA)

		// Solve using Cramer:
		// |surfaceAB.X * px + surfaceAX.X *qx + 1 = 0
		// |surfaceAB.Y * px + surfaceAX.Y *qx = 0
		// and
		// surfaceAB.X * py + surfaceAX.X *qy = 0
		// surfaceAB.X * py + surfaceAX.X *qy + 1 = 0

		px, qx := maths.SolveEquation(surfaceAB, surfaceAC, maths.NewVec3(1, 0, 0))
		py, qy := maths.SolveEquation(surfaceAB, surfaceAC, maths.NewVec3(0, 1, 0))

		triangle.surfaceOx = maths.AddVectors(AB.Scaled(px), AC.Scaled(qx))
		triangle.surfaceOy = maths.AddVectors(AB.Scaled(py), AC.Scaled(qy))
	}
}
Esempio n. 3
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
}
Esempio n. 4
0
// IntersectTriangle checks if the bounding box intersects with a triangle
// 1) To have a vertex in the box
// 2) The edge of the triangle intersects with the box
// 3) The middle of the triangle to be inside the box, while the vertices aren't
func (b *BoundingBox) IntersectTriangle(A, B, C *maths.Vec3) bool {
	if b.Inside(A) || b.Inside(B) || b.Inside(C) {
		return true
	}
	// we construct the ray from A->B, A->C, etc and check whether it intersects with the box
	triangle := [3]*maths.Vec3{A, B, C}
	ray := &ray.Ray{}
	for rayStart := 0; rayStart < 3; rayStart++ {
		for rayEnd := rayStart + 1; rayEnd < 3; rayEnd++ {
			ray.Start = *(triangle[rayStart])
			ray.Direction = *maths.MinusVectors(triangle[rayEnd], triangle[rayStart])
			ray.Init()
			// Check if there's intersection between AB and the box (example)
			if b.Intersect(ray) {
				// we check whether there's intersection between BA and the Box too
				// to be sure the edge isn't outside the box
				//    _____
				//    |    | <----AB there is intersection, but BA----->
				//    |____|
				ray.Start = *triangle[rayEnd]
				ray.Direction = *maths.MinusVectors(triangle[rayStart], triangle[rayEnd])
				ray.Init()
				if b.Intersect(ray) {
					return true
				}
			}
		}
	}
	// we have to check if the inside of the triangle intersects with the box
	AB := maths.MinusVectors(B, A)
	AC := maths.MinusVectors(C, A)
	ABxAC := maths.CrossProduct(AB, AC)
	distance := maths.DotProduct(A, ABxAC)
	rayEnd := &maths.Vec3{}

	for edgeMask := 0; edgeMask < 7; edgeMask++ {
		for axis := uint(0); axis < 3; axis++ {
			if edgeMask&(1<<axis) != 0 {
				continue
			}

			if edgeMask&1 != 0 {
				ray.Start.X = b.MaxVolume[0]
			} else {
				ray.Start.X = b.MinVolume[0]
			}

			if edgeMask&2 != 0 {
				ray.Start.Y = b.MaxVolume[1]
			} else {
				ray.Start.Y = b.MinVolume[1]
			}

			if edgeMask&4 != 0 {
				ray.Start.Z = b.MaxVolume[2]
			} else {
				ray.Start.Z = b.MinVolume[2]
			}

			*rayEnd = ray.Start
			rayEnd.SetDimension(int(axis), b.MaxVolume[axis])

			if (maths.DotProduct(&ray.Start, ABxAC)-distance)*(maths.DotProduct(rayEnd, ABxAC)-distance) <= 0 {
				ray.Direction = *maths.MinusVectors(rayEnd, &ray.Start)
				ray.Init()
				intersected, distance := IntersectTriangle(ray, A, B, C)
				if intersected && distance < 1.0000001 {
					return true
				}
			}
		}
	}

	return false
}