Im creating a particle system of my own, and I have some draw issues with it. It's the first time I use instancing, so it's probable I have some concept errors.
First, I create three buffers: one for the quad that I will use in all particles, one for the transformations (which contains a planed 4x4 matrix for each particle) and one for the colors (four floats per particle):
/*Geometry buffer*/
static const GLfloat vertex_data[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
};
glGenBuffers(1, &geometry_buffer);
glBindBuffer(GL_ARRAY_BUFFER, geometry_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
/* Transform buffer */
glGenBuffers(1, &transform_buffer);
glBindBuffer(GL_ARRAY_BUFFER, transform_buffer);
// Initialize with empty (NULL) buffer : it will be updated later, each frame.
// 16 items, since we give a planed 4x4 matrix
glBufferData(GL_ARRAY_BUFFER, MAX_PARTICLES_PER_EMITTER * 16 * sizeof(GLfloat), NULL, GL_STREAM_DRAW);
/* Color buffer */
color_buffer;
glGenBuffers(1, &color_buffer);
glBindBuffer(GL_ARRAY_BUFFER, color_buffer);
// Initialize with empty (NULL) buffer : it will be updated later, each frame.
glBufferData(GL_ARRAY_BUFFER, MAX_PARTICLES_PER_EMITTER * 4 * sizeof(GLubyte), NULL, GL_STREAM_DRAW);
Each frame, I update the transform and color buffer:
/*Transform*/
glBindBuffer(GL_ARRAY_BUFFER, transform_buffer);
glBufferData(GL_ARRAY_BUFFER, MAX_PARTICLES_PER_EMITTER * 16 * sizeof(GLfloat), NULL, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, Particles.size() * sizeof(GLfloat) * 16, particles_transforms_planed);
/*Color*/
glBindBuffer(GL_ARRAY_BUFFER, color_buffer);
glBufferData(GL_ARRAY_BUFFER, MAX_PARTICLES_PER_EMITTER * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, Particles.size() * sizeof(GLfloat) * 4, particles_color_planed);
particles_transform_planed and particles_color_planed are both arrays of floats that contains the data of all particles
I use this shader of my own:
static const GLchar* ParticleVert[] =
{
"#version 330 core\n"
"layout(location = 0) in vec3 position;\n"
"layout(location = 1) in vec2 texCoord;\n"
"layout(location = 2) in mat4 transform;\n"
"layout(location = 3) in vec4 _color;\n"
"out vec4 ourColor;\n"
"out vec2 TexCoord;\n"
"uniform mat4 viewproj;\n"
"void main()\n"
"{\n"
"gl_Position = viewproj * transform *vec4(position.x,position.y,position.z, 1.0f) ;\n"
"ourColor = _color;\n"
"TexCoord = texCoord;\n"
"}\n"
};
static const GLchar* ParticleFrag[] =
{
"#version 330 core\n"
"in vec4 ourColor;\n"
"in vec2 TexCoord;\n"
"out vec4 color;\n"
"uniform sampler2D albedo;\n"
"void main()\n"
"{\n"
//Z-Buffer Line Shader
"color= ourColor * texture(albedo, TexCoord);\n"
"}\n"
};
Finally, I instantiate all particles like:
/*Vertex buffer*/
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, geometry_buffer);
glVertexAttribPointer(
0, // attribute.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
/*Position buffer*/
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, transform_buffer);
glVertexAttribPointer(
2, // attribute.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
sizeof(GLfloat) * 4 * 4, // stride
(void*)0 // array buffer offset
);
/*Color buffer*/
glEnableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, color_buffer);
glVertexAttribPointer(
3, // attribute.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
float data[MAX_PARTICLES_PER_EMITTER*4] = {};
glGetBufferSubData(GL_ARRAY_BUFFER, 0, MAX_PARTICLES_PER_EMITTER * 4 * sizeof(float), data);
//Pass the viewproj matrix to the shader
uint viewLoc = glGetUniformLocation(program_id, "viewproj");
glUniformMatrix4fv(viewLoc, 1, GL_TRUE, App->renderer3D->active_camera->frustum.ViewProjMatrix().ptr());
glVertexAttribDivisor(0, 0); // particles vertices : always reuse the same 4 vertices -> 0
glVertexAttribDivisor(2, 0); // transform : one per quad (16 floats per quad) -> 1
glVertexAttribDivisor(3, 1); // color : one per quad -> 1
//Draw all particles!
GLsizei particle_count = Particles.size();
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, particle_count);
But, in screen, the particles are drawing like:
Strangely, when I change the color in the editor, the shape of the particle starts to change. I suspect that I'm using the VertexAttribDivisor in the wrong way, and im not sure if OpenGL is taking the transform buffer in chunks of 16.
Anyone sees any error?
Thanks for the help.
PS: i'm not using yet the texture attribute, and i'm not sure if this could cause any issue;
EDIT: I found that the transformation matrix should be passed to the shader like:
/*Position buffer*/
glBindBuffer(GL_ARRAY_BUFFER, transform_buffer);
glEnableVertexAttribArray(3);
glVertexAttribPointer(
3, // attribute.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
sizeof(GLfloat) * 4 * 4, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(4);
glBindBuffer(GL_ARRAY_BUFFER, transform_buffer);
glVertexAttribPointer(
4, // attribute.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
sizeof(GLfloat) * 4 * 4, // stride
(void*)(sizeof(GLfloat) * 4) // array buffer offset
);
glEnableVertexAttribArray(5);
glVertexAttribPointer(
5, // attribute.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
sizeof(GLfloat) * 4 * 4, // stride
(void*)(sizeof(GLfloat) * 4*2) // array buffer offset
);
glEnableVertexAttribArray(6);
glBindBuffer(GL_ARRAY_BUFFER, transform_buffer);
glVertexAttribPointer(
6, // attribute.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
sizeof(GLfloat) * 4 * 4, // stride
(void*)(sizeof(GLfloat) *4* 3) // array buffer offset
);
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
glVertexAttribDivisor(5, 1);
glVertexAttribDivisor(6, 1);
After this changes, if the trasnformation matrix is equal to identity, the particle draws:
Which is correct. The problem: if i apply any transformation (in this case, a rotation to face the camera)...
The color doesn't affect anymore the shape, so i think the problems is now in the view matrices