我有2点法线云。在webgl画布上渲染点之前,我需要将PointCloud1转换为与PointCloud2相同的坐标空间,并且我有转换矩阵T,(rot,scale,trans),它完美地适用于这些点。我想对法线做同样的事情。 在阅读了一些教程之后,我尝试了这个:
n'=转置(反向(T))* n
我理解这背后的数学,但有些教程提到我应该只采用T中的3 * 3矩阵。我不确定我是否应该这样做
如果我使用第二个选项,我会得到n'= [a'b'c'd']。我应该将此向量除以d'以使其均匀吗?
答案 0 :(得分:6)
因为你说你只使用旋转,平移和缩放,所以你不必担心这整个反转置的东西。至少与"缩放"一样长,你的意思是统一缩放。如果使用非均匀缩放,则需要特别考虑正常变换(有关非均匀缩放的背景,请参阅我的答案:normal matrix for non uniform scaling)。
通常,左上3x3子矩阵的逆转置用于转换法线。但在这种情况下,左上角的3x3子矩阵仅包含旋转和缩放。旋转和缩放矩阵的逆转置与原始矩阵相同。所以整个反转置计算都是无操作。
严格来说,均匀缩放矩阵的逆转置与原始矩阵不同。但它仍然是一个统一的缩放矩阵,这意味着唯一的区别是得到的法向量的长度。因为一旦涉及缩放,你必须在转换它们之后重新规范化法线,它仍然没有产生实际的区别。
是否为法线明确创建单独的3x3矩阵,或者在使用0分量扩展的法向量上使用常规4x4矩阵,这在很大程度上取决于优先级。在数学上,结果完全相同。使用4x4矩阵的优点是不会将额外的3x3矩阵传递到着色器中更简单。缺点是它可能效率较低,因为您使用比所需更大的矩阵执行乘法。
实际上,最好的方法IMHO是将单独的3x3普通矩阵传递到着色器,并使其仅包含转换的旋转部分,但不缩放。这样,您可以跳过在应用变换后通常需要重新规范化法线的步骤,因为纯旋转会使矢量的长度保持不变。
在问题的最后部分:如果使用4x4矩阵,请不除以结果向量的第4个分量。第四个组成部分为零,你不想除以零......
答案 1 :(得分:1)
你可以做任何一个,因为它们会产生相同的结果。如果向量中的第四个分量为零,则矩阵的该行对结果没有影响。但是,使用3x3左上角更有效,因为这样可以消除不必要的数学运算。
所以程序是:
答案 2 :(得分:0)
上面的答案很好,但我会向您展示我在WebGL中使用的一些代码片段。
通常我的GLSL顶点着色器看起来如下所示。 NormalMatrix
是在客户端计算的3x3矩阵,作为ModelViewMatrix
的上3x3部分的逆转置,并作为统一变量传递:
attribute vec4 vertexPosition;
attribute vec3 vertexNormal;
...
uniform mat4 ModelViewProjection;
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
...
void main() {
gl_Position = ModelViewProjection*vertexPosition;
vec3 P = vec3(ModelViewMatrix * vertexPosition);
vec3 N = normalize(NormalMatrix * vertexNormal);
vec3 L = normalize(light0Position - P);
...
}
在客户端,我的Matrix4x4
类有一个normal()
方法,可以提取相应的3x3矩阵:
var ModelView = View.mult(Model);
var NormalMatrix = ModelView.normal();
var MVP = Projection.mult(ModelView);
gl.uniformMatrix4fv(program.ModelViewProjection, false, MVP.array);
gl.uniformMatrix4fv(program.ModelViewMatrix, false, ModelView.array);
gl.uniformMatrix3fv(program.NormalMatrix, false, NormalMatrix);
我以列主要(GL)顺序存储矩阵:
function Matrix4x4() {
this.array = [1, 0, 0, 0, // stored in column-major order
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1];
}
normal()
方法实际上返回一个9元素数组,表示按主列顺序排列的3x3矩阵:
Matrix4x4.prototype.normal = function() {
var M = this;
var determinant =
+M.elem(0,0)*(M.elem(1,1)*M.elem(2,2) - M.elem(2,1)*M.elem(1,2))
-M.elem(0,1)*(M.elem(1,0)*M.elem(2,2) - M.elem(1,2)*M.elem(2,0))
+M.elem(0,2)*(M.elem(1,0)*M.elem(2,1) - M.elem(1,1)*M.elem(2,0));
var invDet = 1.0/determinant;
var normalMatrix = [];
var N = function(row,col,val) { normalMatrix[col*3 + row] = val; }
N(0,0, (M.elem(1,1)*M.elem(2,2) - M.elem(2,1)*M.elem(1,2))*invDet);
N(1,0,-(M.elem(0,1)*M.elem(2,2) - M.elem(0,2)*M.elem(2,1))*invDet);
N(2,0, (M.elem(0,1)*M.elem(1,2) - M.elem(0,2)*M.elem(1,1))*invDet);
N(0,1,-(M.elem(1,0)*M.elem(2,2) - M.elem(1,2)*M.elem(2,0))*invDet);
N(1,1, (M.elem(0,0)*M.elem(2,2) - M.elem(0,2)*M.elem(2,0))*invDet);
N(2,1,-(M.elem(0,0)*M.elem(1,2) - M.elem(1,0)*M.elem(0,2))*invDet);
N(0,2, (M.elem(1,0)*M.elem(2,1) - M.elem(2,0)*M.elem(1,1))*invDet);
N(1,2,-(M.elem(0,0)*M.elem(2,1) - M.elem(2,0)*M.elem(0,1))*invDet);
N(2,2, (M.elem(0,0)*M.elem(1,1) - M.elem(1,0)*M.elem(0,1))*invDet);
return normalMatrix;
}
您可以找到我的客户matrix.js
模块here。