예제 #1
0
        private void SplitNode(Node node)
        {
            if (node == null || node.Split)
                return;

            node.Split = true;

            if (node.Visible && node.LeftChild != null)
            {
                node.LeftChild.Visible = true;
                node.RightChild.Visible = true;
            }

            if (node.BaseNeighbor != null && node.BaseNeighbor.BaseNeighbor != node)
            {
                SplitNode(node.BaseNeighbor);
                vertexCounter++;
            }

            SplitNode(node.BaseNeighbor);

            if (node.LeftNeighbor != null)
            {
                if (node.LeftNeighbor.BaseNeighbor == node)
                    node.LeftNeighbor.BaseNeighbor = node.LeftChild;
                else
                    node.LeftNeighbor.RightNeighbor = node.LeftChild;
            }

            if (node.RightNeighbor != null)
            {
                if (node.RightNeighbor.BaseNeighbor == node)
                    node.RightNeighbor.BaseNeighbor = node.RightChild;
                else
                    node.RightNeighbor.LeftNeighbor = node.RightChild;
            }

            if (node.LeftChild != null)
            {
                node.LeftChild.BaseNeighbor = node.LeftNeighbor;
                node.RightChild.BaseNeighbor = node.RightNeighbor;

                node.LeftChild.LeftNeighbor = node.RightChild;
                node.RightChild.RightNeighbor = node.LeftChild;

                if (node.BaseNeighbor != null)
                {
                    node.RightChild.LeftNeighbor = node.BaseNeighbor.LeftChild;
                    node.LeftChild.RightNeighbor = node.BaseNeighbor.RightChild;
                }
            }
        }
예제 #2
0
        private void UpdateNode(Node node, Point p0, Point p1, Point a)
        {
            node.Visible = true;

            if (FrustumCullingEnabled && ViewFrustum.Contains(GetBoundingBox(node)) == ContainmentType.Disjoint)
            {
                node.Visible = false;
                return;
            }

            Point p = GetMidpoint(p0, p1);
            int width = Math.Abs(p0.X - p1.X) + Math.Abs(p0.Y - p1.Y);
            float distanceSquared = (CameraPosition - new Vector3(p.X, GetHeight(p) * Bumpiness, -p.Y)).LengthSquared();

            bool split = SplitCheck(node, width, distanceSquared);

            if (!node.Split && split)
            {
                SplitNode(node);
                vertexCounter++;
            }
            else if (node.Split && !split && CanMerge(node) && CanMerge(node.BaseNeighbor))
            {
                MergeNode(node);
                MergeNode(node.BaseNeighbor);
                vertexCounter--;
            }

            if (node.Split && node.LeftChild != null)
            {
                UpdateNode(node.LeftChild, a, p0, p);
                UpdateNode(node.RightChild, p1, a, p);
            }
        }
예제 #3
0
        private void MergeNode(Node node)
        {
            if (node == null)
                return;

            node.Split = false;

            if (node.LeftChild != null)
            {
                node.LeftNeighbor = node.LeftChild.BaseNeighbor;
                node.RightNeighbor = node.RightChild.BaseNeighbor;
            }

            if (node.LeftNeighbor != null)
            {
                if (node.LeftNeighbor.BaseNeighbor == node.LeftChild)
                    node.LeftNeighbor.BaseNeighbor = node;
                else
                    node.LeftNeighbor.RightNeighbor = node;
            }

            if (node.RightNeighbor != null)
            {
                if (node.RightNeighbor.BaseNeighbor == node.RightChild)
                    node.RightNeighbor.BaseNeighbor = node;
                else
                    node.RightNeighbor.LeftNeighbor = node;
            }
        }
예제 #4
0
        private bool SplitCheck(Node node, int width, float distanceSquared)
        {
            float error = node.Error;

            if (node.BaseNeighbor != null && node.BaseNeighbor.BaseNeighbor == node)
                error = MathHelper.Max(error, node.BaseNeighbor.Error);

            float maxDistance = error * Bumpiness * Quality * width;
            float maxDistanceSquared = maxDistance * maxDistance;

            return distanceSquared < maxDistanceSquared;
        }
예제 #5
0
        private void InitializeTerrain()
        {
            levels = (int)Math.Log(Size - 1, 2) * 2 - 1;

            bottomLeft = new Point(0, 0);
            bottomRight = new Point(Size - 1, 0);
            topLeft = new Point(0, Size - 1);
            topRight = new Point(Size - 1, Size - 1);

            rootLeft = InitializeNode(bottomRight, topLeft, bottomLeft, 0);
            rootRight = InitializeNode(topLeft, bottomRight, topRight, 0);

            rootLeft.BaseNeighbor = rootRight;
            rootRight.BaseNeighbor = rootLeft;
        }
예제 #6
0
        private Node InitializeNode(Point p0, Point p1, Point a, int level)
        {
            Node node = new Node();

            Point p = GetMidpoint(p0, p1);

            node.Error = Math.Abs(GetError(p0, p, p1));
            node.BoundingBox = GetBoundingBox(p0, p1, a);

            if (level < levels)
            {
                node.LeftChild = InitializeNode(a, p0, p, level + 1);
                node.RightChild = InitializeNode(p1, a, p, level + 1);

                if (node.LeftChild.Error > node.Error)
                    node.Error = node.LeftChild.Error;

                if (node.RightChild.Error > node.Error)
                    node.Error = node.RightChild.Error;

                node.BoundingBox = BoundingBox.CreateMerged(node.LeftChild.BoundingBox, node.RightChild.BoundingBox);
            }
            else
                node.BoundingBox = GetBoundingBox(p0, p1, a);

            return node;
        }
예제 #7
0
        private BoundingBox GetBoundingBox(Node node)
        {
            Vector3 min = node.BoundingBox.Min;
            Vector3 max = node.BoundingBox.Max;

            if (!HeightmapEnabled || Bumpiness == 0.0f)
            {
                min.Y = HeightOffset - 1.0f;
                max.Y = HeightOffset + 1.0f;
            }
            else
            {
                min.Y *= Bumpiness;
                max.Y *= Bumpiness;
            }

            if (min.Y > max.Y)
            {
                float y = min.Y;
                min.Y = max.Y;
                max.Y = y;
            }

            return new BoundingBox(min, max);
        }
예제 #8
0
        private void CollectIndices(Node node, Point p0, Point p1, Point a)
        {
            if (node != null && !node.Visible)
                return;

            if (node == null || !node.Split)
            {
                Indices.Add(GetIndex(p0));
                Indices.Add(GetIndex(a));
                Indices.Add(GetIndex(p1));
            }
            else
            {
                Point p = GetMidpoint(p0, p1);

                CollectIndices(node.LeftChild, a, p0, p);
                CollectIndices(node.RightChild, p1, a, p);
            }
        }
예제 #9
0
 private bool CanMerge(Node node)
 {
     return (node == null || node.LeftChild == null || (!node.LeftChild.Split && !node.RightChild.Split));
 }