/// <summary> /// Returns true if the given box intersects the triangle (v0,v1,v2). /// </summary> public static bool Intersects(ref BoundingBox box, ref Vector3 v0, ref Vector3 v1, ref Vector3 v2) { Vector3 boxCenter = (box.Max + box.Min) * 0.5f; Vector3 boxHalfExtent = (box.Max - box.Min) * 0.5f; // Transform the triangle into the local space with the box center at the origin Triangle localTri = new Triangle(); Vector3.Subtract(ref v0, ref boxCenter, out localTri.V0); Vector3.Subtract(ref v1, ref boxCenter, out localTri.V1); Vector3.Subtract(ref v2, ref boxCenter, out localTri.V2); return OriginBoxContains(ref boxHalfExtent, ref localTri) != ContainmentType.Disjoint; }
// Set up initial bounding shapes for the primary (static) and secondary (moving) // bounding shapes along with relevant camera position information. protected override void Initialize() { Console.WriteLine("DEBUG - Game Initialize!"); debugDraw = new DebugDraw(GraphicsDevice); Components.Add(new FrameRateCounter(this)); // Primary frustum Matrix m1 = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 1.77778F, 0.5f, 10.0f); Matrix m2 = Matrix.CreateTranslation(new Vector3(0, 0, -7)); primaryFrustum = new BoundingFrustum(Matrix.Multiply(m2, m1)); cameraOrigins[FrustumGroupIndex] = Vector3.Zero; // Primary axis-aligned box primaryAABox.Min = new Vector3(CAMERA_SPACING - 3, -4, -5); primaryAABox.Max = new Vector3(CAMERA_SPACING + 3, 4, 5); cameraOrigins[AABoxGroupIndex] = new Vector3(CAMERA_SPACING, 0, 0); // Primary oriented box primaryOBox.Center = new Vector3(-CAMERA_SPACING, 0, 0); primaryOBox.HalfExtent = new Vector3(3, 4, 5); primaryOBox.Orientation = Quaternion.CreateFromYawPitchRoll(0.8f, 0.7f, 0); cameraOrigins[OBoxGroupIndex] = primaryOBox.Center; // Primary sphere primarySphere.Center = new Vector3(0, 0, -CAMERA_SPACING); primarySphere.Radius = 5; cameraOrigins[SphereGroupIndex] = primarySphere.Center; // Primary ray primaryRay.Position = new Vector3(0, 0, CAMERA_SPACING); primaryRay.Direction = Vector3.UnitZ; cameraOrigins[RayGroupIndex] = primaryRay.Position; // Initialize all of the secondary objects with default values Vector3 half = new Vector3(0.5F, 0.5F, 0.5F); for (int i = 0; i < NumGroups; i++) { secondarySpheres[i] = new BoundingSphere(Vector3.Zero, 1.0f); secondaryOBoxes[i] = new BoundingOrientedBox(Vector3.Zero, half, Quaternion.Identity); secondaryAABoxes[i] = new BoundingBox(-half, half); secondaryTris[i] = new Triangle(); } rayHitResult = null; currentCamera = 3; cameraOrtho = false; cameraYaw = (float)Math.PI * 0.75F; cameraPitch = MathHelper.PiOver4; cameraDistance = 20; cameraTarget = cameraOrigins[0]; paused = false; base.Initialize(); }
public void DrawWireTriangle(Triangle t, Color color) { DrawWireTriangle(t.V0, t.V1, t.V2, color); }
/// <summary> /// Determines whether the given BoundingOrientedBox contains/intersects/is disjoint from the triangle /// (v0,v1,v2) /// </summary> public static ContainmentType Contains(ref BoundingOrientedBox obox, ref Vector3 v0, ref Vector3 v1, ref Vector3 v2) { // Transform the triangle into the local space of the box, so we can use a // faster axis-aligned box test. // Note than when transforming more than one point, using an intermediate matrix // is faster than doing multiple quaternion transforms directly. Quaternion qinv; Quaternion.Conjugate(ref obox.Orientation, out qinv); Matrix minv; Matrix.CreateFromQuaternion(ref qinv, out minv); Triangle localTri = new Triangle(); localTri.V0 = Vector3.TransformNormal(v0 - obox.Center, minv); localTri.V1 = Vector3.TransformNormal(v1 - obox.Center, minv); localTri.V2 = Vector3.TransformNormal(v2 - obox.Center, minv); return OriginBoxContains(ref obox.HalfExtent, ref localTri); }
/// <summary> /// Tests whether the given box contains, intersects, or is disjoint from the given triangle. /// </summary> public static ContainmentType Contains(ref BoundingBox box, ref Triangle triangle) { return Contains(ref box, ref triangle.V0, ref triangle.V1, ref triangle.V2); }
/// <summary> /// Check if an origin-centered, axis-aligned box with the given half extents contains, /// intersects, or is disjoint from the given triangle. This is used for the box and /// frustum vs. triangle tests. /// </summary> public static ContainmentType OriginBoxContains(ref Vector3 halfExtent, ref Triangle tri) { BoundingBox triBounds = new BoundingBox(); // 'new' to work around NetCF bug triBounds.Min.X = Math.Min(tri.V0.X, Math.Min(tri.V1.X, tri.V2.X)); triBounds.Min.Y = Math.Min(tri.V0.Y, Math.Min(tri.V1.Y, tri.V2.Y)); triBounds.Min.Z = Math.Min(tri.V0.Z, Math.Min(tri.V1.Z, tri.V2.Z)); triBounds.Max.X = Math.Max(tri.V0.X, Math.Max(tri.V1.X, tri.V2.X)); triBounds.Max.Y = Math.Max(tri.V0.Y, Math.Max(tri.V1.Y, tri.V2.Y)); triBounds.Max.Z = Math.Max(tri.V0.Z, Math.Max(tri.V1.Z, tri.V2.Z)); Vector3 triBoundhalfExtent; triBoundhalfExtent.X = (triBounds.Max.X - triBounds.Min.X) * 0.5f; triBoundhalfExtent.Y = (triBounds.Max.Y - triBounds.Min.Y) * 0.5f; triBoundhalfExtent.Z = (triBounds.Max.Z - triBounds.Min.Z) * 0.5f; Vector3 triBoundCenter; triBoundCenter.X = (triBounds.Max.X + triBounds.Min.X) * 0.5f; triBoundCenter.Y = (triBounds.Max.Y + triBounds.Min.Y) * 0.5f; triBoundCenter.Z = (triBounds.Max.Z + triBounds.Min.Z) * 0.5f; if (triBoundhalfExtent.X + halfExtent.X <= Math.Abs(triBoundCenter.X) || triBoundhalfExtent.Y + halfExtent.Y <= Math.Abs(triBoundCenter.Y) || triBoundhalfExtent.Z + halfExtent.Z <= Math.Abs(triBoundCenter.Z)) { return ContainmentType.Disjoint; } if (triBoundhalfExtent.X + Math.Abs(triBoundCenter.X) <= halfExtent.X && triBoundhalfExtent.Y + Math.Abs(triBoundCenter.Y) <= halfExtent.Y && triBoundhalfExtent.Z + Math.Abs(triBoundCenter.Z) <= halfExtent.Z) { return ContainmentType.Contains; } Vector3 edge1, edge2, edge3; Vector3.Subtract(ref tri.V1, ref tri.V0, out edge1); Vector3.Subtract(ref tri.V2, ref tri.V0, out edge2); Vector3 normal; Vector3.Cross(ref edge1, ref edge2, out normal); float triangleDist = Vector3.Dot(tri.V0, normal); if(Math.Abs(normal.X*halfExtent.X) + Math.Abs(normal.Y*halfExtent.Y) + Math.Abs(normal.Z*halfExtent.Z) <= Math.Abs(triangleDist)) { return ContainmentType.Disjoint; } // Worst case: we need to check all 9 possible separating planes // defined by Cross(box edge,triangle edge) // Check for separation in plane containing an axis of box A and and axis of box B // // We need to compute all 9 cross products to find them, but a lot of terms drop out // since we're working in A's local space. Also, since each such plane is parallel // to the defining axis in each box, we know those dot products will be 0 and can // omit them. Vector3.Subtract(ref tri.V1, ref tri.V2, out edge3); float dv0, dv1, dv2, dhalf; // a.X ^ b.X = (1,0,0) ^ edge1 // axis = Vector3(0, -edge1.Z, edge1.Y); dv0 = tri.V0.Z * edge1.Y - tri.V0.Y * edge1.Z; dv1 = tri.V1.Z * edge1.Y - tri.V1.Y * edge1.Z; dv2 = tri.V2.Z * edge1.Y - tri.V2.Y * edge1.Z; dhalf = Math.Abs(halfExtent.Y * edge1.Z) + Math.Abs(halfExtent.Z * edge1.Y); if (Math.Min(dv0, Math.Min(dv1, dv2)) >= dhalf || Math.Max(dv0, Math.Max(dv1, dv2)) <= -dhalf) return ContainmentType.Disjoint; // a.X ^ b.Y = (1,0,0) ^ edge2 // axis = Vector3(0, -edge2.Z, edge2.Y); dv0 = tri.V0.Z * edge2.Y - tri.V0.Y * edge2.Z; dv1 = tri.V1.Z * edge2.Y - tri.V1.Y * edge2.Z; dv2 = tri.V2.Z * edge2.Y - tri.V2.Y * edge2.Z; dhalf = Math.Abs(halfExtent.Y * edge2.Z) + Math.Abs(halfExtent.Z * edge2.Y); if (Math.Min(dv0, Math.Min(dv1, dv2)) >= dhalf || Math.Max(dv0, Math.Max(dv1, dv2)) <= -dhalf) return ContainmentType.Disjoint; // a.X ^ b.Y = (1,0,0) ^ edge3 // axis = Vector3(0, -edge3.Z, edge3.Y); dv0 = tri.V0.Z * edge3.Y - tri.V0.Y * edge3.Z; dv1 = tri.V1.Z * edge3.Y - tri.V1.Y * edge3.Z; dv2 = tri.V2.Z * edge3.Y - tri.V2.Y * edge3.Z; dhalf = Math.Abs(halfExtent.Y * edge3.Z) + Math.Abs(halfExtent.Z * edge3.Y); if (Math.Min(dv0, Math.Min(dv1, dv2)) >= dhalf || Math.Max(dv0, Math.Max(dv1, dv2)) <= -dhalf) return ContainmentType.Disjoint; // a.Y ^ b.X = (0,1,0) ^ edge1 // axis = Vector3(edge1.Z, 0, -edge1.X); dv0 = tri.V0.X * edge1.Z - tri.V0.Z * edge1.X; dv1 = tri.V1.X * edge1.Z - tri.V1.Z * edge1.X; dv2 = tri.V2.X * edge1.Z - tri.V2.Z * edge1.X; dhalf = Math.Abs(halfExtent.X * edge1.Z) + Math.Abs(halfExtent.Z * edge1.X); if (Math.Min(dv0, Math.Min(dv1, dv2)) >= dhalf || Math.Max(dv0, Math.Max(dv1, dv2)) <= -dhalf) return ContainmentType.Disjoint; // a.Y ^ b.X = (0,1,0) ^ edge2 // axis = Vector3(edge2.Z, 0, -edge2.X); dv0 = tri.V0.X * edge2.Z - tri.V0.Z * edge2.X; dv1 = tri.V1.X * edge2.Z - tri.V1.Z * edge2.X; dv2 = tri.V2.X * edge2.Z - tri.V2.Z * edge2.X; dhalf = Math.Abs(halfExtent.X * edge2.Z) + Math.Abs(halfExtent.Z * edge2.X); if (Math.Min(dv0, Math.Min(dv1, dv2)) >= dhalf || Math.Max(dv0, Math.Max(dv1, dv2)) <= -dhalf) return ContainmentType.Disjoint; // a.Y ^ b.X = (0,1,0) ^ bX // axis = Vector3(edge3.Z, 0, -edge3.X); dv0 = tri.V0.X * edge3.Z - tri.V0.Z * edge3.X; dv1 = tri.V1.X * edge3.Z - tri.V1.Z * edge3.X; dv2 = tri.V2.X * edge3.Z - tri.V2.Z * edge3.X; dhalf = Math.Abs(halfExtent.X * edge3.Z) + Math.Abs(halfExtent.Z * edge3.X); if (Math.Min(dv0, Math.Min(dv1, dv2)) >= dhalf || Math.Max(dv0, Math.Max(dv1, dv2)) <= -dhalf) return ContainmentType.Disjoint; // a.Y ^ b.X = (0,0,1) ^ edge1 // axis = Vector3(-edge1.Y, edge1.X, 0); dv0 = tri.V0.Y * edge1.X - tri.V0.X * edge1.Y; dv1 = tri.V1.Y * edge1.X - tri.V1.X * edge1.Y; dv2 = tri.V2.Y * edge1.X - tri.V2.X * edge1.Y; dhalf = Math.Abs(halfExtent.Y * edge1.X) + Math.Abs(halfExtent.X * edge1.Y); if (Math.Min(dv0, Math.Min(dv1, dv2)) >= dhalf || Math.Max(dv0, Math.Max(dv1, dv2)) <= -dhalf) return ContainmentType.Disjoint; // a.Y ^ b.X = (0,0,1) ^ edge2 // axis = Vector3(-edge2.Y, edge2.X, 0); dv0 = tri.V0.Y * edge2.X - tri.V0.X * edge2.Y; dv1 = tri.V1.Y * edge2.X - tri.V1.X * edge2.Y; dv2 = tri.V2.Y * edge2.X - tri.V2.X * edge2.Y; dhalf = Math.Abs(halfExtent.Y * edge2.X) + Math.Abs(halfExtent.X * edge2.Y); if (Math.Min(dv0, Math.Min(dv1, dv2)) >= dhalf || Math.Max(dv0, Math.Max(dv1, dv2)) <= -dhalf) return ContainmentType.Disjoint; // a.Y ^ b.X = (0,0,1) ^ edge3 // axis = Vector3(-edge3.Y, edge3.X, 0); dv0 = tri.V0.Y * edge3.X - tri.V0.X * edge3.Y; dv1 = tri.V1.Y * edge3.X - tri.V1.X * edge3.Y; dv2 = tri.V2.Y * edge3.X - tri.V2.X * edge3.Y; dhalf = Math.Abs(halfExtent.Y * edge3.X) + Math.Abs(halfExtent.X * edge3.Y); if (Math.Min(dv0, Math.Min(dv1, dv2)) >= dhalf || Math.Max(dv0, Math.Max(dv1, dv2)) <= -dhalf) return ContainmentType.Disjoint; return ContainmentType.Intersects; }
/// <summary> /// Determine whether the given triangle intersects the given ray. If there is intersection, /// returns the parametric value of the intersection point on the ray. Otherwise returns null. /// </summary> public static float? Intersects(ref Ray ray, ref Triangle tri) { return Intersects(ref ray, ref tri.V0, ref tri.V1, ref tri.V2); }
/// <summary> /// Returns true if the given sphere intersects the given triangle. /// </summary> public static bool Intersects(ref BoundingSphere sphere, ref Triangle t) { Vector3 p = NearestPointOnTriangle(ref sphere.Center, ref t.V0, ref t.V1, ref t.V2); return Vector3.DistanceSquared(sphere.Center, p) < sphere.Radius * sphere.Radius; }
/// <summary> /// Determines whether the given frustum contains/intersects/is disjoint from the /// given triangle. /// </summary> public static ContainmentType Contains(BoundingFrustum frustum, ref Triangle triangle) { return Contains(frustum, ref triangle.V0, ref triangle.V1, ref triangle.V2); }
/// <summary> /// Determines whether the given sphere contains/intersects/is disjoint from the /// given triangle. /// </summary> public static ContainmentType Contains(ref BoundingSphere sphere, ref Triangle triangle) { return Contains(ref sphere, ref triangle.V0, ref triangle.V1, ref triangle.V2); }