1. ホーム
  2. c++

[解決済み] GLSLドットプロダクトの不具合

2022-02-12 12:56:42

質問

そこで、OpenGLを使って基本的なディフューズ・ライティングを実装しようとしたのです。私は法線ベクトルと光ベクトルを取り、そのベクトルの内積を使ってピクセルの明るさを計算する簡単なシェーダを書きました。以下は、私の出力です。

  • 左から来る光(光ベクトルとして[1, 0, 0)
  • 降り注ぐ光([0, -1, 0]を光ベクトルとする)
  • 後ろから来る光([0, 0, 1]を光ベクトルとして使用)

見ての通り、最初の2つのケースでは問題なく動作しますが、3つ目のケースでは完全に壊れています。ちなみに、[0, 0, -1] もうまくいきませんし、[0, 1, 1] は光が近づいてくるのと同じ出力になります ([0, 1, 0]).以下は私のシェーダーです。

  • バーテックスシェーダ。
#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

uniform vec3 lightDirection;

out vec3 normal;
out vec3 lightDir;

void main()
{
    normal = normalize(aNormal);
    lightDir = normalize(lightDirection);

    gl_Position = projection * view * model * vec4(aPos, 1.0f);
}

  • フラグメントシェーダー。
#version 330 core

in vec3 normal;
in vec3 lightDir;

out vec4 FragColor;

void main()
{
    float grey = max(dot(-lightDir, normal), 0.0f);
    FragColor = vec4(grey, grey, grey, 1.0f);
}

問題はドット積と関係があると推測されますが、理由が見つかりません。

解決方法は?

拡散光は、以下の式で計算されます。 max(dot(-lightDir, normal), 0.0f); . ということは、もし dot (-lightDir, normal) が0より小さい場合、シーンは完全に黒くなります。
は、その ドット積 の2 単位ベクトル は、2つのベクトルがなす角の余弦である。したがって、角度が > 90° と < 270° の場合、結果は 0 より小さくなる。
つまり、背面から光を当てた場合、真っ黒に見えるということです。


光の方向は、ワールド空間におけるベクトルです。 dot(-lightDir, normal) は、法線もワールド空間のベクトルである場合にのみ意味を持ちます。
トランスフォーム normal をモデル空間から世界空間に変換する。

normal = inverse(transpose(mat3(model))) * normalize(aNormal);

( 法線をモデルビュー行列の逆行列の転置で変換する理由は? )