如何计算切线和副法线? [英] How to calculate Tangent and Binormal?

查看:95
本文介绍了如何计算切线和副法线?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 OpenGL 着色语言 (GLSL) 中谈论凹凸贴图、镜面高光和这些东西

我有:

  • 一组顶点(例如 {0.2,0.5,0.1, 0.2,0.4,0.5, ...})
  • 法线数组(例如 {0.0,0.0,1.0, 0.0,1.0,0.0, ...})
  • 点光源在世界空间中的位置(例如 {0.0,1.0,-5.0})
  • 观看者在世界空间中的位置(例如 {0.0,0.0,0.0})(假设观看者位于世界的中心)

现在,我如何计算每个顶点的 Binormal 和 Tangent?我的意思是,计算 Binormals 的公式是什么,我必须根据这些信息使用什么?关于切线?

无论如何我都会构建 TBN 矩阵,所以如果您知道直接基于这些信息构建矩阵的公式会很好!

哦,是的,如果需要,我也有纹理坐标.当我谈论 GLSL 时,每个顶点的解决方案会很好,我的意思是,一个不需要一次访问多个顶点信息的方法.

---- 更新 -----

我找到了这个解决方案:

<前>vec3 切线;vec3 副法线;vec3 c1 = cross(a_normal, vec3(0.0, 0.0, 1.0));vec3 c2 = cross(a_normal, vec3(0.0, 1.0, 0.0));如果(长度(c1)>长度(c2)){切线 = c1;}别的{切线 = c2;}切线 = 归一化(切线);binormal = cross(v_nglNormal, tangent);binormal = 规范化(binormal);

但我不知道它是否100%正确.

解决方案

与您的问题相关的输入数据是纹理坐标.切线和副法线是局部平行于对象表面的向量.在法线贴图的情况下,它们描述的是法线纹理的局部方向.

因此您必须计算纹理向量指向的方向(在模型空间中).假设您有一个三角形 ABC,纹理坐标为 HKL.这给了我们向量:

D = B-AE = C-AF = K-HG = L-H

现在我们想用切线空间 T、U 来表示 D 和 E,即

D = F.s * T + F.t * UE = G.s * T + G.t * U

这是一个有6个未知数和6个方程的线性方程组,可以写成

<代码>|D.x D.y D.z ||F.s F.t ||T.x T.y T.z |||= |||||E.x E.y E.z ||G.s G.t ||U.x U.y U.z |

反转 FG 矩阵产量

<代码>|T.x T.y T.z |1 |G.t -F.t ||D.x D.y D.z |||= ----------------- |||||U.x U.y U.z |F.s G.t - F.t G.s |-G.s F.s ||E.x E.y E.z |

与顶点法线 T 和 U 一起形成局部空间基,称为切线空间,由矩阵描述

<代码>|T.x U.x N.x ||T.y U.y N.y ||T.z U.z N.z |

从切线空间转换到对象空间.要进行照明计算,需要与此相反.稍加练习就会发现:

T' = T - (N·T) NU' = U - (N·U) N - (T'·U) T'

对向量 T' 和 U' 进行归一化,将它们称为切线和副法线,我们获得了从对象到切线空间的矩阵变换,我们在这里进行照明:

<代码>|T'.x T'.y T'.z ||U'.x U'.y U'.z ||N.x N.y N.z |

我们将 T' 和 U' 与顶点法线一起存储为模型几何的一部分(作为顶点属性),以便我们可以在着色器中使用它们进行光照计算.我再说一遍:您不必在着色器中确定切线和副法线,而是预先计算它们并将它们存储为模型几何体的一部分(就像法线一样).

(上面竖线之间的表示法都是矩阵,从不是行列式,它们的表示法中通常使用竖线而不是括号.)

Talking about bump mapping, specular highlight and these kind of things in OpenGL Shading Language (GLSL)

I have:

  • An array of vertices (e.g. {0.2,0.5,0.1, 0.2,0.4,0.5, ...})
  • An array of normals (e.g. {0.0,0.0,1.0, 0.0,1.0,0.0, ...})
  • The position of a point light in world space (e.g. {0.0,1.0,-5.0})
  • The position of the viewer in world space (e.g. {0.0,0.0,0.0}) (assume the viewer is in the center of the world)

Now, how can I calculate the Binormal and Tangent for each vertex? I mean, what is the formula to calculate the Binormals, what I have to use based on those informations? And about the tangent?

I'll construct the TBN Matrix anyway, so if you know a formula to construct the matrix directly based on those informations will be nice!

Oh, yeh, I have the texture coordinates too, if needed. And as I'm talking about GLSL, would be nice a per-vertex solution, I mean, one which doesn't need to access more than one vertex information at a time.

---- Update -----

I found this solution:

vec3 tangent;
vec3 binormal;

vec3 c1 = cross(a_normal, vec3(0.0, 0.0, 1.0));
vec3 c2 = cross(a_normal, vec3(0.0, 1.0, 0.0));

if (length(c1)>length(c2))
{
    tangent = c1;
}
else
{
    tangent = c2;
}

tangent = normalize(tangent);

binormal = cross(v_nglNormal, tangent);
binormal = normalize(binormal);

But I don't know if it is 100% correct.

解决方案

The relevant input data to your problem are the texture coordinates. Tangent and Binormal are vectors locally parallel to the object's surface. And in the case of normal mapping they're describing the local orientation of the normal texture.

So you have to calculate the direction (in the model's space) in which the texturing vectors point. Say you have a triangle ABC, with texture coordinates HKL. This gives us vectors:

D = B-A
E = C-A

F = K-H
G = L-H

Now we want to express D and E in terms of tangent space T, U, i.e.

D = F.s * T + F.t * U
E = G.s * T + G.t * U

This is a system of linear equations with 6 unknowns and 6 equations, it can be written as

| D.x D.y D.z |   | F.s F.t | | T.x T.y T.z |
|             | = |         | |             |
| E.x E.y E.z |   | G.s G.t | | U.x U.y U.z |

Inverting the FG matrix yields

| T.x T.y T.z |           1         |  G.t  -F.t | | D.x D.y D.z |
|             | = ----------------- |            | |             |
| U.x U.y U.z |   F.s G.t - F.t G.s | -G.s   F.s | | E.x E.y E.z |

Together with the vertex normal T and U form a local space basis, called the tangent space, described by the matrix

| T.x U.x N.x |
| T.y U.y N.y |
| T.z U.z N.z |

Transforming from tangent space into object space. To do lighting calculations one needs the inverse of this. With a little bit of exercise one finds:

T' = T - (N·T) N
U' = U - (N·U) N - (T'·U) T'

Normalizing the vectors T' and U', calling them tangent and binormal we obtain the matrix transforming from object into tangent space, where we do the lighting:

| T'.x T'.y T'.z |
| U'.x U'.y U'.z |
| N.x  N.y  N.z  |

We store T' and U' them together with the vertex normal as a part of the model's geometry (as vertex attributes), so that we can use them in the shader for lighting calculations. I repeat: You don't determine tangent and binormal in the shader, you precompute them and store them as part of the model's geometry (just like normals).

(The notation between the vertical bars above are all matrices, never determinants, which normally use vertical bars instead of brackets in their notation.)

这篇关于如何计算切线和副法线?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆