opengl计算面部

时间:2016-02-10 01:47:49

标签: c++ opengl

我正在尝试将从Blender导出的模型加载到OpenGL中。特别是,我按照这个tutorial的源代码来帮助我开始。因为加载器相当简单,它只读取顶点坐标和面索引,忽略法线和tex。

然后计算每张脸的法线:

        float coord1[3] = { Faces_Triangles[triangle_index], Faces_Triangles[triangle_index+1],Faces_Triangles[triangle_index+2]};
        float coord2[3] = {Faces_Triangles[triangle_index+3],Faces_Triangles[triangle_index+4],Faces_Triangles[triangle_index+5]};
    float coord3[3] = {Faces_Triangles[triangle_index+6],Faces_Triangles[triangle_index+7],Faces_Triangles[triangle_index+8]};
float *norm = this->calculateNormal( coord1, coord2, coord3 );


        float* Model_OBJ::calculateNormal( float *coord1, float *coord2, float *coord3 )
        {
           /* calculate Vector1 and Vector2 */
           float va[3], vb[3], vr[3], val;
           va[0] = coord1[0] - coord2[0];
           va[1] = coord1[1] - coord2[1];
           va[2] = coord1[2] - coord2[2];

           vb[0] = coord1[0] - coord3[0];
           vb[1] = coord1[1] - coord3[1];
           vb[2] = coord1[2] - coord3[2];

           /* cross product */
           vr[0] = va[1] * vb[2] - vb[1] * va[2];
           vr[1] = vb[0] * va[2] - va[0] * vb[2];
           vr[2] = va[0] * vb[1] - vb[0] * va[1];

           /* normalization factor */
           val = sqrt( vr[0]*vr[0] + vr[1]*vr[1] + vr[2]*vr[2] );

            float norm[3];
            norm[0] = vr[0]/val;
            norm[1] = vr[1]/val;
            norm[2] = vr[2]/val;


            return norm;
        }

我有2个问题。

  1. 我如何知道正常情况是向内还是向外? .obj文件中每行中是否有一些顶点排序,指示如何计算法线?
  2. 在初始化函数中,他使用GL_SMOOTH。这是不正确的,因为如果使用GL_SMOOTH而不是GL_FLAT,我需要为每个顶点提供法线?

1 个答案:

答案 0 :(得分:4)

问题1

glFrontFace确定风顺序

风顺序意味着一组顶点应该出现的顺序,以使法线被认为是正数。考虑下面的三角形。它的顶点是顺时针定义的。如果我们告诉OpenGL glFrontFace(GL_CW)(顺时针方向是指正面),那么法线基本上就会从屏幕上向你伸出,以便被认为是“向外”。

在旁注中,逆时针是默认值,您应该坚持使用。

无论如何,您需要真正定义法线,尤其是当您想要在场景中进行任何照明时,因为它们用于照明计算。 glFrontFace只是让你告诉OpenGL你想要解释多边形的前面是什么。

在上面的示例和下图中,如果我们告诉OpenGL我们定义了面逆时针以及glEnable d glCullFace并将其设置为{{1然后我们的三角形不会出现,因为我们会看到它的后面,我们告诉OpenGL不要显示多边形的背面。

您可以在此处详细了解面部剔除:Face Culling

Triangle with a clockwise wind

Wavefront GL_BACK has support,如果您不想自己创建法线,则可以在文件中声明法线。只需确保您的导出商添加它们。

另外,Wavefront希望每个顶点都有一个正常的定义:

.obj

其中f v1//vn1 v2//vn2 v3//vn3 ... vN面的顶点,而f是顶点的法线。通过为每个顶点提供法线,您可以获得比通过定义每个面的法线或通过将同一个面的顶点的所有法线设置为相同更平滑的外观。看看这个问题,看看你可以在球体上做出的区别:OpenGL: why do I have to set a normal with glNormal?

如果您的.obj文件没有定义法线,我会使用面定义顺序并跨越定义面的两条边。请考虑此处使用的方法:Calculating a Surface Normal

修改

我想我可能有点困惑。多边形的正面仅与其法线略微相关。法线仅用于照明计算。你没有拥有来拥有它们,但它们是计算对象亮度时使用的一大变量。

我正在同时解释多边形的“前脸”,因为在讨论凸多边形时,你的法线会突然从三角形的“前面”伸出来你想要的形状。

如果你创造了一个巨大的洞穴,或者你的相机主要位于一些凹形内部,那么将法线指向内部是有意义的,因为你的光源可能想要从内部反弹你的形状。

问题2

vnN确定要与GL_SMOOTH

一起使用哪种着色模型

glShadeModel表示平滑着色,其中颜色实际上在每个顶点之间插值,而GL_SMOOTH表示平面着色,其中仅使用一种颜色。通常,您将使用默认值GL_FLAT

在任何一种情况下,你都没有拥有来定义每个顶点的法线。但是,如果你希望GL_SMOOTH看起来“好”,你可能会想要,因为它会在每个顶点之间渲染时进行插值,而不是仅为属性选择一个顶点。

另外,请记住,每当您离开固定功能管道并开始使用着色器时,所有这些都会消失。