[英]How to pass normals to a Vertex Shader in GLSL when using glDrawElements
我正在构建一个简单的 3D 游戏以供练习,并且在使用索引渲染时无法将法线传递给我的着色器。 对于多边形的每个面,每个顶点都有相同的法线值。 对于具有 8 个顶点的立方体,将有 6 * 6 = 36 个法线(因为每个表面都用两个三角形渲染)。 使用索引绘图我只能通过 8 个,每个顶点一个。 这不允许我通过表面法线,只能通过平均顶点法线。
如何将 36 个不同的法线传递给 36 个不同的索引? 使用 glDrawArrays 显然很慢,所以我选择不使用它。
这是我的着色器:
#version 330
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 vertNormal;
smooth out vec4 colour;
uniform vec4 baseColour;
uniform mat4 modelToCameraTrans;
uniform mat3 modelToCameraLight;
uniform vec3 sunPos;
layout(std140) uniform Projection {
mat4 cameraToWindowTrans;
};
void main() {
gl_Position = cameraToWindowTrans * modelToCameraTrans * vec4(position, 1.0f);
vec3 dirToLight = normalize((modelToCameraLight * position) - sunPos);
vec3 camSpaceNorm = normalize(modelToCameraLight * vertNormal);
float angle = clamp(dot(camSpaceNorm, dirToLight), 0.0f, 1.0f);
colour = baseColour * angle * 0.07;
}
这是我目前用来绑定到 VAO 的代码:
glGenVertexArrays(1, &vertexArray);
glBindVertexArray(vertexArray);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, polygonBuffer);
// The position input to the shader is index 0
glEnableVertexAttribArray(POSITION_ATTRIB);
glVertexAttribPointer(POSITION_ATTRIB, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Add the vertex normal to the shader
glBindBuffer(GL_ARRAY_BUFFER, vertexNormBuffer);
glEnableVertexAttribArray(VERTEX_NORMAL_ATTRIB);
glVertexAttribPointer(VERTEX_NORMAL_ATTRIB, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
这是我的渲染器:
glBindVertexArray(vertexArray);
glDrawElements(GL_TRIANGLES, polygonVertexCount, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
对于具有 8 个顶点的立方体,将有 6 * 6 = 36 个法线(因为每个表面都用两个三角形渲染)。
如果错了请纠正我,但我只看到 6 个法线,每个面一个。 该面上的所有顶点都将使用相同的法线。
使用索引绘图我只能通过 8 个,每个顶点一个。 这不允许我通过表面法线,只能通过平均顶点法线。
这就是你的推理失败的地方。 您不仅将顶点位置传递给着色器,还传递了使顶点唯一的一大堆顶点属性。
因此,如果您使用相同的顶点位置 6 次(您经常这样做),但每次使用不同的法线(实际上两个三角形将共享相同的数据),您实际上应该发送该顶点的所有数据 6x,包括位置的副本。
也就是说,您不需要 36 个,您需要4*6=24
独特的属性。 您必须分别发送每个面的所有顶点,因为法线不同,并且每个面您必须在 4 个位置之间有所不同。 您也可以将其视为 8*3,因为您必须复制 8 个位置来处理 3 个不同的法线。
所以你最终会得到类似的东西:
GLFloat positions[] = { 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
...}
GLFloat normals[] = { 1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f,
... }
请注意,虽然在normals
和positions
有重复,但两者在同一位置的组合是唯一的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.