I am using a framebuffer to procedurally create heightmaps with perlin noise in GLSL shaders. There are two main problems that I am experiencing with this. I have a quadtree for the terrain and in the update loop of the program I update this tree. When a quad is split I have to create 4 new heightmaps. When I do this though the heightmaps are severely corrupted. I am not sure why. I even wait one frame before sending the heightmaps to the graphics card to be sampled for the quad. Here is an image displaying the corruption: enter image description here

Notice how the green quad has a successfully rendered heightmap. The green quad is pQ4 as shown below. It's heightmap is rendered after all the other ones. Here is the code that I use for this:

for(int i = 0; i<QuadN.list.size(); i++){

                QuadN q = QuadN.list.get(i);

                Vector3f center = QuadN.getCenter(q);
                float width = q.width; 
                float distance = center.distance(cam.getLocation()); 
                float view = (1.5f * width); 

            if(view >= distance && !q.children && q.width > (8) &&                                                                 q.queuePosition == -1){ //this splits the quad, generating 4 new quads
                     q.queuePosition = i;
                    QuadN pQ1 = q.childs.get(0);
                    QuadN pQ2 = q.childs.get(1);
                    QuadN pQ3 = q.childs.get(2);
                    QuadN pQ4 = q.childs.get(3);

                     float scale = pQ1.width/size;
                //these textures store the heightmaps    
                    Texture2D hm1 = getHeightMap(itexSize, new                                 Vector2f(pQ1.index1 * (scale * ftexSize), pQ1.index2 * (scale * ftexSize)), scale, pQ1);
                    Texture2D hm2 = getHeightMap(itexSize, new Vector2f(pQ2.index1 * (scale * ftexSize), pQ2.index2 * (scale * ftexSize)), scale, pQ2);
                    Texture2D hm3 = getHeightMap(itexSize, new Vector2f(pQ3.index1 * (scale * ftexSize), pQ3.index2 * (scale * ftexSize)), scale, pQ3);
                    Texture2D hm4 = getHeightMap(itexSize, new Vector2f(pQ4.index1 * (scale * ftexSize), pQ4.index2 * (scale * ftexSize)), scale, pQ4);
   //each quad object has a heightmap
                     pQ1.Heightmap = hm1;
                     pQ2.Heightmap = hm2;
                     pQ3.Heightmap = hm3;
                     pQ4.Heightmap = hm4;   
            }else if ( i == q.queuePosition){
     //this forces the quad that was split above to be examined the next frame
     //vp.clearScenes(); clear the viewport so that that heightmaps are not    repeatedly re-rendered as this causes extreme performance problems 
                QuadN q1 = q.childs.get(0);
                QuadN q2 = q.childs.get(1);
                QuadN q3 = q.childs.get(2);
                QuadN q4 = q.childs.get(3);                 
                    q1.mesh.getMaterial().setVector3("Color", new Vector3f(1,1,1));
                    q1.mesh.getMaterial().setFloat("size", q1.width);
                    q1.mesh.getMaterial().setTexture("HeightMap", q1.Heightmap);
                    q1.mesh.getMaterial().setVector2("Offset", q1.heightmapOffset);

                   q2.mesh.getMaterial().setVector3("Color", new Vector3f(1, 0,0));    
                   q2.mesh.getMaterial().setFloat("size", q2.width);
                   q2.mesh.getMaterial().setTexture("HeightMap", q2.Heightmap);
                   q2.mesh.getMaterial().setVector2("Offset", q2.heightmapOffset);

                   q3.mesh.getMaterial().setVector3("Color", new Vector3f(0f, 0,1f));
                   q3.mesh.getMaterial().setFloat("size", q3.width);
                   q3.mesh.getMaterial().setTexture("HeightMap", q3.Heightmap);
                   q3.mesh.getMaterial().setVector2("Offset", q3.heightmapOffset);

                   q4.mesh.getMaterial().setVector3("Color", new Vector3f(0,1f,0));     
                   q4.mesh.getMaterial().setFloat("size", q4.width);
                   q4.mesh.getMaterial().setTexture("HeightMap", q4.Heightmap);
                   q4.mesh.getMaterial().setVector2("Offset", q4.heightmapOffset);


                    q.queuePosition = -1;

Here is also the method getHeightMap(); for reference's sake:

public Texture2D getHeightMap(float TEXTURE_SIZE, Vector2f index, float scale, QuadN currQuad){
    float scaledTexSize = scale * TEXTURE_SIZE;
    Vector2f offset = new Vector2f(currQuad.index1 * scaledTexSize , currQuad.index2 * scaledTexSize);
    Texture2D hm = new Texture2D(itexSize,itexSize,Format.RGBA32F); 
    Quad q = new Quad(2,2);
    mat = new Material(assetManager, "material.j3md"); 
    mat.setVector2("Offset", offset);
    mat.setFloat("Size", TEXTURE_SIZE);
    mat.setFloat("Scale", scale);
    mat.setFloat("H", H);
    mat.setFloat("Amp", amp);
    mat.setFloat("Off", Off);
    mat.setFloat("Gain", gain);
    mat.setFloat("lac", lacunarity);
    ge = new Geometry("Mesh",q);
    mat.setTexture("permSampler2d", permutationTex);
    mat.setTexture("permGradSampler", gradTex);
    FrameBuffer fbo = new FrameBuffer(itexSize,itexSize,1);
    currQuad.centerOff = 0;

return hm;

The second problem I am having pertains to performance. Clearing the viewport as seen above eliminates the single-digit framerate I was seeing before yet now when many quads are being split the framerates plummet. I profiled the program and found that the process "SwapBuffers" is taking over 90% of the time processing time. Is there anyway to alleviate this?

EDIT: I solved the aforementioned corruption problem by creating a separate viewport and framebuffer for each heightmap.

If any further explanation or code is needed please say so. Thank you for the time, I am completely stuck with this so any help at all is appreciated.

  • 3
    \$\begingroup\$ Not sure about the corruption, but 90% time in SwapBuffers likely just means you're GPU-limited (SwapBuffers waits for the GPU to be done with previous frames, among other things). You can use timer queries to profile individual rendering passes on the GPU. \$\endgroup\$ – Nathan Reed Nov 16 '13 at 2:58

Your Answer

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

Browse other questions tagged or ask your own question.