• Advertisement
Sign in to follow this  

Planet rendering issues

This topic is 374 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello fellow game programmers,

 

I'm currently working on a planet rendering application.

I am using the famous 6 quadtree method, where each face is made of an adaptive quadtree.

I'm using only one VBO for the grid and around 8 IBOs for stitching the chunks of different LOD.

 

The problem i'm currently having is that whenever i get close to the surface everything starts to jiggle so i assume that i'm having some floating point precision issues.

The thing is, i can't find a way out of this. My planets are really huge (Earth huge) and i don't want to give up on that.

 

These are the steps that i'm following to create my planet:

 

1. Create a cube out of 6 grids (the grids are managed by the quadtree)

2. The GPU rotates, scales and translates the chunks and then normalizes everything to inflate the cube into a sphere

3. Multiply the vertex with the scale matrix to get it to the desired size.

 

I believe the problem is with scaling the children chunks

For instance, if the size of the root chunk is 6371000.0, it's children are scaled down to 3185500.0 and translated to NW, NE, SE and SW.

 

Maybe for the ground level chunks, the size is so small that floats start going crazy.

 

Vertex Shader code.

vec3 roundChunkVertex = normalize((r_ChunkTransform * vec4(r_Vertex, 1.0)).xyz);
gl_Position = r_Camera * r_Scale * vec4(roundChunkVertex, 1.0);

r_ChunkTransform is a matrix that rotates, translates and scales the chunk.

r_ChunkTransform = R * T * S; 

Where R is the rotation matrix.

switch (side)
    {
        case TS_TOP:
            R = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
            break;
        case TS_BOTTOM:
            R = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));
            break;
        case TS_LEFT:
            R = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, -1.0f, 0.0f));
            break;
        case TS_RIGHT:
            R = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f));
            break;
        case TS_FRONT:
            R = glm::rotate(glm::mat4(1.0f), glm::radians(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
            break;
        case TS_BACK:
            R = glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0.0f, 1.0f, 0.0f));
            break;
    }

 T is the translation matrix that "offsets" the chunk within it's parent.

glm::dmat4 T = glm::translate(glm::mat4(1.0f), glm::vec3(offset, 0.0f));

S scales the grid on the x and y axes.

glm::dmat4 S = glm::scale(glm::mat4(1.0f), glm::vec3(scalar, scalar, 1.0f));

This is the split function

void TerrainNode::split()
{
    this->leaf[NW] = new TerrainNode(this, side, NW, glm::vec2(-.5, 0.5) * (float)scalar + offset, radius, scalar / 2.0);
    this->leaf[NE] = new TerrainNode(this, side, NE, glm::vec2(0.5, 0.5) * (float)scalar + offset, radius, scalar / 2.0);
    this->leaf[SE] = new TerrainNode(this, side, SE, glm::vec2(0.5, -.5) * (float)scalar + offset, radius, scalar / 2.0);
    this->leaf[SW] = new TerrainNode(this, side, SW, glm::vec2(-.5, -.5) * (float)scalar + offset, radius, scalar / 2.0);
        
    this->isSplit = true;
}

I attached a screenshot of the issue.

Thank you.

Share this post


Link to post
Share on other sites
Advertisement

It is work and some people on the site have done it, but effectively you need to break your world not just into a spatial grid, but into multiple origins.  I've read of approaches where they completely rebuild both the scale and the origin after traveling far enough, so you're always in a good range near the middle if floating point values.

For the 90% solution, just calculate your vertex positions using doubles, and then make them local to the quad-tree chunk (by subtracting the chunk centre).

 

Each chunk will have plenty of precision even with single-precision floats (since the chunks are smaller at higher details), and the model-view-projection matrix concatenation causes a smaller and smaller range of depth values as the camera approaches the surface...

Share this post


Link to post
Share on other sites
Look into the multi-frustum technique used by Patrick Cozzi and the Cesium crew. Their book and presentations on terrain rendering are worth reading as well.

Share this post


Link to post
Share on other sites

I've coded a planet visualization engine some years ago and I can say that it's possible to deal with floats.

You can use an 6378.0f value for earth radius and subtract the camera position to each render chunk in order to gain precision at near distances.

Share this post


Link to post
Share on other sites

(just read swiftcoder... This solution is similar but using long doubles)

You can get around the problem by creating your own vector using "long double" values. This will mean you will need to create your own structure that handles the math that the vector structure uses and then modify your noise code to handle it. When you generate the vertex buffer for each LOD you will need to use a center value and add the offset values of each of the vertices to get a location for each vertex (using floats). The verts very far away will have the same problem as before, but they will be so far that the player can't see them. All the while preserving your noise generation precision.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement