我在模型的顶点上做了一个MVP transformation
。理论上,我必须将MVP变换的逆转置矩阵应用到***法线***上。
以下是推导过程:(A, B, C)
是点(x, y, z)
所在平面的法线
对于一个向量,如(x0, y0, z0)
,在齐次坐标中为(x0, y0, z0, 0)
,变换后仍应为向量,如(x1, y1, z1, 0)
,这就要求4 * 4变换矩阵的最后一行除最后一列元素外,其余均为0,否则变换后为(x1, y1, z1, n)
。
事实上,我的MVP变换矩阵在经历逆转置变换之后不能满足这一点。
代码:
Mat<4, 4> View(const Vec3& pos){
Mat<4, 4> pan{1, 0, 0, -pos.x,
0, 1, 0, -pos.y,
0, 0, 1, -pos.z,
0, 0, 0, 1};
Vec3 v = Cross(camera.lookAt, camera.upDirection).Normalize();
Mat<4, 4> rotate{v.x, v.y, v.z, 0,
camera.upDirection.x, camera.upDirection.y, camera.upDirection.z, 0,
-camera.lookAt.x, -camera.lookAt.y, -camera.lookAt.z, 0,
0, 0, 0, 1};
return rotate * pan;
}
Mat<4, 4> Projection(double near, double far, double fov, double aspectRatio){
double angle = fov * PI / 180;
double t = -near * tan(angle / 2);
double b = -t;
double r = t * aspectRatio;
double l = -r;
Mat<4, 4> zoom{2 / (r - l), 0, 0, 0,
0, 2 / (t - b), 0, 0,
0, 0, 2 / (near - far), 0,
0, 0, 0, 1};
Mat<4, 4> pan{1, 0, 0, -(l + r) / 2,
0, 1, 0, -(t + b) / 2,
0, 0, 1, -(near + far) / 2,
0, 0, 0, 1};
Mat<4, 4> extrusion{near, 0, 0, 0,
0, near, 0, 0,
0, 0, near + far, -near * far,
0, 0, 1, 0};
Mat<4, 4> ret = zoom * pan * extrusion;
return ret;
}
Mat<4, 4> modelMatrix = Mat<4, 4>::identity();
Mat<4, 4> viewMatrix = View(camera.position);
Mat<4, 4> projectionMatrix = Projection(-0.1, -50, camera.fov, camera.aspectRatio);
Mat<4, 4> mvp = projectionMatrix * viewMatrix * modelMatrix;
Mat<4, 4> mvpInverseTranspose = mvp.Inverse().Transpose();
MVP:
-2.29032 0 0.763441 -2.68032e-16
0 -2.41421 0 0
-0.317495 0 -0.952486 2.97455
0.316228 0 0.948683 -3.16228
mvp反向转置:
-0.392957 0 0.130986 0
0 -0.414214 0 0
-4.99 0 -14.97 -4.99
-4.69377 0 -14.0813 -5.01
2条答案
按热度按时间67up9zun1#
我似乎明白了这个问题。光照应该在世界空间中计算,所以我只需要将
the model transformation
的逆转置矩阵应用于***法线***。ubby3x7f2#
对于您的问题,使用模型视图矩阵的逆转置矩阵而不是模型视图投影矩阵来将法向量变换到视图空间而不是剪辑空间应该就足够了。
在用逆转置变换之后,w分量不一定是零是可以的。
原因如下:考虑仿射矩阵的逆矩阵
其中0是1x3的零矢量,t是3x1的平移矢量,R是3x3的线性部分,^-1是其逆。
所以它的逆转置是
现在将逆转置乘以[x,y,z,0]^T,你会得到w'=(-R ^-1 * t)^T *[x,y,z]^T +0 * 1!= 0
用仿射矩阵变换法向量的诀窍是取其逆转置,然后忽略结果的w '部分。
也就是说,只需要使用[x',y',z'],你甚至可以做除法(如果w '!= 0),即1/w'*[x',y',z'],因为normalize(1/w *[x',y',z'])= normalize([x',y',z']),记住,对于法向量,你感兴趣的是它们的方向,而不是它们的长度。
平移一个方向是没有意义的。记得你的数学老师在黑板上的不同位置画箭头,并说明基本向量是相同的。对于法向量,使用仿射矩阵左上角的3x3子矩阵就足够了。
但是,您仍然需要对其进行逆转置。
法线通常用于照明。这发生在模型、视图、切线、世界或光空间中。然而,这里的模型-视图-投影(MVP)矩阵包含投影矩阵P形式的投影部分。投影矩阵Map到剪辑空间。剪辑空间不是执行照明的空间,而是剪辑、剔除和准备透视z分割的坐标。
我想,如果你仔细算一下,你应该能做到,但从来没有考虑过甚至想一想。
在剪辑空间之前,在任何空间中进行照明都要容易得多。