protected virtual void ProcessNode(BspNode node, Ray tracingRay, float maxDistance, float traceDistance) { // check if ray already encountered a solid brush if (StopRayTracing) return; if (node.IsLeaf) { ProcessLeaf(node, tracingRay, maxDistance, traceDistance); return; } IntersectResult result = tracingRay.Intersects(node.SplittingPlane); if (result.Hit) { if (result.Distance < maxDistance) { if (node.GetSide(tracingRay.Origin) == PlaneSide.Negative) { ProcessNode(node.BackNode, tracingRay, result.Distance, traceDistance); Vector3 splitPoint = tracingRay.Origin + tracingRay.Direction * result.Distance; ProcessNode(node.FrontNode, new Ray(splitPoint, tracingRay.Direction), maxDistance - result.Distance, traceDistance + result.Distance); } else { ProcessNode(node.FrontNode, tracingRay, result.Distance, traceDistance); Vector3 splitPoint = tracingRay.Origin + tracingRay.Direction * result.Distance; ProcessNode(node.BackNode, new Ray(splitPoint, tracingRay.Direction), maxDistance - result.Distance, traceDistance + result.Distance); } } else ProcessNode(node.GetNextNode(tracingRay.Origin), tracingRay, maxDistance, traceDistance); } else ProcessNode(node.GetNextNode(tracingRay.Origin), tracingRay, maxDistance, traceDistance); }
public bool RayIntersection(Ray ray, out int x, out int z) { // generate a bounding box for the heightmap in its local space AxisAlignedBox axisAlignedBox = new AxisAlignedBox(new Vector3(0, minHeight, 0), new Vector3(width, maxHeight, height)); Vector3 rayLoc = new Vector3((ray.Origin.x - offsetX) / xzScale, ray.Origin.y / yScale, (ray.Origin.z - offsetZ) / xzScale); Vector3 rayDir = new Vector3(ray.Direction.x / xzScale, ray.Direction.y / yScale, ray.Direction.z / xzScale); rayDir.Normalize(); // convert the ray to local heightmap space Ray tmpRay = new Ray(rayLoc, rayDir); // see if the ray intersects with the bounding box IntersectResult result = tmpRay.Intersects(axisAlignedBox); if (result.Hit) { // move rayLoc up to just before the point of intersection rayLoc = rayLoc + rayDir * ( result.Distance - 1 ); // // deal with edge case where ray is coming from outside the heightmap // and is very near edge of map at intersection. // int insideCounter = 20; while ((!Inside(rayLoc)) && (insideCounter > 0)) { rayLoc += ( rayDir * 0.1f ); insideCounter--; } if (insideCounter == 0) { x = 0; z = 0; return false; } x = (int)Math.Round(rayLoc.x); z = (int)Math.Round(rayLoc.z); if (x < 0) { x = 0; } if (x >= width) { x = width - 1; } if (z < 0) { z = 0; } if (z >= height) { z = height - 1; } bool above = rayLoc.y > heightData[x + z * width]; while (Inside(rayLoc)) { // increment the ray rayLoc += rayDir; x = (int)Math.Round(rayLoc.x); z = (int)Math.Round(rayLoc.z); if (x < 0) { x = 0; } if (x >= width) { x = width - 1; } if (z < 0) { z = 0; } if (z >= height) { z = height - 1; } if (above != (rayLoc.y > heightData[x + z * width])) { // we found a hit return true; } } } x = 0; z = 0; return false; }
protected virtual void ProcessLeaf(BspNode leaf, Ray tracingRay, float maxDistance, float traceDistance) { MovableObjectCollection objects = leaf.Objects; int numObjects = objects.Count; //Check ray against objects for(int a = 0; a < numObjects; a++) { MovableObject obj = objects[a]; // Skip this object if collision not enabled if((obj.QueryFlags & queryMask) == 0) continue; //Test object as bounding box IntersectResult result = tracingRay.Intersects(obj.GetWorldBoundingBox()); // if the result came back positive and intersection point is inside // the node, fire the event handler if(result.Hit && result.Distance <= maxDistance) { listener.OnQueryResult(obj, result.Distance + traceDistance); } } PlaneBoundedVolume boundedVolume = new PlaneBoundedVolume(PlaneSide.Positive); BspBrush intersectBrush = null; float intersectBrushDist = float.PositiveInfinity; // Check ray against brushes for (int brushPoint=0; brushPoint < leaf.SolidBrushes.Length; brushPoint++) { BspBrush brush = leaf.SolidBrushes[brushPoint]; if (brush == null) continue; boundedVolume.planes = brush.Planes; IntersectResult result = tracingRay.Intersects(boundedVolume); // if the result came back positive and intersection point is inside // the node, check if this brush is closer if(result.Hit && result.Distance <= maxDistance) { if (result.Distance < intersectBrushDist) { intersectBrushDist = result.Distance; intersectBrush = brush; } } } if (intersectBrush != null) { listener.OnQueryResult(intersectBrush.Fragment, intersectBrushDist + traceDistance); StopRayTracing = true; } }