使用glDrawElements时如何将法线传递给GLSL中的顶点着色器

Cli*_*nio 2 c++ opengl shader lighting glsl

我正在为练习构建一个简单的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;
}
Run Code Online (Sandbox Code Playgroud)

这是我目前用来绑定到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);
Run Code Online (Sandbox Code Playgroud)

这是我的渲染器:

glBindVertexArray(vertexArray);
glDrawElements(GL_TRIANGLES, polygonVertexCount, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
Run Code Online (Sandbox Code Playgroud)

Kil*_*nDS 7

对于具有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,
                      ... }
Run Code Online (Sandbox Code Playgroud)

请注意,虽然在内部normals并且positions有重复,但两者在同一位置的组合是唯一的.

  • 我看不到任何顶点的计算,只有缓冲区.您现在将拥有两个缓冲区,每个缓冲区包含24个元素,而不是具有8个元素的缓冲区和一个包含36个元素 并且仍然是一个有36个索引的索引缓冲区. (2认同)