normalMap的七七八八

本文详细探讨了NormalMap及TangentSpace的概念,并通过实验指出了常见的误解,包括Tangent变换并非总是正交的、不能仅依靠Tangent计算Binormal等问题。同时,提供了正确的处理方法,以确保渲染效果正确。

关于normalMap,主要是要谈谈tangent space,可以自行生成,或者从3dmax里取。

我是这样想的,当检查到mesh的material使用了normalMap,那么mesh就会导出tangent和binormal。

通过2天不停得试验和翻阅文档,有几点认知是需要明确指出:

1.  tangent变换并不是正交变换,大部分情况下顶点normal和三角形表面是不垂直的,tangent和binormal也未互相必垂直。不考虑镜像映射的话还只是误差,镜像映射之后干脆连方向都反了。

2.  如上述,一般的说法,在vertex buffer中只存tangent,而在vertex shader中使用cross(tangent, normal)计算出binormal是不正确的。

3.  美术可能只画半张脸的normalMap,而另一半使用mirror出来。这种情况,使用cross出binormal的效果,就会原本凹的凸,凸的变凹。

 

4.  还有一种说法,是重新计算比如tangent在平面上的投影,也就是Gram-Schmidt orthogonalize,但我的结论是在max中不需要这么做。

5.  直接取max给的tangent和binormal是绝对不行的,那会变成这样,见下图: 

 

左边是ogre自动生成的tangent,右边是直接取max的tangent不作处理,两者的binormal都是cross出来的,两者中间的镜像都是不正确的。

 

 

结论是:

1.  必须是源生tangent, binormal,指望只存1个,用cross出来另一个是想法是错误的。

2.  要处理镜像,不单是tangent,连binormal都可能反向。

 

关键代码如下:

if (hasTangent)
{
    int tangentIndex = mesh->GetFaceVertexTangentBinormal(face->meshFaceIndex, vertexIdx, tangentChannel);
    vertex.tangent 
= mesh->GetTangent(tangentIndex, tangentChannel);
    vertex.binormal 
= mesh->GetBinormal(tangentIndex, tangentChannel);

    if (vertex.binormal % CrossProd(vertex.normal, vertex.tangent) < 0)
        vertex.tangent 
*= -1.0f;

    if (vertex.tangent % CrossProd(vertex.normal, vertex.binormal) < 0)
        vertex.binormal 
*= -1.0f;


这是处理后的NdotL图:

 

注意这个地方:

 

如果不处理则会凹凸相反。

最终的渲染效果:

 

转载于:https://www.cnblogs.com/oiramario/archive/2011/03/15/1985184.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值