2017-02-09 76 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

你的推理是正确的 - 第二个版本是错误的。更直观的方法是分析当切线空间正常时发生的情况是(0, 0, 1)。在这种情况下,你显然希望使用三角法线,这正是第一个版本应该做的。

但是,你喂养一个错误的参数:

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

最后一个参数必须是你从纹理拾取的三角形正常的,不正常的。

+0

'(0,0,1)'的切线空间法线表示该矢量垂直于曲面。将这个乘以TBN矩阵得到三角形法线(也垂直于三角形的表面)。这就说得通了。 – mtrebi

+0

矩阵应该与三角法线组成,而不是切线法线,因为切线法线在切线空间中,而不是在切线和双切线等世界空间中。因此,切线法线可能指向与切线和双切线不垂直的方向。使用三角法线我们知道它在世界空间(如切线和双曲线),并且对他们来说是垂直的(至少在我的简单情况下),因此它们定义了一个有效的变换矩阵。我是对的?谢谢btw! – mtrebi

+0

我不确定是否正确理解您的评论。你是在重新解释我的答案吗?你有没有尝试过 - 它工作? –

相关问题