예제 #1
0
        private void GetQuadTreeVerticesAndIndices(QuadTreeNode quadTree, int level = 0)
        {
            var vertBase = _bvhVerts.Count;
            var corners  = quadTree.Bounds.GetCorners();

            if (level == 9)
            {
                _bvhVerts.AddRange(corners.Select(c => {
                    var color = Color.White;
                    switch (_aabCount % 4)
                    {
                    case 1:
                        color = Color.Blue;
                        break;

                    case 2:
                        color = Color.Magenta;
                        break;

                    case 3:
                        color = Color.Yellow;
                        break;
                    }
                    return(new VertexPC(c, color));
                }));
                _aabCount++;
                _bvhIndices.AddRange(
                    new[] { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 4, 0, 5, 1, 7, 3, 6, 2 }.Select(
                        i => i + vertBase));
            }
            if (quadTree.Children != null)
            {
                foreach (var child in quadTree.Children)
                {
                    GetQuadTreeVerticesAndIndices(child, level + 1);
                }
            }
        }
예제 #2
0
        private QuadTreeNode BuildQuadTree(Vector2 topLeft, Vector2 bottomRight) {
            const float tolerance = 0.01f;

            // search the heightmap in order to get the y-extents of the terrain region
            var minMaxY = GetMinMaxY(topLeft, bottomRight);

            // convert the heightmap index bounds into world-space coordinates
            var minX = topLeft.X * Info.CellSpacing - Width / 2;
            var maxX = bottomRight.X * Info.CellSpacing - Width / 2;
            var minZ = -topLeft.Y * Info.CellSpacing + Depth / 2;
            var maxZ = -bottomRight.Y * Info.CellSpacing + Depth / 2;

            // adjust the bounds to get a very slight overlap of the bounding boxes
            minX -= tolerance;
            maxX += tolerance;
            minZ += tolerance;
            maxZ -= tolerance;

            // construct the new node and assign the world-space bounds of the terrain region
            var quadNode = new QuadTreeNode { Bounds = new BoundingBox(new Vector3(minX, minMaxY.X, minZ), new Vector3(maxX, minMaxY.Y, maxZ)) };

            var width = (int)Math.Floor((bottomRight.X - topLeft.X) / 2);
            var depth = (int)Math.Floor((bottomRight.Y - topLeft.Y) / 2);

            // we will recurse until the terrain regions match our logical terrain tile sizes
            if (width >= TileSize && depth >= TileSize) {
                quadNode.Children = new[] {
                    BuildQuadTree(topLeft, new Vector2(topLeft.X + width, topLeft.Y + depth)), 
                    BuildQuadTree(new Vector2(topLeft.X + width, topLeft.Y), new Vector2(bottomRight.X, topLeft.Y + depth)), 
                    BuildQuadTree(new Vector2(topLeft.X, topLeft.Y + depth), new Vector2(topLeft.X + depth, bottomRight.Y)), 
                    BuildQuadTree(new Vector2(topLeft.X + width, topLeft.Y + depth), bottomRight)
                };
            } else {
                // set the maptile corresponding to this leaf node of the quad tree
                var center = topLeft / TileSize;

                var mapX = (int)Math.Floor(center.X);
                var mapY = (int)Math.Floor(center.Y);
                quadNode.MapTile = GetTile(mapX, mapY);


            }

            return quadNode;
        }
예제 #3
0
        public bool Intersects(Ray ray, out Vector3 hit, out QuadTreeNode node)
        {
            hit = new Vector3(float.MaxValue);


            // This is our terminating condition
            if (Children == null)
            {
                float d;
                // check if the ray intersects this leaf node's bounding box
                if (!Ray.Intersects(ray, Bounds, out d))
                {
                    // No intersection
                    node = null;
                    return(false);
                }
                // return the centerpoint of the leaf's bounding box
                hit  = (Bounds.Minimum + Bounds.Maximum) / 2;
                node = this;
                return(true);
            }

            // If the node has children, we need to intersect each child.
            // We only intersect the child's immediate bounding volume, in order to avoid fully intersecting
            // It is possible that the closest child intersection does not actually contain the closest
            // node that intersects the ray, so we maintain a priority queue of the child nodes that were hit,
            // indexed by the distance to intersection
            var pq = new SortedDictionary <float, QuadTreeNode>();

            foreach (var bvhNode in Children)
            {
                float cd;
                if (Ray.Intersects(ray, bvhNode.Bounds, out cd))
                {
                    while (pq.ContainsKey(cd))
                    {
                        // perturb things slightly so that we don't have duplicate keys
                        cd += MathF.Rand(-0.001f, 0.001f);
                    }
                    pq.Add(cd, bvhNode);
                }
            }

            // If there were no child intersections
            if (pq.Count <= 0)
            {
                node = null;
                return(false);
            }

            // check the child intersections for the nearest intersection
            var intersect = false;
            // setup a very-far away intersection point to compare against
            var          bestHit  = ray.Position + ray.Direction * 1000;
            QuadTreeNode bestNode = null;

            foreach (var bvhNode in pq)
            {
                Vector3      thisHit;
                QuadTreeNode thisNode;
                // intersect the child node recursively
                var wasHit = bvhNode.Value.Intersects(ray, out thisHit, out thisNode);
                if (!wasHit)
                {
                    // no intersection, continue and intersect the other children
                    continue;
                }
                // Make sure that the intersection point is in front of the ray's world-space origin
                var dot = (Vector3.Dot(Vector3.Normalize(thisHit - ray.Position), ray.Direction));
                if (!(dot > 0.9f))
                {
                    continue;
                }

                // check that the intersection is closer than the nearest intersection found thus far
                if (!((ray.Position - thisHit).LengthSquared() < (ray.Position - bestHit).LengthSquared()))
                {
                    continue;
                }

                // if we have found a closer intersection store the new closest intersection
                bestHit   = thisHit;
                bestNode  = thisNode;
                intersect = true;
            }
            // bestHit now contains the closest intersection found, or the distant sentinel value
            hit  = bestHit;
            node = bestNode;
            return(intersect);
        }
예제 #4
0
 public bool Intersects(Ray ray, out Vector3 hit, out QuadTreeNode node)
 {
     return(Root.Intersects(ray, out hit, out node));
 }
예제 #5
0
public bool Intersects(Ray ray, out Vector3 hit, out QuadTreeNode node) {
    hit = new Vector3(float.MaxValue);


    // This is our terminating condition
    if (Children == null) {
        float d;
        // check if the ray intersects this leaf node's bounding box
        if (!Ray.Intersects(ray, Bounds, out d)) {
            // No intersection
            node = null;
            return false;
        }
        // return the centerpoint of the leaf's bounding box
        hit = (Bounds.Minimum + Bounds.Maximum) / 2;
        node = this;
        return true;
    }

    // If the node has children, we need to intersect each child.
    // We only intersect the child's immediate bounding volume, in order to avoid fully intersecting 
    // It is possible that the closest child intersection does not actually contain the closest
    // node that intersects the ray, so we maintain a priority queue of the child nodes that were hit, 
    // indexed by the distance to intersection
    var pq = new SortedDictionary<float, QuadTreeNode>();
    foreach (var bvhNode in Children) {
        float cd;
        if (Ray.Intersects(ray, bvhNode.Bounds, out cd)) {
            while (pq.ContainsKey(cd)) {
                // perturb things slightly so that we don't have duplicate keys
                cd += MathF.Rand(-0.001f, 0.001f);
            }
            pq.Add(cd, bvhNode);
        }
    }

    // If there were no child intersections
    if (pq.Count <= 0) {
        node = null;
        return false;
    }

    // check the child intersections for the nearest intersection
    var intersect = false;
    // setup a very-far away intersection point to compare against
    var bestHit = ray.Position + ray.Direction * 1000;
    QuadTreeNode bestNode = null;
    foreach (var bvhNode in pq) {
        Vector3 thisHit;
        QuadTreeNode thisNode;
        // intersect the child node recursively
        var wasHit = bvhNode.Value.Intersects(ray, out thisHit, out thisNode);
        if (!wasHit) {
            // no intersection, continue and intersect the other children
            continue;
        }
        // Make sure that the intersection point is in front of the ray's world-space origin
        var dot = (Vector3.Dot(Vector3.Normalize(thisHit - ray.Position), ray.Direction));
        if (!(dot > 0.9f)) {
            continue;
        }

        // check that the intersection is closer than the nearest intersection found thus far
        if (!((ray.Position - thisHit).LengthSquared() < (ray.Position - bestHit).LengthSquared()))
            continue;

        // if we have found a closer intersection store the new closest intersection
        bestHit = thisHit;
        bestNode = thisNode;
        intersect = true;
    }
    // bestHit now contains the closest intersection found, or the distant sentinel value
    hit = bestHit;
    node = bestNode;
    return intersect;
}
예제 #6
0
public bool Intersects(Ray ray, out Vector3 hit, out QuadTreeNode node) {
    return Root.Intersects(ray, out hit, out node);
}
예제 #7
0
        private void GetQuadTreeVerticesAndIndices(QuadTreeNode quadTree, int level = 0) {
            var vertBase = _bvhVerts.Count;
            var corners = quadTree.Bounds.GetCorners();
            if (level == 9) {
                _bvhVerts.AddRange(corners.Select(c => {
                    var color = Color.White;
                    switch (_aabCount % 4) {
                        case 1:
                            color = Color.Blue;
                            break;
                        case 2:
                            color = Color.Magenta;
                            break;
                        case 3:
                            color = Color.Yellow;
                            break;
                    }
                    return new VertexPC(c, color);
                }));
                _aabCount++;
                _bvhIndices.AddRange(
                                     new[] { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 4, 0, 5, 1, 7, 3, 6, 2 }.Select(
                                                                                                                             i => i + vertBase));

            }
            if (quadTree.Children != null) {
                foreach (var child in quadTree.Children) {
                    GetQuadTreeVerticesAndIndices(child, level + 1);
                }
            }


        }