/// <summary> /// Ray/PlaneBoundedVolume intersection test. /// </summary> /// <param name="ray"></param> /// <param name="volume"></param> /// <returns>Struct that contains a bool (hit?) and distance.</returns> public static IntersectResult Intersects(Ray ray, PlaneBoundedVolume volume) { List <Plane> planes = volume.planes; float maxExtDist = 0.0f; float minIntDist = float.PositiveInfinity; float dist, denom, nom; for (int i = 0; i < planes.Count; i++) { Plane plane = planes[i]; denom = plane.Normal.Dot(ray.Direction); if (MathUtil.Abs(denom) < float.Epsilon) { // Parallel if (plane.GetSide(ray.Origin) == volume.outside) { return(new IntersectResult(false, 0)); } continue; } nom = plane.Normal.Dot(ray.Origin) + plane.D; dist = -(nom / denom); if (volume.outside == PlaneSide.Negative) { nom = -nom; } if (dist > 0.0f) { if (nom > 0.0f) { if (maxExtDist < dist) { maxExtDist = dist; } } else { if (minIntDist > dist) { minIntDist = dist; } } } else { //Ray points away from plane if (volume.outside == PlaneSide.Negative) { denom = -denom; } if (denom > 0.0f) { return(new IntersectResult(false, 0)); } } } if (maxExtDist > minIntDist) { return(new IntersectResult(false, 0)); } return(new IntersectResult(true, maxExtDist)); }
private void CheckShadowCasters(IList casters, PlaneBoundedVolume nearClipVol, Light light, bool extrudeInSoftware, bool finiteExtrude, bool zfailAlgo, Camera camera, float extrudeDistance, bool stencil2sided, List<Light> tmpLightList) { int flags; for(int i = 0; i < casters.Count; i++) { ShadowCaster caster = (ShadowCaster)casters[i]; if(nearClipVol.Intersects(caster.GetWorldBoundingBox())) { // We have a zfail case, we must use zfail for all objects zfailAlgo = true; break; } } for(int ci = 0; ci < casters.Count; ci++) { ShadowCaster caster = (ShadowCaster)casters[ci]; flags = 0; if (light.Type != LightType.Directional) { extrudeDistance = caster.GetPointExtrusionDistance(light); } if (!extrudeInSoftware && !finiteExtrude) { // hardware extrusion, to infinity (and beyond!) flags |= (int) ShadowRenderableFlags.ExtrudeToInfinity; } if(zfailAlgo) { // We need to include the light and / or dark cap // But only if they will be visible if(camera.IsObjectVisible(caster.GetLightCapBounds())) { flags |= (int) ShadowRenderableFlags.IncludeLightCap; } } // Dark cap (no dark cap for directional lights using // hardware extrusion to infinity) if(!((flags & (int)ShadowRenderableFlags.ExtrudeToInfinity) != 0 && light.Type == LightType.Directional) && camera.IsObjectVisible(caster.GetDarkCapBounds(light, extrudeDistance))) { flags |= (int) ShadowRenderableFlags.IncludeDarkCap; } // get shadow renderables IEnumerator renderables = caster.GetShadowVolumeRenderableEnumerator( shadowTechnique, light, shadowIndexBuffer, extrudeInSoftware, extrudeDistance, flags); // If using one-sided stencil, render the first pass of all shadow // renderables before all the second passes for (int i = 0; i < (stencil2sided ? 1 : 2); i++) { if (i == 1) renderables = caster.GetLastShadowVolumeRenderableEnumerator(); while(renderables.MoveNext()) { ShadowRenderable sr = (ShadowRenderable)renderables.Current; // omit hidden renderables if (sr.IsVisible) { // render volume, including dark and (maybe) light caps RenderSingleShadowVolumeToStencil(sr, zfailAlgo, stencil2sided, tmpLightList, (i > 0)); // optionally render separate light cap if (sr.IsLightCapSeperate && ((flags & (int)ShadowRenderableFlags.IncludeLightCap)) > 0) { // must always fail depth check targetRenderSystem.DepthFunction = CompareFunction.AlwaysFail; Debug.Assert(sr.LightCapRenderable != null, "Shadow renderable is missing a separate light cap renderable!"); RenderSingleShadowVolumeToStencil(sr.LightCapRenderable, zfailAlgo, stencil2sided, tmpLightList, (i > 0)); // reset depth function targetRenderSystem.DepthFunction = CompareFunction.Less; } } } } } }
/// <summary> /// Tests whether this ray intersects the given PlaneBoundedVolume. /// </summary> /// <param name="volume"></param> /// <returns> /// Struct containing info on whether there was a hit, and the distance from the /// origin of this ray where the intersect happened. /// </returns> public IntersectResult Intersects(PlaneBoundedVolume volume) { return(MathUtil.Intersects(this, volume)); }
/// <summary> /// Tests whether this ray intersects the given PlaneBoundedVolume. /// </summary> /// <param name="volume"></param> /// <returns> /// Struct containing info on whether there was a hit, and the distance from the /// origin of this ray where the intersect happened. /// </returns> public IntersectResult Intersects(PlaneBoundedVolume volume) { return MathUtil.Intersects(this, volume); }
public override void Execute(IIntersectionSceneQueryListener listener) { //Go through each leaf node in BspLevel and check movables against each other and world //Issue: some movable-movable intersections could be reported twice if 2 movables //overlap 2 leaves? BspLevel lvl = ((BspSceneManager) this.creator).Level; int leafPoint = lvl.LeafStart; int numLeaves = lvl.NumLeaves; Bsp.Collections.Map objIntersections = new Bsp.Collections.Map(); PlaneBoundedVolume boundedVolume = new PlaneBoundedVolume(PlaneSide.Positive); while ((numLeaves--) != 0) { BspNode leaf = lvl.Nodes[leafPoint]; MovableObjectCollection objects = leaf.Objects; int numObjects = objects.Count; for(int a = 0; a < numObjects; a++) { MovableObject aObj = objects[a]; // Skip this object if collision not enabled if((aObj.QueryFlags & queryMask) == 0) continue; if(a < (numObjects - 1)) { // Check object against others in this node int b = a; for (++b; b < numObjects; ++b) { MovableObject bObj = objects[b]; // Apply mask to b (both must pass) if ((bObj.QueryFlags & queryMask) != 0) { AxisAlignedBox box1 = aObj.GetWorldBoundingBox(); AxisAlignedBox box2 = bObj.GetWorldBoundingBox(); if (box1.Intersects(box2)) { //Check if this pair is already reported bool alreadyReported = false; IList interObjList = objIntersections.FindBucket(aObj); if (interObjList != null) if (interObjList.Contains(bObj)) alreadyReported = true; if (!alreadyReported) { objIntersections.Insert(aObj,bObj); listener.OnQueryResult(aObj,bObj); } } } } } // Check object against brushes /*----This is for bounding sphere----- float radius = aObj.BoundingRadius; //-------------------------------------------*/ for (int brushPoint=0; brushPoint < leaf.SolidBrushes.Length; brushPoint++) { BspBrush brush = leaf.SolidBrushes[brushPoint]; if (brush == null) continue; bool brushIntersect = true; // Assume intersecting for now /*----This is for bounding sphere----- IEnumerator planes = brush.Planes.GetEnumerator(); while (planes.MoveNext()) { float dist = ((Plane)planes.Current).GetDistance(pos); if (dist > radius) { // Definitely excluded brushIntersect = false; break; } } //-------------------------------------------*/ boundedVolume.planes = brush.Planes; //Test object as bounding box if (!boundedVolume.Intersects(aObj.GetWorldBoundingBox())) brushIntersect = false; if (brushIntersect) { //Check if this pair is already reported bool alreadyReported = false; IList interObjList = objIntersections.FindBucket(aObj); if (interObjList != null) if (interObjList.Contains(brush)) alreadyReported = true; if (!alreadyReported) { objIntersections.Insert(aObj,brush); // report this brush as it's WorldFragment brush.Fragment.FragmentType = WorldFragmentType.PlaneBoundedRegion; listener.OnQueryResult(aObj,brush.Fragment); } } } } ++leafPoint; } }
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; } }
protected virtual void ProcessLeaf(BspNode leaf) { MovableObjectCollection objects = leaf.Objects; int numObjects = objects.Count; //Check sphere 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 if(sphere.Intersects(obj.GetWorldBoundingBox())) { if (!foundIntersections.Contains(obj)) { listener.OnQueryResult(obj); foundIntersections.Add(obj); } } } PlaneBoundedVolume boundedVolume = new PlaneBoundedVolume(PlaneSide.Positive); // 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; if(boundedVolume.Intersects(sphere)) { listener.OnQueryResult(brush.Fragment); } } }