OpenGL ES on iOS --- 光照进阶

OpenGL ES on iOS --- 光照进阶

简述

本文记录我记录我学习 坐标体系和矩阵转换的过程,加深学习便于后续查询,可能有些描述不够准确,或者内容不够充实,还请多多指正,共同学习.

光源分类

在基础光照时,学习了光照对物体的作用,也就相当于物体的材质,这次主要说 现实生活中的光源

平行光

当光源无限远时,从其发射过来的的光可以近似的看做平行光(例如太阳);这时 光线的方向都是一致的.

平行光
 float ambientStrength = 0.3;    //环境因子
    float specularStrength = 2.0;
    float reflectance = 256.0;

    //平行光方向
    vec3 paraLightDir = normalize(vec3(-0.2,-1.0,-0.3));

    //环境光
    vec3 ambient = ambientStrength * texture(Texture,outTexCoord).rgb;

    //漫反射
    vec3 norm = normalize(outNormal);
    vec3 lightDir = normalize(lightPo - FragPo);    //当前顶点 至 光源的的单位向量
    float diff = max(dot(norm,paraLightDir),0.0);
    vec3 diffuse = diff * lightColor*texture(Texture,outTexCoord).rgb;

    //镜面反射
    vec3 viewDir = normalize(viewPo - FragPo);
    vec3 reflectDir = reflect(-paraLightDir,outNormal);
    float spec = pow(max(dot(viewDir, reflectDir),0.0),reflectance);
    vec3 specular = specularStrength * spec * texture(specularTexture,outTexCoord).rgb;

    //光线衰弱
    float constantPara = 1.0f;
    float linearPara = 0.09f;
    float quadraticPara = 0.032f;
    float LFDistance = length(lightPo - FragPo);
    float lightWeakPara = 1.0/(constantPara + linearPara * LFDistance + quadraticPara * (LFDistance*LFDistance));

    vec3 res = ambient + diffuse + specular;

    FragColor = vec4(res,1.0);

点光源

点光源就是比较正常的光源,光从光源四散发出,光线的向量就等于光源到物体的向量.


点光源
    float ambientStrength = 0.3;    //环境因子
    float specularStrength = 2.0;
    float reflectance = 256.0;

    float constantPara = 1.0f;    //常亮
    float linearPara = 0.09f;     //线性部分因数
    float quadraticPara = 0.032f; //二次项部分因数

    //环境光
    vec3 ambient = ambientStrength * texture(Texture,outTexCoord).rgb;

    //漫反射
    vec3 norm = normalize(outNormal);
    vec3 lightDir = normalize(lightPo - FragPo);    //当前顶点 至 光源的的单位向量

    //点光源
    float diff = max(dot(norm,lightDir),0.0);   //光源与法线夹角
    vec3 diffuse = diff * lightColor*texture(Texture,outTexCoord).rgb;

    //镜面反射
    vec3 viewDir = normalize(viewPo - FragPo);
    vec3 reflectDir = reflect(-lightDir,outNormal);

    float spec = pow(max(dot(viewDir, reflectDir),0.0),reflectance);
    vec3 specular = specularStrength * spec * texture(specularTexture,outTexCoord).rgb;

    float LFDistance = length(lightPo - FragPo);
    float lightWeakPara = 1.0/(constantPara + linearPara * LFDistance + quadraticPara * (LFDistance*LFDistance));

    vec3 res = (ambient + diffuse + specular)*lightWeakPara;

    FragColor = vec4(res,1.0);

聚光源

聚光源的效果就相当于 手电筒,好比朝向指定范围的点光源~


聚光源

在使用聚光源时,就需要指定 聚光朝向SpotDir,和切光角ϕ. 当光源指向点的向量和SpotDir的夹角大于ϕ时,则无法被光源照射到.

但是这样的明暗边界十分明显,效果不够真实

初始版本

这时,我们就需要将过渡边缘平滑,这时 我们就需要引入两个参数, 内锥角和外锥角. 外锥角就是切光角,而内锥角以内不需要平滑效果, 内锥角和外锥角之间需要平滑过度.
代码如下

    /(一些复杂的计算操作 应该让CPU做,提高效率,不变的量也建议外部传输,避免重复计算)
    float inCutOff = cos(radians(10.0f));   //内锥角cos值
    float outCutOff = cos(radians(15.0f));  //外锥角cos值
    vec3 spotDir = vec3(-1.2f,-1.0f,-2.0f); //聚光朝向
    
    float theta = dot(lightDir,normalize(-spotDir));    //光源指向物体的向量 和 聚光朝向的 cos值
    float epsilon  = inCutOff - outCutOff;  //内外锥角cos差值
    
    //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);
结果

光线衰弱

在现实情况中,光源发出的光线是会随着距离的增长而衰减的, 而且也不是线性衰减的,表现为在距离光源近的这段距离衰减的较快, 在距离光源较远的情况下衰减较慢.
通常使用这个公式来模拟光线衰减.

衰减公式

常数项通常保持为1.0,它的主要作用是保证分母永远不会比1小,否则的话在某些距离上它反而会增加强度,这肯定不是我们想要的效果
一次项会与距离值相乘,以线性的方式减少强度
二次项会与距离的平方相乘,让光源以二次递减的方式减少强度。二次项在距离比较小的时候影响会比一次项小很多,但当距离值比较大的时候它就会比一次项更大了

效果展示
参数距离表
    float LFDistance = length(lightPo - FragPo);
    float lightWeakPara = 1.0/(constantPara + linearPara * LFDistance + quadraticPara * (LFDistance*LFDistance));

    vec3 res = (ambient + diffuse + specular)*lightWeakPara;

光照贴图

在一张纹理图中,由于材质不同,所呈现的效果也会有所不同,如同下面这个箱子,金属边框和木头在相同光源下所呈现的1效果肯定有所不同.

木箱纹理

这时为了在显示光照效果时将其区分开来,则需要引入光照贴图的概念~ 如下图


镜面光照贴图

在该贴图中,对应木头部分为黑色vec3(0.0); 而在金属边框部分 则对应的为灰色, 这样在计算 漫反射或者镜面时,将其作为参考系数,则可以让其呈现不同的效果.

vec3 spe = texture(specularTexture,outTexCoord).rgb;   //获取镜面光照贴图
 
vec3 viewDir = normalize(viewPo - FragPo);
vec3 reflectDir = reflect(-lightDir,outNormal);

float spec = pow(max(dot(viewDir, reflectDir),0.0),spL.reflectance);
vec3 specular = point_specularStrength * spec * spe;    //使用光照贴图纹理
镜面光照纹理效果

是可以看出箱子铁框的镜面效果 比 木头的效果要强

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容