程序领域的法线映射

时间:2014-01-18 22:37:02

标签: vector 3d raytracing normals

我是视频游戏的学生,我们正在使用C ++中的raytracer。我们正在使用我们的教师图书馆。

我们创建程序对象(在我们的例子中是一个球体),Camera为屏幕的每个像素发送一条光线,并且光线会发回有关它所击中的内容的信息。

我们中的一些人决定整合Normal Maps。因此,首先,我们在对象上发送了光线,查看了我们击中球体的法线贴图纹素的值,将其转换为矢量,对其进行标准化并将其发送回来代替对象的法线。结果非常好,但当然,它没有考虑“面部”的方向(它是程序性的,所以没有面孔,但它给出了这个想法),因此渲染是平坦的。

我们仍然不知道如何将纹理的法线(在切线空间中)与对象的法线“混合”在一起。这是我们的代码:

// TGfxVec3 is part of our teachers library, and is a 3d vector like this:
//    TGfxVec3( 12.7f, -13.4f, 52.0f )

// The sphere being at the origin and of radius 1, and tHit.m_tPosition being the
// exact position at the surface of the sphere where the ray hit, the normal of this
// point is the position hit by the ray.
TGfxVec3 tNormal = tHit.m_tPosition;
TGfxVec3 tTangent = Vec3CrossProduct( tNormal , m_tAxisZ );

TGfxVec3 tBiNormal = Vec3CrossProduct( tNormal , tTangent );

TGfxVec3 tTextureNorm = 2*(TGfxVec3( pNorm[0], pNorm[1], pNorm[2] )/255)-TGfxVec3( -1.0f, -1.0f, -1.0f );
// pNorm[0], pNorm[1], pNorm[2] are respectively the channels Red, Green,
// and Blue of the Normal Map texture.
// We put them in a 3D vector, divid them by 255 so their value go from 0 to 1,
// multiply them by 2, and then substract a vector, so their rang goes from -1 to +1.

tHit.m_tNorm = TGfxVec3( tTangente.x*tTextNorm.x + tCoTangente.x*tTextNorm.x + 
tNorm.x*tTextNorm.x, tTangente.y*tTextNorm.y + tCoTangente.y*tTextNorm.y + 
tNorm.y*tTextNorm.y, tTangente.z*tTextNorm.z + tCoTangente.z*tTextNorm.z + 
tNorm.z*tTextNorm.z ).Normalize();
// Here, after some research, I came across this : http://www.txutxi.com/?p=316 ,
// that allow us to convert the normal map tangent space to the object space.

结果仍然不好。我主要担心的是Tangent和Binormals。参考轴(此处:m_tAxisZ,球体的Z轴)是不正确的。但我不知道该怎么做,或者即使我正在做的事情真的很好。所以我来这里寻求帮助。

2 个答案:

答案 0 :(得分:0)

同时,你大多是正确而完全错误的。

切线空间法线贴图使用变换矩阵将纹理中的切线空间法线转换为另一个空间(如对象或世界空间),或者转换切线空间中的光以计算同一空间中所有内容的光照。 / p>

Bi-normal是一个常见的错误,应该命名为bi-tangent。

有时可以在简单几何体上计算TBN,就像在高度图上一样,因为很容易推导出切线和常规网格上的双切线。但是在球体上,具有固定轴的交叉技巧将导致极点处的奇点,其中叉积给出零长度向量。

最后,即使忽略极点奇点,在将矩阵应用于切线空间法线之前,必须对TBN进行归一化。您可能还会错过转置,因为3x3正交矩阵逆是转置,如果从切线到对象,您需要的是原始TBN矩阵的逆。

由于这一切,我们经常将TBN存储为几何中的额外信息,从纹理坐标(您引用的URL链接到该计算描述)计算,并在运行时使用其他值进行插值。

Rem:使用几何nornal作为TBN法线有一个粗略的简化,但首先没有理由它们匹配。

答案 1 :(得分:0)

所以,我们终于做到了。 :D好的,我会尽力清楚。为此,两张图片:

(1):http://i.imgur.com/cHwrR9A.png

(2):http://i.imgur.com/mGPH1RW.png

(我的绘画技巧不相同,我知道)。

因此,主要问题是找到Tangent“T”和Bi-tangent“B”。我们已经有了正常的“N”。我们的圆总是位于半径为1的原点,其表面上的点等于该点的法线(第一个图像上的黑色和红色矢量)。所以,我们必须找到该点的切线(绿色)。为此,我们只需要从PI / 2 rad旋转矢量:

使用N(x,y):

T = ( -N.y , N.x )

但是,我们是3D。所以这一点并不总是在赤道上。我们可以通过忽略我们点的Y中的位置来简单地解决这个问题,并且仅使用另外两个组件来规范化矢量。因此,在第二个图像上,我们有P(我们将其Y值设置为0),我们将新矢量标准化为P'。

使用P(x,y,z):

P' = ( P.x, 0, P.z).Normalize();

然后,我们回到我的第一条消息来找到T.最后,我们得到B与N和T之间的叉积。最后,我们通过考虑法线贴图来计算该点的法线

变量“Map”包含法线贴图的三个通道(RGB),每个夹点从-1到1夹紧,T,N和B都是3D矢量:

( Map.R*T + Map.G*B + Map.B*N ).Normalize();

就是这样,你可以正常考虑你的法线贴图。 :)希望这对其他人有用。