我做了一些测试,下面是我的看法:
OBJ 导出脚本会忽略顶点法线,而是使用面法线。
为了测试,我做了一个简单的形状,由 2 个三角形组成,如下图所示:
并导出到 OBJ。您应该期望 4 个向量法线 (vn),因为您有 4 个向量,或者如果优化了 3 个,因为中间的 2 个向量是相同的。但相反,它只输出 2 个 vn-s:
vn -0.000000 1.000000 0.000000
vn -1.000000 -0.000000 -0.000000
更重要的是,如果您查看面部定义,您会发现更有趣的东西:
f 1//1 4//1 3//1
f 4//2 2//2 3//2
查看单行中 // 后面的数字。他们是一样的。这意味着对于一个面内的所有顶点,使用相同的法线。这意味着,这些不是顶点的法线,而是面的法线。所以这就是为什么为相同的顶点分配不同的法线。当顶点号4 用于定义第一个面接收第一个面的法线,用于定义第二个面时,使用第二个面的法线。
编辑
您可以像这样计算顶点法线:
- 查找每个顶点的出现并将其所有法线放入集合 A 中
- 添加法线各自的坐标:
vn = (x1 + x2 + ... + xn, y1 + y2 + ... + yn, z1 + z2 + ... + zn)
- 计算向量长度:h = sqrt(vnx^2 + vny^2 + vnz^2)
- 归一化向量 vn:vn = (vnx / h, vny / h, vnz / h)
使用我之前的例子(在图像上找到的那个),顶部和底部的向量只出现一次,所以你不需要做任何事情(顶点的法线与顶点的法线相同)脸)。在中间的顶点上:它们出现两次,一次出现在顶部三角形,法线为 (0, 1, 0),底部的法线为 (-1, 0, 0),因此我们这些顶点的法线集是 { (0, 1, 0), (-1, 0, 0)}。添加这些给出:(0 - 1, 1 + 0, 0 + 0) = (-1, 1, 0)。计算长度:h = sqrt((-1)^2 + 1^2) = sqrt(2)。将向量除以它得到 norm(vn) = vn / h = (-1 / sqrt(2), 1 / sqrt(2), 0)。如果您查看中间法线的 Front Ortho(左上角)的图片,您会看到 -x 和 +y 相等的分量,而向量的长度为 1。您可以看到我们的结果有长度1 通过再次计算它的长度:1/2 + 1/2 + 0 = 1。这就是我们必须归一化以获得长度 1 的原因。