计算三角形网格的tangent space

本文介绍了一种用于Bump Mapping中的Tangent Space计算方法。通过将灯光转换到切线空间,可以提高真实感渲染效果。文章详细介绍了如何从三角形网格计算法线、切线和副法线,并给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

     又一篇学习笔记,参考Mathematics for 3D Game Programming and Computer Graphics和ShaderX4上一篇关于tangent space计算的文章写的东西。对于计算时需要分裂顶点的内容看的还不是太清楚-_-b。另外,目前的算法还不能完美处理镜像或者在纹理不连续处可能出现的问题,就算在Farcry中,很多问题也是通过美工来“隐藏”的,再一次应证了之前对美工重要性的结论^^。

 

 

 

 

 算法:

      Tangent spaceBump Map中有着重要作用,通常需要把灯光转换到tangent space进行计算。对由参数方程计算出的规则曲面(比如,球体,圆环)来说,很容易通过方程计算出tangent space,但对任意的三角形网格来说,则没有那么简单。

Tangent space是一个三维空间。对3D空间中的一个顶点来说,切空间的三条座标轴分别对应该点的法线N,切线T,和副法线(binormalB,显然,对不同的顶点来说,切空间是不同的。那么在已知三角形三个顶点及其纹理坐标的时候,如何计算出NTB呢?

目前已知的数据有三角形的三个顶点在世界坐标中的位置: P0, P1,P2, 以及相应的纹理坐标在纹理空间中的位置C0 (U0,V0)C1C2,则有:

 

P10 = P1 – P0

P­20 = P2 - P1 ,

C10 = C1 – C0 = (U1-U0, V1-V0) = ( U10 ,V10)

C20 = C2 – C0.= (U2-U0, V2-V0) = ( U20 ,V20)

 

注意,P10在世界坐标中的方向和C10在纹理空间中的方向是一致的(这一点确实比较抽象,偶画图研究了好久才弄明白-_-),同样,20C20也是如此,发现这一点很重要,可以说是整个计算的基石。进一步来说,TB分别和纹理坐标轴UV是平行的。因此我们有:

 

P10 = U10T + V10B

P­20 = U20T + V20B

把矢量展开得到:

 

两边乘以[C10 C20]的逆矩阵,最后得到

 

法线N = T x B

这样我们就得到了坐标从切空间转变到世界坐标下的变换矩阵M = [ T B N ],当然,更加常用的是M的逆矩阵。注意,这里计算得出的只是面法线,如果需要计算每个顶点的法线,则应该对共享该顶点的多个面的法线取均值,求出结果。

 

实现:

 

 

 

 

 

 

 ogre calculate tangent:

Vector3 Math::calculateTangentSpaceVector(
 const Vector3& position1, const Vector3& position2, const Vector3& position3,
 Real u1, Real v1, Real u2, Real v2, Real u3, Real v3)
 {
   //side0 is the vector along one side of the triangle of vertices passed in,
   //and side1 is the vector along another side. Taking the cross product of these returns the normal.
   Vector3 side0 = position1 - position2;
   Vector3 side1 = position3 - position1;
   //Calculate face normal
   Vector3 normal = side1.crossProduct(side0);
   normal.normalise();
   //Now we use a formula to calculate the tangent.
   Real deltaV0 = v1 - v2;
   Real deltaV1 = v3 - v1;
   Vector3 tangent = deltaV1 * side0 - deltaV0 * side1;
   tangent.normalise();
   //Calculate binormal
   Real deltaU0 = u1 - u2;
   Real deltaU1 = u3 - u1;
   Vector3 binormal = deltaU1 * side0 - deltaU0 * side1;
   binormal.normalise();
   //Now, we take the cross product of the tangents to get a vector which
   //should point in the same direction as our normal calculated above.
   //If it points in the opposite direction (the dot product between the normals is less than zero),
   //then we need to reverse the s and t tangents.
   //This is because the triangle has been mirrored when going from tangent space to object space.
   //reverse tangents if necessary
   Vector3 tangentCross = tangent.crossProduct(binormal);
   if (tangentCross.dotProduct(normal) < 0.0f)
   {
     tangent = -tangent;
     binormal = -binormal;
   }

 return tangent;

 }

### TBN Algorithm in Computer Graphics Normal Mapping TBN (Tangent-Bitangent-Normal)矩阵是一种用于法线贴图的技术,在计算机图形学中广泛应用于提高表面细节的表现力。通过构建局部坐标系,该技术能够将模型空间中的光照计算转换到切线空间下进行操作。 #### 切线空间与法线贴图 为了实现更精细的材质表现效果,通常会利用法线贴图来模拟微小几何结构的变化。然而,由于法线贴图是在物体表面上定义的方向场,因此需要将其从纹理空间变换至世界空间或视图空间以便于光照计算[^1]。这一过程依赖于由顶点数据预先计算得到的TBN基底向量集合——即切线(Tangent),副法线(Bitangent/Binormal),以及法线(Normal)[^2]。 #### 构建TBN Matrix 具体来说,对于每一个三角形网格上的顶点v_i, 都要分别求解其对应的三个正交单位矢量t,b,n: - **Normal Vector n**: 这是从标准几何形状继承而来的原始表面朝向外侧方向; - **Tangent Vector t**: 它位于当前多边形平面内并与u-v参数化映射轴平行; - **Bitangent/ Binormal b**: 可视为上述两者叉乘所得结果,确保最终形成右手定则下的三维直角框架体系。 这些值一般存储在mesh文件当中或者动态生成,并经过插值得应用在整个fragment之上。随后组合成如下形式的3×3旋转矩阵: \[ \text{Matrix}_{\text{TBN}} = \begin{bmatrix} tx & ty & tz \\ bx & by & bz\\ nx & ny & nz \end{bmatrix} \] 此矩阵的作用就是把来自normal map里的信息投影回world space里去参与后续渲染管线内的各项运算处理流程之中. ```glsl // GLSL Shader Code Example for Transforming Normals Using TBN Matrix vec3 tangentSpaceNormal = texture(normalMap, TexCoords).rgb; tangentSpaceNormal = normalize(tangentSpaceNormal * 2.0 - 1.0); mat3 TBN = mat3(Tangent, Bitangent, Normal); vec3 worldSpaceNormal = normalize(TBN * tangentSpaceNormal); ``` 以上展示了如何在一个片段着色器程序内部完成基于已知TBN矩阵情况下来调整输入normals的过程实例代码段落.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值