【问题标题】:Flipped computed face normals after iOS OpenGl ES .obj loading a unit cubeiOS OpenGL ES .obj 加载单位立方体后翻转计算的面法线
【发布时间】:2011-10-20 04:08:34
【问题描述】:

我正在尝试将模型从 Maya 导出并加载到一个非常简单的 iOS OpenGL ES 设置中。为此,我编写了一个 ruby​​ obj 解析器,它基本上采用顶点和法线并将它们计算成一个我简单地包含的 C 头文件。简单三角单位立方体的输出结构如下:

Vertex3D cubeVertices[] = {
   {{-0.500000f, -0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{0,1,2},{0,6,7},{0,7,1},{0,6,4},{0,4,2}},5},
   {{0.500000f, -0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{1,0,2},{1,2,3},{1,0,7},{1,7,3}},4},
   {{-0.500000f, 0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{2,0,1},{2,1,3},{2,3,4},{2,4,0}},4},
   {{0.500000f, 0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{3,2,1},{3,2,4},{3,4,5},{3,1,7},{3,7,5}},5},
   {{-0.500000f, 0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{4,2,3},{4,3,5},{4,5,6},{4,6,0},{4,0,2}},5},
   {{0.500000f, 0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{5,4,3},{5,4,6},{5,6,7},{5,3,7}},4},
   {{-0.500000f, -0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{6,4,5},{6,5,7},{6,7,0},{6,0,4}},4},
   {{0.500000f, -0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{7,6,5},{7,6,0},{7,0,1},{7,1,3},{7,3,5}},5}
};

GLubyte cubeFaceIndices[] = {
   0, 1, 2,
   2, 1, 3,
   2, 3, 4,
   4, 3, 5,
   4, 5, 6,
   6, 5, 7,
   6, 7, 0,
   0, 7, 1,
   1, 7, 3,
   3, 7, 5,
   6, 0, 4,
   4, 0, 2
};

Vertex3D 的定义是

struct Vertex3D {
   vec3 position;
   vec3 normal;
   vec4 color;
   Index3D connected_faces[100];
   int connectedFaceCount;
};
typedef struct Vertex3D Vertex3D;

现在我需要重新计算我的顶点法线,因为我想要动画一些顶点的运动。为此,我只是将所有连接的顶点索引添加到每个顶点,这就是 connected_faces 索引数组的用途。

对于计算,我只需使用叉积计算所有面部法线。为此,我只需要使用存储在 Index3D 中的 3 个顶点,加载位置,减去第一个顶点,这样我就得到了向量并计算叉积。然后我将属于这个顶点的所有叉积相加,并对向量进行归一化,这就是我最终的顶点法线。

我遇到的问题是,碰巧有 2 个面具有相同的面正常,例如三角立方体总是有 2 个三角形将四边形分开,该面的法线方向相反。如果我将它们相加,以便稍后计算,它们的总和当然是 N​​ull-Vector。我知道发生这种情况是因为在某些情况下 2 个顶点没有正确的顺序,这意味着 A 应该被 B 替换,但我不知道我必须翻转哪个。

是否有任何数学方法可以估计法线的走向,以及我是计算 AxB 还是 BxA?我在 Maya 中仔细检查了法线,它们在那里非常完美。

编辑:我现在订购了连接面,效果很好。我正在使用以下方法计算法线:

// every vertex
GLsizei vertexCount = sizeof(cubeVertices) / sizeof(Vertex3D);
for (int i = 0; i < vertexCount; i++) {
    vec3 newNormal = {0.0f, 0.0f, 0.0f};

    // every vertex connected to the current vertex
    GLsizei faceCount = cubeVertices[i].connectedFaceCount;
    for(int j = 0; j < faceCount; j++){

        Index3D index = cubeVertices[i].connected_faces[j];

        vec3 vectorA = cubeVertices[index.a].position;
        vec3 vectorB = cubeVertices[index.b].position;
        vec3 vectorC = cubeVertices[index.c].position;
        vec3 vectorNormal = {0.0f, 0.0f, 0.0f};

        substractVectors(&vectorB, &vectorA);
        substractVectors(&vectorC, &vectorA);

        makeNormal(&vectorB, &vectorC, &vectorNormal);
        addVectors(&newNormal, &vectorNormal);
    }

    // set normal for current vertex
    normalize(&newNormal);
    cubeVertices[i].normal = newNormal;
}

但现在我遇到的问题是,通过三角剖分,有时我有 2 条法线指向完全相同的方向,这不会导致我预期的 { 0.33f, 0.33f, 0.33f } 顶点法线。这是正确的行为,还是有其他方法可以计算?

非常感谢您的帮助!

【问题讨论】:

  • 也许发布正常的计算代码将有助于解决您的问题。
  • 我现在添加了正常的计算,仍然有一些小问题。感谢您的第二条建议,要在 2 次往返中完成所有计算,接下来我将尝试。
  • 好的,更新了我的答案。顺便说一句,这实际上是三个往返,因为您当然需要将顶点法线初始化为零(但简单性仍然值得)。

标签: opengl-es flip vertex normals


【解决方案1】:

这取决于面的顶点顺序。如果它们是逆时针排列的(当从外面看脸时),那么你计算的脸法线为AxB,用A = (v1-v0)B = (v2-v0),如果顺时针排列你必须切换A和B。

但只要您始终如一地为每张脸执行此操作,它就应该有效。否则立方体中的面的方向不一致,也许有人(导出器?)在将四边形转换为三角形或类似的东西时弄乱了方向。

顺便说一句,您可以在没有connected_faces 数组的情况下计算它们,只需遍历面/索引数组一次,计算每个面的面法线并将其添加到相应的三个顶点的法线,然后是单个顶点数组遍历用于规范化法线。

编辑:您可以尝试在 OpenGL 中通过剔除正面或背面来渲染它们(使用glCullFace(GL_BACK)glEnable(GL_CULL_FACE))。如果内部(或外部,取决于剔除模式)的一些三角形被剔除而一些没有被剔除,则三角形的方向不一致并且您的立方体数据被破坏。

编辑:根据您更新的问题,我认为至少您不再有 0 法线。代码看起来也不错。事实上,并非每个法线都有三个相似的坐标(顺便说一句,它不是 0.33 而是 1/sqrt(3),但我知道你的意思)对于由三角形构建的立方体来说是很自然的。在极端情况下,您可能会得到连接到 6 个或仅 3 个三角形的顶点。在所有其他情况下(这应该发生),您将无法获得完美的拐角法线。

这是由于立方体的三角剖分。您不再看到立方体(由 6 个面和 8 个顶点构成,每个顶点正好连接到 3 个面),而是一个三角形网格,顶点连接到 3 到 6 个三角形之间的任意数量。您的程序逻辑不知道某些三角形属于一起并形成一个四边形。这也是一般网格的常见问题。例如,在四边形网格(由四边形构建)上执行任何细分算法会产生不同的几何形状,而不是在该网格的三角剖分上执行相同的细分(每个四边形有两个三角形)。

如果您真的需要处理四边形,则需要一些更高级别的抽象来表示四边形层(可能是顶部的另一个数据结构或只是三角形的特殊排序,例如每对连续的 tris 形成一个四边形)。否则,您也可以完全使用四边形,因为 OpenGL 可以直接渲染四边形(尽管我不确定未弃用的 GL 或至少 ES 是否已经放弃了对四边形的支持)。

编辑:在你的情况下,你可以订购它,所以每两个三角形形成一个四边形。然后在法线计算中你总是处理两个三角形,计算其中一个的法线,然后只更新四个不同顶点的顶点法线。

【讨论】:

  • 好的,非常感谢您抽出宝贵时间。我现在通过三角测量看到了不完美立方体的要点,只是想确保我走在正确的道路上。 OpenGL ES 只支持 a.f.a.i.k 三角形,所以我不能采用四边形。正如你所想的那样,我现在正在计算三个往返计算,并且由于我的目标网格更具有有机性质,因此法线可能会很好地工作。
猜你喜欢
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
相关资源
最近更新 更多