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)); } } }
public static OcclusionResult OcclusionQuery( ushort zoneId0, float x0, float y0, float z0, ushort zoneId1, float x1, float y1, float z1, ref Vector3 hitpoint) { OcclusionResult result; SegmentTestInfo info = new SegmentTestInfo(); long timeBegin = DebugEnable ? Timer.Value : 0; try { ZoneInfo zone = _zones[zoneId0]; if (zone == null || zone.Collision == null) { result = OcclusionResult.NotLoaded; } else if (!zone.Enabled) { return(OcclusionResult.NotEnabled); } else if (zoneId0 != zoneId1) { result = OcclusionResult.NotImplemented; } else { x0 = 65535.0f - x0; x1 = 65535.0f - x1; Vector3 p0 = new Vector3(x0, y0, z0), p1 = new Vector3(x1, y1, z1); if (SegmentTest(p0, p1, zone.Collision, zone.Collision.BSP, 0, ref info)) { bool hit = true; double nearest = GetDistance(p0, info.HitPoint); var hitPoint = new Vector3(info.HitPoint.X, info.HitPoint.Y, info.HitPoint.Z); hitpoint = info.HitPoint; int count = 0; //find the nearest to origin triangle hit while (hit) { var nextPoint = Lerp(info.HitPoint, p0, 0.01); hit = SegmentTest(p0, nextPoint, zone.Collision, zone.Collision.BSP, 0, ref info); if (hit && (info.HitPoint.X != hitPoint.X || info.HitPoint.Y != hitPoint.Y || info.HitPoint.Z != hitPoint.Z) && GetDistance(p0, info.HitPoint) < nearest) { hitpoint = info.HitPoint; } hitPoint = new Vector3(info.HitPoint.X, info.HitPoint.Y, info.HitPoint.Z); if (count > 100) { break; } count++; } result = OcclusionResult.Occluded; hitpoint.X = 65535.0f - hitpoint.X; } else { result = OcclusionResult.NotOccluded; } } } catch { result = OcclusionResult.InternalError; } if (DebugEnable) { long microseconds = (Timer.Value - timeBegin) * 1000000 / Timer.Frequency; float timePerTri = microseconds / (float)info.NumTrianglesTested; String msg = String.Format( "LOS Check: ({0}, {1}, {2}, {3}) -> ({4}, {5}, {6}, {7}) -> ", zoneId0, x0, y0, z0, zoneId1, x1, y1, z1); Console.Write(msg); Console.WriteLine(result.ToString() + " [nodes=" + info.NumNodesTested + ", triangles=" + info.NumTrianglesTested + ", μs=" + microseconds + ", μs/tri=" + timePerTri + "]"); } return(result); }