在opengl中为了模拟光线或进行光照计算和阴影计算,我们往往需要首先计算法线。法线是一个向量,顶点法线(Vertex Normal)是过顶点的一个矢量,用于在高洛德着色(Gouraud Shading)中的计算光照和纹理效果。在生成曲面时,通常令顶点法线和相邻平面的法线保持等角,这样进行渲染时,会在平面接缝处产生一种平滑过渡的效果。表面的光照强度(即反射光量)是和光线方向与法线方向的夹角成正比的,夹角越小表面就会看起来越亮(具体可以参考)。

    我们知道求一个面的法线,但是一个顶点的法线怎么求呢?其实求出来的也是一种大概的法线。我们根据这个顶点旁边的点,每三个点确定一个平面,用这个点和其他点,每三个组合一个平面,分别求出每个平面法线后,把所有平面的法线叠加在一起,然后再单位化即是该点的法线。关于顶点和面的法线相关内容,请参考我转载的另一篇文章(顶点法线和面法线

android opengles 顶点数组 opengl顶点法线_c++

如上图所示,根据V0,V1和V2确定的平面(每个顶点Vi有x,y和z),我们可以求出这个平面的法线:

    va = V1 - V0

    vb = V2 - V0

    根据向量求法线的公式我们可以得出,向量va和vb的叉乘 ,即为所求法向量。

    即为:法线 norm = va X vb(向量叉乘)       norm(x, y, z)

    具体为:norm.x = va.y * vb.z - va.z * vb.y

                    norm.y = va.z * vb.x - va.x * vb.z

                    norm.z = va.x * vb.y - va.y * vb.x

    或者我们可以用一些第三方计算几何数学库来处理向量的计算,例如glm库(OpenGL Mathematics几何数学库),另一个类似的数学库是:Shading Language Math for C++。使用glm库的计算如下:

     glm::Vec3  va, vb, norm;

     norm = glm::Cross(va, vb);    //直接利用叉乘函数即可计算

上述讲了怎么求一个面的法线,那么如何求一个顶点的法线就很容易了,下面是分别针对格网数据和三角网数据求顶点法线的情况。

    1)格网数据

*以下内容源自http://www.cppblog.com/flashboy/archive/2008/09/19/62263.html,包括图片。

    为地形使用面法线最大的问题就是它看起来一块一块的, 因为每个面的亮度都是恒定的,并且每个方向的面上的亮度都有明显的区别。为了看起来更加的光滑,我们必须为每个顶点计算法线,而不是每个面计算法线。当计算顶点法线的时候,我们有必要考虑到此顶点共享的所有面,所以我们用方形举例,每个顶点(排除掉角落和边缘的顶点)被四个多边形共享。这个顶点的法线就应该是所有共享面法线的和在归一化的结果。

android opengles 顶点数组 opengl顶点法线_可视化_02

有了前面求法线的公式,现在我们求图中中间顶点的法线就比较方便了。在上面的图里,v1,v2,v3和v4是向量,v代表了中心顶点的法线,每个vij表示每个共享面的法线,所以例如v12是右下方面的单位长度的法线。那么法线 v = v12 + v23 + v34 + v41

    为了使表面看起来更加光滑,有两种方法,第一种我们可以采用计算8个相邻顶点的法线,具体做法与计算四个顶点类似。第二种方法是对法线进行插值,具体是在着色器中完成,由于现在大多使用可编程管线,我们可以采用Phong光照模型,把顶点法线传到顶点着色器中,然后在片段着色器中对法线进行插值,使之看起来更光滑,但这种方法做出来的效果并不适合所有模型,看起来太鲜亮,有的模型需要偏暗色彩。如下图为phong光照模型下绘制的茶壶。图片源自:

android opengles 顶点数组 opengl顶点法线_归一化_03


2)三角网

    

android opengles 顶点数组 opengl顶点法线_归一化_04

 v = v12 + v23 + v34 + v41

    最后,另一个必要的步骤获得正确的光照是归一化这个向量,就是让它是单位长度,OpenGL在计算光照的时候需要考虑归一化的法向量。归一化的过程意味着第一步首先计算向量的长度,然后向量的每个部分除以此长度。具体可以参考http://www.cppblog.com/flashboy/archive/2008/09/19/62263.html

如果使用glm库的话,直接可以使用glm::Normalize()这个函数归一化。


References: