2017-04-05 8 views
2

現在、these lessonsに基づく学習経験としてOpenGLをエミュレートするソフトウェアレンダラーを実装しています。プロジェクトのコードはfound here.3Dグラフィックスメッシュの法線ベクトルの回転が倍増

頂点の法線を扱うのがかなり困難です。私は、行列が直交していないときにモデル行列の逆転置を使うべきであることを知っているモデル行列でそれらを変換したいと思います。光の方向は、世界の空間で指定する必要がありますので、法線を変換し、次に光の強度を計算するために使用された世界の空間光の方向のドット積を変換する必要があります。

これは問題です。ここでうまくいきます。モデルを見て上の軸でカメラを45度回転させています。

Front view

Iが任意の軸で90度モデルを回転させる場合は、今のところ、最大の軸をとり、光の方向は、他の方法を指すように反転。あなたがここで見ることができるように、光は背中から来ています。

enter image description here

私は180度に回転している場合、それは再び罰金です。ここに示されているように、私は90度、45度光点に回転する場合

enter image description here

。光がどこから来ているかを見るためにスパイクに注目してください。

enter image description here

これは時間のために私が困惑しています。何が間違っているのか分かりません。それはあたかも回転で回転が倍増しているかのようです。光のベクトルはいえ変更されていない、ここを見て:

vec4 SmoothShader::Vertex(int iFace, int nthVert) 
{ 
    vec3 vposition = model->vert(iFace, nthVert); 
    vec4 projectionSpace = MVP * embed<4>(vposition); 

    vec3 light = vec3(0, 0, 1); 

    mat4 normTrans = M.invert_transpose(); 
    vec4 normal = normTrans * embed<4>(model->normal(iFace, nthVert), 0.f); 
    vec3 norm = proj<3>(normal); 
    intensity[nthVert] = std::max(0.0f, norm.normalise() * light.normalise()); 

    return projectionSpace; 
} 

bool SmoothShader::Fragment(vec3 barycentric, vec3 &Colour) 
{ 
    float pixelIntensity = intensity * barycentric; 
    Colour = vec3(255, 122, 122) * pixelIntensity; 
    return true; 
} 

MVP(モデル、ビュー、投影)とM(モデル)の行列は次のように計算されます。

// Model Matrix, converts to world space 
mat4 scale = MakeScale(o->scale); 
mat4 translate = MakeTranslate(o->position); 
mat4 rotate = MakeRotate(o->rotation); 

// Move objects backward from the camera's position 
mat4 cameraTranslate = MakeTranslate(vec3(-cameraPosition.x, -cameraPosition.y, -cameraPosition.z)); 

// Get the camera's rotated basis vectors to rotate everything to camera space. 
vec3 Forward; 
vec3 Right; 
vec3 Up; 
GetAxesFromRotation(cameraRotation, Forward, Right, Up); 
mat4 cameraRotate = MakeLookAt(Forward, Up); 

// Convert from camera space to perspective projection space 
mat4 projection = MakePerspective(surf->w, surf->h, 1, 10, cameraFOV); 

// Convert from projection space (-1, 1) to viewport space 
mat4 viewport = MakeViewport(surf->w, surf->h); 

mat4 M = translate * rotate * scale; 
mat4 MVP = viewport * projection * cameraRotate * cameraTranslate * M; 

任意のアイデア何私は間違っている?

答えて

1

逆行列ではなく、モデル行列を使用して法線を変換する必要があります。頂点の位置とは反対の方向に頂点の法線を回転させるため、照明はそのまま動作します。

vec4 normal = M * embed<4>(model->normal(iFace, nthVert), 0.f); 

、このような混乱を回避することが世界スペースへオブジェクト空間からの変換であるので、私は、命名体系advocated by Tom Forsythを使用することをお勧めします、とMworld_from_object行列を呼ぶだろう。

vec4 light_world = vec4(0.f, 0.f, 1.f, 0.f); 
vec4 normal_object = embed<4>(model->normal(iFace, nthVert), 0.f); 
vec4 normal_world = world_from_object * normal_object; 
float intensity = std::max(0.f, light_world * normal_world); 

このスキームを使用していた場合は、間違った変換を使用していたことが明らかです。 - モデルのローカル座標系

  • ビュー空間 - のローカル座標系

    • オブジェクト空間:私は個人的に異なる空間を記述するために、次の用語を使用

      mat4 object_from_world = world_from_object.invert_transpose(); 
      vec4 normal_world = object_from_world * normal_object; // wrong! 
      

      あなたのカメラ

    • ライトスペース - ライトのローカル座標系
    • ワールド空間 - あなたのシーンのグローバル座標系
    • クリップ空間 - 正規化された画面には、そのよう

    を調整し、私はclip_from_object行列MVP行列を呼ぶだろう。

  • +0

    は、変更はありません。モデル行列はこの場合直交しているため、逆転置は実際には同じことです。しかし、多くのオンライン情報源では、非一様なスケーリング(直交ではない)を行う場合、法線を変換するときに逆転置が必要であると言われています。 – Constan7ine

    +0

    @ Constan7ine申し訳ありません。私は間違ってあなたが逆数を乗じていると思った。逆転置は理にかなっています。もう一度見てみましょう。 –

    +0

    @ Constan7ine私は他の問題を見ることができません。私はあなたの問題がコードベースのどこかにあると思う。 –

    1

    あなたはとしてシェーダにモデル行列を渡している:

       o->shader->M = cameraRotate * cameraTranslate * Model; 
    

    だから、実際のM行列はつまり、あなたが今のModelViewスペースに乗算している、モデルマトリックスが、マトリックスのModelViewではありません。私は確信していませんが、おそらくそれがあいまいな結果につながるかもしれません。私は、これは動作しません怖い

    +0

    さて、それはgithubのレポからです、それは少し古いです。上記の画像は、モデルマトリックスだけを通過するときに撮影されたものです。しかし、ありがとう。 – Constan7ine

    関連する問題