2017-02-09 17 views
1

Я создаю рендеринг, используя растрирование и глубину буферизации в CPU, и теперь я включил карты нормалей. Все работает, как вы можете видеть на следующем изображении:Касательное пространство для World Space (матрица 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

Матрица должна быть составлена ​​с нормальным треугольником, а не касательной нормалью, потому что касательная нормаль находится в касательном пространстве, а не в мировом пространстве, как касательная и бинагентная. Поэтому касательная нормаль может указывать в направлении, не перпендикулярном касательной и бинагентной. Используя нормальный треугольник, мы знаем, что он находится в мировом пространстве (как касательный и бинагентный), и это перпендикулярно им (по крайней мере, в моем простом случае) и, следовательно, они определяют действительную матрицу преобразования. Я не ошибаюсь? Спасибо, кстати! – mtrebi

+0

Я не уверен, правильно ли понимаю ваш комментарий. Вы перефразировали мой ответ? Вы пробовали - это сработало? –