Jump to content
  • Advertisement
IceCave

OpenGL ES Instancing draws nothing

Recommended Posts

Posted (edited)

I am successfully drawing single objects with glDrawElements and I am now trying to render at least one object with glDrawElementsInstanced instead. However the object just flashes for a frame (or more, I can't tell) and then stays invisible. The main problem is I can't see what is happening on the shader side so I can't debug it. I was hoping for some experienced members taking a look before I Keep searching with Trial and error.

All I did was changing the vertex shader to this

#version 310 es

uniform mat4 projectionMatrix;
//uniform mat4 modelMatrix;
in mat4 modelMatrix;
uniform mat4 worldMatrix;

in vec4 in_Position;
in vec2 in_TextureCoord;

out vec2 pass_TextureCoord;

void main(void) {
	gl_Position = projectionMatrix * worldMatrix * modelMatrix * in_Position;
	
	pass_TextureCoord = in_TextureCoord;
}

and instead of using this every frame:

GLES31.glUniformMatrix4fv(currentShader.getUniLocations()[1], 1, false, matrix.getArray(), 0);

I am now doing this every frame:

ByteBuffer buffer = createBuffer( matrix.getArray() );

GLES31.glBindVertexArray(vaoID);
int id = attriLocations[index];
if (id != -1) {
    for( int i = 0; i < 4; i++ ) {
        GLES31.glEnableVertexAttribArray(id+i);
    }
    GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, vboIDs[index]);
    GLES31.glBufferData(GLES31.GL_ARRAY_BUFFER, buffer.size(), buffer, GLES31.GL_DYNAMIC_DRAW);

    for( int i = 0; i < 4; i++ ) {
        GLES31.glVertexAttribPointer(id+i, 4, GLES31.GL_FLOAT, false, 4 * 4 * 4, i * 4 * 4);
    }
    for( int i = 0; i < 4; i++ ) {
        GLES31.glVertexAttribDivisor(id+i, 1);
    }
}
GLES31.glBindVertexArray(0);
GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0);

It draws for a very short period (probably one frame) and then nothing at all, anymore. The other still non-instanced objects keep being drawn correctly and OpenGL throws no Error.

Edited by IceCave

Share this post


Link to post
Share on other sites
Advertisement
At first:
Try to use glGetShaderInfoLog function after shader linking code and glGetError for error detection.
Second:
Your "every frame code" is so bad. Sorry.
FOR loop 3 times with same logic in render method (int i = 0; i < 4; i++) it's not cool.
In my mind you need to set glVertexAttribPointer firstly and then glEnableVertexAttribArray.
Third:
Did you understand how glBufferData method working? Are you sure that buffer.size() returned good value?
P.S.
Sorry for my english.
I hope you will succeed

I do most of this things one time in initialize method and just when buffers have changes:

public void Initialize(BufferUsageHint bufferUsageHint = BufferUsageHint.StaticDraw)
{
VBO_ID = GL.GenBuffer();
VAO_ID = GL.GenVertexArray();
EBO_ID = GL.GenBuffer();
GL.BindVertexArray(VAO_ID);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_ID);
GL.BufferData(BufferTarget.ArrayBuffer, sizeof(float) * DrawVertices.Length, DrawVertices, bufferUsageHint);
// Coords attribute
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, sizeof(float) * 8, 0);
GL.EnableVertexAttribArray(0);
// Textures attribute
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, sizeof(float) * 8, sizeof(float) * 3);
GL.EnableVertexAttribArray(1);
// Normals attribute
GL.VertexAttribPointer(2, 3, VertexAttribPointerType.Float, false, sizeof(float) * 8, sizeof(float) * 5);
GL.EnableVertexAttribArray(2);
// Indices buffer
GL.BindBuffer(BufferTarget.ElementArrayBuffer, EBO_ID);
GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(int) * Indices.Length, Indices, bufferUsageHint);
}

And my draw method looks like this:

public void Draw(ShaderProgram shaderProgram, BeginMode beginMode = BeginMode.Triangles)
{
// SHADER SET UNIFORMS...
GL.BindVertexArray(VAO_ID);
GL.DrawElements(beginMode, Indices.Length, DrawElementsType.UnsignedInt, 0);
GL.BindVertexArray(0);
}

 

Share this post


Link to post
Share on other sites
Posted (edited)

for instanced rendering, you need 3 buffer objects: (ok, the IBO is optional used with indexed rendering)

1. a vertex buffer (VBO)

2. an index buffer (IBO) ... as you had without instancing

3. an instance buffer, which contains mat4 modelmatrices of ALL object (with the same mesh)

 

all these are put together in 1 vertex array (VAO), VBO and IBO code as before, but the difference is that your "mat4 ModelMatrix" in the shader will be an "attribute mat4" rather than a "uniform mat4" and the VAO attribute gets a glVertexAttribDivisor(attribute, 1) to make sure that for each mesh, only 1 matrix gets streamed to the shader.

finally instancing doesnt work without an instanced draw call: glDrawElementsInstanced(..., instancecount); make sure your instance buffer contains at least "instancecount" matrices

https://www.khronos.org/opengl/wiki/Vertex_Rendering#Instancing

https://sites.google.com/site/john87connor/advanced-opengl-tutorials/tutorial-11-instanced-rendering

glGenVertexArrays(1, &m_vertexarray);
glGenBuffers(1, &m_vertexbuffer);
glGenBuffers(1, &m_instancebuffer);

glBindVertexArray(m_vertexarray);

glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 0));
glVertexAttribPointer(1, 4, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 3));
glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindBuffer(GL_ARRAY_BUFFER, m_instancebuffer);
glVertexAttribPointer(2, 4, GL_FLOAT, false, sizeof(ModelInstance), (void*)(sizeof(float) * 0));
glVertexAttribPointer(3, 4, GL_FLOAT, false, sizeof(ModelInstance), (void*)(sizeof(float) * 4));
glVertexAttribPointer(4, 4, GL_FLOAT, false, sizeof(ModelInstance), (void*)(sizeof(float) * 8));
glVertexAttribPointer(5, 4, GL_FLOAT, false, sizeof(ModelInstance), (void*)(sizeof(float) * 12));
glBindBuffer(GL_ARRAY_BUFFER, 0);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);

// sent these attributes only once per instance to the program:
glVertexAttribDivisor(2, 1);
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
glVertexAttribDivisor(5, 1);

glBindVertexArray(0);

 

Edited by john_connor

Share this post


Link to post
Share on other sites

I examined your answers and my code carefully and found that I have to call

GLES31.glBindVertexArray(0);

before enabling another shader! What made the whole situation even more confusing was that it worked for a very Long time without and also worked again when I just enabled the other shader and VAO twice in a row - whatever reason this might be.

Anyway, it works and that is what counts.

 

On ‎1‎/‎3‎/‎2019 at 10:55 PM, Aleh Lipka said:
Second:
Your "every frame code" is so bad. Sorry.
FOR loop 3 times with same logic in render method (int i = 0; i < 4; i++) it's not cool.
In my mind you need to set glVertexAttribPointer firstly and then glEnableVertexAttribArray.

It's done 4 times because mat4 attributes in a shader are actually 4x vec4. The ids of the 4 vec4s are then:
id+0
id+1
id+2
id+3

I just wanted to clarify that because maybe you want to use mat4s as an attribute as well, one day, saving you some trouble I had. ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!