OpenGL ES 学习教程(十) Light casters 之 Spot Light (聚光灯)
来源:互联网 发布:淘宝客在哪推广 编辑:程序博客网 时间:2024/06/06 05:36
本文参考
http://learnopengl-cn.readthedocs.org/zh/latest/02%20Lighting/05%20Light%20casters/
这里是最后一种光 了,前面学习了 平行光、定点光,这一次来学习 聚光灯。
聚光灯 是朝某一个方向 照射的光,而且有一个固定的半径 ,在这个半径之内,物体才受到光照影响,这个范围之外的物体就不会被光照影响到。
聚光灯在现实生活中的例子有:手电筒、路灯等。 转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
( 游戏中的手电筒 就是聚光灯 )
简单的来说,聚光灯就是指定一个圈,在这个圈里面就计算光照,在这个圈外面就不计算光照。
我简单的画了一张图来解释转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
仍然以前面的 Lighting Map (高光贴图) 工程来进行修改,去除 Diffuse 和 Specular ,只保留 Ambient 来便于测试。
首先在 片段着色器中修改 Light ,添加 position ( 聚光灯位置 ) 、 spotdirection ( 聚光灯指向 ) 、cutOff ( 聚光灯范围 指定角度的 cos 值 )。
如下 ( GLProgram_Cube.h Line 108 ):
"struct Light" //替换光的RGB分量强度"{""vec3 position;" //聚光灯 位置;"vec3 spotdirection;" //聚光灯 指向,就像路灯总是指向地面,我这里是指向屏幕里面;"vec3 ambient;""float cutOff;"//聚光灯范围 cos(角度);"};"
然后计算片段 指向 光源 的向量;
计算 (片段-光源) 向量 与 聚光灯指向向量的角度的余弦值.
如果计算出来的值比 指定的聚光灯范围 cos(角度) 的值更大,说明角度更小,在聚光灯范围内,就照亮,否则就黑的。
如下 ( GLProgram_Cube.h Line 120 ):转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
"void main()""{""vec3 lightDir=normalize(m_light.position - out_fragpos);" //计算片段 指向 光源 的向量;"float theta = dot(lightDir,normalize(-m_light.spotdirection));" //计算 (片段-光源) 向量 与 聚光灯指向向量的角度的余弦值. 这个灯光的方向 是指向屏幕里面的,所以这里用了负值!!"if(theta > m_light.cutOff)" //如果计算出来的值比 指定的聚光灯范围 cos(角度) 的值更大,说明角度更小,在聚光灯范围内,就照亮,否则就黑的。"{""vec3 ambient=vec3(texture2D(m_diffusetexture,m_outUV))*m_light.ambient;"//环境光;"gl_FragColor=vec4(ambient,1.0);""}""else""{""gl_FragColor=vec4(0.0,0.0,0.0,1.0);""}""}"
然后获取属性 ( GLProgram_Cube.h Line 150 ):
m_lightspotdirection = glGetUniformLocation(m_programId, "m_light.spotdirection");m_lightAmbient = glGetUniformLocation(m_programId, "m_light.ambient");m_lightpos = glGetUniformLocation(m_programId, "m_light.position");m_lightCutOff = glGetUniformLocation(m_programId, "m_light.cutOff");
然后设置属性值 ( MyApp.h Line 111 ):
//传入light;glUniform3f(m_programCube.m_lightpos, cameraX, cameraY, 10.0f);//传入灯光的位置glUniform3f(m_programCube.m_lightAmbient, 1.0f, 1.0f, 1.0f);glUniform3f(m_programCube.m_lightspotdirection, cameraX, cameraY, -1.0f); //灯光朝向;float cos = glm::cos(glm::radians(12.0f)); //话说我这个相机的距离 ,和这个Cube的角度,不到30度;glUniform1f(m_programCube.m_lightCutOff, cos);
我们计算一下,我这里创建了 9 个箱子,X 轴范围是 -3 到 3 。聚光灯的位置是 (0,0,10) ,聚光灯是朝向 ( 0,0,-1 ) 。
那么可以算的 这 9 个箱子 ,在聚光灯的 30度范围之内。
所以我这里取了 12度 来作为测试。
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
测试结果
测试工程下载:
http://pan.baidu.com/s/1jHpYiSe
上面的聚光灯效果太硬,边缘分界太明显,我们可以在边缘处加一个慢慢变暗的效果。
在上面工程基础上,我们给聚光灯添加一个外边框范围 outerCutOff 。
然后通过计算片段位置 与 内边框 和外边框的距离远近,来调整边缘处灯光的强弱。
首先添加外边框范围 outerCutOff ( GLProgram_Cube.h Line106 )
"struct Light" //替换光的RGB分量强度"{""vec3 position;" //聚光灯 位置;"vec3 spotdirection;" //聚光灯 指向,就像路灯总是指向地面,我这里是指向屏幕里面;"vec3 ambient;""float cutOff;"//聚光灯范围 cos(角度) 内圈;"float outerCutOff;" //聚光灯范围 cos(角度) 外圈;"};""uniform Light m_light;"
然后计算 内圈和外圈之间的光照亮度变化 ( GLProgram_Cube.h Line119 )
"void main()""{""vec3 lightDir=normalize(m_light.position - out_fragpos);" //计算片段 指向 光源 的向量;"float theta = dot(lightDir,normalize(-m_light.spotdirection));" //计算 (片段-光源) 向量 与 聚光灯指向向量的角度的余弦值. 这个灯光的方向 是指向屏幕里面的,所以这里用了负值!!"float epsion = m_light.cutOff - m_light.outerCutOff;" //cos(内圈与聚光灯方向角度) - cos(外圈与聚光灯方向角度);"float autenuation = clamp( (theta - m_light.outerCutOff) / epsion ,0.0,1.0 );"//然后用cos(片段与聚光灯方向角度) - cos(外圈与聚光灯方向角度)。这个意思就是,当片段已经到达 内圈边缘的时候,autenuation=(内圈角度-外圈角度) / (内圈角度-外圈角度) ==1 ,受到100% 光照。然后如果片段已经到达外圈边缘的时候,autenuation = (外圈角度-外圈角度) / (内圈角度-外圈角度) ==0,就没有光照了。片段越靠近外圈边缘,光照越弱,直到到达了外圈边缘,就没有了光照。"vec3 ambient=vec3(texture2D(m_diffusetexture,m_outUV))*m_light.ambient;"//环境光;"ambient = ambient * autenuation;""gl_FragColor=vec4(ambient,1.0);""}"
这里使用了 clamp 来限定值范围为 ( 0.0 , 1.0 )
autenuation 是这样算的:
用cos(片段与聚光灯方向角度) - cos(外圈与聚光灯方向角度)。
这个意思就是,当片段已经到达 内圈边缘的时候,autenuation=(内圈角度-外圈角度) / (内圈角度-外圈角度) ==1 ,受到100% 光照。然后如果片段已经到达外圈边缘的时候,autenuation = (外圈角度-外圈角度) / (内圈角度-外圈角度) ==0,就没有光照了。片段越靠近外圈边缘,光照越弱,直到到达了外圈边缘,就没有了光照。
然后传入值 ( MyApp.h Line118 )
float cutoffCos = glm::cos(glm::radians(12.0f)); //话说我这个相机的距离 ,和这个Cube的角度,不到30度;float outcutoffCos = glm::cos(glm::radians(20.0f));glUniform1f(m_programCube.m_lightCutOff, cutoffCos);glUniform1f(m_programCube.m_lightOuterCutOff, outcutoffCos);
这里选定 12度 为内圈, 20度为外圈,测试效果如下图:
测试项目下载:
http://pan.baidu.com/s/1mh31fUK
- OpenGL ES 学习教程(十) Light casters 之 Spot Light (聚光灯)
- OpenGL ES 学习教程(十) Light casters 之 Directional Light (平行光)
- OpenGL ES 学习教程(十) Light casters 之 Point Light (定点光)
- 【Modern OpenGL】光照类型 Light casters
- OpenGL-聚光灯-spot
- Spot Light Per Pixel
- Unity3D教程之Light光源
- opengl 教程(21) 聚光灯
- [OpenGL ES 07-2]Per-Vertex Light及深度缓存
- [OpenGL ES 08]Per-Pixel Light及卡通效果
- [OpenGL ES 08]Per-Pixel Light及卡通效果
- [OpenGL ES 07-2]Per-Vertex Light及深度缓存
- [OpenGL ES 08]Per-Pixel Light及卡通效果
- [OpenGL ES 07-2]Per-Vertex Light及深度缓存
- [OpenGL ES 08]Per-Pixel Light及卡通效果
- unity里面聚光灯(SPOT)光照计算学习!
- Unity学习之Deferred Light
- 逐象素的Spot Light的实现
- Experimental Educational Round: VolBIT Formulas Blitz(J)打表找规律
- 1007. Maximum Subsequence Sum (25)
- OpenJudge百炼习题解答(C++)--题4109:公共朋友-Common Friends
- hdu 3001 Travelling 状压dp
- JQuery学习—JQuery的Validform学习
- OpenGL ES 学习教程(十) Light casters 之 Spot Light (聚光灯)
- macbook pro安装linux系统
- HDU 5630 Rikka with Chess
- VS2015--win32工程配置的一些想法之warning LNK4042: 对象被多次指定;已忽略多余的指定
- 机器学习系列(3)_逻辑回归应用之Kaggle泰坦尼克之灾
- UVA 12658 模拟
- VS2010~VS2013中文注释带红色下划线的解决方法
- 在文章中使用amsmath宏包的原因
- 积跬步至千里系列之十--编译Android源码实践