Bruno Kremel
Bruno Kremel

Reputation: 125

Undeterministic unwanted additional triangles on Android OpenGL ES rendering under SDL

I'm developing simple game (Kula world clone) for mobile devices (currently on android devices). The problem is that sometimes I get additional (no missing) triangles on random models in game, all in undeterministic fashion (triangles appears on random models on random places between application runs). Also it is sometimes almost unnoticeable on my HTC phone, but always massive on my Nexus 7 tablet.

I am using OpenGL ES 2 and SDL2. Application is written in C++ for code portability.

I was thinking about some buggy model loading code, but I think that it would be deterministic and there would be also some missing triangles not only additional. But the fact that it's non-deterministic and device depended leads me that it is more likely some bug in rendering.

Here are some screenshots:

From my HTC Desire C:

enter image description here

and

enter image description here

Much worse on my Nexus 7:

Vertex shader source:

attribute vec3 position;
attribute vec2 tc;
uniform mat4 mvp; 
varying vec2 coord; 
varying vec3 color;
void main() { gl_Position = mvp*vec4(position,1); coord = tc; }

and model drawing code:

void Entity::draw(GLuint HpositionAttrib, GLuint HtcAttrib, GLuint HtextureUniform, GLuint HmvpUniform,     glm::mat4 tmvp)
{
    glUniformMatrix4fv(HmvpUniform, 1, GL_FALSE, glm::value_ptr(localTransforms(tmvp)));
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glUniform1i(HtextureUniform, 0);

    glEnableVertexAttribArray(HpositionAttrib);
    glEnableVertexAttribArray(HtcAttrib);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
    glVertexAttribPointer(HpositionAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLubyte *)NULL + offsetof(vertex, position));
    glVertexAttribPointer(HtcAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLubyte *)NULL + offsetof(vertex, uvmap));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject);
#ifdef DEBUG
    SDL_Log("buffer: %d vertex: %d elements: %d\n",VBOSize, sizeof(GLushort), VBOSize/sizeof(GLushort));
#endif
    glDrawElements(GL_TRIANGLES, VBOSize/sizeof(unsigned short), GL_UNSIGNED_SHORT, NULL);

    glDrawElements(GL_TRIANGLES, VBOSize/sizeof(GLushort), GL_UNSIGNED_SHORT, NULL);
    glDisableVertexAttribArray(HpositionAttrib);
    glDisableVertexAttribArray(HtcAttrib);
}

//Edit: I have addresed issues metioned by Andon M. Coleman

And there is definition of VBOSize: It is instance variable declared:

    size_t VBOSize, EBOSize;

and is initialized as follows:

    VBOSize(vertices.size()*sizeof(vertex)), EBOSize(indexes.size()*sizeof(GLushort))

Where vertices is:

    std::vector<vertex> vertices;
    std::vector<GLushort> indexes;

These vectors are initialised from external file.

And I am using it like this:

    glGenBuffers(1, &vertexBufferObject);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
    glBufferData(GL_ARRAY_BUFFER, VBOSize, &vertices[0], GL_STATIC_DRAW);
    glGenBuffers(1, &elementBufferObject);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, EBOSize, &indexes[0], GL_STATIC_DRAW);

Upvotes: 0

Views: 466

Answers (1)

Andon M. Coleman
Andon M. Coleman

Reputation: 43319

Why are you using GLuint for some things, but where it really matters you are matching GL_UNSIGNED_SHORT with your C compiler's intrinsic unsigned short? GLushort is the proper typedef to use, the majority of the time GLushort will probably be unsigned short, but if there were ever a time where this typedef was not the same it would definitely be on an embedded platform.

Also, do not cast the result of offsetof to (void *). size_t (which the offsetof macro uses) does not have to be the same size as your platform's native data pointer type (if anything, it will be less than or equal to the pointer size). Consider (GLubyte *)NULL + offsetof (...) instead. Using a size_t value in pointer arithmetic is safe, but casting size_t to a pointer is not.

Neither one of these things is likely to fix your problem, but they are portability issues that you should avoid. The real problem is almost certainly related to overrunning your element array. GL can use indices that are out-of-range without crashing, in fact outside of WebGL most OpenGL and OpenGL ES implementations do not even define any common behavior for out-of-range buffer access.

I would like to know how VBOSize is defined, as this is most likely the culprit.

Update:

You are using the wrong size in your call to glDrawElements (...) it should be the number of elements in your Index Buffer (EBOSize you have called it). Thus, glDrawElements(GL_TRIANGLES, EBOSize/sizeof(GLushort), GL_UNSIGNED_SHORT, NULL); should fix your problem.

Upvotes: 1

Related Questions