OpenGL ES 光照计算

  • 光照计算在片元着色器执行,计算每一个像素点的颜色

一、光照计算

1、环境光计算

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

  • 环境光 = 光的颜色 * 材质颜色;
    光是有颜色的,比如红光、绿光等;
    材质颜色也就是纹理颜色。

2、发射光的计算

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

  • 物体本身是有颜色的,比如手电筒,其本身能发光,发出的光的颜色就是发射颜色。

3、漫反射光照计算

  • 光照有阴面和阳面,由法线计算光与物体之间的夹角,这个夹角分为入射角和反射角

漫反射颜色 = 光源的漫反射颜色 * 物体的漫反射材质颜色 * DiffuseFactor

DiffuseFactor = max(0, dot(N, L));

  • 漫反射因子DiffuseFactor 是光线与顶点法线向量的点积,是光线与法线之间的夹角,其值不能小于0

4、镜面光计算

镜面反射颜色 = 光源的镜面光颜色 * 物体的镜面材质颜色 * SpecularFactor

SpecularFactor = power(max(0, dot(N, H)), shininess);
H:视线向量E 与光线向量L 的半向量
dot(N, H):H,N的点积几何意义,平方线与法线夹角的cos值
shininess:高光的反光度

  • 镜面因子SpecularFactor,shininess反光度越小光照越集中

5、普通光照计算

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

衰减因子计算

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

tips:环境光、漫反射光和镜面光的强度都会受距离的增大而衰减,只有发射光和全局环境光的强度不会受影响

6、聚光灯因子

聚光灯夹角cos值 = power(max(0, dot(单位光源位置, 单位光线向量)), 聚光灯指数);

单位光线向量:是从光源指向顶点的单位向量
聚光灯指数:表示聚光灯的亮度程度
公式解读:单位光源位置 * 单位光线向量 点积 的 聚光灯指数次方

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

7、光照计算终极公式

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

平面光终极公式

  • 平面光也就是平行光,没有具体的方向

点光源终极公式

  • 比如灯泡光源,点光源是有方向的

二、光照的GLSL实现

1、环境光的GLSL实现

varying vec3 objectColor;
void main() {

    //至少有10%的光照到物体所有面
    float ambientStrength = 0.1;

    //环境光颜色 = 环境光比率 * 环境光颜色
    vec3 ambient = ambientStrength * lightColor;

    //最终颜色 = 环境光颜色 * 物体颜色
    vec3 result = ambient * objectColor;
    //vec3转化成vec4
    gl_FragColor = vec4(result, 1.0);

}

2、漫反射光的GLSL实现

uniform vec3 lightColor;     //光源颜色
uniform vec3 lightPo;         //光源位置
uniform vec3 objectColor; //物体颜色
uniform vec3 viewPo;        //物体位置
varying vec3 outNormal;  //传入当前顶点平面的法向量

//确保法线为单位向量,normalize为内建函数,把法向量转换成单位向量
vec3 norm = normalize(outNormal);
//顶点指向光源的单位向量
vec3 lightDir = normalize(lightPo -   FragPo);
//得到两向量的cos值,小于0则为0
float diff = max(dot(norm, lightDir), 0.0);
//夹角乘以光照颜色得到漫反射的光源向量
vec3 diffuse = diff * lightColor;

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

3、镜面光的GLSL实现

//镜面强度
float specularStrength = 0.5;

//顶点指向观察点的单位向量
vec3 viewDir = normalize(viewPo - FragPo);

//光线在顶点的反射线(传入光源指向顶点的向量),镜面光是反方向的光线
vec3 reflectDir = reflect(-lightDir, outNormal);

//夹角cos值,取256次幂,镜面因子
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 256.0);

vec3 specular = specularStrength * spec * lightColor;

4、衰减因子计算

//距离衰减常量
float constantPara = 1.0;
//线性衰减常量
float linearPara = 0.09;
//二次衰减因子
float quadraticPara = 0.032;
//距离
float lightWeakPara = 1.0/(constantPara + linearPara * LFDistance + quadraticPara * (LFDistance * LFDistance));

5、聚光灯过渡计算

//一些复杂的计算操作应该让CPU做以提高效率,不变的量也建议外部传输,避免重复计算
//内锥角cos值
float inCutoff = cos(radians(10.0));
//外锥角cos值
float outCutoff = cos(radians(15.0));
//聚光朝向
vec3 spotDir = vec3(-1.2, -1.0, -2.0);

//光源指向物体的向量和聚光朝向的cos值
float theta = dot(lightDir, normalize(-spotDir));
//内外锥角cos差值
float epsilon = inCutoff - outCutoff;

//clamp(a, b, c);若b<a<c则函数返回a,若不是则返回最小b,最大c
/*(theta - outCutoff)/epsilon 若theta的角度小于内锥角则其值>=1,
若theta的角度大于外锥角则其值<=0,这样光线就在内外锥角之间平滑变化*/
float intensity = clamp((theta - outCutoff) / epsilon, 0.0, 1.0);

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 光照是OpenGL ES里很重要的一部分,下面我们来学习总结一下如何计算不同的光照效果。 光照基础1、环境光照2、...
    jakeXu阅读 3,959评论 1 14
  • 光照基础 环境光 漫反射光 镜面光 光照特性 发射光:由物体自身发光 环境光:环境中充分散射的光,而且无法分辨它的...
    JunkieBa阅读 3,280评论 0 0
  • 现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是以目前我们所拥有的处理能力无法模拟的。因此OpenGL的...
    zhongxiaoyue阅读 4,106评论 0 1
  • 冯氏光照模型:主要结构由3个元素组成:环境(Ambient)光照、漫反射(Diffuse)光照和镜面(Specul...
    盾子阅读 3,647评论 0 0
  • 一朵红花 文/付朝兰 一朵鲜艳的红花 开在小小绿叶下 静静等待有缘人 花钱把她抱回家
    付朝兰阅读 4,705评论 16 25

友情链接更多精彩内容