/// <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;
                            }
                        }
                    }
                }
            }
        }
Beispiel #3
0
 /// <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);
                }
            }
        }