6

個々の位置と回転を持ついくつかのモデルがあるシーンがあります。法線が与えられると、シェーダーは各ピクセルに単純な双方向ライティングを適用します。

それが私の頂点シェーダーです。

#version 150

in vec3 position;
in vec3 normal;
in vec2 texcoord;

out vec3 f_normal;
out vec2 f_texcoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;

void main()
{
    mat4 mvp = proj * view * model;

    f_normal   = normal;
    f_texcoord = texcoord;

    gl_Position = mvp * vec4(position, 1.0);
}

そして、これがフラグメントシェーダーです。

#version 150

in vec3 f_normal;
in vec2 f_texcoord;

uniform sampler2D tex;

vec3 sun = vec3(0.5, 1.0, 1.5);

void main()
{
    vec3 light = max(0.0, dot(normalize(f_normal), normalize(sun)));

    gl_FragColor = texture(tex, f_texcoord) * vec4(light, 1.0);
}

回転のないオブジェクトの場合、これは正常に機能します。ただし、回転モデルの場合、照明も回転します。もちろん、そうではありません。

その理由は、法線が回転しないためです。すでに試しf_normal = model * normal;ましたが、これは法線に回転と変換の両方を適用します。

では、ライティングのためにフラグメントシェーダーに送信する前に、頂点シェーダーで法線を回転させるにはどうすればよいですか?一般的なアプローチは何ですか?

4

2 に答える 2

5

model-view-projection行列の上位3行/列で法線を変換する必要があります。(ただし、スケーリングを実行している場合は、この行列の逆転置を使用する必要があります。この記事を参照してください)。

mat3 normalMatrix = mat3(mvp);
normalMatrix = inverse(normalMatrix);
normalMatrix = transpose(normalMatrix);
f_normal = normalize(normal * normalMatrix);
// You should also send your tranformed position to the fragment shader
f_position = vec3(mvp * vec4(position, 1.0));

フラグメントシェーダーでは、光源からフラグメントまでの距離を計算して正規化する必要があります。法線と光ベクトルの内積を求め、これに光の色を掛けます。

vec3 light = normalize(sun - f_position);
light = max(dot(f_normal, light), 0.0) * vec3(1.0, 1.0, 1.0);
gl_FragColor = texture(tex, f_texcoord) * vec4(light, 1.0);

私のコードには間違いなく最適化の余地があります。

この本OpenGL4.0ShadingLanguageCookbookをお勧めします。

于 2013-01-07T14:27:08.380 に答える
0

次の解決策は私のモデルで機能しますが、その背後にある数学についてはあまり深く理解していません。これが私の情報源です:深さとリアリズムの追加-表面法線

通常のベクトルに適用する必要のある変換は、次のように表されます。N'= N *(M -1T

基本的に、これは、法線(N)にModelView行列の逆転置(M)を掛けることを意味します。M行列が4x4の場合、通常の乗算​​には、結果として得られる(M -1Tの左上の3x3象限を使用する必要があります。

繰り返しますが、これは私にとってはうまくいきますが、数学をうまく説明することはできません。

于 2013-01-07T13:57:35.303 に答える