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

如何在3D模型非均匀缩放时重新计算法线?

非均匀缩放后重新计算3D模型法线的正确姿势

嘿,这个问题我太熟了——非均匀缩放后法线跑偏是3D渲染里的经典坑,我来给你掰扯清楚怎么解决,再结合你说的例子说明白~

问题本质

当你对3D模型做非均匀缩放(也就是X/Y/Z三个轴向的缩放比例不一样,比如X拉2倍、Y不变、Z压0.5倍)时,普通的顶点缩放会直接“拉伸”法线向量,但法线是方向向量,它需要保持单位长度且严格垂直于模型表面,这种粗暴的拉伸会彻底破坏法线的特性,导致光照渲染完全出错。

你提到的两个场景示例

  • 图1:未缩放的模型
    这时候模型的法线(N)是完全正确的:它垂直于对应表面,长度为1,渲染时的光影效果完全符合预期——比如物体的明暗过渡自然,高光位置精准,看起来质感正常。
  • 图2:非均匀缩放后的模型
    直接对顶点做非均匀缩放后,法线会被同步拉伸变形,这时候它既不再垂直于表面,长度也不是单位长度了。举个直观的例子:把一个立方体在X轴拉长2倍,原本垂直于侧面的法线会被拉成X方向偏长的向量,渲染出来的侧面会显得“发灰”,高光位置也会偏移,完全不符合真实的光影逻辑。

解决方法:用逆转置矩阵变换法线

要修复这个问题,不能直接用缩放矩阵去乘法线,而是要使用缩放矩阵的逆矩阵的转置来处理法线向量,最后再做归一化(把长度变回1)。

给你一段GLSL的伪代码示例,这是实时渲染里最常用的处理方式:

// 假设modelMatrix包含了模型的缩放、旋转、平移变换
mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
vec3 correctedNormal = normalize(normalMatrix * originalNormal);

简单解释下:

  1. 先从模型矩阵里提取出3x3的旋转缩放部分(去掉平移,因为法线是方向向量,平移不影响)
  2. 求这个矩阵的逆矩阵:用来抵消非均匀缩放对法线的拉伸影响
  3. 对逆矩阵做转置:因为法线是协变向量,和顶点(逆变向量)的变换规则不同,转置后才能保证变换后的法线依然垂直于表面
  4. 最后归一化:确保法线回到单位长度,保证光照计算的准确性

额外提一句:如果是均匀缩放(三个轴缩放比例相同),直接缩放法线再归一化也能凑合用,但非均匀缩放必须用逆转置矩阵,这是核心区别哦。

内容的提问来源于stack exchange,提问作者magallanes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:19:50