Setup of matrix for instance shader

↘锁芯ラ 提交于 2019-12-05 10:49:58

You have discovered the hard way that vertex attribute locations are always 4-component.

The only way to make a 4x4 matrix a per-vertex attribute is if you concede that mat4 is 4x as large as vec4.

Consider the declaration of your mat4 vertex attribute:

layout(location = 3) in mat4 instanceMatrix;

You might naturally think that location 3 stores 16 floating-point values, but you would be wrong. Locations in GLSL are always 4-component. Thus, mat4 instanceMatrix actually occupies 4 different locations.

This is essentially how instanceMatrix actually works:

layout(location = 3) in vec4 instanceMatrix_Column0;
layout(location = 4) in vec4 instanceMatrix_Column1;
layout(location = 5) in vec4 instanceMatrix_Column2;
layout(location = 6) in vec4 instanceMatrix_Column3;

Fortunately, you do not have to write your shader that way, it is perfectly valid to have a mat4 vertex attribute.

However, you do have to write your C# code to behave that way:

GL.BindBuffer(BufferTarget.ArrayBuffer, matrixBuffer);
GL.VertexAttribPointer(3, 4, VertexAttribPointerType.Float, false, 64,  0); // c0
GL.VertexAttribPointer(4, 4, VertexAttribPointerType.Float, false, 64, 16); // c1
GL.VertexAttribPointer(5, 4, VertexAttribPointerType.Float, false, 64, 32); // c2
GL.VertexAttribPointer(6, 4, VertexAttribPointerType.Float, false, 64, 48); // c3

Likewise, you must setup your vertex attribute divisor for all 4 locations:

GL.VertexAttribDivisor (3, 1);
GL.VertexAttribDivisor (4, 1);
GL.VertexAttribDivisor (5, 1);
GL.VertexAttribDivisor (6, 1);

Incidentally, because vertex attributes are always 4-component, you can actually declare:

layout(location = 0) in vec4 position;

And stop writing ugly code like this:

gl_Position = instanceMatrix * projMatrix * vec4(position, 1.0);

This is because missing components in a vertex attribute are automatically expanded by OpenGL.

      (0.0, 0.0, 0.0, 1.0)

If you declare a vertex attribute as vec4 in the GLSL shader, but only supply data for XYZ, then W is automatically assigned a value of 1.0.


In actuality, you do not want to store your matrices per-vertex. That is a waste of multiple vertex attribute locations. What you may consider is an array of uniforms, or better yet a uniform buffer. You can index this array using the Vertex Shader pre-declared variable: gl_InstanceID. That is really the most sensible way to approach this, because you may find yourself using more properties per-instance than you have vertex attribute locations (mininum 16 in GL 3.3, only a few GPUs actually support more than 16).

Keep in mind that there is a limit to the number of vec4 uniforms a vertex shader can use in a single invocation, and that a mat4 counts as 4x the size of a vec4. Using a uniform buffer will allow you to draw many more instances than a plain old array of uniforms would.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!