You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebGL中mat3.normalFromMat4的使用方法及原理技术咨询

嘿,这个问题我当初刚碰WebGL光照的时候也卡了好久!让我一步步给你掰明白normalMatrix到底是咋回事,还有mat3.normalFromMat4该咋用~

为啥法线不能直接用模型视图矩阵?

首先得搞清楚:顶点是位置向量,用模型视图矩阵变换没问题,但法线是方向向量——它的核心作用是保持和表面切线垂直。如果直接用模型视图矩阵(尤其是当模型有非均匀缩放的时候),法线会被“拉歪”,不再垂直于表面,光照计算直接就崩了。这时候就必须用专门的normalMatrix来变换法线。

「取前3x3+逆转置」的原理

你看的《计算机图形学导论》里的步骤,其实就是normalMatrix的计算逻辑,拆解一下:

  • 砍掉第四行第四列:模型视图矩阵的第四部分是用来处理平移的,但法线是方向向量,平移不影响方向,所以直接提取前3×3的矩阵就够了。
  • 求逆矩阵:如果模型被缩放了,逆矩阵能把缩放的影响“反向修正”,保证法线的方向不会被拉伸得离谱。
  • 转置矩阵:这是向量变换的数学要求——要保证法线和变换后的表面切线依然垂直,就必须用逆矩阵的转置来变换法线。如果你的模型只有旋转和平移(没有非均匀缩放),逆矩阵等于转置,这时候逆转置后的矩阵和原矩阵前3×3一样,可以偷懒直接用,但有缩放的话必须老老实实算。
mat3.normalFromMat4的实际用法

这个函数就是帮你把上面的步骤自动化了!你不用手动写复杂的矩阵逆和转置运算,只需要传入你的模型视图矩阵,它会自动输出正确的normalMatrix。

举个原生WebGL的完整例子:

顶点着色器部分

precision mediump float;

uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;

attribute vec3 position;
attribute vec3 normal;

varying vec3 vNormal; // 传递给片元着色器的变换后法线

void main() {
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  // 变换后记得归一化,避免缩放导致法线长度变化
  vNormal = normalize(normalMatrix * normal);
}

JavaScript端代码(用gl-matrix库)

// 假设你已经构建好了模型视图矩阵(比如用mat4组合平移/旋转/缩放)
const modelViewMatrix = mat4.create();
mat4.lookAt(modelViewMatrix, [0, 2, 5], [0, 0, 0], [0, 1, 0]); // 示例:相机看向原点

// 计算normalMatrix
const normalMatrix = mat3.create();
mat3.normalFromMat4(normalMatrix, modelViewMatrix);

// 将normalMatrix传给着色器uniform
const normalMatrixLoc = gl.getUniformLocation(program, 'normalMatrix');
gl.uniformMatrix3fv(normalMatrixLoc, false, normalMatrix);
额外提一句Three.js画质的小建议

你说Three.js纹理映射画质下降,大概率是纹理过滤的默认设置导致的。原生WebGL里你可以手动控制纹理过滤参数,比如加载纹理时设置:

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

这样能获得更清晰的纹理效果,避免Three.js默认的低精度过滤带来的模糊。

内容的提问来源于stack exchange,提问作者alan.raceQs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 20:28:12