Tangent算法的缺陷及修正办法

来源:http://www.sunnycrystal.net/showdocs.aspx?id=23

一、Tangent算法缺陷

    笔者前几日翻出以前做的坦克模型想在D3D中进行NormalMap方式的渲染,结果发现坦克车体上几个面的高光、NormalMap的凹凸方向不对,后来经过多方跟踪调试,发现问题出在模型身上。共有两个问题:

    1、原来模型在3DSMax里应用了UVW Map的修改器,而在该修改器里,U Tile的方向被Flip过,所以,贴图的U坐标轴实际是反的,而V轴不变。则按照ComputeTangent的算法,先把指向+V的Tangent单位向量求出来,然后最后再用Normal 叉乘 Tangent 求 Binormal,则此时叉乘出的Binormal和实际Binormal是方向正好是反的。不应该是Normal 叉乘 Tangent,而应该是Tangent 叉乘 Normal 才对。
    所以微软等某些Tangent的算法是有缺陷的,它对应的3dsmax模型应该是UV Gizmo没有Flip或者旋转过的,而一般在美术建模阶段是很有可能对UVW Gizmo进行旋转、Flip等操作的。

    2、UVW Map映射方式的问题。我的模型有些部件通过UVW Map中的Planar模式映射UV,则出现了这样的情况:构成一个面的3个顶点,其中1、2顶点的U坐标相同,1、3顶点的U坐标不同,1、2、3顶点的V坐标均相同,(U1 == U2 && U1 != U3 && V1 == V2  && V1 == V3),这样的面是无法得到正确的Tangent的,因为Tangent垂直于这个面。当然我们也可以假设在这个面中一条垂直于Binormal的向量为Tangent。但因尽量避免这种Planar模式对于一个物体映射UV的情况

    所以,如果采用常见的Tangent求法,就要求三角形的3个顶点在UV坐标空间的图形仍然为三角形,而不能是一条线或一个点,同时U轴到V轴应该满足顺时针夹角为90度。

二、缺陷的解决

    有人提出可以用NVidia 的 MenshMender 类来修正这个问题,亲手试验了一下,发现这个办法不是很理想,有些面仍然有问题,而且NVidia为了解决问题,分裂出来了过多的顶点。

    后来,我想到了一个修正办法,就是维持ComputeTangent的算法不变,而在Mesh的NormalMap层纹理坐标上进行修正,这个办法因为修改了NormalMap的贴图坐标,适用于关键要得到正确Per-Pixel光照而可以忽略NormalMap贴图方向的情况,比如NormalMap纹理表示的是一块平坦表面或者沙粒路面等没有大型可辨识凹凸图形的情况,比如通过NormalMap增加人脸肌肉凹凸细节的话就不推荐用此方法修正,因为有可能在待修正三角面上出现原本没有的细节。

    我们知道,Compute Tangent出错的原因之一,就是一个三角形所对应在UV空间中的图形是一条线或者是一个点,所以,我们修正的原理就是通过修改三角形3个顶点的UV值,使三角形在UV空间中能保证3个点不构成一条直线,或者3个点重合,仍然是一个三角形。所以,为了实现这个目标,我们可以通过一种Box的方式来进行纹理坐标映射,类似于CubeMap的纹理坐标映射。

    具体算法如下:

    首先要计算出整个Mesh的AABB包围盒,然后计算每一个三角形的面法线,假设一个坐标在原点的正方体(注意:不是AABB盒)包围了这个三角形,我们先求出面法线与正方体的哪个面相交,然后根据对应的面来映射UV。

    举个例子:如果法线与正Y面相交(Positive Y),则我们可以通过该三角形的X、Z坐标进行纹理映射,X轴为+U坐标轴,-Z轴为+V坐标轴,同时通过AABB的X轴长度、Z轴长度及AABB的X最小值、Z最大值得到该三角形三个顶点的新UV坐标(NormalMap纹理的UV坐标)。正方体另外5个面也依此原理计算。

    U1 = ( X1 - AABB.MinPt.X ) * e;
    V1 = ( AABB.MaxPt.Z - Z1 ) * e;
    e: UV Tile的比例因子

    注意:这个算法也需要分裂顶点,当计算出当前顶点的新UV的时候如果发线新UV已经计算过了,而且与这次算出来的新UV不一致,说明这个顶点被两个三角形共享,且纹理坐标不一致,需要分裂。

    最后,用常规的ComputeTangent算法和修正过后的NormalMap纹理坐标即可得到正确的Tangent、Binormal。附图如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值