一:基础定义
1:颜色定义:
对于大多数计算机显示器来说,颜色信息的显示只是依靠三种光波的组合:红,绿,蓝.所以颜色可以用红,绿,蓝三元素表示,每个
分量都在0到1区间,颜色即能够代表光的光谱成分,也能代表光的强度.颜色可用和一个三维向量表示,有加法和乘法.
2:光源:
1):环境光:环境光是一种低强度的光,由光线经过周围环境表面多次反射后形成的,利用环境光可以描述一块区域的亮度,通常在场
景中,环境光的颜色是一个常量.
2):太阳光:即定向光源,特点是从无穷远出发射光线,光线是平行的,光线强度不会随着距离衰减.
3):点光源:在有限空间内某个点上发出的光线,光线强度会随着距离衰减.衰减系数一般是距离的二次多项式倒数.
4):聚光灯:特点是有主照射方向,强度随着距离衰减,并且光线延着中心向外衰减.
二:漫反射
理想的漫反射表面把光线向所有方向均匀的散射,因此,这样的表面在所有观察者看来亮度都一样,理想的慢反射表面是如此粗糙,以至于向各个方向反射的光线强度都相等.这样的表面被成为Lambert表面(兰博特),OpenGL固定管线,或者Shader基于这个定律来建模.
漫反射公式推导:
1: 先看看漫反射强度跟哪些参数有关系? , 如图所示:
对于横截面积为A的光束, 其被光束照射的面积是A/[email protected], 也就说明单位面积上,光的强度是以[email protected]系数进行衰减的, 那么[email protected]又是光线和表面法线的点乘.
2: 慢反射公式推导:
设@是法向量N, 和光源L之间的夹角, 则, [email protected] = 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镜面指数;
镜面指数m控制镜面强光的集中程度, 小的m值产生模糊的强光, 大的m值产生明显的强光. 一个对镜面强光进行描述的可信模型:
镜面反射值 = S*C*(max(R*V,0)^m), 条件是(N*L>0);
这个模型的含义是, 当光线与法线成锐角时, 观察者能接收到反射光线, 并且强度随着发射光线与观察者夹角成指数变化.
虽然这个模型能计算出镜面反射, 每一次计算,都涉及到反射光线, 但实际中,反射光线可能有无数条, 计算量太大, 能否有一种简化模型呢.
一种办法是, 在光源位置向量与观察者向量, 取一个中间向量, 叫做平分向量H, 如图所示:
当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; //反射结果(没有加距离衰减)