func TestBoundingBoxSplit(t *testing.T) { box := &BoundingBox{ MinVolume: [3]float64{-3.18, -3.96, -1.77}, MaxVolume: [3]float64{4.58, 1.74, 4.56}, } ray := &ray.Ray{ Start: *maths.NewVec3(4.49, -7.3, 5.53), Direction: *maths.NewVec3(-0.60, 0.5, -0.62), } ray.Init() if !box.Intersect(ray) { t.Error("ray should intersect big box") } left, right := box.Split(2, 1.39) assertEqualVectors(t, maths.NewVec3(-3.18, -3.96, -1.77), maths.NewVec3Array(left.MinVolume)) assertEqualVectors(t, maths.NewVec3(-3.18, -3.96, 1.39), maths.NewVec3Array(right.MinVolume)) assertEqualVectors(t, maths.NewVec3(4.58, 1.74, 1.39), maths.NewVec3Array(left.MaxVolume)) assertEqualVectors(t, maths.NewVec3(4.58, 1.74, 4.56), maths.NewVec3Array(right.MaxVolume)) if box.IntersectWall(2, 1.39, ray) { t.Error("ray shouldn't intersect the wall") } if right.Intersect(ray) { t.Error("ray shouldn't intersect right") } if !left.Intersect(ray) { t.Error("ray should intersect left") } }
// 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 }