Wednesday, August 29, 2012

GPU based Geometry Clipmapping I

Currently, I’m trying to implement GPU based geometry clipmaps for fast terrain rendering. The idea was taken from GPU Gems 2, but was too complicated for me. So I’ve made it easier:

Each LOD is represented by a color for red being the highest LOD and green the lowest. I use for each LOD 12 sectors via 16x16 vertices. The inner Layer has no other LOD, so its made of 16 sectors. Each time the LOD decreases, the sector size gets squared. So we can reach very huge landscapes with autofading LOD. To further increase performance and primary memory, we only submit one sector to the shader. This sector is 17x17 vertices big to provide 16x16 faces. The shader transforms and scales the vertice and gets the heightmap uv-coordinates. But later more.
But now some details. To save memory, I use only a Vector2 for the vertices. The 3rd dimension will be added by the shader later on. But because XNA doesn't provide such a struct, we use
private struct VertexPosition
{
    public Vector2 Position { get; set; }

    public static readonly VertexDeclaration VertexDeclaration =
        new VertexDeclaration(new VertexElement(0,
        VertexElementFormat.Vector2,
        VertexElementUsage.Position, 0));
}
For indicating the current texture coordinate, position and size we will use the vertex shader. First we define the Vertex Buffer and Index Buffer.
private VertexPosition[] _vertices;
private int[] _indices;
As said before, we only initialize 16x16 faces and transform them in the vertex shader. The initialization looks like this:
        private void InitializeVertices()
        {
            //Initialize for 16x16. Using 17x17 to remove gaps

            _vertices = new VertexPosition[17 * 17];

            for (int x = 0; x <= 16; x++)
            {
                for (int y = 0; y <= 16; y++)
                {
                    _vertices[x + y * 17] = new VertexPosition 
                     { Position = new Vector2(x, y) };//LOD = 1
                }
            }

            _indices = new int[16 * 16 * 6];
            int counter = 0;

            for (int x = 0; x < 16; x++)
            {
                for (int y = 0; y < 16; y++)
                {
                    int topLeft = x + y * 65;
                    int topRight = (x + 1) + y * 65;
                    int lowerLeft = x + (y + 1) * 65;
                    int lowerRight = (x + 1) + (y + 1) * 65;

                    _indices[counter++] = lowerLeft;
                    _indices[counter++] = topRight;
                    _indices[counter++] = topLeft;

                    _indices[counter++] = lowerLeft;
                    _indices[counter++] = lowerRight;
                    _indices[counter++] = topRight;
                }
            }
        }

No comments:

Post a Comment