1
votes

I'm having an issue in my OpenGL application where OpenGL appears to add a vertex at the origin of some of my meshes. The issue has me befuddled because it seems to only affect meshes composed of triangle strips. The basic procedure used to create the screenshot at the end of the post is as follows:

  1. Use simple math to generate vertices that lie on the unit sphere, as well as texture coordinates and element indices.
  2. Load the data from step 1 into buffers bound to a VAO.
  3. Every frame: bind the VAO and draw with glDrawElements()

Prior to posting, I checked the vertex data for (a simplified version of) my mesh at each stage in the process, and at no time is there a vertex at the origin (in model-space). However, if you look at the screenshot at the end of the post, there is obviously a vertex at the center of the mesh, and its presence is deforming my mesh and causing issues with texturing.

I'm pretty inexperienced with 3D graphics, and have never heard of an issue like this before, so I'm not sure what other useful information I can provide. If there's anything else, let me know in the comments.

A screenshot from my running application. A model of the Earth is rendered with, from left to right, GL_POINTS, GL_LINE_LOOP, GL_TRIANGLE_STRIP (The same model of the Earth drawn as GL_POINTS, GL_LINE_LOOP, and GL_TRIANGLE_STRIP, respectively)

UPDATE: As requested, here's the code that sets up and draws my vertex arrays:

public void init(GL3 gl){
    //If there is no graphics data, this object isn't going to get rendered and we should just leave
    if(gData == null){
        return;
    }

    //Prepare the index data
    short[] indexData = gData.getIndexArray();
    indexCount = indexData.length;

    //This is required because interleaving the data
    //screws with how the data is laid out in memory
    for(int i = 0; i < indexCount; i++){
        indexData[i] *= gData.getVertexData().size();
        indexData[i] = indexData[i] < 0 ? -1 : indexData[i]; 
    }

    //Put the program together
    glProgram = gl.glCreateProgram();
    for(Shader shader : gData.getShaders()){
        shader.compile(gl);
        gl.glAttachShader(glProgram, shader.location);
    }
    gl.glLinkProgram(glProgram);
    int[] result = new int[1];
    gl.glGetProgramiv(glProgram, GL3.GL_LINK_STATUS, result, 0);
    if(result[0] != GL3.GL_TRUE){
        byte[] info = new byte[512];
        gl.glGetProgramInfoLog(glProgram, 512, result, 0, info, 0);
        Logger.log(new String(info), Logger.ERROR, "GameObject -- init -- Link Error");
    }

    //Interleave the per-vertex data
    float[] vertexData = interleave(gData.getVertexData().toArray(new VertexData[0]));

    //Generate buffers
    gl.glGenVertexArrays(1, glBuffer, 0);
    gl.glGenBuffers(2, glBuffer, 1);
    if(checkGLErrors(gl, "After generating VAO and buffers")){
        sHandler.Quit();
    }

    //Bind the VAO, program, and buffers. In that order.
    gl.glBindVertexArray(glBuffer[0]);
    if(checkGLErrors(gl, "After binding VAO")){
        sHandler.Quit();
    }
    gl.glUseProgram(glProgram);
    if(checkGLErrors(gl, "After binding program")){
        sHandler.Quit();
    }
    gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, glBuffer[1]);
    gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, glBuffer[2]);
    if(checkGLErrors(gl, "After binding buffers")){
        sHandler.Quit();
    }

    //Send in the per-vertex data
    gl.glBufferData(
            GL3.GL_ARRAY_BUFFER,
            vertexData.length * SIZEOF_FLOAT,
            FloatBuffer.wrap(vertexData),
            GL3.GL_STATIC_DRAW);
    if(checkGLErrors(gl, "After loading data into the buffers")){
        sHandler.Quit();
    }

    //Set up pointers to the vertex attributes
    for(VertexData a : gData.getVertexData()){
        a.location = gl.glGetAttribLocation(glProgram, a.name);
        gl.glVertexAttribPointer(a.location, a.components, GL3.GL_FLOAT, false, a.stride * SIZEOF_FLOAT, a.offset * SIZEOF_FLOAT);
        gl.glEnableVertexAttribArray(a.location);
        if(checkGLErrors(gl, "After setting pointers to the vertex attributes")){
            sHandler.Quit();
        }
    }

    //Set up pointers to the uniform variables
    for(UniformData uniform : gData.getUniformData()){
        uniform.location = gl.glGetUniformLocation(glProgram, uniform.name);
        if(checkGLErrors(gl, "After setting pointers to the uniform variables")){
            sHandler.Quit();
        }
    }

    //Send in index data
    gl.glBufferData(
            GL3.GL_ELEMENT_ARRAY_BUFFER, 
            indexData.length * SIZEOF_SHORT, 
            ShortBuffer.wrap(indexData), 
            GL3.GL_STATIC_DRAW);
    if(checkGLErrors(gl, "After loading in index data")){
        sHandler.Quit();
    }

    //Load textures
    for(int i = 0; i < glTextures.length; i++){
        glTextures[i] = gData.getTextureData().get(i).loadTexture(gl);
        if(checkGLErrors(gl, "After loading texture "+i)){
            sHandler.Quit();
        }
    }

    //Bind only the first texture....
    if(glTextures.length >= 1){
        gl.glBindTexture(GL3.GL_TEXTURE_2D, glTextures[0]);
        if(checkGLErrors(gl, "After binding textures")){
            sHandler.Quit();
        }
    }

    //-----BEGIN OPENGL STATE SETTINGS-----

    //Depth Testing
    gl.glEnable(GL3.GL_DEPTH_TEST);
    gl.glDepthFunc(GL3.GL_LEQUAL);

    //Primitive Restart
    gl.glEnable(GL3.GL_PRIMITIVE_RESTART);
    gl.glPrimitiveRestartIndex(-1);

    //Enlargen points
    gl.glPointSize(5.0f);

    //-----END OPENGL STATE SETTINGS-----

    //...And we're done here.
    gl.glBindVertexArray(0);

    if(checkGLErrors(gl, "After completing Object Initialization")){
        sHandler.Quit();
    }
}

public void draw(GL3 gl){
    //Check to see if this object actually needs to be drawn
    if(gData == null){
        return;
    }

    //Bind the vertex array
    gl.glBindVertexArray(glBuffer[0]);
    gl.glUseProgram(glProgram);
    checkGLErrors(gl, "After binding vertex array");

    //Load the uniform data
    for(UniformData uniform: gData.getUniformData()){
        uniform.loadData(gl);
    }
    checkGLErrors(gl, "After loading uniform data");

    //Draw
    gl.glDrawElements(gData.getPrimitive(), indexCount, GL3.GL_UNSIGNED_SHORT, 0);

    //Unbind
    gl.glBindVertexArray(0);

    checkGLErrors(gl, "After finishing draw");
}
1
So where's your code that sets up your vertex arrays and draws them?Nicol Bolas
Most probably you have made a mistake when generating data of the sphere. OpenGL would never add a vertex on its own. Try dumping the vertices of the sphere you generated and see if there is a mistake in it (probably one (or perhaps more) vertices at position 0,0,0)Shahbaz
There's clearly a vertex at the origin in all three models, so I don't know why you think "it seems to only affect meshes composed of triangle strips"Ben Voigt
@Ben Voigt, I'm going to chalk that one up to n00b confusion and not knowing the jargon well enough to put together coherent sentences. What I meant to convey was that all three models were drawn using the same vertex data and element indices, I just changed the primitive type when drawing them. I laid out the element indices for triangle strips, and the error didn't happen on other models which had their indices laid out for GL_TRIANGLES or GL_LINES.rjacks
@rjacks: Ok, that definitely explains it, since the other types don't require restart, so you wouldn't have added those pseudo-vertices.Ben Voigt

1 Answers

2
votes

gl.glPrimitiveRestartIndex(-1);

That doesn't look right, as the parameter to glPrimitiveRestartIndex is unsigned. The result is that the restart index is set to 4294967295.

gl.glDrawElements(gData.getPrimitive(), indexCount, GL3.GL_UNSIGNED_SHORT, 0);

And here, the indices are unsigned short. (GLuint)-1 != (GLushort)-1, so the "restart" points in your VBO aren't causing restart, they're causing index 65535 to be used, which being outside the range of the data, is treated as (0,0,0).