So I tried rendering multiple particles with a for loop and found that that eats up quite a bit of data/memory. I found out about this pretty legit sounding thing known as instancing! I thought it looked pretty complex and I was right! I tried my best to implement it for silly little particles but all I get is a blank screen. It loads the particles and everything just fine, only problem is during rendering where I get the blank screen. I will post my code below and see what you guys think. This is very beneficial to my current project. I am probably doing something completely wrong here, due to the fact that I don’t really understand it. I will post the code below as well as my vertex shader. Thanks for the help in advance!
void Particles::setup(string texturedata, double maxparticles)
{
maxpart = maxparticles;
particle_position_data = new GLfloat[maxpart * 12];
particle_texcoord_data = new GLfloat[maxpart * 12];
particle.resize(maxpart);
for(int i = 0; i<maxpart; i++)
particle[i].life = -1;
moving = false;
alpha = startalpha = 1;
velx = vely = rotatespeed = rotating = shrinking = decaying = life = sw = sh = 0;
glGenBuffers(1, &particle_position_buffer);
glBindBuffer(GL_ARRAY_BUFFER, particle_position_buffer);
glBufferData(GL_ARRAY_BUFFER, maxparticles * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW);
glGenBuffers(1, &particle_texcoord_buffer);
glBindBuffer(GL_ARRAY_BUFFER, particle_texcoord_buffer);
glBufferData(GL_ARRAY_BUFFER, maxparticles * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW);
}
void Particles::setmove( double startx, double starty, double startwidth, double startheight, double rotation, double xvel, double yvel, double lifeseconds, bool decay, bool shrink, bool rotate)
{
for(int i=0; i<maxpart; i++)
{
particle[i].x = startx + (rand()%30);
particle[i].y = starty + (rand()%30);
particle[i].size = startwidth;
particle[i].spritex = 0;
particle[i].spritey = 0;
particle[i].xnext = 1;
particle[i].ynext = 1;
// first triangle of particle quad
particle_position_data[12*i+0] = particle[i].x;
particle_position_data[12*i+1] = particle[i].y - particle[i].size;
particle_position_data[12*i+2] = particle[i].x;
particle_position_data[12*i+3] = particle[i].y;
particle_position_data[12*i+4] = particle[i].x + particle[i].size;
particle_position_data[12*i+5] = particle[i].y;
// second triangle
particle_position_data[12*i+6] = particle[i].x + particle[i].size;
particle_position_data[12*i+7] = particle[i].y;
particle_position_data[12*i+8] = particle[i].x + particle[i].size;
particle_position_data[12*i+9] = particle[i].y - particle[i].size;
particle_position_data[12*i+10] = particle[i].x;
particle_position_data[12*i+11] = particle[i].y - particle[i].size;
//first triangle for texcoords
particle_texcoord_data[12*i+0] = particle[i].spritex;
particle_texcoord_data[12*i+1] = particle[i].spritey;
particle_texcoord_data[12*i+2] = particle[i].spritex;
particle_texcoord_data[12*i+3] = particle[i].spritey + particle[i].ynext;
particle_texcoord_data[12*i+4] = particle[i].spritex + particle[i].xnext;
particle_texcoord_data[12*i+5] = particle[i].spritey + particle[i].ynext;
//second triangle
particle_texcoord_data[12*i+6] = particle[i].spritex + particle[i].xnext;
particle_texcoord_data[12*i+7] = particle[i].spritex + particle[i].ynext;
particle_texcoord_data[12*i+8] = particle[i].spritex + particle[i].xnext;
particle_texcoord_data[12*i+9] = particle[i].spritey;
particle_texcoord_data[12*i+10] = particle[i].spritex;
particle_texcoord_data[12*i+11] = particle[i].spritey;
particlecount = i;
}
}
void Particles::render(unsigned int program, unsigned int Texture, Camera camera, RenderPipeline pipeline, double r, double g, double b)
{
pipeline.pushMatrix();
pipeline.ortho(0,640,640,0,-1,1);
pipeline.translate( camera.calcx(), camera.calcy(), 0);
pipeline.updateMatrices(program);
glBindBuffer(GL_ARRAY_BUFFER, particle_position_buffer);
glBufferData(GL_ARRAY_BUFFER, maxpart * 12 * sizeof(GLfloat), NULL, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, particlecount * sizeof(GLfloat) * 4, particle_position_data);
glBindBuffer(GL_ARRAY_BUFFER, particle_texcoord_buffer);
glBufferData(GL_ARRAY_BUFFER, maxpart * 12 * sizeof(GLfloat), NULL, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, particlecount * sizeof(GLfloat) * 4, particle_texcoord_data);
glBindTexture(GL_TEXTURE_2D, Texture);
glUniform1i(glGetUniformLocation(program,"img"),0);
//color and boolean variables for particle arrays
glUniform4f(glGetUniformLocation(program,"color"),r,g,b,1);
glUniform1i(glGetUniformLocation(program,"array"),1); //this lets the shader know that we have an array of particles and are indexing
int position=glGetAttribLocation(program, "vertexpos");
int texcoord=glGetAttribLocation(program, "texcoord");
//attribute of particle's vertices
glEnableVertexAttribArray(position);
glBindBuffer(GL_ARRAY_BUFFER, particle_position_buffer);
glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
//attribute of particles' texture coordinates
glEnableVertexAttribArray(texcoord);
glBindBuffer(GL_ARRAY_BUFFER, particle_texcoord_buffer);
glVertexAttribPointer(texcoord, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
//glVertexAttribDivisor(index, 0); every particle has same vertices (this will not be used due to the complexity of putting all this info in the shader
glVertexAttribDivisor(position, 1); // positions, one per particle
glVertexAttribDivisor(texcoord, 1); // same with the texture coordinates
// draw all the silly little particles
glDrawArraysInstancedEXT(GL_TRIANGLE_STRIP, 0, 4, particlecount);
glDisableVertexAttribArray(position);
glDisableVertexAttribArray(texcoord);
glBindBuffer(GL_ARRAY_BUFFER,0);
pipeline.popMatrix();
}
//particle class
struct PartContainer
{
double x;
double y;
double size;
double life;
double spritex, spritey;
double xnext, ynext;
};
class Particles
{
public:
vector <PartContainer> particle;
void setup(string texturedata, double maxparticles);
void setmove( double startx, double starty, double startwidth, double startheight, double rotation = 10, double xvel=0, double yvel=0, double lifeseconds=10, bool decay = true, bool shrink = true, bool rotate = true);
void move();
void render(unsigned int program, unsigned int Texture, Camera camera, RenderPipeline pipeline, double r = 1, double g = 1, double b = 1);
bool moving, decaying, shrinking, rotating;
double alpha, startalpha, velx, vely, life, sw, sh, rotatespeed;
int maxpart, particlecount;
bool vertset;
double size;
GLfloat* particle_position_data;
GLfloat* particle_texcoord_data;
GLuint particle_position_buffer;
GLuint particle_texcoord_buffer;
};
And here is the Vertex Shader
attribute vec2 vertexpos;
attribute vec2 texcoord;
varying vec2 texcoordvarying;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 normalMatrix;
void main()
{
gl_Position=modelViewProjectionMatrix*vec4(vertexpos,0.0,1.0);
texcoordvarying=texcoord;
}