OpenGL_ES-光照(光照基础,漫反射,镜面反射)

时间:2021-12-30 04:12:26

:基础定义

    1:颜色定义:

      对于大多数计算机显示器来说,颜色信息的显示只是依靠三种光波的组合:,绿,.所以颜色可以用红,绿,蓝三元素表示,每个   分量都在01区间,颜色即能够代表光的光谱成分,也能代表光的强度.颜色可用和一个三维向量表示,有加法和乘法.


     2:光源:

           1):环境光:环境光是一种低强度的光,由光线经过周围环境表面多次反射后形成的,利用环境光可以描述一块区域的亮度,通常在场  景中,环境光的颜色是一个常量.

           2):太阳光:即定向光源,特点是从无穷远出发射光线,光线是平行的,光线强度不会随着距离衰减.

           3):点光源:在有限空间内某个点上发出的光线,光线强度会随着距离衰减.衰减系数一般是距离的二次多项式倒数.

           4):聚光灯:特点是有主照射方向,强度随着距离衰减,并且光线延着中心向外衰减.

                             

:漫反射

        理想的漫反射表面把光线向所有方向均匀的散射,因此,这样的表面在所有观察者看来亮度都一样,理想的慢反射表面是如此粗糙,以至于向各个方向反射的光线强度都相等.这样的表面被成为Lambert表面(兰博特),OpenGL固定管线,或者Shader基于这个定律来建模.

       

         漫反射公式推导:

        1: 先看看漫反射强度跟哪些参数有关系?  , 如图所示:


OpenGL_ES-光照(光照基础,漫反射,镜面反射)

        对于横截面积为A的光束, 其被光束照射的面积是A/Cos@, 也就说明单位面积上,光的强度是以Cos@系数进行衰减的, 那么Cose@又是光线和表面法线的点乘.

        

        2: 慢反射公式推导:

            设@是法向量N, 和光源L之间的夹角, 则, cos@ = L*N;

            设慢反射系数K, 则慢反射光强度I  =  K(L*N);

            设光线传播衰减系数为  1/(a + bd + cd^2); 则  I  = [1/(a + bd + cd^2)] *  K(L*N);


 

        Shader例子:

       

 vec3normal; //光照平面的法线 V

vec3position; //光源位置 P

float dotVP; //法线和光源向量点乘值

float diffause; //光的漫反射颜色

dotVP =dot(normal, position); //向量点乘

dotVP =max(dotVP, 0); //当法线和光源向量夹角为顿角的就没有光照了.

floatDiffause = diffause*dotVP; //漫反射结果(没有加距离衰减)


:镜面反射

       相信大家小时候玩过镜子,镜子反射光时会很耀眼,镜面反射会形成强烈的光反射,反射的路线与入射方向 和表面法线形成的反射方向保持一致,镜面反射依赖于观察者所处的位置.当反射方向指向观察者时,光线最强,当反射光线离开观察者时,光线强度呈指数下降;

          镜面反射公式推导:

         具体公式推导过程:如图所示, V: 观察者, R: 反射光线, N:法线, L: 入射光线; S: 反射颜色, C:入射光强度,m镜面指数;

         OpenGL_ES-光照(光照基础,漫反射,镜面反射)

           

          镜面指数m控制镜面强光的集中程度, 小的m值产生模糊的强光, 大的m值产生明显的强光. 一个对镜面强光进行描述的可信模型:

          镜面反射值 = S*C*(max(R*V,0)^m), 条件是(N*L>0);

          这个模型的含义是, 当光线与法线成锐角时, 观察者能接收到反射光线, 并且强度随着发射光线与观察者夹角成指数变化.

          虽然这个模型能计算出镜面反射, 每一次计算,都涉及到反射光线, 但实际中,反射光线可能有无数条, 计算量太大, 能否有一种简化模型呢. 

          一种办法是, 在光源位置向量与观察者向量, 取一个中间向量, 叫做平分向量H, 如图所示:

          OpenGL_ES-光照(光照基础,漫反射,镜面反射)

           当H和法线N重合时, 反射到观察者的光线最近, 当H和法线N角度变大时,光线减弱. 由此,调整反射模型为:

           镜面反射值 = S*C*(max(H*N,0)^m), 条件是(N*L>0)


       Shader例子:

        
 vec3normal; //光照平面的法线V

vec3halfVector; //光线平分向量方向H,含义参见上一篇博客

floatdotHV; //法线和光线点乘值

floatshininess; //镜面指数,控制镜面强光集中度

floatspecular; //镜面反射颜色

dotHV= dot(normal, halfVector); //光线平分向量与法线点乘

dotHV= max(0, dotHV);//夹角呈顿角按0值处理

floatpf = 0.0;//光线反射强度

pf= pow(dotHV, shininess);

specular= specular * pf; //反射结果(没有加距离衰减)