Esempio n. 1
0
    //
    // Recursively render all triangles
    //
    public void RecursRender(TriTreeNode tri, int leftX, int leftY, int rightX, int rightY, int apexX, int apexY)
    {
        // If we are not rendered all the way down the tree, enter
        if (!tri.isRendered)
        {
            if (tri.LeftChild != null)                 // All non-leaf nodes have both children, so just check for one
            {
                // Get the center of the hypotenuse with a graceful bitshift operation
                int centerX = (leftX + rightX) >> 1;
                int centerY = (leftY + rightY) >> 1;

                // Traverse down the sides of the tree
                RecursRender(tri.LeftChild, apexX, apexY, leftX, leftY, centerX, centerY);
                RecursRender(tri.RightChild, rightX, rightY, apexX, apexY, centerX, centerY);

                // If our left and right children are fully rendered, then so are we
                if (tri.LeftChild.isRendered && tri.RightChild.isRendered)
                {
                    tri.isRendered = true;
                }
            }
            // Else we are a leaf, so render us
            else if (Landscape.FreeTriangleIndexes.Count > 0)
            {
                // Set the height of all three triangle vertices
                float leftZ  = m_HeightMap[leftX, leftY];
                float rightZ = m_HeightMap[rightX, rightY];
                float apexZ  = m_HeightMap[apexX, apexY];

                // Render with indexed vertices and triangles
                RenderIndexed(tri, leftX, leftY, leftZ, rightX, rightY, rightZ, apexX, apexY, apexZ);
            }
        }
    }
Esempio n. 2
0
    //
    // Merge down traverses down the tree and deletes leaf nodes so that the parent can be rendered instead
    //
    void MergeDown(TriTreeNode tri)
    {
        // If we are a leaf node, then we cannot merge
        if (tri.LeftChild == null)
        {
            return;
        }

        // Can we merge?
        if (Mergable(tri))
        {
            // If we have no base neighbor, then we are at an edge and can merge
            if (tri.BaseNeighbor == null)
            {
                Merge(tri);
            }
            else
            {
                // Else we must be a diamond to merge, make sure the neighbor is merged before merging the self
                if (Mergable(tri.BaseNeighbor))
                {
                    Merge(tri.BaseNeighbor);
                    Merge(tri);
                    return;
                }

                return;
            }
            return;
        }

        // Recursively merge all children
        MergeDown(tri.LeftChild);
        MergeDown(tri.RightChild);
    }
Esempio n. 3
0
 public TriTreeNode(uint pLine, uint pRow, int pValue, TriTreeNode pLeftChild, TriTreeNode pRightChild)
 {
     mPosLine    = pLine;
     mPosRow     = pRow;
     mValue      = pValue;
     mLeftChild  = pLeftChild;
     mRightChild = pRightChild;
 }
Esempio n. 4
0
 public TriTreeNode(uint pLine, uint pRow, int pValue)
 {
     mPosLine    = pLine;
     mPosRow     = pRow;
     mValue      = pValue;
     mLeftChild  = null;
     mRightChild = null;
 }
Esempio n. 5
0
    //
    // Reset all ancestor tessellateflags
    //
    public void ResetTessellateflags(TriTreeNode tri)
    {
        if (tri.Parent != null)
        {
            ResetRenderflags(tri.Parent);
        }

        tri.isTessellated = false;
    }
Esempio n. 6
0
        public void Delete()
        {
            if (mLeftChild != null)
            {
                mLeftChild.Delete();
            }
            if (mRightChild != null)
            {
                mRightChild.Delete();
            }

            mValue      = 0;
            mLeftChild  = null;
            mRightChild = null;
        }
Esempio n. 7
0
    //
    // Mergable returns true if we can merge, false if we can't
    //
    bool Mergable(TriTreeNode tri)
    {
        // If we are merged, return false
        if (tri.LeftChild == null)
        {
            return(false);
        }

        // If there are no grandchildren, return true
        if ((tri.LeftChild.LeftChild == null) && (tri.RightChild.LeftChild == null))
        {
            return(true);
        }

        return(false);
    }
Esempio n. 8
0
    // Render by simply adding vertices to the VertexList, this will result in an excessive amount of duplicates, it's a middle-ground between OpenGL and Dictionary, it uses indexed triangles and vertices
    void RenderIndexed(TriTreeNode tri, float leftX, float leftY, float leftZ, float rightX, float rightY, float rightZ, float apexX, float apexY, float apexZ)
    {
        // Get the index pointing to a place in VertexList and TriangleList where 3 consecutive vertices are free
        int freeIndex = Landscape.FreeTriangleIndexes.Pop();

        // We are a leaf node and we are rendered
        tri.isRendered = true;
        tri.indexTri   = freeIndex;

        Landscape.VertexList[freeIndex]     = new Vector3(leftX, leftZ, leftY);
        Landscape.VertexList[freeIndex + 1] = new Vector3(rightX, rightZ, rightY);
        Landscape.VertexList[freeIndex + 2] = new Vector3(apexX, apexZ, apexY);

        //Landscape.UVs[freeIndex] = new Vector2(leftX, leftY);
        //Landscape.UVs[freeIndex + 1] = new Vector2(rightX, rightY);
        //Landscape.UVs[freeIndex + 2] = new Vector2(apexX, apexY);
    }
Esempio n. 9
0
    public void SetData(List <List <int> > pDataList)
    {
        if (mRoot != null)
        {
            mRoot.Delete();
        }

        List <TriTreeNode> lineNodeList      = new List <TriTreeNode>(2);
        List <TriTreeNode> lineNodeChildList = new List <TriTreeNode>(2);

        for (int i = pDataList.Count - 1; i >= 0; --i)
        {
            lineNodeList.Clear();

            // 맨 아래부터 데이터를 만들어준다.
            for (int j = 0; j < pDataList[i].Count; ++j)
            {
                lineNodeList.Add(new TriTreeNode((uint)i, (uint)j, pDataList[i][j]));
            }

            // 아래 리스트의 데이터를 상위 리스트의 데이터의 자식으로 넣어준다.
            for (int j = 0; j < lineNodeList.Count && j < lineNodeChildList.Count; ++j)
            {
                lineNodeList[j].SetLeftChild(lineNodeChildList[j]);
                lineNodeList[j].SetRightChild(lineNodeChildList[j + 1]);
            }

            // 리스트 복사
            lineNodeChildList.Clear();
            for (int j = 0; j < lineNodeList.Count; ++j)
            {
                lineNodeChildList.Add(lineNodeList[j]);
            }
        }

        if (lineNodeList.Count != 1)
        {
            Console.WriteLine("Wrong Data Setting !!");
        }

        mRoot = lineNodeList[0];
    }
Esempio n. 10
0
    //
    // The recursive split which creates new child tris if possible
    //
    public void Split(TriTreeNode tri)
    {
        // Return if we are already split
        if (tri.LeftChild != null)
        {
            return;
        }

        // If not in a diamond with our BaseNeighbor, split the neighbor first
        if (tri.BaseNeighbor != null && (tri.BaseNeighbor.BaseNeighbor != tri))
        {
            Split(tri.BaseNeighbor);
        }

        // Attempt to create new children nodes
        tri.LeftChild  = Landscape.AllocateTri();
        tri.RightChild = Landscape.AllocateTri();

        // Creation of two children succeeded
        // If current triangle is rendered, stop rendering it and free the triangles
        if (tri.isRendered)
        {
            Landscape.FreeTriangleIndexes.Push(tri.indexTri);

            Landscape.VertexList[tri.indexTri]     = new Vector3();
            Landscape.VertexList[tri.indexTri + 1] = new Vector3();
            Landscape.VertexList[tri.indexTri + 2] = new Vector3();

            tri.indexTri = -1;

            // We will not begin to split - recursively reset render flags
            ResetRenderflags(tri);
        }

        // We will not begin to split - recursively reset tessellation flags
        ResetTessellateflags(tri);


        // Note:
        // When we handle tris, we pivot from the apex vertex, not the left or right vertices. (Which is when we look at our BaseNeighbor)
        // Ex.
        // leftParentTri.LeftNeighbor will be above the patch, and leftParentTri.RightNeighbor will be to the left of the patch
        //
        // leftParent.LeftNeighbor
        //
        // --------------------
        // |  left          / |
        // | Parent      /    |
        // |          /       |  rightParent.RightNeighbor
        // |       /   right  |
        // |    /     Parent  |
        // | /                |
        // --------------------
        //
        // rightParent.LeftNeighbor


        // Pass useful parent information to children
        tri.LeftChild.BaseNeighbor = tri.LeftNeighbor;
        tri.LeftChild.LeftNeighbor = tri.RightChild;

        tri.LeftChild.Parent  = tri;
        tri.RightChild.Parent = tri;

        tri.RightChild.BaseNeighbor  = tri.RightNeighbor;
        tri.RightChild.RightNeighbor = tri.LeftChild;

        // Link our Left Neighbor to the new children
        if (tri.LeftNeighbor != null)
        {
            if (tri.LeftNeighbor.BaseNeighbor == tri)
            {
                tri.LeftNeighbor.BaseNeighbor = tri.LeftChild;
            }
            else if (tri.LeftNeighbor.LeftNeighbor == tri)
            {
                tri.LeftNeighbor.LeftNeighbor = tri.LeftChild;
            }
            else if (tri.LeftNeighbor.RightNeighbor == tri)
            {
                tri.LeftNeighbor.RightNeighbor = tri.LeftChild;
            }
        }

        // Link our Right Neighbor to the new children
        if (tri.RightNeighbor != null)
        {
            if (tri.RightNeighbor.BaseNeighbor == tri)
            {
                tri.RightNeighbor.BaseNeighbor = tri.RightChild;
            }
            else if (tri.RightNeighbor.RightNeighbor == tri)
            {
                tri.RightNeighbor.RightNeighbor = tri.RightChild;
            }
            else if (tri.RightNeighbor.LeftNeighbor == tri)
            {
                tri.RightNeighbor.LeftNeighbor = tri.RightChild;
            }
        }

        // Link our Base Neighbor to the new children
        if (tri.BaseNeighbor != null)
        {
            if (tri.BaseNeighbor.LeftChild != null)
            {
                tri.BaseNeighbor.LeftChild.RightNeighbor = tri.RightChild;
                tri.BaseNeighbor.RightChild.LeftNeighbor = tri.LeftChild;
                tri.LeftChild.RightNeighbor = tri.BaseNeighbor.RightChild;
                tri.RightChild.LeftNeighbor = tri.BaseNeighbor.LeftChild;
            }
            else
            {
                Split(tri.BaseNeighbor);  // Now split BaseNeighbor
            }
        }
        else
        {
            // An edge triangle, trivial case.
            tri.LeftChild.RightNeighbor = null;
            tri.RightChild.LeftNeighbor = null;
        }
    }
Esempio n. 11
0
    //
    // Merge the children
    //
    void Merge(TriTreeNode tri)
    {
        // If there is no child, then we are already merged
        if (tri.LeftChild == null)
        {
            return;
        }

        // Get the base neighbor of the left child and connect to parent
        if (tri.LeftChild.BaseNeighbor != null)
        {
            if (tri.LeftChild.BaseNeighbor.LeftNeighbor == tri.LeftChild)
            {
                tri.LeftChild.BaseNeighbor.LeftNeighbor = tri;
            }
            if (tri.LeftChild.BaseNeighbor.RightNeighbor == tri.LeftChild)
            {
                tri.LeftChild.BaseNeighbor.RightNeighbor = tri;
            }
            if (tri.LeftChild.BaseNeighbor.BaseNeighbor == tri.LeftChild)
            {
                tri.LeftChild.BaseNeighbor.BaseNeighbor = tri;
                if (tri.LeftNeighbor == tri.LeftChild.BaseNeighbor.Parent)
                {
                    tri.LeftNeighbor = tri.LeftChild.BaseNeighbor;
                }
            }

            // For ease
            TriTreeNode baseNeighbor = tri.LeftChild.BaseNeighbor;

            // We need to check if tri.LeftChild.BaseNeighbor has a parent which is also bound to this triangle
            // then we also need to update its connections to be set to the parent
            if (baseNeighbor.Parent != null)
            {
                if (baseNeighbor.Parent.LeftNeighbor == tri.LeftChild)
                {
                    baseNeighbor.Parent.LeftNeighbor = tri;
                }
                if (baseNeighbor.Parent.RightNeighbor == tri.LeftChild)
                {
                    baseNeighbor.Parent.RightNeighbor = tri;
                }
                if (baseNeighbor.Parent.BaseNeighbor == tri.LeftChild)
                {
                    baseNeighbor.Parent.BaseNeighbor = tri;
                }
            }
        }

        // Same for the right child
        if (tri.RightChild.BaseNeighbor != null)
        {
            if (tri.RightChild.BaseNeighbor.LeftNeighbor == tri.RightChild)
            {
                tri.RightChild.BaseNeighbor.LeftNeighbor = tri;
            }
            if (tri.RightChild.BaseNeighbor.RightNeighbor == tri.RightChild)
            {
                tri.RightChild.BaseNeighbor.RightNeighbor = tri;
            }
            if (tri.RightChild.BaseNeighbor.BaseNeighbor == tri.RightChild)
            {
                tri.RightChild.BaseNeighbor.BaseNeighbor = tri;
                if (tri.RightNeighbor == tri.RightChild.BaseNeighbor.Parent)
                {
                    tri.RightNeighbor = tri.RightChild.BaseNeighbor;
                }
            }

            // For getting a shorter expression
            TriTreeNode baseNeighbor = tri.RightChild.BaseNeighbor;

            // We need to check if tri.RightChild.BaseNeighbor has a parent which is also bound to this triangle
            // then we also need to update its connections to be set to the parent
            if (baseNeighbor.Parent != null)
            {
                if (baseNeighbor.Parent.LeftNeighbor == tri.RightChild)
                {
                    baseNeighbor.Parent.LeftNeighbor = tri;
                }
                if (baseNeighbor.Parent.RightNeighbor == tri.RightChild)
                {
                    baseNeighbor.Parent.RightNeighbor = tri;
                }
                if (baseNeighbor.Parent.BaseNeighbor == tri.RightChild)
                {
                    baseNeighbor.Parent.BaseNeighbor = tri;
                }
            }
        }

        // Free the LeftChild index and let it be used by another rendered triangle
        if (tri.LeftChild.isRendered)
        {
            Landscape.VertexList[tri.LeftChild.indexTri]     = new Vector3();
            Landscape.VertexList[tri.LeftChild.indexTri + 1] = new Vector3();
            Landscape.VertexList[tri.LeftChild.indexTri + 2] = new Vector3();

            Landscape.FreeTriangleIndexes.Push(tri.LeftChild.indexTri);

            ResetRenderflags(tri.LeftChild);
        }

        // Free the RightChild index and let it be used by another rendered triangle
        if (tri.RightChild.isRendered)
        {
            Landscape.VertexList[tri.RightChild.indexTri]     = new Vector3();
            Landscape.VertexList[tri.RightChild.indexTri + 1] = new Vector3();
            Landscape.VertexList[tri.RightChild.indexTri + 2] = new Vector3();

            Landscape.FreeTriangleIndexes.Push(tri.RightChild.indexTri);

            ResetRenderflags(tri.RightChild);
        }

        // Add two new nodes to TriTreeNodeStack, available for allocation
        // The garbage collector will automatically detect and destroy tri.LeftChild and RightChild
        Landscape.TriTreeNodeStack.Push(new TriTreeNode());
        Landscape.TriTreeNodeStack.Push(new TriTreeNode());

        // Make the current node a leaf node
        tri.LeftChild  = null;
        tri.RightChild = null;
    }
Esempio n. 12
0
 //
 // Collapse the tree and free up any now useless triangles for new use
 //
 public void CollapsePatchTree(TriTreeNode tri)
 {
     MergeDown(tri);
 }
Esempio n. 13
0
    //
    // Split triangles according to variance
    //
    public void RecursTessellate(TriTreeNode tri, int leftX, int leftY, int rightX, int rightY, int apexX, int apexY, int node)
    {
        float TriVariance = 0;

        // Get hypotenuse XY positions
        int centerX = (leftX + rightX) >> 1;
        int centerY = (leftY + rightY) >> 1;

        // If we are not visiting a leaf node
        if (node < (1 << VARIANCE_DEPTH))
        {
            // Note:
            // This solution is 22.5% faster, but it will render 30-50% of triangles behind the camera

            // If the terrain is not flat here, calculate TriVariance
            if (m_TempVariance[node] > 1)
            {
                // Calculate distance from the camera to the node
                float distance = 1.0f + Vector3.Distance(Camera.main.transform.position, new Vector3(centerX, m_HeightMap[centerX, centerY], centerY));

                // Consider distance and variance
                TriVariance = ((float)m_TempVariance[node] * Landscape.MAP_SIZE * 2.0F) / distance;
            }

            /*
             * // This solution is slower, but it will render barely any useless triangles, < 10%
             * if (m_TempVariance[node] > 1)
             * {
             *  // Define the points and vectors
             *  Vector3 C = Camera.main.transform.position;
             *  Vector3 F = Camera.main.transform.forward;
             *  Vector3 P = new Vector3(centerX, m_HeightMap[centerX, centerY], centerY);
             *
             *  // Calculate the distances between node and camera
             *  float Distance_P_C = Vector3.Distance(P, C);
             *  float Distance_FPC_P = Vector3.Distance(((Distance_P_C) * F) + C, P);
             *
             *  // If the distance to the patch is greater than the distance from the perfect position to the patch, it is certainly within view
             *  // We add PATCH_HYPOTENUSE to account for the width of the patches so that we don't skip rendering a patch
             *  if (Distance_P_C + Landscape.PATCH_CUBE_HYPOTENUSE_DIV2 > Distance_FPC_P)
             *  {
             *      TriVariance = ((float)m_TempVariance[node] * Landscape.MAP_SIZE * 2.0F) / Distance_P_C;
             *  }
             * }
             */
        }

        // If node >= 512, then we must split because we are a leaf node
        // If we are not fully tessellated and TriVariance exceeds gFrameVaraince (which alternates to optimally spread triangles) then split
        // Adding VARIANCE_TOLERANCE-check increases efficiency by roughly 17%
        if (!tri.isTessellated && ((node >= (1 << VARIANCE_DEPTH)) || (TriVariance > Landscape.frameVariance + Landscape.VARIANCE_TOLERANCE)))
        {
            // Attempt to split this tri
            Split(tri);

            // If this tri was split and we are not too small, recurse and repeat for children
            if (tri.LeftChild != null && ((Mathf.Abs(leftX - rightX) >= 3) || (Mathf.Abs(leftY - rightY) >= 3)))
            {
                RecursTessellate(tri.LeftChild, apexX, apexY, leftX, leftY, centerX, centerY, node << 1);
                RecursTessellate(tri.RightChild, rightX, rightY, apexX, apexY, centerX, centerY, 1 + (node << 1));
            }
        }
        // If we can tolerate a merge, we are not splitting and children are eligible for a merge, merge
        else if (TriVariance < Landscape.frameVariance - Landscape.VARIANCE_TOLERANCE && tri.LeftChild != null && tri.isRendered)
        {
            MergeDown(tri);
        }


        // If all children are fully tessellated tessellated, then we are fully tessellated
        if (tri.LeftChild != null && tri.LeftChild.isTessellated && tri.RightChild.isTessellated)
        {
            tri.isTessellated = true;
        }
        // Else if we are a leaf node, then we are fully tessellated
        else if (node >= (1 << VARIANCE_DEPTH))
        {
            tri.isTessellated = true;
        }
    }
Esempio n. 14
0
 public void SetRightChild(TriTreeNode pRightChild)
 {
     mRightChild = pRightChild;
 }
Esempio n. 15
0
 public void SetLeftChild(TriTreeNode pLeftChild)
 {
     mLeftChild = pLeftChild;
 }