49

私はここ数週間 OpenGL を学んでおり、Phong シェーダーの実装で問題が発生しました。smooth修飾子を使用しているにもかかわらず、頂点間の補間を行わないようです。ここで何か不足していますか?当然のことながら、頂点シェーダーとフラグメント シェーダーのコードは、OpenGL SuperBible Fifth Edition から大幅に引用されています。この本を強くお勧めします!

頂点シェーダー:

#version 330
in vec4 vVertex;
in vec3 vNormal;
uniform mat4 mvpMatrix;  // mvp = ModelViewProjection
uniform mat4 mvMatrix; // mv = ModelView
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;

void main(void) {
 vVaryingNormal = normalMatrix * vNormal;
 vec4 vPosition4 = mvMatrix * vVertex;
 vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
 vVaryingLightDir = normalize(vLightPosition - vPosition3);
 gl_Position = mvpMatrix * vVertex;
}

フラグメント シェーダー:

#version 330
out vec4 vFragColor;
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;

void main(void) {
 float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
 vFragColor = diff * diffuseColor;
 vFragColor += ambientColor;
 vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir),normalize(vVaryingNormal)));
 float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));

 if(diff != 0) {
   float fSpec = pow(spec, 32.0);
   vFragColor.rgb += vec3(fSpec, fSpec, fSpec);
 }

}

ウィキペディアのこの (パブリック ドメイン) 画像は、取得している画像の種類と目的を正確に示しています。「フラット」画像を取得していますが、「フォン」画像が必要です。

どんな助けでも大歓迎です。ありがとうございました!

編集:違いがある場合は、PyOpenGL 3.0.1 と Python 2.6 を使用しています。

編集2:

解決

問題は私のジオメトリにあることがわかりました。コスは正しかった。Blender モデルでこの問題を抱えている他の人のために、Kos はそうすることがうまくいくと指摘しましたEdit->Faces->Set Smooth。Wings 3D は「箱から出してすぐに」動作することがわかりました。

4

2 に答える 2

66

この回答への追加として、法線を視覚化できる単純なジオメトリ シェーダーを次に示します。属性の場所とマトリックスの送信方法に基づいて、必要に応じて付属の頂点シェーダーを変更します。

しかし、最初に、結果の例として、私たちの友人であるスタンフォードバニーの巨大なバニーヘッドの写真 !

スタンフォード バニーの法線

重要な警告:適切な法線マトリックスの代わりに、モデルビュー マトリックスを使用して法線を変換することに注意してください。モデルビューに不均一なスケーリングが含まれている場合、これは正しく機能しません。また、法線の長さは正確ではありませんが、法線の方向を確認したいだけであれば、ほとんど問題になりません。

頂点シェーダー:

#version 330

layout(location = 0) in vec4 position;
layout(location = 1) in vec4 normal;
layout(location = 2) in mat4 mv;

out Data
{
    vec4 position;
    vec4 normal;
    vec4 color;
    mat4 mvp;
} vdata;

uniform mat4 projection;

void main()
{
    vdata.mvp = projection * mv;
    vdata.position = position;
    vdata.normal = normal;
}

ジオメトリ シェーダー:

#version 330
layout(triangles) in;
layout(line_strip, max_vertices = 6) out;

in Data
{
    vec4 position;
    vec4 normal;
    vec4 color;
    mat4 mvp;
} vdata[3];

out Data
{
    vec4 color;
} gdata;

void main()
{
    const vec4 green = vec4(0.0f, 1.0f, 0.0f, 1.0f);
    const vec4 blue = vec4(0.0f, 0.0f, 1.0f, 1.0f);

    for (int i = 0; i < 3; i++)
    {
        gl_Position = vdata[i].mvp * vdata[i].position;
        gdata.color = green;
        EmitVertex();

        gl_Position = vdata[i].mvp * (vdata[i].position + vdata[i].normal);
        gdata.color = blue;
        EmitVertex();

        EndPrimitive();
    }
}

フラグメント シェーダー:

#version 330

in Data
{
    vec4 color;
} gdata;

out vec4 outputColor;

void main()
{
    outputColor = gdata.color;
}
于 2011-02-28T14:18:34.973 に答える
50

うーん...法線をvarying変数として補間しているので、フラグメントシェーダーはピクセルごとの正しい法線を受け取る必要があります。

左の画像のように結果が得られているという事実の唯一の説明 (私が考えることができる) は、特定の面のすべてのフラグメントが最終的に同じ法線を受け取るということです。次のようなフラグメント シェーダで確認できます。

void main() {
   vFragColor = normalize(vVaryingNormal);
}

もしそうなら、疑問は残ります:なぜですか?頂点シェーダーは問題ないようです。

ジオメトリに何か問題があるのではないでしょうか? シェーダーに送信するデータは何ですか? 面ごとの法線だけでなく、頂点ごとの法線を正しく計算しましたか?

法線

オレンジ色の線は斜めの面の法線、赤い線は水平面の法線です。

データが上の画像のように見える場合、正しいシェーダーを使用してもフラット シェーディングが得られます。下の画像のように、頂点ごとの法線が正しいことを確認してください。(球の計算は非常に簡単です。)

于 2011-01-16T14:00:38.023 に答える