介绍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?我的意思是,计算双正态量的公式是什么,我必须根据这些信息使用什么?关于切线?
我会构造TBN矩阵无论如何,所以如果你知道一个公式来构造矩阵直接基于这些信息将是很好的!
哦,是的,我也有纹理坐标,如果需要的话。就像我所说的GLSL,是一个很好的逐顶点解决方案,我的意思是,一个不需要一次访问多个顶点信息的方案。
----更新-----
我找到了这个解决方案:
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);
但我不知道它是否100%正确。
4条答案
按热度按时间2hh7jdfx1#
与问题相关的输入数据是纹理坐标。切线和Binormal是局部平行于对象曲面的向量。在法线贴图的情况下,它们描述了法线纹理的局部方向。
所以你必须计算纹理向量指向的方向(在模型的空间中)。假设你有一个三角形ABC,纹理坐标为HKL。这给了我们向量:
现在我们想用切空间T,U来表示D和E,即
这是一个有6个未知数和6个方程的线性方程组,它可以写为
对FG矩阵求逆产生
与顶点法线T和U一起形成局部空间基,称为切空间,由矩阵描述
从切线空间转换到对象空间。要进行照明计算,需要与此相反。只要稍加练习,你就会发现:
归一化向量T'和U',称它们为正切和副法线,我们获得从对象到正切空间的矩阵变换,其中我们进行照明:
我们将T'和U'与顶点法线一起存储为模型几何的一部分(作为顶点属性),以便我们可以在着色器中使用它们进行照明计算。我重复一遍:您不需要在着色器中确定切线和副法线,而是预先计算它们并将其存储为模型几何体的一部分(就像法线一样)。
(The上面竖线之间的符号都是矩阵,而不是行列式,它们通常在符号中使用竖线而不是括号。
lndjwyie2#
一般来说,有两种生成TBN矩阵的方法:离线和在线。
*在线=在片段着色器中使用派生指令。这些推导为多边形的每个点给予了平坦的TBN基。为了得到一个光滑的,我们必须重新正交化它的基础上一个给定的(光滑)顶点法线。该过程在GPU上比初始TBN提取更繁重。
*Off-line=准备切线作为顶点属性。这是更难得到的,因为它不仅会添加另一个顶点属性,而且还需要重新组合所有其他属性。此外,它不会100%给予你一个更好的性能,因为你会得到额外的成本存储/传递/动画(!)vector 3顶点属性。
很多地方(谷歌一下)都描述了这个数学,包括@datenwolf的帖子。
这里的问题是,两个顶点可能具有相同的法线和纹理坐标,但切线不同。这意味着你不能只给一个顶点添加一个顶点属性,你需要把顶点分成2个,并为克隆指定不同的切线。
获得每个顶点唯一切线(和其他属性)的最佳方法是在导出器中尽早完成。在按属性对纯顶点进行排序的阶段,您只需要将切向量添加到排序键。
作为这个问题的激进解决方案,考虑使用四元数。单个四元数(vec 4)可以成功地表示预定义便利性的切向空间。它很容易保持正交(包括传递到片段着色器),存储和提取正常,如果需要的话。关于KRI wiki的更多信息。
7bsow1i63#
基于kvark的回答,我想补充更多的想法。
如果你需要一个正交化的切空间矩阵,你必须做一些工作,无论如何。即使添加切线和副法线属性,它们也将在着色器阶段进行插值,并且在结束时它们既不归一化也不彼此垂直。
假设我们有一个归一化法线向量
n
,我们有切线t
和副法线b
,或者我们可以根据下面的导数计算它们:当然,一个正交化的切空间矩阵可以通过使用叉积来计算,但这只适用于右手系统。如果矩阵被镜像(左手系统),它将转向右手系统:
在上面的代码片段中,如果切空间是左手系统,则副法向量被反转。为了避免这种情况,必须走一条艰难的道路:
正交化任何矩阵的常用方法是Gram–Schmidt process:
另一种可能性是使用2*2矩阵的行列式,其由纹理坐标
texC_dx
、texC_dy
的导数产生,以考虑副法线向量的方向。其思想是正交矩阵的行列式为1,并且正交镜像矩阵的确定的行列式为-1。行列式既可以用GLSL函数
determinant( mat2( texC_dx, texC_dy )
来计算,也可以用它的公式texC_dx.x * texC_dy.y - texC_dy.x * texC_dx.y
来计算。对于正交归一化切线空间矩阵的计算,不再需要副法线向量,并且可以避免副法线向量的单位向量(
normalize
)的计算。7nbnzgx94#
有多种方法可以计算切线,如果法线贴图烘焙器的计算方式与渲染器不同,您将得到细微的瑕疵。许多面包师使用MikkTSpace算法,这与片段衍生物技巧不同。
幸运的是,如果你有一个使用MikkTSpace的程序的索引网格(并且没有相反方向的纹理坐标三角形共享索引),算法的难点部分主要是为你完成的,你可以像这样重建切线:
在顶点着色器中,它们被旋转到世界空间中:
然后,副法线和世界空间法线的计算如下(参见http://mikktspace.com/):
(The副法线通常是按像素计算的,但有些面包师给予你选择按顶点计算并进行插值。This page有关于特定程序的信息。)