   Glvertexattribpointer(): Understanding The 'Stride' Parameter
  The glVertexAttribPointer() manual page has this to say about the 'stride' parameter:Specifies the byte offset between consecutive generic vertex attributes. If 'stride' is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0.This leads me to believe that 'stride' measures the 'space' between the END of the attribute for a given vertex and the START of the attribute for the next vertex in a VBO. However from testing I cannot confirm this. Consider the following code:static float VDATA[2][6][3] = {{{  10.25,  20.00,  20.00 },{  10.25, -19.75,  20.00 },{  50.25,  20.00,  20.00 },{  10.25, -19.75,  20.00 },{  50.25, -19.75,  20.00 },{  50.25,  20.00,  20.00 }},{{ -50.75,  20.00,  20.00 },{ -50.75, -19.75,  20.00 },{ -10.75,  20.00,  20.00 },{ -50.75, -19.75,  20.00 },{ -10.75, -19.75,  20.00 },{ -10.75,  20.00,  20.00 }}};static uint32_t ELEM[12] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };static bool initialized = false;static void engineRender( void ){GLint idx = 0;if ( !initialized ) {initialized = true;/* VBO */glGenBuffers( 1, &state->vbo );glBindBuffer( GL_ARRAY_BUFFER, state->vbo );glBufferData( GL_ARRAY_BUFFER, 4 * 9 * sizeof( float ), /* 4(triangles) * 9(floats per triangle, 3 for each vertex) */ &VDATA[0][0][0], /* both quads */ GL_STATIC_DRAW );glGenBuffers( 1, &state->ebo );glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, state->ebo );glBufferData( GL_ELEMENT_ARRAY_BUFFER, 4 * 3 * sizeof( uint32_t ), /* 4(triangles) * 3(indices per triangle) */ ELEM, GL_STATIC_DRAW );}glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );/* * First draw - left side, blue squares */engineLookAt( 0.0, 0.0, 5.0,   /* camera position */ 0.0, 0.0, 0.0,   /* camera target location */ 0.0, 1.0, 0.0    /* UP vector */    );state->color[0] = 0.0; state->color[1] = 0.0; state->color[2] = 1.0;engineTranslate( -1.5, 0.0, 0.0 );engineScale( 0.02, 0.02, 0.02 );glUseProgram( state->prog->prog_name );idx = glGetUniformLocation( state->prog->prog_name, "matWorldview" );glUniformMatrix4fv( idx, 1, GL_FALSE, state->world );idx = glGetUniformLocation( state->prog->prog_name, "matProjection" );glUniformMatrix4fv( idx, 1, GL_FALSE, state->proj );idx = glGetUniformLocation( state->prog->prog_name, "vecColor" );glUniform3fv( idx, 1, state->color );glBindBuffer( GL_ARRAY_BUFFER, state->vbo );glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, state->ebo );idx = glGetAttribLocation( state->prog->prog_name, "attrPosition" );glEnableVertexAttribArray( idx );glVertexAttribPointer( idx,    3,    GL_FLOAT,    GL_FALSE,    0,    ( GLvoid * )0 );glDrawElements( state->draw_mode, 12, GL_UNSIGNED_INT, 0 );glDisableVertexAttribArray( idx );/* * Second draw - right side, red squares */engineLookAt( 0.0, 0.0, 5.0,   /* camera position */ 0.0, 0.0, 0.0,   /* camera target location */ 0.0, 1.0, 0.0    /* UP vector */    );state->color[0] = 1.0; state->color[1] = 0.0; state->color[2] = 0.0;engineTranslate( 1.5, 0.0, 0.0 );engineScale( 0.02, 0.02, 0.02 );glUseProgram( state->prog->prog_name );idx = glGetUniformLocation( state->prog->prog_name, "matWorldview" );glUniformMatrix4fv( idx, 1, GL_FALSE, state->world );idx = glGetUniformLocation( state->prog->prog_name, "matProjection" );glUniformMatrix4fv( idx, 1, GL_FALSE, state->proj );idx = glGetUniformLocation( state->prog->prog_name, "vecColor" );glUniform3fv( idx, 1, state->color );glBindBuffer( GL_ARRAY_BUFFER, state->vbo );glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, state->ebo );idx = glGetAttribLocation( state->prog->prog_name, "attrPosition" );glEnableVertexAttribArray( idx );glVertexAttribPointer( idx,    3,    GL_FLOAT,    GL_FALSE,    3 * sizeof( float ),    ( GLvoid * )0 );glDrawElements( state->draw_mode, 12, GL_UNSIGNED_INT, 0 );glDisableVertexAttribArray( idx );SDL_GL_SwapBuffers();}Only one attribute per vertex is defined: the position (3 floats). The same geometry (the exact same VBO to be precise) is drawn twice, with different arguments given to the 'stride' argument of glVertexAttribPointer:glVertexAttribPointer( idx, 3, GL_FLOAT, GL_FALSE, 0, ( GLvoid * )0 );andglVertexAttribPointer( idx, 3, GL_FLOAT, GL_FALSE, 3 * sizeof( float ), ( GLvoid * )0 );respectively. The attributes are tightly packed in the array yet the vertex attribute pointers act as if they are equivalent. My question is: why ?
  The stride defines the bytes between the start of one vertex and the start of another. Zero is a special case number for when you are lazy and don't feel like calculating the byte offset yourself. You are correct that you will get the same result when using 0 and 3*sizeof(float) in your case. When you say '0' all it means is "figure out the width of this vertex and use that for the stride, because the data is tightly packed".   ;  I was afraid of that. I was actually hoping for end-to-start measurements and the possibility to specify negative values for 'stride'. Anyway, thank you for your quick reply.   