简体   繁体   中英

OpenGL Vertex Arrays and GL_TRIANGLE_STRIP drawing error

I'm implementing a height map with GL_TRIANGLE_STRIPS and the LWJGL OpenGL Java Bindings. When I draw 'direct' using 'GL_BEGIN/GL_END' it works perfectly but when the heightmap is to big it works slow.

As I want to move on using VBO's I'm now learning how to use Vertex Array's. This is where I have a problem, the drawing is just wrong. It seems that the last triangle of the strip returns to the first one. Perheps a picture is better:

Good drawing: 好的直接绘图

Bad Vertex array drawing: 错误的顶点阵列图

My code is the following for normal drawing:

public void renderDirect() {
    //adapt the camera to the map
    float scale = 5.0f / Math.max(w - 1, l - 1);
    GL11.glScalef(scale, scale, scale);
    GL11.glTranslatef(-(float) (w - 1) / 2, 0.0f, -(float) (l - 1) / 2);

    //choose map color
    GL11.glColor3f(0.3f, 0.9f, 0.0f);

    for (int z = 0; z < l - 1; z++) {
        //Makes OpenGL draw a triangle at every three consecutive vertices
        GL11.glBegin(GL11.GL_TRIANGLE_STRIP);
        for (int x = 0; x < w; x++) {
            Vector3f normal = getNormal(x, z);
            GL11.glNormal3f(normal.getX(), normal.getY(), normal.getZ());
            GL11.glVertex3f(x, getHeight(x, z), z);
            normal = getNormal(x, z + 1);
            GL11.glNormal3f(normal.getX(), normal.getY(), normal.getZ());
            GL11.glVertex3f(x, getHeight(x, z + 1), z + 1);
        }
        glEnd();
    }
}

My code is the following for vertex array drawing:

private void loadArrays(){
    //calculate the length of the buffers
    bLength = (l-1) * w * 6;
    //create the normal and vertex buffer array's
    dataBuffer = BufferUtils.createFloatBuffer(bLength*2);
    cBuffer = BufferUtils.createFloatBuffer(bLength);

    for (int z = 0; z < l - 1; z++) {
        //Fill up the buffers
        for (int x = 0; x < w; x++) {
            Vector3f normal = getNormal(x, z);
            dataBuffer.put(x).put(getHeight(x,z)).put(z);
            dataBuffer.put(normal.getX()).put(normal.getY()).put(normal.getZ());
            normal = getNormal(x, z + 1);
            dataBuffer.put(x).put(getHeight(x,z+1)).put(z+1);
            dataBuffer.put(normal.getX()).put(normal.getY()).put(normal.getZ());              
        }
    } 
}

int stride = 6*4;
public void renderDirect() {
    //adapt the camera to the map
    float scale = 5.0f / Math.max(w - 1, l - 1);
    GL11.glScalef(scale, scale, scale);
    GL11.glTranslatef(-(float) (w - 1) / 2, 0.0f, -(float) (l - 1) / 2);

    //choose map color
    GL11.glColor3f(0.3f, 0.9f, 0.0f);

    //Draw the vertex arrays
    glEnableClientState(GL_VERTEX_ARRAY);      
    glEnableClientState(GL_NORMAL_ARRAY); 

    dataBuffer.position(0);
    glVertexPointer(3, stride, dataBuffer);
    dataBuffer.position(3);
    glNormalPointer(stride,dataBuffer);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, bLength/3);    

    glDisableClientState(GL_VERTEX_ARRAY);      
    glDisableClientState(GL_NORMAL_ARRAY);
}    

What am I doing wrong?

Concatenating triangle strips back-to-back like that will not work as you expect.

Either call glDrawArrays() in a loop adjusting the first and count parameters to draw your original N triangle strips, or add degenerate triangles to the end of each row to reset the strip starting position.

Or just use GL_TRIANGLES :)

Another solution that can safe you a lot of time if the number of consecutively drawn triangles in your strip is high enough is the following:

When rendering triangle strips you provide a stream of vertex information to OpenGL and it renders a triangle for each new vertex (eg sequence ABCDEF gives you the triangles ABC,BCD,CDE,DEF). Now, this will always be a single strip (that's why it's called GL_TRIANGLE_STRIP and noth the common plural naming).

Anyway, if you need to introduce a gap you may use several calls to your draw function (although that is what you want to avoid, right), but you may also make use of invalid polygons.

An invalid polygon is one that has no surface. You can create an invalid polygon by providing identical points like ABB or ABA. As far as I know such a polygon will be rejected quite early in the pipeline and it therefore doesn't give you much overhead. Now to your particular problem. Assume you have a gap (indicated by the vertical bar) like this "ABC|DEF". Modify your stream to look like this "ABCCEEDEF". This abomination gives you the triangles ABC, BCC, CCE, CEE, EDE, DEF. If you account for the early rejection of the invalid ones you get ABC and DEF - exactly what you wanted.

Ergo, in total each gap blows up your vertex stream by three triangles which in turn makes it pretty easy to see when you break even complexity-wise.

Anyway, if you need to build a gap, just you may do so by providing an invalid triangle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM