Dmitry
Dmitry

Reputation: 563

WebGL: vertex buffer with more than 4-dimensional coordinates?

For now I have three separate vertex buffers: 1. XYZ-buffer 2. NX,NY,NZ-buffer 3. UV-buffer

So this is 8 floats total. In future will add also tangent and bitangent info, so +6 floats.

Here's how I declare them for shader:

shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute);

shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);

Here I pass them to shader program:

gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexCoordBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexNormalBuffer);
gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexTextureCoordBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);

Since buffers are separate I can define them as vec3 and vec2 in shader:

attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;

But what if I combine them to a single buffer with 8 floats per vertex? So, the item size will be 8:

gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexCoordBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 8, gl.FLOAT, false, 0, 0);

But how do I access them in shader? vec8 ? There's maximum vec4! So how do I ?

Upvotes: 4

Views: 2206

Answers (2)

Kevin Reid
Kevin Reid

Reputation: 43872

You can create a single buffer which holds all the attributes for each vertex, using the stride and offset parameters (which you have currently set to 0) to define an interleaving the attributes. In fact, I have heard you should do this to improve locality of memory access per vertex.

The stride is the total number of bytes per vertex (rather, the spacing between occurrences of the same attribute), and the offset is the byte index where the first occurrence of the particular attribute is. So, to take your example attributes and read them from a single buffer:

gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexAttrBuffer);
var step = Float32Array.BYTES_PER_ELEMENT;
var total = 3 + 3 + 2;
var stride = step * total;
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 3, gl.FLOAT, stride, 0);
gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, 3, gl.FLOAT, false, stride, step * 3);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 2, gl.FLOAT, false, stride, step * 6);

The buffer would be loaded from a Float32Array whose elements go

[px1, py1, pz1, nx1, ny1, nz1, u1, v1,
 px2, py2, pz2, nx2, ny2, nz2, u2, v2,
 ...]

Upvotes: 5

Dragan Okanovic
Dragan Okanovic

Reputation: 7781

Maximum is vec4, you're right, and only way for webGL. You might try passing arrays as attribute: GLSL per vertex fixed size array, but OpenGL ES 2.0 doesn't support it, so this option is available only in desktop OpenGL. But I don't see real need of doing that, so you will be okay with vec4 no matter what you do, and passing arrays attribute is something you probably shouldn't do.

Hope this helps.

Upvotes: 0

Related Questions