Esempio n. 1
0
        private static void MeasureIntersectionPerformance(HeightField heightfield, Vector3 start, Vector3 end, int iterations)
        {
            Vector3 direction = end - start;

            MyIntersector intersector = new MyIntersector(heightfield);
            FootprintDebugInfo debugInfo = new FootprintDebugInfo();
            Intersection isec = intersector.Intersect(start, end, ref debugInfo);
            int visitedPixels = debugInfo.VisitedPixels.Count;

            Stopwatch sw = Stopwatch.StartNew();
            for (int i = 0; i < iterations; i++)
            {
                Intersection intersection = intersector.Intersect(start, end);
            }
            sw.Stop();

            Console.WriteLine("Intersection?: {0}", isec != null);
            Console.WriteLine("Ray length: {0:0.0}", direction.Length);
            Console.WriteLine("Visited pixels: {0}", visitedPixels);
            Console.WriteLine("Iterations: {0}", iterations);
            Console.WriteLine("Total time: {0} ms", sw.ElapsedMilliseconds);
            Console.WriteLine("Average time: {0:0.000} ms", sw.ElapsedMilliseconds / (double)iterations);
            double throughput = iterations / ((double)sw.ElapsedMilliseconds * 0.001);
            Console.WriteLine("Throughput: {0:0.000} traversals/s", throughput);
            Console.WriteLine("Throughput of visited pixels: {0:0.000} Mpx/s", throughput * visitedPixels * 1e-6);
        }
Esempio n. 2
0
        internal override Intersection Intersect(
            Vector3 start, Vector3 end,
            ref FootprintDebugInfo debugInfo)
        {
            int stepCount = 5;

            //float near = 2;
            //float far = 10;
            //Vector2 start = (near / (float)ray.Direction.Z) * new Vector2((float)ray.Origin.X, (float)ray.Origin.Y);
            //Vector3d rayEnd = ray.Origin + ray.Direction;
            //Vector2 end = (far / (float)ray.Direction.Z) * new Vector2((float)rayEnd.X, (float)rayEnd.Y);

            Vector2 startXY = start.Xy;
            Vector2 endXY   = end.Xy;

            float depthSize    = 1;
            float currentDepth = 0;
            float isecDepth    = 1;

            Vector2 position = startXY;

            for (int i = 0; i < stepCount; i++)
            {
                depthSize *= 0.5f;
                position   = startXY + currentDepth * endXY;
                float hfDepth = HeightField.GetDepthBilinear(position, 0);
                if (currentDepth >= hfDepth)
                {
                    isecDepth     = currentDepth;
                    currentDepth -= 2 * depthSize;
                }
                currentDepth += depthSize;
            }
            if (isecDepth < (1 - 0.0001))
            {
                return(new Intersection(new Vector3d(position.X, position.Y, isecDepth)));
            }
            else
            {
                return(null);
            }
        }
        internal override Intersection Intersect(
            Vector3 start, Vector3 end,
            ref FootprintDebugInfo debugInfo)
        {
            int stepCount = 5;

            //float near = 2;
            //float far = 10;
            //Vector2 start = (near / (float)ray.Direction.Z) * new Vector2((float)ray.Origin.X, (float)ray.Origin.Y);
            //Vector3d rayEnd = ray.Origin + ray.Direction;
            //Vector2 end = (far / (float)ray.Direction.Z) * new Vector2((float)rayEnd.X, (float)rayEnd.Y);

            Vector2 startXY = start.Xy;
            Vector2 endXY = end.Xy;

            float depthSize = 1;
            float currentDepth = 0;
            float isecDepth = 1;

            Vector2 position = startXY;

            for (int i = 0; i < stepCount; i++)
            {
                depthSize *= 0.5f;
                position = startXY + currentDepth * endXY;
                float hfDepth = HeightField.GetDepthBilinear(position, 0);
                if (currentDepth >= hfDepth)
                {
                    isecDepth = currentDepth;
                    currentDepth -= 2 * depthSize;
                }
                currentDepth += depthSize;
            }
            if (isecDepth < (1 - 0.0001))
            {
                return new Intersection(new Vector3d(position.X, position.Y, isecDepth));
            }
            else
            {
                return null;
            }
        }
        internal override Intersection Intersect(Vector3 start, Vector3 end, ref FootprintDebugInfo debugInfo)
        {
            int steps = (int)Math.Floor(Math.Max((end - start).Xy.Length, 1));
            Vector3 rayStep = (end - start) / (float)steps;
            //Vector3 rayStep = (end - start) / (float)Steps;

            Vector3 currentPos = start;
            int prevIndicator = GetRayLayerIndicator(start.Z, HeightField.GetDepthBilinear(start.Xy, 0));
            int isecLayer = 0;

            for (int i = 0; i < steps; i++)
            {
                currentPos += rayStep;
                float layerDepth = HeightField.GetDepthBilinear(currentPos.Xy, 0);
                int indicator = GetRayLayerIndicator(currentPos.Z, layerDepth);
                if (layerDepth > 0)
                {
                    // some data present

                    // Find the first layer with indicator value 1. In case
                    // of a single layer it is the single value.
                    int indicatorDiff = prevIndicator - indicator;
                    if (indicatorDiff == 1)
                    {
                        isecLayer = 1;
                    }
                    if (isecLayer != 0)
                    {
                        if (debugInfo != null)
                        {
                            debugInfo.LayerOfIntersection = isecLayer - 1;
                        }
                        return new Intersection((Vector3d)currentPos);
                        // TODO: grab color from the particular color layer
                    }
                }
                prevIndicator = indicator;
            }
            return null;
        }
        internal override Intersection Intersect(Vector3 start, Vector3 end, ref FootprintDebugInfo debugInfo)
        {
            int     steps   = (int)Math.Floor(Math.Max((end - start).Xy.Length, 1));
            Vector3 rayStep = (end - start) / (float)steps;
            //Vector3 rayStep = (end - start) / (float)Steps;

            Vector3 currentPos    = start;
            int     prevIndicator = GetRayLayerIndicator(start.Z, HeightField.GetDepthBilinear(start.Xy, 0));
            int     isecLayer     = 0;

            for (int i = 0; i < steps; i++)
            {
                currentPos += rayStep;
                float layerDepth = HeightField.GetDepthBilinear(currentPos.Xy, 0);
                int   indicator  = GetRayLayerIndicator(currentPos.Z, layerDepth);
                if (layerDepth > 0)
                {
                    // some data present

                    // Find the first layer with indicator value 1. In case
                    // of a single layer it is the single value.
                    int indicatorDiff = prevIndicator - indicator;
                    if (indicatorDiff == 1)
                    {
                        isecLayer = 1;
                    }
                    if (isecLayer != 0)
                    {
                        if (debugInfo != null)
                        {
                            debugInfo.LayerOfIntersection = isecLayer - 1;
                        }
                        return(new Intersection((Vector3d)currentPos));
                        // TODO: grab color from the particular color layer
                    }
                }
                prevIndicator = indicator;
            }
            return(null);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        internal override Intersection Intersect(
            Vector3 start, Vector3 end,
            ref FootprintDebugInfo debugInfo)
        {
            bool collectDebugInfo = debugInfo != null;

            #region initialization
            Vector2 rayStart = start.Xy;
            Vector2 rayEnd   = end.Xy;
            Vector3 dir      = end - start;
            Vector2 rayDir   = dir.Xy;

            // make sure the denominator in tMax and tDelta is not zero
            if (Math.Abs(rayDir.X) < epsilonForRayDir)
            {
                rayDir.X = epsilonForRayDir;
            }
            if (Math.Abs(rayDir.Y) < epsilonForRayDir)
            {
                rayDir.Y = epsilonForRayDir;
            }

            Vector2 step = new Vector2(Math.Sign(rayDir.X), Math.Sign(rayDir.Y));

            Vector2 currentPixel = GetPixelCorner(start.Xy, step);
            Vector2 endPixel     = GetPixelCorner(start.Xy + rayDir, -step);

            Vector2 boundary = new Vector2(
                currentPixel.X + ((step.X > 0) ? 1 : 0),
                currentPixel.Y + ((step.Y > 0) ? 1 : 0));

            Vector2 boundaryToStart = boundary - rayStart;

            Vector2 rayDirInv = new Vector2(1 / rayDir.X, 1 / rayDir.Y);

            Vector2 tMax   = new Vector2(boundaryToStart.X * rayDirInv.X, boundaryToStart.Y * rayDirInv.Y);
            Vector2 tDelta = new Vector2(step.X * rayDirInv.X, step.Y * rayDirInv.Y);

            if (collectDebugInfo)
            {
                debugInfo.StartPixel = currentPixel;
                debugInfo.EndPixel   = endPixel;
            }

            #endregion

            #region traversal

            List <Vector2> footprintPixels = new List <Vector2>();

            int maxIterations = (int)(2 * rayDir.Length);
            int iterations    = 0;
            debugInfo.EntryPoints.Add(rayStart);
            Vector3 entry = start;
            while (currentPixel != endPixel)
            {
                if (collectDebugInfo)
                {
                    debugInfo.VisitedPixels.Add(currentPixel);
                    //debugInfo.EntryPoints.Add(rayStart + Math.Min(tMax.X, tMax.Y) * rayDir);
                    debugInfo.EntryPoints.Add(entry.Xy);
                }

                Vector3 exit;
                if (tMax.X < tMax.Y)
                {
                    exit            = start + tMax.X * dir;
                    tMax.X         += tDelta.X;
                    currentPixel.X += step.X;
                }
                else
                {
                    exit            = start + tMax.Y * dir;
                    tMax.Y         += tDelta.Y;
                    currentPixel.Y += step.Y;
                }

                // height field intersection
                for (int layer = 0; layer < this.HeightField.LayerCount; layer++)
                {
                    float layerZ = this.HeightField.GetDepth((int)currentPixel.X, (int)currentPixel.Y, layer);
                    // we could compare:
                    // (1) sign(entry.Z - hf[pixel.xy]) != sign(exit.Z - hf[pixel.xy])
                    // (2) sign(entry.Z - hf[entry.xy]) != sign(exit.Z - hf[exit.xy])
                    // (3) sign(entry.Z - hf[middle.xy]) != sign(exit.Z - hf[middle.xy])
                    //Vector2 middle = 0.5f * (exit.Xy - entry.Xy);
                    //float layerZ = this.HeightField.GetDepth((int)middle.X, (int)middle.Y, 0);
                    if ((Math.Sign(layerZ - entry.Z) != Math.Sign(layerZ - exit.Z)))
                    {
                        if (collectDebugInfo)
                        {
                            debugInfo.LayerOfIntersection = layer;
                        }
                        return(new Intersection(new Vector3d(currentPixel.X, currentPixel.Y, layerZ)));
                    }
                }

                entry = exit;

                if (iterations == maxIterations)
                {
                    break;
                }
                iterations++;
            }
            debugInfo.VisitedPixels.Add(currentPixel);
            debugInfo.EntryPoints.Add(rayEnd);

            #endregion

            return(null);
        }
Esempio n. 7
0
        /// <summary>
        /// Intersects a height field with a ray.
        /// </summary>
        /// <remarks>
        /// <para>
        /// A height field is a layered 2D table with depth values. At each
        /// position there can be multiple pixels in layers ordered by
        /// increasing depth.
        /// </para>
        /// <para>
        /// This procedures find the position of intersection in the
        /// height field along with the depth of the intersected pixel, or
        /// a zero vector in case of no intersection, and indicates if there
        /// was an intersection.
        /// </para>
        /// <para>
        /// Note that there is are only divisions at beginning and the loop
        /// contains only additions, multiplications, Math.Abs() and
        /// height field table lookups.
        /// </para>
        /// <para>
        /// Based on the line footprint traversal algorithm. See
        /// BokehLab.Math.LineFootprint.
        /// </para>
        /// </remarks>
        /// <param name="ray">incoming ray</param>
        /// <param name="heightfield">height field to be intersected</param>
        /// <returns>Intersection instance - position of the intersection in
        /// the height field (only the pixel corner, not the exact position)
        /// - if the was an intersection; null otherwise</returns>
        internal override Intersection Intersect(
            Vector3 start, Vector3 end,
            ref FootprintDebugInfo debugInfo)
        {
            bool collectDebugInfo = debugInfo != null;

            Vector3 rayDirection = end - start;

            if (Math.Abs(rayDirection.Z) < epsilonForCorners)
            {
                return null;
            }
            bool rayGoesFromDepth = rayDirection.Z < 0;

            Vector2 dir = rayDirection.Xy;
            bool rayGoesRatherHorizontal = Math.Abs(dir.X) > Math.Abs(dir.Y);

            Vector2 dirInv = new Vector2((float)(1 / dir.X), (float)(1 / dir.Y));
            Vector2 rayDzOverDxy = rayDirection.Z * dirInv;
            // direction to the nearest corner: [1,1], [1,-1], [-1,1] or [-1,-1]
            Vector2 relDir = new Vector2(Math.Sign(dir.X), Math.Sign(dir.Y));
            bool isDirectionAxisAligned = relDir.X * relDir.Y == 0;
            // relDir converted to a single pixel: [1,1], [1,0], [0,1] or [0,0]
            Vector2 relCorner = isDirectionAxisAligned ? relDir : (0.5f * (relDir + new Vector2(1, 1)));

            // point where the 2D ray projection enters the current pixel
            Vector3 entry = start;
            Vector2 entryXY = entry.Xy;

            Vector2 currentPixel = GetPixelCorner(entryXY, relDir);
            Vector2 endPixel = GetPixelCorner(end.Xy, -relDir);

            if (collectDebugInfo)
            {
                debugInfo.StartPixel = currentPixel;
                debugInfo.EndPixel = endPixel;
            }

            // absolute position of the nearest corner
            Vector2 corner = currentPixel + relCorner;

            // depth of the last square in the previous pixel which was
            // completely in front of the ray
            float? previousLastZ = null;

            while (currentPixel != endPixel)
            {
                if (collectDebugInfo)
                {
                    debugInfo.VisitedPixels.Add(currentPixel);
                    debugInfo.EntryPoints.Add(entryXY);
                }

                if ((currentPixel.X < 0) || (currentPixel.X >= this.HeightField.Width) ||
                    (currentPixel.Y < 0) || (currentPixel.Y >= this.HeightField.Height))
                {
                    return null;
                }

                // We can only decide the orientation to nearest corner only
                // if the ray direction in the XY plane is axis aligned.
                // Otherwise we have to use the original relative direction.
                // Also this direction is used if traversing directly across
                // the corner.

                Vector2 nextDir = relDir; // across the corner by default
                if (!isDirectionAxisAligned)
                {
                    // Get a direction of a vector perpendicular to directions
                    // from the current position both to the nearest corner and
                    // the end of the ray (it is aligned with the Z axis).

                    float crossLength = (corner.X - entryXY.X) * (end.Y - entryXY.Y)
                        - (corner.Y - entryXY.Y) * (end.X - entryXY.X);
                    //   it is equavalent to:
                    // float crossLength = Cross2d(corner - entryXY, end.Xy - entryXY);
                    //   or to:
                    // float crossLength = Vector3.Cross(new Vector3(corner - entryXY), new Vector3(rayEnd - entryXY)).Z;

                    // The direction of the cross vector determines the relative
                    // orientation of the two examined vectors:
                    // 0 (+- epsilon) -> go across the corner
                    // > 0 -> go to the clockwise edge
                    // < 0 -> go to the counter-clockwise edge

                    if (Math.Abs(crossLength) > epsilonForCorners)
                    {
                        // add a vector perpendicular in one or another direction
                        // to get a vector 45 degrees apart from the corner
                        Vector2 cw = new Vector2(-relDir.Y, relDir.X);
                        if (crossLength > 0)
                        {
                            // (relDir + ccw) / 2 -> clockwise edge
                            nextDir += cw;
                        }
                        else
                        {
                            // (relDir - ccw) / 2 -> counter-clockwise edge
                            nextDir -= cw;
                        }
                        nextDir *= 0.5f;
                    }
                }

                // point where the 2D ray projection exits the current pixel
                Vector3 exit = new Vector3(IntersectPixelEdge2d(entryXY, dir, dirInv, corner, nextDir));
                if (rayGoesRatherHorizontal)
                {
                    exit.Z = start.Z + (exit.X - start.X) * rayDzOverDxy.X;
                }
                else
                {
                    exit.Z = start.Z + (exit.Y - start.Y) * rayDzOverDxy.Y;
                }

                // compute intersection with the height field pixel (in several layers)
                Intersection isec = IntersectLayerAtPixel(currentPixel, entry.Z, exit.Z, rayGoesFromDepth, collectDebugInfo, debugInfo, ref previousLastZ);
                if (isec != null)
                {
                    return isec;
                }

                entry = exit;
                entryXY = entry.Xy;
                currentPixel += nextDir;
                corner += nextDir;
            }

            // tail of the ray (the end pixel)
            if (collectDebugInfo)
            {
                debugInfo.VisitedPixels.Add(currentPixel);
                debugInfo.EntryPoints.Add(entryXY);
            }
            return IntersectLayerAtPixel(currentPixel, entry.Z, end.Z, rayGoesFromDepth, collectDebugInfo, debugInfo, ref previousLastZ);
        }
Esempio n. 8
0
 private Intersection IntersectLayerAtPixel(
     Vector2 currentPixel,
     float entryZ,
     float exitZ,
     bool rayGoesFromDepth,
     bool collectDebugInfo,
     FootprintDebugInfo debugInfo,
     ref float? previousLastZ)
 {
     // depth of the last square in the current pixel which was
     // completely in front of the ray
     float? currentLastZ = null;
     int layer;
     for (layer = 0; layer < this.HeightField.LayerCount; layer++)
     {
         // Tests whether a ray going over a height field pixel intersects it or not.
         //
         // There is an intersection if the heightfield pixel depth is between
         // depths of ray entry and exit points. In case of equality (up to
         // epsilon) the ray touches the pixel. Otherwise it misses the pixel.
         float layerZ = this.HeightField.GetDepth((int)currentPixel.X, (int)currentPixel.Y, layer);
         if (layerZ == 1)
         {
             // early termination - no data in the height field
             break;
         }
         if (layer == 0)
         {
             currentLastZ = layerZ;
         }
         if (Math.Sign(entryZ - layerZ) != Math.Sign(exitZ - layerZ))
         {
             // ray crosses the square, proper intersection
             if (collectDebugInfo)
             {
                 debugInfo.LayerOfIntersection = layer;
             }
             return new Intersection(new Vector3d(currentPixel.X, currentPixel.Y, layerZ));
         }
         else if ((layerZ > exitZ) ^ rayGoesFromDepth)
         {
             // termination since the rest of layers is also behind
             break;
         }
         // else: ray misses the square in front of it
         currentLastZ = layerZ;
     }
     // ray misses the square behind it
     if (previousLastZ.HasValue && currentLastZ.HasValue)
     {
         //float diff = (rayGoesFromDepth ? -1 : 1) *
         //    (previousLastZ.Value - currentLastZ.Value);
         //if ((diff > 0) && (diff < epsilonForClosePixelDepth))
         //{
         float diff = previousLastZ.Value - currentLastZ.Value;
         if ((Math.Sign(currentLastZ.Value - entryZ) != Math.Sign(previousLastZ.Value - entryZ)) &&
             (Math.Abs(diff) < EpsilonForClosePixelDepth))
         {
             // in case the squares of subsequent pixels are too
             // close and the ray goes between them we can consider
             // it an intersection
             if (collectDebugInfo)
             {
                 debugInfo.LayerOfIntersection = layer;
             }
             return new Intersection(new Vector3d(currentPixel.X, currentPixel.Y, 0.5f * diff));
         }
     }
     previousLastZ = currentLastZ;
     return null;
 }
Esempio n. 9
0
        /// <summary>
        /// Intersects a height field with a ray.
        /// </summary>
        /// <remarks>
        /// <para>
        /// A height field is a layered 2D table with depth values. At each
        /// position there can be multiple pixels in layers ordered by
        /// increasing depth.
        /// </para>
        /// <para>
        /// This procedures find the position of intersection in the
        /// height field along with the depth of the intersected pixel, or
        /// a zero vector in case of no intersection, and indicates if there
        /// was an intersection.
        /// </para>
        /// <para>
        /// Note that there is are only divisions at beginning and the loop
        /// contains only additions, multiplications, Math.Abs() and
        /// height field table lookups.
        /// </para>
        /// <para>
        /// Based on the line footprint traversal algorithm. See
        /// BokehLab.Math.LineFootprint.
        /// </para>
        /// </remarks>
        /// <param name="ray">incoming ray</param>
        /// <param name="heightfield">height field to be intersected</param>
        /// <returns>Intersection instance - position of the intersection in
        /// the height field (only the pixel corner, not the exact position)
        /// - if the was an intersection; null otherwise</returns>
        internal override Intersection Intersect(
            Vector3 start, Vector3 end,
            ref FootprintDebugInfo debugInfo)
        {
            bool collectDebugInfo = debugInfo != null;

            Vector3 rayDirection = end - start;

            if (Math.Abs(rayDirection.Z) < epsilonForCorners)
            {
                return(null);
            }
            bool rayGoesFromDepth = rayDirection.Z < 0;

            Vector2 dir = rayDirection.Xy;
            bool    rayGoesRatherHorizontal = Math.Abs(dir.X) > Math.Abs(dir.Y);

            Vector2 dirInv       = new Vector2((float)(1 / dir.X), (float)(1 / dir.Y));
            Vector2 rayDzOverDxy = rayDirection.Z * dirInv;
            // direction to the nearest corner: [1,1], [1,-1], [-1,1] or [-1,-1]
            Vector2 relDir = new Vector2(Math.Sign(dir.X), Math.Sign(dir.Y));
            bool    isDirectionAxisAligned = relDir.X * relDir.Y == 0;
            // relDir converted to a single pixel: [1,1], [1,0], [0,1] or [0,0]
            Vector2 relCorner = isDirectionAxisAligned ? relDir : (0.5f * (relDir + new Vector2(1, 1)));

            // point where the 2D ray projection enters the current pixel
            Vector3 entry   = start;
            Vector2 entryXY = entry.Xy;

            Vector2 currentPixel = GetPixelCorner(entryXY, relDir);
            Vector2 endPixel     = GetPixelCorner(end.Xy, -relDir);

            if (collectDebugInfo)
            {
                debugInfo.StartPixel = currentPixel;
                debugInfo.EndPixel   = endPixel;
            }

            // absolute position of the nearest corner
            Vector2 corner = currentPixel + relCorner;

            // depth of the last square in the previous pixel which was
            // completely in front of the ray
            float?previousLastZ = null;

            while (currentPixel != endPixel)
            {
                if (collectDebugInfo)
                {
                    debugInfo.VisitedPixels.Add(currentPixel);
                    debugInfo.EntryPoints.Add(entryXY);
                }

                if ((currentPixel.X < 0) || (currentPixel.X >= this.HeightField.Width) ||
                    (currentPixel.Y < 0) || (currentPixel.Y >= this.HeightField.Height))
                {
                    return(null);
                }

                // We can only decide the orientation to nearest corner only
                // if the ray direction in the XY plane is axis aligned.
                // Otherwise we have to use the original relative direction.
                // Also this direction is used if traversing directly across
                // the corner.

                Vector2 nextDir = relDir; // across the corner by default
                if (!isDirectionAxisAligned)
                {
                    // Get a direction of a vector perpendicular to directions
                    // from the current position both to the nearest corner and
                    // the end of the ray (it is aligned with the Z axis).

                    float crossLength = (corner.X - entryXY.X) * (end.Y - entryXY.Y)
                                        - (corner.Y - entryXY.Y) * (end.X - entryXY.X);
                    //   it is equavalent to:
                    // float crossLength = Cross2d(corner - entryXY, end.Xy - entryXY);
                    //   or to:
                    // float crossLength = Vector3.Cross(new Vector3(corner - entryXY), new Vector3(rayEnd - entryXY)).Z;

                    // The direction of the cross vector determines the relative
                    // orientation of the two examined vectors:
                    // 0 (+- epsilon) -> go across the corner
                    // > 0 -> go to the clockwise edge
                    // < 0 -> go to the counter-clockwise edge

                    if (Math.Abs(crossLength) > epsilonForCorners)
                    {
                        // add a vector perpendicular in one or another direction
                        // to get a vector 45 degrees apart from the corner
                        Vector2 cw = new Vector2(-relDir.Y, relDir.X);
                        if (crossLength > 0)
                        {
                            // (relDir + ccw) / 2 -> clockwise edge
                            nextDir += cw;
                        }
                        else
                        {
                            // (relDir - ccw) / 2 -> counter-clockwise edge
                            nextDir -= cw;
                        }
                        nextDir *= 0.5f;
                    }
                }

                // point where the 2D ray projection exits the current pixel
                Vector3 exit = new Vector3(IntersectPixelEdge2d(entryXY, dir, dirInv, corner, nextDir));
                if (rayGoesRatherHorizontal)
                {
                    exit.Z = start.Z + (exit.X - start.X) * rayDzOverDxy.X;
                }
                else
                {
                    exit.Z = start.Z + (exit.Y - start.Y) * rayDzOverDxy.Y;
                }

                // compute intersection with the height field pixel (in several layers)
                Intersection isec = IntersectLayerAtPixel(currentPixel, entry.Z, exit.Z, rayGoesFromDepth, collectDebugInfo, debugInfo, ref previousLastZ);
                if (isec != null)
                {
                    return(isec);
                }

                entry         = exit;
                entryXY       = entry.Xy;
                currentPixel += nextDir;
                corner       += nextDir;
            }

            // tail of the ray (the end pixel)
            if (collectDebugInfo)
            {
                debugInfo.VisitedPixels.Add(currentPixel);
                debugInfo.EntryPoints.Add(entryXY);
            }
            return(IntersectLayerAtPixel(currentPixel, entry.Z, end.Z, rayGoesFromDepth, collectDebugInfo, debugInfo, ref previousLastZ));
        }
Esempio n. 10
0
        private Intersection IntersectLayerAtPixel(
            Vector2 currentPixel,
            float entryZ,
            float exitZ,
            bool rayGoesFromDepth,
            bool collectDebugInfo,
            FootprintDebugInfo debugInfo,
            ref float?previousLastZ)
        {
            // depth of the last square in the current pixel which was
            // completely in front of the ray
            float?currentLastZ = null;
            int   layer;

            for (layer = 0; layer < this.HeightField.LayerCount; layer++)
            {
                // Tests whether a ray going over a height field pixel intersects it or not.
                //
                // There is an intersection if the heightfield pixel depth is between
                // depths of ray entry and exit points. In case of equality (up to
                // epsilon) the ray touches the pixel. Otherwise it misses the pixel.
                float layerZ = this.HeightField.GetDepth((int)currentPixel.X, (int)currentPixel.Y, layer);
                if (layerZ == 1)
                {
                    // early termination - no data in the height field
                    break;
                }
                if (layer == 0)
                {
                    currentLastZ = layerZ;
                }
                if (Math.Sign(entryZ - layerZ) != Math.Sign(exitZ - layerZ))
                {
                    // ray crosses the square, proper intersection
                    if (collectDebugInfo)
                    {
                        debugInfo.LayerOfIntersection = layer;
                    }
                    return(new Intersection(new Vector3d(currentPixel.X, currentPixel.Y, layerZ)));
                }
                else if ((layerZ > exitZ) ^ rayGoesFromDepth)
                {
                    // termination since the rest of layers is also behind
                    break;
                }
                // else: ray misses the square in front of it
                currentLastZ = layerZ;
            }
            // ray misses the square behind it
            if (previousLastZ.HasValue && currentLastZ.HasValue)
            {
                //float diff = (rayGoesFromDepth ? -1 : 1) *
                //    (previousLastZ.Value - currentLastZ.Value);
                //if ((diff > 0) && (diff < epsilonForClosePixelDepth))
                //{
                float diff = previousLastZ.Value - currentLastZ.Value;
                if ((Math.Sign(currentLastZ.Value - entryZ) != Math.Sign(previousLastZ.Value - entryZ)) &&
                    (Math.Abs(diff) < EpsilonForClosePixelDepth))
                {
                    // in case the squares of subsequent pixels are too
                    // close and the ray goes between them we can consider
                    // it an intersection
                    if (collectDebugInfo)
                    {
                        debugInfo.LayerOfIntersection = layer;
                    }
                    return(new Intersection(new Vector3d(currentPixel.X, currentPixel.Y, 0.5f * diff)));
                }
            }
            previousLastZ = currentLastZ;
            return(null);
        }
Esempio n. 11
0
 internal abstract Intersection Intersect(Vector3 start, Vector3 end, ref FootprintDebugInfo debugInfo);
        public Intersection Intersect(Ray ray)
        {
            FootprintDebugInfo debugInfo = null;

            return(Intersect((Vector3)ray.Origin, (Vector3)(ray.Origin + ray.Direction), ref debugInfo));
        }
        public Intersection Intersect(Vector3 start, Vector3 end)
        {
            FootprintDebugInfo debugInfo = null;

            return(Intersect(start, end, ref debugInfo));
        }
 internal abstract Intersection Intersect(Vector3 start, Vector3 end, ref FootprintDebugInfo debugInfo);
Esempio n. 15
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        internal override Intersection Intersect(
            Vector3 start, Vector3 end,
            ref FootprintDebugInfo debugInfo)
        {
            bool collectDebugInfo = debugInfo != null;

            #region initialization
            Vector2 rayStart = start.Xy;
            Vector2 rayEnd = end.Xy;
            Vector3 dir = end - start;
            Vector2 rayDir = dir.Xy;

            // make sure the denominator in tMax and tDelta is not zero
            if (Math.Abs(rayDir.X) < epsilonForRayDir)
            {
                rayDir.X = epsilonForRayDir;
            }
            if (Math.Abs(rayDir.Y) < epsilonForRayDir)
            {
                rayDir.Y = epsilonForRayDir;
            }

            Vector2 step = new Vector2(Math.Sign(rayDir.X), Math.Sign(rayDir.Y));

            Vector2 currentPixel = GetPixelCorner(start.Xy, step);
            Vector2 endPixel = GetPixelCorner(start.Xy + rayDir, -step);

            Vector2 boundary = new Vector2(
                currentPixel.X + ((step.X > 0) ? 1 : 0),
                currentPixel.Y + ((step.Y > 0) ? 1 : 0));

            Vector2 boundaryToStart = boundary - rayStart;

            Vector2 rayDirInv = new Vector2(1 / rayDir.X, 1 / rayDir.Y);

            Vector2 tMax = new Vector2(boundaryToStart.X * rayDirInv.X, boundaryToStart.Y * rayDirInv.Y);
            Vector2 tDelta = new Vector2(step.X * rayDirInv.X, step.Y * rayDirInv.Y);

            if (collectDebugInfo)
            {
                debugInfo.StartPixel = currentPixel;
                debugInfo.EndPixel = endPixel;
            }

            #endregion

            #region traversal

            List<Vector2> footprintPixels = new List<Vector2>();

            int maxIterations = (int)(2 * rayDir.Length);
            int iterations = 0;
            debugInfo.EntryPoints.Add(rayStart);
            Vector3 entry = start;
            while (currentPixel != endPixel)
            {
                if (collectDebugInfo)
                {
                    debugInfo.VisitedPixels.Add(currentPixel);
                    //debugInfo.EntryPoints.Add(rayStart + Math.Min(tMax.X, tMax.Y) * rayDir);
                    debugInfo.EntryPoints.Add(entry.Xy);
                }

                Vector3 exit;
                if (tMax.X < tMax.Y)
                {
                    exit = start + tMax.X * dir;
                    tMax.X += tDelta.X;
                    currentPixel.X += step.X;
                }
                else
                {
                    exit = start + tMax.Y * dir;
                    tMax.Y += tDelta.Y;
                    currentPixel.Y += step.Y;
                }

                // height field intersection
                for (int layer = 0; layer < this.HeightField.LayerCount; layer++)
                {
                    float layerZ = this.HeightField.GetDepth((int)currentPixel.X, (int)currentPixel.Y, layer);
                    // we could compare:
                    // (1) sign(entry.Z - hf[pixel.xy]) != sign(exit.Z - hf[pixel.xy])
                    // (2) sign(entry.Z - hf[entry.xy]) != sign(exit.Z - hf[exit.xy])
                    // (3) sign(entry.Z - hf[middle.xy]) != sign(exit.Z - hf[middle.xy])
                    //Vector2 middle = 0.5f * (exit.Xy - entry.Xy);
                    //float layerZ = this.HeightField.GetDepth((int)middle.X, (int)middle.Y, 0);
                    if ((Math.Sign(layerZ - entry.Z) != Math.Sign(layerZ - exit.Z)))
                    {
                        if (collectDebugInfo)
                        {
                            debugInfo.LayerOfIntersection = layer;
                        }
                        return new Intersection(new Vector3d(currentPixel.X, currentPixel.Y, layerZ));
                    }
                }

                entry = exit;

                if (iterations == maxIterations) break;
                iterations++;
            }
            debugInfo.VisitedPixels.Add(currentPixel);
            debugInfo.EntryPoints.Add(rayEnd);

            #endregion

            return null;
        }
Esempio n. 16
0
        private void ComputeIntersection(bool withDebugInfo)
        {
            rayStartPoint = new Point((int)rayStart.X, (int)rayStart.Y);
            rayEndPoint = new Point((int)rayEnd.X, (int)rayEnd.Y);
            if (withDebugInfo)
            {
                footprintDebugInfo = new FootprintDebugInfo();
            }
            else
            {
                footprintDebugInfo = null;
            }
            intersection = selectedIntersector.Intersect(rayStart, rayEnd, ref footprintDebugInfo);
            intersectionLabel.Text = (intersection != null) ? intersection.Position.ToString() : "none";
            isecLayerLabel.Text = (footprintDebugInfo != null) && (intersection != null) ? footprintDebugInfo.LayerOfIntersection.ToString() : "";

            heightFieldPanel.Invalidate();
            footprintTraversalPanel.Invalidate();
        }