OpenGL ES光照计算

作者: 聪莞 | 来源:发表于2019-06-20 10:46 被阅读6次

光照基础

  1. 环境光照:利用环境光可以描述一块区域的亮度,通常在场景中,环境光的颜色是一个常量
  2. 漫反射光照:光线向所有方向均匀的散射
  3. 镜面光照:反射的路线与入射方向和表面法线形成的反射方向保持一致,镜面反射依赖于观察者所处的位置.当反射方向指向观察者时,光线最强,当反射光线离开观察者时,光线强度呈指数下降
image.png

光照特性

  1. 发射光:物体本身发光
  2. 环境光:在环境中散射的光,无法判断方向
  3. 漫反射光:光线来着某个方向,在物体各个方向反射
  4. 镜面高光:光线来着特定的方向,在物体表面以特定的方向反射

在物理学中,光线如果射入理想的光滑平面,则反射后的光线是很规则的(这样的反射称为镜面反射)。光线如果射入粗糙的、不光滑的平面,则反射后的光线是杂乱的(这样的反射称为漫反射)。现实生活中的物体在反射光线时,并不是绝对的镜面反射或漫反射,但可以看成是这两种反射的叠加。对于光源发出的光线,可以分别设置其经过镜面反射和漫反射后的光线强度。对于被光线照射的材质,也可以分别设置光线经过镜面反射和漫反射后的光线强度。这些因素综合起来,就形成了最终的光照效果。

材质属性

  1. 泛射材质
  2. 漫反射材质
  3. 镜面泛射材质
  4. 发射材质

材质是指接受光照的各种物体的表面,由于物体如何反射光线只由物体表面决定(OpenGL中没有考虑光的折射),材质特点就决定了物体反射光线的特点。

光照计算

环境光计算

环境光 = 光源的环境光颜色 * 物体的材质颜色

varying vec3 objectColor;
void main() {
//设定有%20的光到达物体表面
float ambientStrength = 0.2;
//环境光颜色
vec3 ambient = ambientStrength * lightColor;
//最终颜色
vec3 result = ambient * objectColor;
gl_FragColor = vec4(result,1.0);
}

发射光计算

发射颜色 = 物体的反射材质颜色

漫反射光照计算

image.png

光照的方向(顶点指向灯泡的向量) 和 表面法线会有一个角度Θ,根据自然现象,Θ越大,光照越弱,角度越小,光照越强。
假设:Ld表示光源漫反射颜色,Od表示某个物体的漫反射颜色,那么漫反射公式就是 Ld * Kd * cos(Θ),而cos(Θ)又等于s和n的点乘,所以漫反射的计算公式为:(DiffuseFactor为漫反射因子)

漫反射颜色 = 光源的漫反射颜色 * 物体漫反射材质颜色 *DiffuseFactor
DiffuseFactor = max(0,dot(s,n))
uniform vec3 lightColor;    //光源颜色
uniform vec3 lightPo;      //光源位置
uniform vec3 objectColor;    //物体颜色
uniform vec3 viewPo;      //物体位置
uniform vec3 outNormal;  //当前顶点平面的法向量

//确保法线为单位向量
vec3 norm = normalize(outNormal);
//顶点指向光源的单位向量
vec3 lightDir = normalize(lightPo - viewPo);
//得到cos值,小于0则为0
float diff = max(dot(norm,lightDir),0);

vec3 result = lightColor * objectColor * diff;
gl_FragColor = vec4(result,1.0);

镜面光计算

反射的方向跟观察者有一个夹角Θ,假设镜面指数为reflectance,那么镜面反射因子计算为:
SpecularFactor = power(max(dot(camera_direction,reflected_light),0),reflectance);
Power(Number,Power)。其中Number表示底数,Power表示幂值。
如2的10次方,可以写为:POWER(2,10)。

假设specularStrength为镜面强度,镜面光计算为:

result = specularStrength *SpecularFactor * objectColor * lightColor
//镜面强度
float specularStrength = 0.5;
//顶点指向观察者的单位向量
vec3 viewDir = normalize(viewPo - FragPo);
//求反射线(光源基于法线为outNormal的平面产生的反射线)
vec3 reflectDir = reflect(-lightDir,outNormal);
//求得cos值,取256次幂
flost spec = pow(max(dot(viewDir,reflectDir),0),256);
//求得镜面光照
vec3 result = specularStrenth * spec * objectColor *lightColor

gl_FragColor = vec4(result,1.0);

但是这种算法的每一次计算,都涉及到反射光线, 但实际中,反射光线可能有无数条, 计算量太大, 能否有一种简化模型呢?
一种办法是, 在光源位置向量与观察者向量, 取一个中间向量, 叫做平分向量H, 如图所示:


image.png

当H和法线N重合时, 反射到观察者的光线最近, 当H和法线N角度变大时,光线减弱。
所以我们可以调整夹角为 H和N的角度 。
法线计算公式:


image.png
平分向量H的计算:

vec3 H = normalize(L + V)

光照计算

光照颜色 = (环境颜色 + 漫反射颜色 + 镜面反射颜色) * 衰减因子

衰减因子计算公式

image.png

衰减因子 = 1.0/(距离衰减常量 + 线性衰减常量 * 距离 + 二次衰减常量 * 距离的平方)
距离衰减常量,线性衰减常量和二次衰减常量均为常量值。

注意!环境光,漫反射光和镜⾯光的强度都会受距离的增大而衰减,只有发射光和全局环境光的强度不会受影响。

float constantPara = 1.0f;    //距离衰减常量
float linearPara = 0.09f;    //线性衰减常量
float quadraticPara = 0.032;  //二次衰减因子
float distance = length(lightPo - FragPo); //距离

//衰减因子
float lightWeakPara = 1.0/(constantPara + linearPara * distance + quadraticPara *  distance * distance);

聚光灯因子(聚光灯 可以想象成手电筒这样的光源)

聚光灯夹角cos值 = power(max(0,dot(单位光源位置,单位光线向量量)),聚光灯指数);
单位光线向量是从光源指向顶点的单位向量、
聚光灯指数,表示聚光灯的亮度成都、
公式解读:
单位光源位置 * 单位光线向量点积的聚光灯指数次⽅

聚光灯过渡处理:


image.png

增加过渡计算:
聚光灯因子 = clamp((外环的聚光灯⻆度cos值 - 当前顶点的聚光灯⻆度cos值) / (外环的聚光灯角度cos值- 内环聚光灯的角度的cos值),0,1);

clamp()为区间指定函数,将结果控制在 0 - 1,即小于0为0,大于1为1.

    //聚光灯切角 (一些复杂的计算操作 应该让CPU做,提高效率,不变的量也建议外部传输,避免重复计算)
    float inCutOff = cos(radians(10.0f));
    float outCutOff = cos(radians(15.0f));
    vec3 spotDir = vec3(-1.2f,-1.0f,-2.0f);
    
    //聚光灯因子 = clamp((外环的聚光灯角度cos值 - 当前顶点的聚光灯角度cos值)/(外环的聚光灯角度cos值- 内环聚光灯的角度的cos值),0,1);
    float theta = dot(lightDir,normalize(-spotDir));
    //(外环的聚光灯角度cos值- 内环聚光灯的角度的cos值)
    float epsilon  = inCutOff - outCutOff;
    //(外环的聚光灯角度cos值 - 当前顶点的聚光灯角度cos值) / (外环的聚光灯角度cos值- 内环聚光灯的角度的cos值)
    float intensity = clamp((theta - outCutOff)/epsilon,0.0,1.0);

光照最终计算公式:

光照颜色 = 发射颜色 + 全局环境颜色 + (环境颜色 + 漫反射颜色 + 镜面反射颜色) * 聚光灯效果 * 衰减因⼦

光源分多种,不容的光源类型(点光源、聚光灯、平行光),计算方式略有不同。开发中需要根据实际场景进行合适的选择和综合计算。

相关文章

  • OpenGL ES光照计算

    光照是OpenGL ES里很重要的一部分,下面我们来学习总结一下如何计算不同的光照效果。 光照基础1、环境光照2、...

  • OpenGL ES 􏳆􏰤􏷐􏶾􏲗􏵘光照计算

    光照基础 环境光 漫反射光 镜面光 光照特性 发射光:由物体自身发光 环境光:环境中充分散射的光,而且无法分辨它的...

  • OpenGL ES光照计算

    光照基础 环境光照:利用环境光可以描述一块区域的亮度,通常在场景中,环境光的颜色是一个常量 漫反射光照:光线向所有...

  • OpenGL ES 光照计算

    冯氏光照模型:主要结构由3个元素组成:环境(Ambient)光照、漫反射(Diffuse)光照和镜面(Specul...

  • OPenGL ES光照计算

    现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是以目前我们所拥有的处理能力无法模拟的。因此OpenGL的...

  • OpenGL ES 光照计算

    光照计算在片元着色器执行,计算每一个像素点的颜色 一、光照计算 1、环境光计算 环境光 = 光源的环境光颜色 * ...

  • OpenGL ES 光照计算

    光照基础 1.环境光照(ambient) 2.漫反射光照(diffuse) 3.镜面光照(specular) 光照...

  • OpenGL ES之旅(四)-- OpenGL ES 光照计算

    光照是个很复杂的话题,尤其是多光源,阴影的计算。在这篇文章中,我会详细介绍不同类型光的性质以及物体的材质属性,以及...

  • OpenGL ES(八)-光照计算

    光照基础 从生理学的角度上讲,眼睛之所以看见各种物体,是因为光线直接或间接的从它们那里到达了眼睛。人类对于光线强弱...

  • OpenGL ES 关于光照计算

    有关光照的代码公式, 在此用CC老师已经写好的代码做一个记录, 方便以后使用的时候查询. 记录一个函数-->根据你...

网友评论

    本文标题:OpenGL ES光照计算

    本文链接:https://www.haomeiwen.com/subject/jtckqctx.html