GLSL Instancing - 顶点数据的最大输入数?

Posted

技术标签:

【中文标题】GLSL Instancing - 顶点数据的最大输入数?【英文标题】:GLSL Instancing - Max number of inputs for vertex data? 【发布时间】:2013-08-31 01:52:02 【问题描述】:

我正在尝试在我的 OpenGL 程序中实现实例化。我让它工作,然后决定通过将模型-视图-投影乘法矩阵作为输入发送到 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);

【问题讨论】:

世界到相机和相机到透视矩阵不改变每个实例。所以没有必要让它们成为每个实例的数据。另外,您根本不应该使用任何世界空间。你应该从模型到相机空间。一个属性矩阵和一个均匀矩阵。 世界到相机的矩阵是模型*视图,所以它会随着实例的变化而变化,因为模型矩阵每次都在变化,不是吗?而且我认为让 CPU 计算模型到相机矩阵而不是 GPU 会更好。 (模型到相机的空间和世界到相机的空间是一回事,对吧?) "world-to-camera 矩阵是 ModelView*" 不,这是 model-to-camera 矩阵;世界到相机只是“视图”。是的,它确实会在每个实例中发生变化,但这就是我的观点。您只需要 一个 矩阵来更改每个实例。它应该是模型到相机的矩阵,因为在世界空间中工作是一个糟糕的主意。 对不起,我还是不明白。如果你的意思是我的代码中的“uniform mat4 V”行应该被省略,我只需要那个 View 矩阵来计算我的片段着色器中的一些光照效果。如果不是,应该省略/替换哪一行代码? 我假设 models 是模型到世界的矩阵(仅供参考:GLSL 没有标识符大小限制。为这些使用更好的名称)。您不应该在世界空间中进行任何计算。您可以在世界空间中做的任何事情都可以在相机空间或相对于相机但在方向上与世界对齐的空间中完成。所以你不需要models。而且你不需要modelsVP,因为你必须计算vertexPosition_cameraspace无论如何。所以你不妨使用P 将其转换为gl_Position 【参考方案1】:

OpenGL 要求实现至少提供 16 个 4 分量顶点属性。因此,不能保证所有实现都支持 16 的索引;有关详细信息,请参阅GL_MAX_VERTEX_ATTRIBS

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

【讨论】:

我是这么认为的!我想我得让 GPU 做一个额外的矩阵乘法。【参考方案2】:

您使用了太多顶点属性。以下是如何在不更改任何代码的情况下减少属性数量(任何功能更改都是改进)。下面假设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;

看到了吗?是不是简单多了?顶点着色器中的制服更少,片段着色器的输出更少,数学计算更少,顶点属性更少。

您需要做的就是将片段着色器更改为使用相机空间位置,而不是世界空间位置。这应该是一个相当容易的改变。

【讨论】:

非常感谢您抽出时间来解释这一切。我的代码现在更高效、更易于阅读,而且我对矩阵空间有了更多的了解。虽然我仍然在我的一个处理 2D 图像的着色器程序中使用世界空间,因为它不使用视图或投影矩阵。

以上是关于GLSL Instancing - 顶点数据的最大输入数?的主要内容,如果未能解决你的问题,请参考以下文章

3D Computer Grapihcs Using OpenGL - 14 OpenGL Instancing

glsl attributes变量怎么用

GLSL 每个顶点固定大小的数组

OpenGL3:高级篇 GLSL

Unity中使用GPU Instancing优化SkinnedMesh渲染

GLSL语法以及如何与程序链接