2017-02-09 6 views
1

CPUでラスタライザとデプスバッファリングを使用してレンダラを構築しています。これで法線マップが追加されました。あなたは次の画像で見ることができるようにすべての作品:ワールド空間への接線空間(TBNマトリックス)

enter image description here

問題は、それが動作してもいることを、私はなぜ理解していない、ということです!実装は私の考えに反するものです。これは、各フラグメントに通常を取得するためのコードです:

const Vector3D TexturedMaterial::getNormal(const Triangle3D& triangle_world, const Vector2D& text_coords) const { 
    Vector3D tangent, bitangent; 
    calculateTangentSpace(tangent, bitangent, triangle_world); 
    // Gets the normal from a RGB Texture [0,1] and maps it to [-1, 1] 
    const Vector3D normal_tangent = (Vector3D) getTextureColor(m_texture_normal, m_texture_normal_width, m_texture_normal_height, text_coords); 
    const Vector3D normal_world = TangentToWorld(normal_tangent, tangent, bitangent, normal_tangent); 

    return normal_world; 
} 


void TexturedMaterial::calculateTangentSpace(Vector3D& tangent, Vector3D& bitangent, const Triangle3D& triangle_world) const { 
    const Vector3D q1 = triangle_world.v2.position - triangle_world.v1.position; 
    const Vector3D q2 = triangle_world.v3.position - triangle_world.v2.position; 

    const double s1 = triangle_world.v2.texture_coords.x - triangle_world.v1.texture_coords.x; 
    const double s2 = triangle_world.v3.texture_coords.x - triangle_world.v2.texture_coords.x; 

    const double t1 = triangle_world.v2.texture_coords.y - triangle_world.v1.texture_coords.y; 
    const double t2 = triangle_world.v3.texture_coords.y - triangle_world.v2.texture_coords.y; 


    tangent = t2 * q1 - t1 * q2; 
    bitangent = -s2 * q1 + s1 * q2; 

    tangent.normalize(); 
    bitangent.normalize(); 
} 

私の混乱はここにある:

私は行ベクトルで働いていると仮定すると
const Vector3D TexturedMaterial::TangentToWorld(const Vector3D& v, const Vector3D& tangent, const Vector3D& bitangent, const Vector3D& normal) const { 
    const int handness = -1; // Left coordinate system 
    // Vworld = Vtangent * TBN 
    Vector3D v_world = { 
    v.x * tangent.x + v.y * bitangent.x + v.z * normal.x, 
    v.x * tangent.y + v.y * bitangent.y + v.z * normal.y, 
    v.x * tangent.z + v.y * bitangent.z + v.z * normal.z, 
    }; 
    // Vworld = Vtangent * TBN(-1) = V * TBN(T) 
    Vector3D v_world2 = { 
    v.x * tangent.x + v.y * tangent.y + v.z * tangent.z, 
    v.x * bitangent.x + v.y * bitangent.y + v.z * bitangent.z, 
    v.x * normal.x + v.y * normal.y + v.z * normal.z, 
    }; 

    v_world2.normalize(); 
    // return handness * v_world; --> DOES NOT WORK 
    return handness * v_world2; --> WORKS 
} 

その後
V = (Vx, Vy, Vz) 

     [Tx Ty Tz] 
TBN = [Bx By Bz] 
     [Nx Ny Nz] 

      [Tx Bx Nx] 
TBN(-1) = [Ty By Ny] // Assume basis are orthogonal TBN(-1) = TBN(T) 
      [Tz Bz Nz] 

を、 T、B、およびNがの世界座標系で表されるTBNの基底ベクトルである場合、変換は次のようになります。

Vworld = Vtangent * TBN 
Vtangent = Vworld * TBN(-1) 

しかし、私のコードでは、まったく逆のことをしています。接線空間の法線をワールド空間に変換するために、私はTBNの逆数を乗算しています。

私が紛失しているか、または間違っていることは何ですか? T、B、Nは世界座標系で間違って表現されていると仮定していますか?

ありがとうございました!

答えて

0

あなたの推論は正しい - 第2のバージョンは間違っています。より直観的な方法は、接線空間法線が(0, 0, 1)のときに何が起こるかを分析することです。この場合、明らかに三角形の法線を使用したいと思います。これはまさに最初のバージョンが行うべきことです。

しかし、あなたは間違ったパラメータを供給されています

const Vector3D normal_world = TangentToWorld(normal_tangent, 
              tangent, bitangent, normal_tangent); 

最後のパラメータを使用すると、テクスチャからフェッチ通常の三角形ではなく、正常であることが必要です。

+0

'(0、0、1) 'の正接空間法線は、このベクトルがサーフェスに対して垂直であることを意味します。これをTBN行列と掛け合わせると、正確に三角法線(三角形のサーフェスに垂直)も得られます。それは理にかなっている。 – mtrebi

+0

行列は接線法線ではなく三角法線で構成する必要があります。これは、接線法線が正接空間にあり、正接とビットのような世界空間ではないからです。したがって、接線法線は接線と正接に垂直でない方向を指すことができます。三角形の法線を使うと、それが(正接と逆のような)世界の空間にあり、それは(少なくとも私の単純なケースでは)それらに反しているので、彼らは有効な変換行列を定義します。私は正しいですよ?ありがとうbtw! – mtrebi

+0

あなたのコメントを正しく理解しているかどうか分かりません。あなたは私の答えを言い換えましたか?試しましたか?それはうまくいったのですか? –

関連する問題