材质
材质也即物体的光照属性,我们使用材质(Material)来模拟物体在真实光照环境下的光照表现。
#version 330 core
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
uniform Material material;
- ambient:环境光照下物体反射光颜色
- diffuse:漫反射光照下物体反射光颜色
- specular:镜面反射光照下物体反射光颜色
- shininess:影响镜面高光的散射/半径
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
三个组成部分的计算方法:
// 环境光
vec3 ambient = Light.ambient * Material.ambient;
// 漫反射, lightDir 是片元到光源的方向向量
float diff = max(dot(lightDir, Normal), 0.0);
vec3 diffuse = Light.diffuse * diff * Material.diffuse;
// 镜面反射, viewDir 是片元到摄像机的方向向量
// 计算反射光线时,入射光线是从光源到片元
vec3 reflectDir = reflect(-lightDir, Normal);
// 幂次越大,坡越抖,也即反射的亮斑越小,镜面程度越高
float spec = pow(max(dot(reflectDir, viewDir),0.0), 32.0);
vec3 specular = Light.specular * spec * Material.specular;
// 累加三个部分即可
vec3 resultColor = ambient + diffuse + specular;
光照贴图
我们可以使用贴图来更加近似地模拟真实环境,同样为了更加容易区分出物体表面的漫反射以及镜面反射,我们可以使用漫反射贴图和镜面反射贴图来控制反射的颜色,同样对于某些自发光的物体,我么你还可以使用mission纹理来模拟自发光。
上面是一张漫反射纹理,我们再获取对应坐标的位置后,使用纹理颜色替换材质颜色进行漫反射计算即可。
与漫反射贴图类似,我们可以将镜面反射纹理颜色乘到原来的镜面反射颜色部分。
投光物
顾名思义就是将光线投出去的东西,也即光源。
- 生活中所有的光源都是点光源,太阳就是无数的点光源组成的,因为距离很远,我们可以把太阳看成一个点光源。假设光源上两个点距离Dis,光源到物体距离R,那么这个两个点光源到该物体的夹角为Dis/R,由于R很大,所以夹角近似为0,可以认为从两个光源来的光线重合,也即可以认为是一个点光源。可以得出结论,当距离足够远时,可以把多个点光源看成一个点光源。
- 同样,当半径非常大时,圆上两个距离很近的点,这两个点之间的角度差(Dis/R)近似为0,也即圆心到这两点的直线夹角为0,也即不相交(以上都是近似)。可以得出结论,当距离足够远时,可以把点光源看成平行光源。
- 考虑到真实环境中的光线衰减(散射、折射、频率降低等等),我们可以使用线性函数近似莫斯这个过程,通过指定多项式的因子,来控制衰减速度变化,通常我们使用二次就足够了,公式:
,D是到光源的距离,通过指定不同的a、b值,我们就可以模拟不用的衰减变化曲线。
- 经过遮挡物,遮挡物后的光线会被阻挡,我们使用聚光来模拟这种情况(类似手电筒),也即一个点光源加上限制的光源散射角度范围。一般情况下可投影的范围是个圆形,这时只需要比较片元到光源的方向是否在限制角度内即可,但是也存起可投影范围不是圆形的情况,例如方形,那么这个时候,可以控制模板测试?
- 但是真实情况手电筒并不是点光源,当距离比较近时,半影区会比较明显,这时可以使用近似方法模拟这种半影,例如半影区一次线性变化(角度or余弦值?)等等。
多光源
灵活利用之前提到的光源即可。