obj文件 - 平均法线

时间:2012-08-27 09:59:38

标签: opengl 3d

我有一个以这种方式存储数据的obj文件:

v value1 value2 value3  
f value1 value2 value3

首先,我计算面部的法线,然后为该面部的每个顶点指定:

for(int i = 0; i < verticesInd.size(); i+=3)
{
    glm::vec3 normal = glm::normalize(glm::cross(glm::vec3(vertices[verticesInd[i + 1]]) - glm::vec3(vertices[verticesInd[i]]), glm::vec3(vertices[verticesInd[i + 2]]) - glm::vec3(vertices[verticesInd[i]])));
    out_Normals[i] = normal;
    out_Normals[i + 1] = normal;
    out_Normals[i + 2] = normal;
}

为了实现平面着色,我可以复制顶点:

for(int i = 0; i < verticesInd.size(); i++)
{
    out_Vertices.push_back(vertices[verticesInd[i]]);
} 

然后使用glDrawArrays绘制对象:

glDrawArrays(GL_TRIANGLES, 0, out_Vertices.size());

为了获得平滑的阴影,我需要平均每个顶点的法线,但我不知道如何找到相邻的面。

编辑1:我在f:

之前没有注意到单个参数
v value1 value2 value3
s 1  
f value1 value2 value3

编辑2:法线平均值

glm::vec3 tNormal;
for(int i = 0; i < vertices.size(); i++)
{
    for(int  j = 0; j < verticesInd.size(); j++)
    {
        if(verticesInd[j] == i)
        {
            tNormal += faceNormals[j / 3];
        }
    }
    aNormals.push_back(glm::normalize(tNormal));
    tNormal = glm::vec3(0,0,0);
}

编辑3 面部法线:

for(int i = 0; i < verticesInd.size(); i+=3)
{
    glm::vec3 normal = glm::normalize(glm::cross(glm::vec3(vertices[verticesInd[i + 1]]) - glm::vec3(vertices[verticesInd[i]]), glm::vec3(vertices[verticesInd[i + 2]]) - glm::vec3(vertices[verticesInd[i]])));
    faceNormals.push_back(normal);
}

3 个答案:

答案 0 :(得分:1)

在大多数对象格式中,相邻的面应该是共享顶点。在顶点处找到平滑的阴影法线应该是平均使用该顶点的任何面的法线的问题。

我建议您创建一个与现有顶点数组大小相同的新数组。

迭代每个面,并为每个顶点索引添加该顶点的面与新数组的法线。

在过程结束时,将结果法线向量标准化,然后使用它而不是先前计算的面法线。

如果我正确理解您的数据结构,它将看起来像这样:

glm::vec3 aNormals[];   // one for each vertex - use the appropriate constructor

for (int i = 0; i < verticesInd.size(); ++i) {
    int f = i / 3;                 // which face is this index part of (3 per face?)
    int v = verticesInd[i];        // which vertex number is being used
    aNormals[v] += faceNormals[f]; // add the face normal to this vertex
}

// now normalise aNormals

答案 1 :(得分:0)

在每个片段照明上关注此人https://www.youtube.com/watch?v=MRD_zN0SWh0&feature=plcp。据我所知,它包含了相同的方程式,用于在每个顶点的基础上找到法线。

您需要一张面孔列表。如果你曾经见过过wavefront obj。它们包含多个三角形索引4,7,2 1,2,3。每3个数字代表一张脸。使用普通网格,每个点只能使用3次。如果您发现每个组都有3,那么您可以找到每个脸。找到相应的正常值,然后取平均值。

Alnitak也有有效的信息。你有一个顶点列表,然后将它们列为3组,这样你就可以重复使用顶点(共享)作为面数据。

答案 2 :(得分:0)

  

我不知道如何找到相邻的面孔。

向临时的in-OBJ-loader顶点存储中添加一个面列表。在处理面线时,将新面添加到它引用的每个顶点的面列表中。

这样你就可以在最后旋转所有顶点,查找它所属的面部,抓住面法线并对它们求平均值。

如果您的OBJ没有这么好的烘焙连接信息(并且没有必要),那么您必须在每个顶点上进行最近邻搜索才能找到顶点(和相应的面)靠近它。使用您最喜欢的spatial index来加速这些类型的查询。