计算顶点法线时遇到小问题(OpenGL ES)

3

我对顶点法线有一点问题。

结果看起来有些奇怪。首先看一下这些图片:

在3D软件中的原始模型。

使用从文件中导入的法线的Per-Fragment lighting,该文件是以OBJ格式导入的网格。

使用自己的程序计算法线的Per-Fragment lighting。

你注意到了吗? 使用OBJ文件中的法线时一切都正常。但是当我使用自己的程序根据顶点计算法线时,有些地方似乎有问题。

当Z值变为负数(使用右手坐标系)时,法线看起来很奇怪。在物体的其他部分一切正常,但网格上只有一条想象的直线看起来很奇怪。这个问题也存在于其他网格上,总是发生在同一个地方,即Z = 0。

我的计算法线程序是大家都知道的,假设ABC是一个三角形:

vec3 normal = normalize(cross(C - A, B - A));

然后将正常结果添加到已计算的正常缓冲区中。

我看到一些人说要计算每个三角形的面积,并乘以法线,甚至检查缓冲区上的法线和新法线之间的点积,但我已经尝试过这些方法,只有一些小变化,但仍然存在同样的问题。

你以前见过这种情况吗?你知道如何解决吗?

这是一些代码:

// Looping at each triangle
vec3 distBA = vec3Subtract(vB, vA);
vec3 distCA = vec3Subtract(vC, vA);

vec3 normal = vec3Cross(distBA, distCA);

// Each normalBuffer represents one vertex.
normalBuffer[i1] = vec3Add(normal, normalBuffer[i1]);
normalBuffer[i2] = vec3Add(normal, normalBuffer[i2]);
normalBuffer[i3] = vec3Add(normal, normalBuffer[i3]);

// After pass through all faces/triangles.

// Looping at each Vertex structure.
normal = vec3Normalize(normalBuffer[i]);

鉴于错误似乎是每像素而不是每多边形,可能错误在着色器中,您能否也发布该代码? - UncleZeiv
着色器在两种情况下都是相同的(来自OBJ的法线和我计算的法线)。使用来自OBJ的法线一切正常,因此我不认为问题出在那里。缓冲区是用于对来自不同三角形但属于同一顶点的法线进行求和,例如相邻的三角形。我真的想不出为什么会发生这种情况。 - user464230
另一个测试要运行:渲染一条穿过 z=0 线的单个三角形。这将清楚地显示问题的一部分是否在着色中。此外:禁用高光反射。总的来说,尽可能简化测试用例,以排除各种“干扰”。 - UncleZeiv
我找到了!!!嗨,叔叔,谢谢您的关心,但我终于找到问题所在了。这与我们在这里讨论的任何事情都无关,着色器很完美,创建法线的代码也非常好,一切都没问题......问题出在我的思维逻辑上。当我将OBJ文件更改为COLLADA文件并进行一些测试时,解决方案就出现了。简单来说,我用OBJ逻辑思考,但使用类似COLLADA逻辑的结构。OBJ文件每个面都有一个法线,这意味着如果4个顶点具有相同的法线0,1,0,则OBJ文件不会重复此操作,但COLLADA会。 - user464230
“Z=0”只是一个巧合。现在我正在更改解析器以正确处理这个新逻辑,然后正确计算法线。再次感谢UncleZeiv的关注,你帮助我不跳过这个问题并继续前进。谢谢。 - user464230
显示剩余2条评论
2个回答

1

根据您如何计算每个片段的光照(即是否将点积夹在0-1范围内),您看到的可能只是法线反转的问题。根据您如何选择ABC,顶点处的法线可能指向任一方向。要区分三角形的外部和内部,通常需要更多信息,例如顶点的绕序。您考虑到这一点了吗?


我已经尝试了所有A、B、C的计算组合,但其他结果都是完全错误的... 我仍在寻找解决方案... - user464230
我的意思略有不同。我并不是说你在错误的顺序中选择了A、B、C。我是说这个顺序可能取决于其他一些信息,这些信息对于一半的茶壶来说是正确的,但对于另一半来说是错误的。因此,在这种情况下,我不会期望任何特定的组合是正确的。无论如何,如果尝试所有这些组合都没有给你带来任何额外的见解,那么它可能不是正确的方向。 - UncleZeiv

0

你是否对“然后将正常结果添加到已计算的正常缓冲区中”进行了归一化处理?我不确定你是否必须这样做,但是加上它也不会有坏处。而且,在此过程中,检查NaN和无穷大也是必要的。

在你的归一化函数中,你是否检查传入向量的长度是否大于0?

我怀疑你的向量库中某个地方存在一个严重的错误,特别是因为问题仅出现在Z轴上。


是的,我已经按照你说的做了...这让我疯了...看,我编辑了问题并添加了一些代码。 - user464230

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接