Vertex attributes - separated components

Motivation:

There are principally 2 basic ways how to organize vertex attributes in OpenGL buffers.

  1. Interleaved - for each vertex all attribute types are grouped together, example: (VNCVNCVNCVNCVNC)
  2. Separated - for each attribute type all vertices are grouped together, example: (VVVVVNNNNNCCCCC)

Just for explanation - V stands for vertex position (coordinate vector), N stands for vertex normal (normal vector), C stands for vertex primary color (color vector). This description is used in OpenGL wiki article “Vertex Specification Best Practices” at https://www.khronos.org/opengl/wiki/Vertex_Specification_Best_Practices#Formatting_VBO_Data.

Question:

Is it possible to reach such a level of vertex attribute separation where I can group even components of mentioned vectors together? In other words, I need to delivery to the OpenGL engine the x-components of all vertices as a continuous series first, followed by continuous series of y-components, etc. The reason is that I have got the raw data in that form and I don’t want to rearrange it, as it is crazily expensive, naturally.

Examples:
(VxVxVxVxVxVyVyVyVyVyVzVzVzVzVzVwVwVwVwVw) - for each coordinate component [x,y,z,w] all vertices are grouped together
(CrCrCrCrCrCgCgCgCgCgCbCbCbCbCbCaCaCaCaCa) - for each color component [r,g,b,a] all vertices are grouped together

Just treat each vertex component as as much different attributes.
For example, vertex attribute 0 will be vertex x, attribute 1 will be vertex y… and so on.

Thank you, Silence, I see what you mean … in glVertexAttribPointer(), if I set size=1, stride=N (total # of vertices) and type to appropriate data type of my raw data, then it should work …

attr(0N+0)=V0x, attr(0N+1)=V1x, attr(0N+2)=V2x, …
attr(1
N+0)=V0y, attr(1N+1)=V1y, attr(1N+2)=V2y, …
attr(2N+0)=V0z, attr(2N+1)=V1z, attr(2N+2)=V2z, …
attr(3
N+0)=V0w, attr(3N+1)=V1w, attr(3N+2)=V2w, …

I just wonder, how it will look like on the data receiving party inside shaders …

No. The stride will be the size of a single component. You will have as many attributes as components (i.e. 4 for the position, 3 for the normal, 4 for the colour, so 11 in total). If all components are in the same buffer, then each attribute will have an offset equal to the total size of all prior components. The data will be accessed in the vertex shader as 11 distinct “float” variables.

IOW, something like


glBindBuffer(GL_ARRAY_BUFFER, position_buf);
glVertexAttribPointer(glGetAttribLocation(pgm,"vx"),1,GL_FLOAT,GL_FALSE,sizeof(GLfloat),0*nverts*4*sizeof(GLfloat));
glVertexAttribPointer(glGetAttribLocation(pgm,"vy"),1,GL_FLOAT,GL_FALSE,sizeof(GLfloat),1*nverts*4*sizeof(GLfloat));
glVertexAttribPointer(glGetAttribLocation(pgm,"vz"),1,GL_FLOAT,GL_FALSE,sizeof(GLfloat),2*nverts*4*sizeof(GLfloat));
glVertexAttribPointer(glGetAttribLocation(pgm,"vw"),1,GL_FLOAT,GL_FALSE,sizeof(GLfloat),3*nverts*4*sizeof(GLfloat));
glBindBuffer(GL_ARRAY_BUFFER, normal_buf);
glVertexAttribPointer(glGetAttribLocation(pgm,"nx"),1,GL_FLOAT,GL_FALSE,sizeof(GLfloat),0*nverts*3*sizeof(GLfloat));
glVertexAttribPointer(glGetAttribLocation(pgm,"ny"),1,GL_FLOAT,GL_FALSE,sizeof(GLfloat),1*nverts*3*sizeof(GLfloat));
glVertexAttribPointer(glGetAttribLocation(pgm,"nz"),1,GL_FLOAT,GL_FALSE,sizeof(GLfloat),2*nverts*3*sizeof(GLfloat));
glBindBuffer(GL_ARRAY_BUFFER, color_buf);
glVertexAttribPointer(glGetAttribLocation(pgm,"cr"),1,GL_UNSIGNED_BYTE,GL_TRUE,sizeof(GLubyte),0*nverts*4*sizeof(GLubyte));
glVertexAttribPointer(glGetAttribLocation(pgm,"cg"),1,GL_UNSIGNED_BYTE,GL_TRUE,sizeof(GLubyte),1*nverts*4*sizeof(GLubyte));
glVertexAttribPointer(glGetAttribLocation(pgm,"cb"),1,GL_UNSIGNED_BYTE,GL_TRUE,sizeof(GLubyte),2*nverts*4*sizeof(GLubyte));
glVertexAttribPointer(glGetAttribLocation(pgm,"ca"),1,GL_UNSIGNED_BYTE,GL_TRUE,sizeof(GLubyte),3*nverts*4*sizeof(GLubyte));

Another thing. Are you doing stream or dynamic rendering ?
If this is static, then it would certainly be better to rearrange them since you’ll upload only once. Then the shaders will directly have vec3, vec4 instead of building new ones from each attribute. Your C code might also suffer less if you need to play with these values.

Well, now I am getting a bit confused … does this really meet my original requirement “… I need to delivery to the OpenGL engine the x-components of all vertices as a continuous series first, followed by continuous series of y-components, etc …”? I need to feed OpenGL with continuous in-memory block of x-es (each x side-by-side with each other, nothing in between), then block of y-s, z-s and w-s …

The process is pretty much dynamic. The raw data is coming from measuring instrument, thus varying for each rendering.

Sure. You have a single buffer with all vertex x, followed by all vertex y and so on.

I understand.

Uhh, the stride=N (total # of vertices) is definitely nonsense, sorry for my mistake.

But anyway, in GClements code snippet, shouldn’t be rather stride=0 instead of stride=sizeof(datatype), expressing the data is “tightly packed” then?

Same end result; stride=sizeof(dataype) is tightly-packed in this case.