cocos2D-X源码分析之从cocos2D-X学习OpenGL(16)----基本光照

时间:2023-02-08 00:05:15

       cocos引擎目前已经支持3d功能,之前在3d教程中介绍了cocos2d-x的3d功能中的光照,但是只是粗略的介绍了四种光源,因为光照的重要性和复杂性,这个系列文章会分两篇介绍光照,本篇介绍光照的基础-ADS模型,下一篇详细介绍几种光源。

       ADS模型是光照的基本模型,包括Ambient(环境光),Diffuse(漫反射)和Specular(点光源)三种光照在物体上的效果是这样的:

cocos2D-X源码分析之从cocos2D-X学习OpenGL(16)----基本光照

       三种光照共同影响物体,模拟出一般的光照效果,被称作ADS模型,也叫Phong模型。

       环境光是一个来自远处的光源,它会让物体显示一些颜色,全局照明的原理非常简单,它用光的颜色乘以一个很小的常量ambient因子,然后乘以物体颜色,最后得到环境光照射物体之后的颜色。

       在cocos2d-x中,在Mesh类(网格,3d模型渲染的最小单元)中以uniform的方式向着色器传递光照的参数,处理环境光的时候,是直接传递环境光颜色,但是在创建环境光的时候要设置一个强度值,在传递前,会用光强乘以颜色再传,在应用程序中处理好计算可以减少着色器的计算量,是个提高效率的好方法。

auto ambLight = static_cast<AmbientLight *>(light);const Color3B &col = ambLight->getDisplayedColor();
ambientColor.add(col.r / 255.0f * intensity, col.g / 255.0f * intensity, col.b / 255.0f * intensity);
       漫反射就没那么简单了,它模拟一个发光物对物体方向性的影响,它是ADS模型中最重要的组成部分,面向光源的一面比其他面更亮,它涉及到一些数学和物理概念,如图所示:

cocos2D-X源码分析之从cocos2D-X学习OpenGL(16)----基本光照

       我们在初中物理中学习过光的发射,它是光照和平面的垂直方向(法线方向)形成入射角,反射是入射角等于发射角,光线会从另一个方向反射出去,在模拟计算光照的时候,我们仍然需要法线这个概念,因为当入射光线和法线夹角为0时,光照的效果是最大化的,当为90度时,光照的效果几乎为0,我们要模拟出这个效果。

       法线向量是垂直于顶点表面的向量,由于顶点没有表面的概念,我们利用顶点周围的顶点计算出这个顶点的表面,因为向量叉乘可以得到垂直于两个向量的向量,我们可以用这种方法得到法向量,有时为了模拟凹凸不平的平面效果,我们还会使用法线贴图去定义每个点的法线向量。

       下一步我们就获得光的方向,光源类提供了获得光照的方法:

Vec3 SpotLight::getDirection() const{    Mat4 mat = getNodeToParentTransform();    return Vec3(-mat.m[8], -mat.m[9], -mat.m[10]);}Vec3 SpotLight::getDirectionInWorld() const{    Mat4 mat = getNodeToWorldTransform();    return Vec3(-mat.m[8], -mat.m[9], -mat.m[10]);}
      两个向量准备好了,我们就可以计算漫反射光照了:

vec3 computeLighting(vec3 normalVector, vec3 lightDirection, vec3 lightColor, float attenuation){    float diffuse = max(dot(normalVector, lightDirection), 0.0);    vec3 diffuseColor = lightColor  * diffuse * attenuation;        return diffuseColor;}
       最后一个参数attenuation是为计算另外两种光源准备的,这里就会传1,而漫反射光就是法向量乘以光源方向,注意,因为法向量由平面指向外方向,所以对应的“光方向”就是由物体平面的点指向光源,所以传的时候,是真正光源方向的相反数:

for (int i = 0; i < MAX_DIRECTIONAL_LIGHT_NUM; ++i){    vec3 lightDirection = normalize(u_DirLightSourceDirection[i] * 2.0);    combinedColor.xyz += computeLighting(normal, -lightDirection, u_DirLightSourceColor[i], 1.0);}
       ADS模型就剩下Specular高光了,它也是依照光的方向向量和法向量,另外还会参考视角方向,基本算法就是将光线方向(注意,这次是真正的光线方向了)通过GLSL内置的reflect函数计算出反射光线,然后用反射光线乘以视线方向,从而获得光照参数,这个光照参数还要进行一次幂操作,之一要多少次幂和光线强度有关,被称作发光值,发光值越高,反射光的能力越强,散射的越少,高光点越小,下图就是不同高光值得影响

cocos2D-X源码分析之从cocos2D-X学习OpenGL(16)----基本光照

       cocos2d-x并没有进行这部分的光照计算,基本采用的都是反射光的计算方法,在聚光灯和点光源的处理上就是乘以不同的attenuation,它们的具体算法会在下一篇中计算,将不同的光照影响加在一起,就得到物体最终显示的颜色。

       下一篇将分析不同的发光体。

       能力不足,水平有限,如有错误,欢迎指出。