Основываясь на ответе kvark, я хотел бы добавить больше мыслей.
Если вам нужна ортонормированная матрица касательного пространства, вам нужно как-то выполнить какую-то работу.Даже если вы добавите касательные и бинормальные атрибуты, они будут интерполированы на этапах шейдера, и в конце они не нормализуются и не являются нормальными друг к другу.
Давайте предположим, что у нас есть нормализованный нормальный вектор n
, и у нас есть тангенс t
и бинормаль b
, или мы можем вычислить их из производных следующим образом:
// derivations of the fragment position
vec3 pos_dx = dFdx( fragPos );
vec3 pos_dy = dFdy( fragPos );
// derivations of the texture coordinate
vec2 texC_dx = dFdx( texCoord );
vec2 texC_dy = dFdy( texCoord );
// tangent vector and binormal vector
vec3 t = texC_dy.y * pos_dx - texC_dx.y * pos_dy;
vec3 b = texC_dx.x * pos_dy - texC_dy.x * pos_dx;
Конечно, ортонормированная матрица пространства касательных может бытьрассчитывается с использованием перекрестного произведения, но это будет работать только для правосторонних систем.Если матрица была зеркально отражена (левая система), она превратится в правую систему:
t = cross( cross( n, t ), t ); // orthonormalization of the tangent vector
b = cross( n, t ); // orthonormalization of the binormal vector
// may invert the binormal vector
mat3 tbn = mat3( normalize(t), normalize(b), n );
В фрагменте кода над бинормальным вектором происходит обратное преобразование, если касательное пространство является левой системой.Чтобы избежать этого, трудный путь должен быть пройден:
t = cross( cross( n, t ), t ); // orthonormalization of the tangent vector
b = cross( b, cross( b, n ) ); // orthonormalization of the binormal vectors to the normal vector
b = cross( cross( t, b ), t ); // orthonormalization of the binormal vectors to the tangent vector
mat3 tbn = mat3( normalize(t), normalize(b), n );
Распространенным способом ортогонализации любой матрицы является процесс Грама – Шмидта :
t = t - n * dot( t, n ); // orthonormalization ot the tangent vectors
b = b - n * dot( b, n ); // orthonormalization of the binormal vectors to the normal vector
b = b - t * dot( b, t ); // orthonormalization of the binormal vectors to the tangent vector
mat3 tbn = mat3( normalize(t), normalize(b), n );
Другойвозможность состоит в том, чтобы использовать определитель матрицы 2 * 2, которая получается из производных координат текстуры texC_dx
, texC_dy
, чтобы принять во внимание направление бинормального вектора.Идея состоит в том, что определитель ортогональной матрицы равен 1, а определитель ортогональной зеркальной матрицы равен -1.
Определитель может быть вычислен с помощью функции GLSL determinant( mat2( texC_dx, texC_dy )
или вычислен с помощью нее.формула texC_dx.x * texC_dy.y - texC_dy.x * texC_dx.y
.
Для вычисления ортонормированной касательной пространственной матрицы бинормальный вектор больше не требуется, и можно вычислить единичный вектор (normalize
) бинормального вектора.
float texDet = texC_dx.x * texC_dy.y - texC_dy.x * texC_dx.y;
vec3 t = texC_dy.y * pos_dx - texC_dx.y * pos_dy;
t = normalize( t - n * dot( t, n ) );
vec3 b = cross( n, t ); // b is normlized because n and t are orthonormalized unit vectors
mat3 tbn = mat3( t, sign( texDet ) * b, n ); // take in account the direction of the binormal vector