Esempio n. 1
0
        public PatchROAM(LandscapeROAM landscape, Camera cam, int heightX, int heightY, int worldX, int worldY, int patchSize, int mapSize)
        {
            this.landscape     = landscape;
            this.cam           = cam;
            this.varianceDepth = 8;
            this.patchSize     = patchSize;
            this.mapSize       = mapSize;

            // Clear all the relationships
            m_BaseLeft  = new TriTreeNode();
            m_BaseRight = new TriTreeNode();

            m_BaseLeft.setBaseNeighbor(m_BaseRight);
            m_BaseRight.setBaseNeighbor(m_BaseLeft);

            // Store Patch offsets for the world and heightmap.
            this.worldX = worldX;
            this.worldY = worldY;

            // Store pointer to first byte of the height data for this patch.
            this.heightX = heightX;
            this.heightY = heightY;

            // Initialize flags
            m_VarianceDirty = 1;
            m_isVisible     = 0;

            m_VarianceLeft  = new ushort[1 << (varianceDepth)];         // Left variance tree
            m_VarianceRight = new ushort[1 << (varianceDepth)];         // Right variance tree

            Vector3 center = new Vector3(worldX + patchSize / 2, 0.0f, -worldY - patchSize / 2);

            bs = new BoundingSphere(center, patchSize);
        }
Esempio n. 2
0
        // ---------------------------------------------------------------------
        // Render the tree.  Simple no-fan method.
        //
        public void recursRender(TriTreeNode tri, int leftX, int leftY, int rightX, int rightY, int apexX, int apexY)
        {
            if (tri != null && tri.getLeftChild() != null) // All non-leaf nodes have both children, so just check for one
            {
                int centerX = (leftX + rightX) >> 1;       // Compute X coordinate of center of Hypotenuse
                int centerY = (leftY + rightY) >> 1;       // Compute Y coord...

                recursRender(tri.getLeftChild(), apexX, apexY, leftX, leftY, centerX, centerY);
                recursRender(tri.getRightChild(), rightX, rightY, apexX, apexY, centerX, centerY);
            }
            else                                                                        // A leaf node!  Output a triangle to be rendered.
            {
                float leftZ  = landscape.getHeightMap(heightX + leftX, heightY + leftY);
                float rightZ = landscape.getHeightMap(heightX + rightX, heightY + rightY);
                float apexZ  = landscape.getHeightMap(heightX + apexX, heightY + apexY);

                // Actual number of rendered triangles...
                landscape.NumTrisRendered++;

                // Perform lighting calculations.
                Vector3[] vec    = new Vector3[3];
                Vector3   normal = new Vector3();

                // Create a vertex normal for this triangle.
                // NOTE: This is an extremely slow operation for illustration purposes only.
                //       You should use a texture map with the lighting pre-applied to the texture.

                vec[0].X = leftX;
                vec[0].Y = leftZ;
                vec[0].Z = leftY;

                vec[1].X = rightX;
                vec[1].Y = rightZ;
                vec[1].Z = rightY;

                vec[2].X = apexX;
                vec[2].Y = apexZ;
                vec[2].Z = apexY;

                normal = RenderEngine.calcNormal(vec);
                normal.Normalize();
                float u = ((float)leftX + (float)worldX) / (float)mapSize;
                float v = ((float)leftY + (float)worldY) / (float)mapSize;

                landscape.Verts[landscape.NumVertsRendered] = new PositionNormalMultiTexture(new Vector3((float)landscape.getPosition().X + worldX + (float)leftX, landscape.getPosition().Y + (float)leftZ, (float)-landscape.getPosition().Z - worldY - (float)leftY), normal, new Vector2(u, v), new Vector2(u, v));
                landscape.NumVertsRendered++;

                u = ((float)rightX + (float)worldX) / (float)mapSize;
                v = ((float)rightY + (float)worldY) / (float)mapSize;

                landscape.Verts[landscape.NumVertsRendered] = new PositionNormalMultiTexture(new Vector3((float)landscape.getPosition().X + worldX + (float)rightX, landscape.getPosition().Y + (float)rightZ, (float)-landscape.getPosition().Z - worldY - (float)rightY), normal, new Vector2(u, v), new Vector2(u, v));
                landscape.NumVertsRendered++;

                u = ((float)apexX + (float)worldX) / (float)mapSize;
                v = ((float)apexY + (float)worldY) / (float)mapSize;

                landscape.Verts[landscape.NumVertsRendered] = new PositionNormalMultiTexture(new Vector3((float)landscape.getPosition().X + worldX + (float)apexX, landscape.getPosition().Y + (float)apexZ, (float)-landscape.getPosition().Z - worldY - (float)apexY), normal, new Vector2(u, v), new Vector2(u, v));
                landscape.NumVertsRendered++;
            }
        }
Esempio n. 3
0
        // ---------------------------------------------------------------------
        // Tessellate a Patch.
        // Will continue to split until the variance metric is met.
        //
        public void recursTessellate(TriTreeNode tri, int leftX, int leftY, int rightX, int rightY, int apexX, int apexY, int node, ushort[] m_CurrentVariance)
        {
            float triVariance = 0.0f;
            int   centerX     = (leftX + rightX) >> 1; // Compute X coordinate of center of Hypotenuse
            int   centerY     = (leftY + rightY) >> 1; // Compute Y coord...

            if (node < (1 << varianceDepth))
            {
                // Extremely slow distance metric (sqrt is used).
                // Replace this with a faster one!
                float distance = 1.0f + (float)Math.Sqrt(Math.Pow(centerX - cam.VEye.X, 2) + Math.Pow(centerY + cam.VEye.Z, 2));

                // Egads!  A division too?  What's this world coming to!
                // This should also be replaced with a faster operation.
                triVariance = ((float)m_CurrentVariance[node] * mapSize * 2) / distance;        // Take both distance and variance into consideration
            }

            if ((node >= (1 << varianceDepth)) ||                                         // IF we do not have variance info for this node, then we must have gotten here by splitting, so continue down to the lowest level.
                (triVariance > landscape.FrameVariance))                                  // OR if we are not below the variance tree, test for variance.
            {
                split(tri);                                                               // Split this triangle.
                if (tri != null && tri.getLeftChild() != null &&                          // If this triangle was split, try to split it's children as well.
                    ((Math.Abs(leftX - rightX) >= 2) || (Math.Abs(leftY - rightY) >= 2))) // Tessellate all the way down to one vertex per height field entry
                {
                    recursTessellate(tri.getLeftChild(), apexX, apexY, leftX, leftY, centerX, centerY, node << 1, m_CurrentVariance);
                    recursTessellate(tri.getRightChild(), rightX, rightY, apexX, apexY, centerX, centerY, 1 + (node << 1), m_CurrentVariance);
                }
            }
        }
Esempio n. 4
0
 public void setRightNeighbor(TriTreeNode tri)
 {
     if (tri == null)
     {
         this.rightNeighbor = new TriTreeNode();
     }
     this.rightNeighbor = tri;
 }
Esempio n. 5
0
 public void setBaseNeighbor(TriTreeNode tri)
 {
     if (tri == null)
     {
         this.baseNeighbor = new TriTreeNode();
     }
     this.baseNeighbor = tri;
 }
Esempio n. 6
0
 public void setRightChild(TriTreeNode tri)
 {
     if (tri == null)
     {
         this.rightChild = new TriTreeNode();
     }
     this.rightChild = tri;
 }
Esempio n. 7
0
 public void setLeftChild(TriTreeNode tri)
 {
     if (tri == null)
     {
         this.leftChild = new TriTreeNode();
     }
     this.leftChild = tri;
 }
Esempio n. 8
0
 public TriTreeNode()
 {
     lz                 = rz = az = 0.0f;
     this.leftChild     = null;
     this.rightChild    = null;
     this.baseNeighbor  = null;
     this.leftNeighbor  = null;
     this.rightNeighbor = null;
 }
Esempio n. 9
0
 // ---------------------------------------------------------------------
 // Allocate a TriTreeNode from the pool.
 //
 public TriTreeNode allocateTri()
 {
     // If we've run out of TriTreeNodes, just return NULL (this is handled gracefully)
     if (nextTriNode >= poolSize - 1)
     {
         return(null);
     }
     nextTriNode++;
     triPool[nextTriNode] = new TriTreeNode();
     return(triPool[nextTriNode]);
 }
Esempio n. 10
0
        // ---------------------------------------------------------------------
        // Split a single Triangle and link it into the mesh.
        // Will correctly force-split diamonds.
        //
        public void split(TriTreeNode tri)
        {
            if (tri != null)
            {
                // We are already split, no need to do it again.
                if (tri.getLeftChild() != null)
                {
                    return;
                }

                // If this triangle is not in a proper diamond, force split our base neighbor
                if (tri.getBaseNeighbor() != null && tri.getBaseNeighbor().getBaseNeighbor() != tri)
                {
                    split(tri.getBaseNeighbor());
                }

                // Create children and link into mesh
                tri.setLeftChild(landscape.allocateTri());
                tri.setRightChild(landscape.allocateTri());

                // If creation failed, just exit.
                if (tri.getLeftChild() == null)
                {
                    return;
                }
                if (tri.getRightChild() == null)
                {
                    return;
                }
                // Fill in the information we can get from the parent (neighbor pointers)
                tri.getLeftChild().setBaseNeighbor(tri.getLeftNeighbor());
                tri.getLeftChild().setLeftNeighbor(tri.getRightChild());

                tri.getRightChild().setBaseNeighbor(tri.getRightNeighbor());
                tri.getRightChild().setRightNeighbor(tri.getLeftChild());

                // Link our Left Neighbor to the new children
                if (tri.getLeftNeighbor() != null)
                {
                    if (tri.getLeftNeighbor().getBaseNeighbor() == tri)
                    {
                        tri.getLeftNeighbor().setBaseNeighbor(tri.getLeftChild());
                    }
                    else if (tri.getLeftNeighbor().getLeftNeighbor() == tri)
                    {
                        tri.getLeftNeighbor().setLeftNeighbor(tri.getLeftChild());
                    }
                    else if (tri.getLeftNeighbor().getRightNeighbor() == tri)
                    {
                        tri.getLeftNeighbor().setRightNeighbor(tri.getLeftChild());
                    }
                    else
                    {
                        ;// Illegal Left Neighbor!
                    }
                }

                // Link our Right Neighbor to the new children
                if (tri.getRightNeighbor() != null)
                {
                    if (tri.getRightNeighbor().getBaseNeighbor() == tri)
                    {
                        tri.getRightNeighbor().setBaseNeighbor(tri.getRightChild());
                    }
                    else if (tri.getRightNeighbor().getRightNeighbor() == tri)
                    {
                        tri.getRightNeighbor().setRightNeighbor(tri.getRightChild());
                    }
                    else if (tri.getRightNeighbor().getLeftNeighbor() == tri)
                    {
                        tri.getRightNeighbor().setLeftNeighbor(tri.getRightChild());
                    }
                    else
                    {
                        ;// Illegal Right Neighbor!
                    }
                }

                // Link our Base Neighbor to the new children
                if (tri.getBaseNeighbor() != null)
                {
                    if (tri.getBaseNeighbor().getLeftChild() != null)
                    {
                        tri.getBaseNeighbor().getLeftChild().setRightNeighbor(tri.getRightChild());
                        tri.getBaseNeighbor().getRightChild().setLeftNeighbor(tri.getLeftChild());
                        tri.getLeftChild().setRightNeighbor(tri.getBaseNeighbor().getRightChild());
                        tri.getRightChild().setLeftNeighbor(tri.getBaseNeighbor().getLeftChild());
                    }
                    else
                    {
                        split(tri.getBaseNeighbor());  // Base Neighbor (in a diamond with us) was not split yet, so do that now.
                    }
                }
                else
                {
                    // An edge triangle, trivial case.
                    tri.getLeftChild().setRightNeighbor(null);
                    tri.getRightChild().setLeftNeighbor(null);
                }
            }
        }