GLSL实例化-顶点数据的最大输入数量是多少?

8

我正在尝试在我的OpenGL程序中实现Instancing。我已经让它工作了,然后决定通过将Model-View-Projection乘法矩阵作为输入发送到GLSL程序中来使我的GLSL代码更加高效,这样CPU会为每个实例计算它,而不是GPU。这是我的顶点着色器代码(大部分与我的问题无关):

#version 330 core

// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 2) in vec3 vertexColor;
layout(location = 3) in vec3 vertexNormal_modelspace;
layout(location = 6) in mat4 models;
layout(location = 10) in mat4 modelsV;
layout(location = 14) in mat4 modelsVP;

// Output data ; will be interpolated for each fragment.
out vec3 newColor;

out vec3 Position_worldspace;

out vec3 Normal_cameraspace;
out vec3 EyeDirection_cameraspace;

// Values that stay constant for the whole mesh.
uniform mat4 MVP;
uniform mat4 MV;
uniform mat4 P;
uniform mat4 V;
uniform mat4 M;
uniform int num_lights;
uniform vec3 Lights[256];

void main(){

// Output position of the vertex, in clip space : MVP * position
gl_Position =  P * modelsV * vec4(vertexPosition_modelspace,1);

// Position of the vertex, in worldspace : M * position
Position_worldspace = (models * vec4(vertexPosition_modelspace,1)).xyz;

// Vector that goes from the vertex to the camera, in camera space.
// In camera space, the camera is at the origin (0,0,0).
vec3 vertexPosition_cameraspace = ( modelsV * vec4(vertexPosition_modelspace,1)).xyz;
EyeDirection_cameraspace = vec3(0,0,0) - vertexPosition_cameraspace;    

// Normal of the the vertex, in camera space
Normal_cameraspace = ( modelsV * vec4(vertexNormal_modelspace,0)).xyz;

// UV of the vertex. No special space for this one.
newColor = vertexColor;

}

上述代码有效,但仅因为我没有使用最后一个输入的modelsVP计算gl_position。如果我使用它(而不是计算P * modelsV),实例将无法绘制,并且会出现以下错误:
Linking program
Compiling shader : GLSL/meshColor.vertexshader
Compiling shader : GLSL/meshColor.fragmentshader
Linking program
Vertex info
0(10) : error C5102: input semantic attribute "ATTR" has too big of a numeric index (16)
0(10) : error C5102: input semantic attribute "ATTR" has too big of a numeric index (16)
0(10) : error C5041: cannot locate suitable resource to bind variable "modelsVP". Possibly large array.

我确定我在我的OpenGL代码中正确地链接了它,因为如果我将输入位置modelsVP与modelsV交换,使其变为10而不是14,我就能够使用它,但不能使用modelsV。你的顶点着色器中的输入数量是否有最大限制?我真的想不出还有其他原因会导致这个错误...
我将包括更多相关的OpenGL代码,但我相当确定它是正确的(它不都在同一个类或方法中):
// Buffer data for VBO. The numbers must match the layout in the GLSL code.
#define position 0 
#define uv 1
#define color 2
#define normal 3 
#define tangent 4
#define bitangent 5
#define model 6      // 4x4 matrices take 4 positions
#define modelV 10
#define modelVP 14
#define num_buffers 18

GLuint VBO[num_buffers];
glGenBuffers(num_buffers, VBO);

for( int i=0; i<ModelMatrices.size(); i++ )
{
mvp.push_back( projection * view * ModelMatrices.at(i) );
mv.push_back( view * ModelMatrices.at(i) );
}

glBindBuffer(GL_ARRAY_BUFFER, VBO[model]);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * ModelMatrices.size(), &ModelMatrices[0], GL_DYNAMIC_DRAW);
for (unsigned int i = 0; i < 4 ; i++) {

glEnableVertexAttribArray(model + i);
glVertexAttribPointer(model + i, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), 
(const GLvoid*)(sizeof(GLfloat) * i * 4));
glVertexAttribDivisor(model + i, 1);
}

glBindBuffer(GL_ARRAY_BUFFER, VBO[modelV]);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * mv.size(), &mv[0], GL_DYNAMIC_DRAW);
for (unsigned int i = 0; i < 4 ; i++) {

glEnableVertexAttribArray(modelV + i);
glVertexAttribPointer(modelV + i, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), 
(const GLvoid*)(sizeof(GLfloat) * i * 4));
glVertexAttribDivisor(modelV + i, 1);
}

glBindBuffer(GL_ARRAY_BUFFER, VBO[modelVP]);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * mvp.size(), &mvp[0], GL_DYNAMIC_DRAW);
for (unsigned int i = 0; i < 4 ; i++) {

glEnableVertexAttribArray(modelVP + i);
glVertexAttribPointer(modelVP + i, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (const GLvoid*)(sizeof(GLfloat) * i * 4));
glVertexAttribDivisor(modelVP + i, 1);
}

3
世界到相机和相机到透视矩阵在每个实例中都不会改变。因此它们不需要成为每个实例的数据。另外,您根本不应该使用任何世界空间,而是应该直接从模型到相机空间进行操作。一个属性矩阵和一个统一矩阵即可。 - Nicol Bolas
世界到相机矩阵是模型*视图,因此每个实例都会改变,因为每次更改的是模型矩阵,对吧?我认为让CPU计算模型到相机矩阵比GPU更好。 (模型到相机空间和世界到相机空间是一样的,对吧?) - Drake
1
“世界到相机矩阵是模型视图”不,那是模型到相机矩阵;世界到相机矩阵只是“视图”。而且,它确实会因每个实例而改变,但这就是我的观点。你只需要一个每个实例都会改变的矩阵。它应该是模型到相机矩阵,因为在世界空间中工作是一个可怕的想法。 - Nicol Bolas
抱歉,我还是不明白。如果你的意思是我的代码中的“uniform mat4 V”这一行应该省略,那么我需要这个视图矩阵来计算片段着色器中的某些光照效果。如果不是,请问哪一行代码应该被省略/替换? - Drake
1
我假设models是模型矩阵(顺带一提:GLSL没有标识符大小限制。为这些使用更好的名称)。您不应该在世界空间中进行任何计算。在世界空间中可以进行的任何操作都可以在相机空间或位置上与相机定向对齐的空间中进行。因此,您不需要models。而且您也不需要modelsVP,因为您必须在任何情况下计算vertexPosition_cameraspace。所以您最好只需使用P将其转换为gl_Position - Nicol Bolas
我强烈推荐使用四元数。你所有的属性都可以压缩到{ vec3 position; quat4 tangent; vec3 texcoord; vec4 color; vec3 modelPosition; quat4 modelOrientation; }中,这适用于6个属性位置。 - Yakov Galka
2个回答

14

OpenGL规定实现必须提供至少16个4分量顶点属性。因此,并非所有实现都保证支持索引为16;有关更多详细信息,请参见GL_MAX_VERTEX_ATTRIBS

您的mat4顶点属性计为4个4分量属性,因此,在仅支持16个4分量顶点属性的实现中,索引14超出范围。


我就知道!我想我得让GPU多做一次矩阵乘法。 - Drake

7

您正在使用过多的顶点属性。以下是如何减少属性数量而不更改代码(任何功能更改都是改进)的方法。以下假设models是“模型到世界”矩阵,modelsV是“模型到相机”矩阵,并且modelsVP是“模型到投影”矩阵:

#version 330 core

// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 2) in vec3 vertexColor;
layout(location = 3) in vec3 vertexNormal_modelspace;
layout(location = 6) in mat4 modelsV;

// Output data ; will be interpolated for each fragment.
out vec3 newColor;

//The fragment shader should work in *camera* space, not world space.
out vec4 Position_cameraspace;

out vec3 Normal_cameraspace;
//out vec3 EyeDirection_cameraspace; Can be computed from Position_cameraspace in the FS.

// Values that stay constant for the whole mesh.
uniform mat4 P;

void main()
{
  Position_cameraspace = modelsV * vec4(vertexPosition_modelspace, 1.0);

  gl_Position = P * Position_cameraspace;

  Normal_cameraspace = ( modelsV * vec4(vertexNormal_modelspace,0)).xyz;

  newColor = vertexColor;
}

看到了吗?是不是更简单了?在顶点着色器中少用一些统一变量,减少片元着色器的输出,少进行一些数学计算和减少顶点属性。

你需要做的就是修改片元着色器使用相机空间位置而不是世界空间位置。这应该是一个相当容易的改变。


我无法感谢你花时间解释所有这些的足够了。我的代码现在更加高效和易于阅读,而且我对矩阵空间有了更深入的理解。虽然我仍然在处理二维图像的着色器程序中使用世界空间,因为它不使用视图或投影矩阵。 - Drake

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接