3

練習用に単純な 3D ゲームを作成していますが、インデックス付きレンダリングを使用しているときに法線をシェーダーに渡すのに問題があります。ポリゴンの面ごとに、各頂点に同じ法線値があります。8 つの頂点を持つ立方体の場合、法線は 6 * 6 = 36 になります (各サーフェスが 2 つの三角形でレンダリングされるため)。インデックス付きの描画では、頂点ごとに 1 つずつ、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);
4

1 に答える 1

8

8 つの頂点を持つ立方体の場合、法線は 6 * 6 = 36 になります (各サーフェスが 2 つの三角形でレンダリングされるため)。

間違っている場合は訂正してください。ただし、面ごとに 1 つずつ、6 つの法線しか表示されません。その面のすべての頂点は同じ法線を使用します。

インデックス付きの描画では、頂点ごとに 1 つずつ、8 つしか渡すことができません。これにより、サーフェス法線を渡すことはできず、平均化された頂点法線のみを渡すことができます。

ここであなたの推論は失敗します。頂点の位置をシェーダーに渡すだけでなく、頂点を一意にする頂点属性全体を渡します。

したがって、同じ頂点位置を 6 回使用する場合 (これはよくあることです)、毎回異なる法線を使用する場合 (実際には 2 つの三角形が同じデータを共有します)、実際にはその頂点のすべてのデータを 6 回送信する必要があります。場所の複製。

そうは言っても、36 は必要ありません4*6=24。固有の属性が必要です。法線が異なり、面ごとに 4 つの位置で異なる必要があるため、面ごとにすべての頂点を個別に送信する必要があります。3 つの異なる法線を処理するために複製する必要がある 8 つの位置があるため、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,
                      ... }

while withinnormalspositionsの繰り返しがありますが、同じ位置での両方の組み合わせはユニークであることに注意してください。

于 2012-08-20T11:19:54.040 に答える