0
\$\begingroup\$

I am trying to get a terrain rendering system I wrote a while ago with LWJGL. This terrain rendering system is quite simple: a quad mesh is split as the camera moves closer to it, each time a new quad is created a FBO is used to render a heightmap using perlin noise implemented in a pixel shader. This texture is then applied to the quad and sampled for normals and elevation. The problem I am having with it is a bit odd... So the camera starts out at a reasonable distance away from the root quad. This causes it to be split into 4 quads, each with their own heightmap. This can be represented as follows: enter image description here

As the camera moves closer the program acts as expected and the nearest quad (the white one) is split into 4 children quads, again, each with their own heightmap.

enter image description here

Now here is where the problems start to arise... When the camera moves even closer the blue quad that you see above (the larger one) is split into 4 quads as expected. Yet what is strange is that the smallest green quad's heightmap is changed to be the heightmap of the largest red quad shown above...

enter image description here

1 is the quad that has it's heightmap changed when the blue quad is split. #2 refers to the quad that the green quad seems to "take" it's new heightmap from.

This continues to happen with different quads as the camera moves closer. Yet it is only the green quads that exhibit this type of behavior. I suspect this because the green quad is the last quad to have a heightmap rendered and this can be seen as follows:

QuadMesh q1 = q.children.get(0);
        QuadMesh q2 = q.children.get(1);
        QuadMesh q3 = q.children.get(2);
        QuadMesh q4 = q.children.get(3);

        Heightmap.getHeightmap(q1);
        Heightmap.getHeightmap(q2);
        Heightmap.getHeightmap(q3);
        //q4 is the green quad 
        Heightmap.getHeightmap(q4);

The getHeightmap() method looks like so:

public static void getHeightmap(QuadMesh q){
    float scale = q.width/1024;
    float size = q.width;
    int unit = heightmapTextureUnit;
    glActiveTexture(GL_TEXTURE0 + unit);
    int heightmapTexture = glGenTextures();
    glBindTexture(GL_TEXTURE_2D, heightmapTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 256, 256, 0, GL_RGB, GL_FLOAT, (java.nio.ByteBuffer)null);


    int framebuffer = glGenFramebuffers();
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    glDrawBuffer(GL_COLOR_ATTACHMENT0);

    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, heightmapTexture, 0);
    glViewport(0,0,256,256);
    glUseProgram(noiseProgram);
    glUniform1i(glGetUniformLocation(noiseProgram, "permSampler2d"), permutationTextureUnit);
    glUniform1i(glGetUniformLocation(noiseProgram, "permGradSampler"), gradientTextureUnit);
    glUniform3f(glGetUniformLocation(noiseProgram, "meshOffset"), q.meshOffset.x, q.meshOffset.y, q.meshOffset.z);
    glUniform1f(glGetUniformLocation(noiseProgram, "scale"), scale);
    glUniform1f(glGetUniformLocation(noiseProgram, "size"), size);
    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
    drawQuad();    

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glDeleteFramebuffers(framebuffer);
    glViewport(0,0,1024,768);
    q.HeightmapTexture = heightmapTexture;
    q.HeightmapUnit = unit;  
    heightmapTextureUnit++;
}

To render a quad, the following method is used:

public void render(Matrix4f view, Matrix4f projection){
    glUseProgram(p_ID);

    float scale = width/1024;

    FloatBuffer matBuffer = BufferUtils.createFloatBuffer(16);

    this.cubeMatrix.store(matBuffer);
    matBuffer.flip();
    glUniformMatrix4(glGetUniformLocation(p_ID, "cubeMatrix"), false, matBuffer);

    view.store(matBuffer);
    matBuffer.flip();
    glUniformMatrix4(glGetUniformLocation(p_ID, "V"), false, matBuffer);

    projection.store(matBuffer);
    matBuffer.flip();
    glUniformMatrix4(glGetUniformLocation(p_ID, "P"), false, matBuffer);

    glUniform1f(glGetUniformLocation(p_ID, "scale"), scale);
    glUniform1f(glGetUniformLocation(p_ID, "size"), width);
    glUniform1f(glGetUniformLocation(p_ID, "intensity"), intensity);
    glUniform3f(glGetUniformLocation(p_ID, "meshOffset"), this.meshOffset.x, this.meshOffset.y, this.meshOffset.z);
    glUniform3f(glGetUniformLocation(p_ID, "color"), color.x, color.y, color.z);
    glUniform1i(glGetUniformLocation(p_ID, "heightmap"), HeightmapUnit);

    glBindVertexArray(VAO_ID);  
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO_ID);

    if(Main.wireframe)
    glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    else 
    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
    glDrawElements(GL_TRIANGLES, QuadData.getIndexLength(), GL_UNSIGNED_INT, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glBindVertexArray(0); 
    glUseProgram(0);
}

EDIT: So going through the program a little bit more carefully returned a few errors. Apparently when heightmapTextureUnit gets to be 80 and above the error "GL_INVALID_ENUM" is returned when the texture is activated. This is returned when the arguemnt of glActiveTexture() is not within the bound of GL_MAX_COMBINED_TEXTURE_IMAGE_UNIT. Is it impossible for me to have more than 80 textures? Also the error GL_INVALID_OPERATION is returned when I use the glDrawElements() method...but only when there are around 150 quads active. What causes this?

\$\endgroup\$
  • \$\begingroup\$ Does glGetError() return an error? \$\endgroup\$ – Eejin Aug 27 '14 at 18:02
  • \$\begingroup\$ nope, it just returns 0 \$\endgroup\$ – pl12 Aug 28 '14 at 0:30
1
\$\begingroup\$

Although your question is well formed and the screenshots help a lot understanding the problem, it would be very hard or impossible for others to identify your bug with the given information. It's also hard to tell what more information is needed. Fortunately you are asking how to proceed on debugging the problem, and that is answerable.

If a bug is too hard to find with step-by-step debugging, which seems to be the case here, it needs to be narrowed down. Here you could try the following approaches to limit the scope of the bug:

  • Change the pixel shader generating the height map to produce constant height based on the quadrant. If the bug disappears, it was in the shader.
  • Modify the algorithm to divide the quad to more than 4 subquads, e.g. 8 or 16. Is the bug still in the last subquad only?
  • Replace the GPU terrain generation with CPU generation.
  • Use static images as the height map.
  • Remove the LOD and just divide the whole terrain evenly to these subquads.

Hopefully some of the above ideas allow you to narrow down the bug and to ask a more specific question or solve it yourself.

\$\endgroup\$
  • \$\begingroup\$ Hmm ok. I will try eliminating parts of the program and see what works. Thanks. \$\endgroup\$ – pl12 Aug 31 '14 at 20:23
0
\$\begingroup\$

I figured out the issue... Instead of incrementing the texture unit every time I created a heightmap, I should have been just been re-using the same texture unit for every heightmap.

Thanks for your time!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.