private static BSPNodeInfo ReadBSPNode(BinaryReader reader) { BSPNodeInfo node = new BSPNodeInfo(); bool isLeaf = reader.ReadByte() != 0; if (isLeaf) { UInt32 numTriangles = reader.ReadUInt32(); node.Triangles = new int[numTriangles]; for (UInt32 i = 0; i < numTriangles; i++) { node.Triangles[i] = reader.ReadInt32(); } } else { node.P.N = ReadVector3(reader); node.P.D = reader.ReadSingle(); node.Back = ReadBSPNode(reader); node.Front = ReadBSPNode(reader); } return(node); }
private static int NodeTriangleTest(Vector3 p0, Vector3 p1, CollisionInfo collision, BSPNodeInfo node, ref Vector3 hitPoint) { if (node.Triangles.Length == 0) { return(-1); } Vector3 d = (p1 - p0); float distanceToTarget = d.Length; // If the end point is basically the same as the start point, then there is no occlusion if (d.Length < Epsilon) { return(-1); } d = d.Normalize(); for (int i = 0; i < node.Triangles.Length; i++) { int t = node.Triangles[i]; var triangle = collision.Triangles[t]; var fixture = collision.Fixtures[triangle.fixture]; if (fixture.Hidden) { return(-1); } Vector3 v0 = collision.Vertices[triangle.i0]; Vector3 v1 = collision.Vertices[triangle.i1]; Vector3 v2 = collision.Vertices[triangle.i2]; float distance; if (RayTestTriangle(out distance, p0, d, v0, v1, v2, ref hitPoint)) { if (distance < distanceToTarget) { return(i); } } } return(-1); }
private static bool SegmentTest(Vector3 p0, Vector3 p1, CollisionInfo collision, BSPNodeInfo node, int depth, ref SegmentTestInfo info) { if (node == null) { return(false); } info.NumNodesTested++; info.MaxDepthReached = Math.Max(info.MaxDepthReached, depth); if (node.IsLeaf) { TriangleInfo hitTriangle = new TriangleInfo(); int tri = NodeTriangleTest(p0, p1, collision, node, ref info.HitPoint); info.NumTrianglesTested += (tri != -1) ? (tri + 1) : node.Triangles.Length; info.HitTriangle = hitTriangle; return(tri != -1); } else { float d0 = Vector3.Dot(node.P.N, p0) - node.P.D; float d1 = Vector3.Dot(node.P.N, p1) - node.P.D; if (d0 < -Epsilon && d1 < -Epsilon) { // Both points behind plane return(SegmentTest(p0, p1, collision, node.Back, depth + 1, ref info)); } else if (d0 > Epsilon && d1 > Epsilon) { // Both points in front of plane return(SegmentTest(p0, p1, collision, node.Front, depth + 1, ref info)); } else { // Points span plane return(SegmentTest(p0, p1, collision, node.Front, depth + 1, ref info) || SegmentTest(p0, p1, collision, node.Back, depth + 1, ref info)); } } }