Advertisement

Instancing draws nothing

Started by January 01, 2019 07:58 PM
3 comments, last by IceCave 6 years, 1 month ago

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.

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);
}

 

Advertisement

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);

 

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. ;)

This topic is closed to new replies.

Advertisement