0
\$\begingroup\$

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: enter image description here

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: enter image description here

Which is correct. The problem: if i apply any transformation (in this case, a rotation to face the camera)... enter image description here

The color doesn't affect anymore the shape, so i think the problems is now in the view matrices

\$\endgroup\$
1
\$\begingroup\$

Ok, error solved. The thing was that the transform matrix had to be trasposed.

\$\endgroup\$
  • \$\begingroup\$ You said "when I change the color in the editor, the shape of the particle starts to change" - how is that connected with the matrix? \$\endgroup\$ – Kromster Jun 6 '18 at 10:35
  • \$\begingroup\$ @Kromster - looks like the colour issue was fixed in their edit toward the bottom of the question: "The color doesn't affect anymore the shape, so i think the problems is now in the view matrices" \$\endgroup\$ – DMGregory Jul 14 '18 at 13:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.