## Particle Vertex Array

Apprentice
Posts: 9
Joined: 2010.02
Post: #1
Hi,

how i can render particles, with Vertex arrays. I have this simple structur

Code:
```typedef struct _particle {         float        finalColor[4];     float        vertices[12]; . . . }Particle;```

init
Code:
```_particles[i].vertices[0] =_particles[i].position[0]-(_particles[i].size/2); _particles[i].vertices[1] =_particles[i].position[1]-(_particles[i].size/2); _particles[i].vertices[2] =_particles[i].position[2];          _particles[i].vertices[3] =_particles[i].position[0]+(_particles[i].size/2); _particles[i].vertices[4] =_particles[i].position[1]-(_particles[i].size/2); _particles[i].vertices[5] =_particles[i].position[2];          _particles[i].vertices[6] =_particles[i].position[0]+(_particles[i].size/2); _particles[i].vertices[7] =_particles[i].position[1]+(_particles[i].size/2); _particles[i].vertices[8] =_particles[i].position[2];          _particles[i].vertices[9] =_particles[i].position[0]-(_particles[i].size/2); _particles[i].vertices[10] =_particles[i].position[1]+(_particles[i].size/2); _particles[i].vertices[11] =_particles[i].position[2];```

and i like to render the particles like this:
Code:
```glVertexPointer(3, GL_FLOAT, sizeof(Particle), &_particles[0].vertices); glDrawArrays(GL_QUADS, 0, NUM_PARTICLES);```

but, that seems to be wrong. Someone an idea?
Moderator
Posts: 1,563
Joined: 2003.10
Post: #2
Looks like there are two problems here:
• The stride parameter to glVertexPointer is the number of bytes from the end of one vertex to the beginning of the next, as opposed to the number of bytes from the beginning of one vertex to the beginning of the next. This tripped me up, too. You'll want something like sizeof(struct _particle) - sizeof(_particles[0].vertices).
• ...However, this won't actually work, because the stride specifies the bytes between vertices, as opposed to the space between primitives. You may need to reorganize your data so that the space between each set of vertex coordinates is consistent. As it's currently set up, you have a 16-byte chunk between each quad, but the vertices in the quad itself are tightly packed.
Apprentice
Posts: 9
Joined: 2010.02
Post: #3
Thanks,
but how can i do this.

Moderator
Posts: 1,563
Joined: 2003.10
Post: #4
You'll need to model the data in your application in some way that allows lists of vertices to either be contiguous across the entire array you're drawing, or to have uniform byte spacing between each vertex across the entire array. How you accomplish this is really up to you; do whatever makes the most sense to fit into your current data model given the above constraints.
Sage
Posts: 1,199
Joined: 2004.10
Post: #5
Here's how I arranged my data, for a foliage system ( a specialized particle system ).

Code:
```struct foliage_vertex {     static const int INTERLEAVED_FORMAT = GL_T2F_C3F_V3F;          inline foliage_vertex( void ) {}          inline foliage_vertex( const foliage_vertex &c ):         texcoord( c.texcoord ),         color( c.color ),         position( c.position )     {}     inline foliage_vertex( const vec2 &tc, const vec3 &c, const vec3 &p ):         texcoord( tc ),         color( c ),         position( p )     {}          inline foliage_vertex &operator = ( const foliage_vertex &c )     {         texcoord = c.texcoord;         color = c.color;         position = c.position;         return *this;     }          vec2 texcoord;     vec3 color, position; }; struct foliage_quad {     foliage_vertex a,b,c,d;          inline foliage_quad( void ) {}     inline foliage_quad( const foliage_quad &f ):         a( f.a ),         b( f.b ),         c( f.c ),         d( f.d )     {}     inline foliage_quad &operator = ( const foliage_quad &f )     {         a = f.a;         b = f.b;         c = f.c;         d = f.d;         return *this;     }      }; ... later std::vector< foliage_quad > _foliage;```

And to submit it to GL:
Code:
```glInterleavedArrays( foliage_vertex::INTERLEAVED_FORMAT, 0, &(_foliage.front()) ); glDrawArrays( GL_QUADS, 0, _numQuads * 4 ); glDisableClientState( GL_VERTEX_ARRAY ); glDisableClientState( GL_COLOR_ARRAY ); glDisableClientState( GL_TEXTURE_COORD_ARRAY );```

Works for me!

Note: I'm billboarding in a vertex shader, so in principle I could use a VBO instead of a vertex array. BUT: I'm periodically depth-sorting the vertices, so I need to stream them. I could probably switch to a streaming or write-only vbo-format, but my foliage system allocation strategy is a little rough, and I don't want to blow out my vram.
Apprentice
Posts: 9
Joined: 2008.01
Post: #6
ThemsAllTook Wrote:Looks like there are two problems here:
• The stride parameter to glVertexPointer is the number of bytes from the end of one vertex to the beginning of the next, as opposed to the number of bytes from the beginning of one vertex to the beginning of the next. This tripped me up, too. You'll want something like sizeof(struct _particle) - sizeof(_particles[0].vertices).

Err, are you sure about that? I just wrote some testing code to render a VBO and the stride is the number of byte from the start of a vertice to the next.

For example, if you have
Code:
```// FIXME: dirty testing code     size_t float_count = vertex_count * (3 + 3 + 2 + 2 + 1);     buf_len = sizeof(GLfloat) * float_count;     buf = malloc(buf_len);     uint32_t i;     for(i = 0; !feof(fd) && i < float_count;) {         // FIXME: fscanf is dirty, only for testing, move to binary when working.         vec3 v;         // pos         fscanf(fd, "%f %f %f\n", &v.f[0], &v.f[1], &v.f[2]);         v = v_div3f(v, 100000);         buf[i++] = v.f[0];         buf[i++] = v.f[1];         buf[i++] = v.f[2];         // norm         fscanf(fd, "%f %f %f\n", &v.f[0], &v.f[1], &v.f[2]);         v = v_div3f(v, 100000);         buf[i++] = v.f[0];         buf[i++] = v.f[1];         buf[i++] = v.f[2];         // uv0         fscanf(fd, "%f %f\n", &v.f[0], &v.f[1]);         v = v_div3f(v, 100000);         buf[i++] = v.f[0];         buf[i++] = v.f[1];         // uv1         fscanf(fd, "%f %f\n", &v.f[0], &v.f[1]);         v = v_div3f(v, 100000);         buf[i++] = v.f[0];         buf[i++] = v.f[1];         // flags         fscanf(fd, "%f\n", &v.f[0]);         buf[i++] = v.f[0]; }```

You will do something like:

Code:
```#define glOffsetf(_x) ((const GLvoid *)(_x * sizeof(GLfloat)))     #define glStridef(_x) (_x * sizeof(GLfloat))     glEnableClientState(GL_VERTEX_ARRAY);     glEnableClientState(GL_NORMAL_ARRAY);     glEnableClientState(GL_TEXTURE_COORD_ARRAY);     glBindBuffer(GL_ARRAY_BUFFER, vbo);          glVertexPointer(3, GL_FLOAT, glStridef(11), glOffsetf(0));         glNormalPointer(GL_FLOAT, glStridef(11), glOffsetf(3));     glClientActiveTexture(GL_TEXTURE0);     glTexCoordPointer(2, GL_FLOAT, glStridef(11), glOffsetf(6));     glClientActiveTexture(GL_TEXTURE1);     glTexCoordPointer(2, GL_FLOAT, glStridef(11), glOffsetf(8));     glEnableVertexAttribArray(attrib_loc);     glVertexAttribPointer(attrib_loc, 1, GL_FLOAT, GL_FALSE, glStridef(11), glOffsetf(10));     glDrawArrays(GL_TRIANGLES, 0, vertex_count);```

Note that the stride is always 11 * sizeof(GLfloat).

This code is working properly (even if it's dirty).
Luminary
Posts: 5,143
Joined: 2002.04
Post: #7
kuon is correct; stride is either 0 ("tightly packed") or number of bytes from the beginning of one vertex to the beginning of the next.
Moderator
Posts: 1,563
Joined: 2003.10
Post: #8
Hmm, my mistake. The man page isn't worded as clearly as it could be...
Moderator
Posts: 3,591
Joined: 2003.06
Post: #9
ThemsAllTook Wrote:The man page isn't worded as clearly as it could be...

... Nice save!
Apprentice
Posts: 9
Joined: 2010.02
Post: #10
Thanks for suggestions