现代OpenGL+Qt学习笔记之十二:模拟聚光灯
2017-10-12 21:48
567 查看
现代OpenGL+Qt学习笔记之十二:模拟聚光灯
主要内容
本文将实现一种特殊的光源,该光源的位置定义在一个圆锥的顶点上,光的照射范围仅在圆锥范围内,且光强在该圆锥的中心轴上时最强的,而随着空间点到该中心轴的距离的增加,光强也随之减少。这就是现实中的聚光灯效果,本文将通过GLSL介绍如何模拟这种现实中的聚光灯。效果如下图所示:聚光灯模拟
通过上面的介绍我们知道,聚光灯光源是由一个圆锥确定其位置、方向、照射范围等属性的,那么我们如何定义该圆锥呢?如图,要确定该圆锥,需要一个光源方向d,光源位置p以及一个截光角(cutoff angle)c,有了这些量,该圆锥也就确定了,要完全确定光源,还需要光源在中心轴处的最强光强,以及光强向圆锥边界的衰减方式。
本文将采用逐片元渲染的方式实现聚光灯的模拟,即主要聚光灯效果的实现是在片元着色器中实现的。在实现中,我们主要要考虑两种情况,一是当要渲染的点在圆锥之外时,我们将只计算和保留该点的环境光分量,而当要渲染的点是在圆锥之内时,我们就要分别计算3种光的分量,这里和之前的不同点是需要先计算该点的光强。本文的代码相比较之前的代码修改比较大,首先删除了3个事件处理函数,取而代之的用一个计时器触发渲染的动态效果。具体实现可见源码。
下面重点介绍其中的着色器的实现,其中片元着色器的内容如下,实现了主要的光照计算功能:
#version 430 in vec3 Position; in vec3 Normal; struct SpotLightInfo { vec4 position; // Position in eye coords vec3 intensity; vec3 direction; // Direction of the spotlight in eye coords. float exponent; // Angular attenuation exponent float cutoff; // Cutoff angle (between 0 and 90) }; uniform SpotLightInfo Spot; uniform vec3 Kd; // Diffuse reflectivity uniform vec3 Ka; // Ambient reflectivity uniform vec3 Ks; // Specular reflectivity uniform float Shininess; // Specular shininess factor layout( location = 0 ) out vec4 FragColor; vec3 adsWithSpotlight( ) { vec3 n = normalize(Normal); vec3 s = normalize( vec3( Spot.position) - Position ); vec3 spotDir = normalize( Spot.direction); float angle = acos( dot(-s, spotDir) ); float cutoff = radians( clamp( Spot.cutoff, 0.0, 90.0 ) ); vec3 ambient = Spot.intensity * Ka; if( angle < cutoff ) { float spotFactor = pow( dot(-s, spotDir), Spot.exponent ); vec3 v = normalize(vec3(-Position)); vec3 h = normalize( v + s ); return ambient + spotFactor * Spot.intensity * ( Kd * max( dot(s, n), 0.0 ) + Ks * pow( max( dot(h,n), 0.0 ), Shininess ) ); } else { return ambient; } } void main() { FragColor = vec4(adsWithSpotlight(), 1.0); }
顶点着色器的内容修改如下:
#version 430 layout (location = 0) in vec3 VertexPosition; layout (location = 1) in vec3 VertexNormal; out vec3 Position; out vec3 Normal; uniform mat4 ModelViewMatrix; uniform mat3 NormalMatrix; uniform mat4 ProjectionMatrix; uniform mat4 MVP; void main() { Normal = normalize( No c1be rmalMatrix * VertexNormal); Position = vec3( ModelViewMatrix * vec4(VertexPosition,1.0) ); gl_Position = MVP * vec4(VertexPosition,1.0); }
顶点着色器只进行了简单法向和位置变换并输出到下一个阶段。在片元着色器中定义的聚光灯光源共有5个属性,其中4个前面已经有直接的介绍,分别是位置position、截光角cutoff、中心轴方向direction和光强intensity,还有一个是exponent,是一个光强随着角度的衰减指数,当空间点到光源的连线向量(-s)与中心轴方向的夹角增大时,光想会以指数衰减,即衰减的因子定义为:
factor=(−s⋅spotDir)exponent
见片元着色器32行,其中spotDir是中心轴方向的单位化向量。31行的判断是判断当前计算的点是否在光源照射范围内,如果不在,就只会计算该点的环境光。
&emp;在主程序端对所有的uniform变量进行赋值,并给定几个要渲染的对象,本示例中给了3个对象,分别是一个圆环体、一个茶壶、和一个平面(作为地面),其中圆环体和茶壶前面其实都接触过了,平面的添加方式基本相同。
本示例还利用QTimer对象实现了聚光灯方向的动态变换效果。最终的实现结果如下(具体实现细见源码):
源码地址:http://download.csdn.net/download/chaojiwudixiaofeixia/10020811
相关文章推荐
- [DX9/10.1]在现代硬件上模拟调色板贴图
- OpenGL曲面纹理贴图技术--波浪的模拟(转 作者 Y_Y)
- 【LWJGL2 WIKI】【现代OpenGL篇】用BufferSubData更新VBO方形
- 跨越OpenGL和D3D的鸿沟(二):现代OpenGL
- OpenGL曲面纹理贴图技术--波浪的模拟
- OpenGL 简易太阳系模拟 总结
- 现代OpenGL自学----纹理测试
- 模拟实现string(深浅拷贝,传统现代写法)
- 现代OpenGL的介绍 第1章:图形流水线
- OpenGL模拟太阳系运行
- OpenGL教程翻译 第二十一课 聚光灯
- 现代OpenGL介绍 第一章:绘制管线
- 现代OpenGL教程 01 - 入门指南
- 【LWJGL2 WIKI】【现代OpenGL篇】用DrawArrays画方形
- 现代OpenGL+Qt学习笔记之六:绘制可旋转、带光照效果的三维物体
- 现代OpenGL教程 01 - 入门指南
- 现代OpenGL的介绍 第4章:用Phong着色渲染动态3D场景
- 现代OpenGL教程 01 - 入门指南
- OpenGL 4.0 GLSL 用立方体贴图和 环境贴图 模拟反射效果
- OpenGL中逆变换和模拟变换gluUnProject