OpenGL(十二) 光源类型 平行光 、 点光源 、 聚光灯 的实现
2017-05-17 10:49
531 查看
常规的 光源类型 有三种。最简单的自然是平行光。稍复杂些的为点光源,最复杂的为聚光灯。总体说来,在可编程管线中原理是一样的。在OpenGL代码中传入必要的参数,在shader中进行相关的计算绘制出效果。本文分别介绍三种效果的shader实现。
float lightPos[] = { 0.0f,1.5f,0.0f,0.0f };
float diffuseLightColor[] = { 1.0f,1.0f,1.0f,1.0f };
glUniformMatrix4fv(gpuProgram.GetLocation("M"), 1,GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(gpuProgram.GetLocation("V"), 1, GL_FALSE, identity);
glUniformMatrix4fv(gpuProgram.GetLocation("P"), 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glUniformMatrix4fv(gpuProgram.GetLocation("NM"), 1, GL_FALSE, glm::value_ptr(normalMatrix));
glUniform4fv(gpuProgram.GetLocation("U_LightPos"), 1, lightPos);
glUniform4fv(gpuProgram.GetLocation("U_DiffuseLightColor"), 1, diffuseLightColor);
//fs
void main(){
//...
vec3 n = normalize(V_Normal);
vec3 L = U_LightPos.xyz;
float diffuseIntensity=max(0.0,dot(L,n));
vec4 diffuseColor=U_DiffuseLightColor*diffuseIntensity;
//...
gl_FragColor=ambientColor+diffuseColor;
}
获取的光线方向直接与法线点乘,即为光照强度。
float constantFactor = 1.0;
float linearFactor = 0.2;
float expFactor=0.0;
glUniform1f(gpuProgram.GetLocation("U_ConstantFactorn"), 1, constantFactor);
glUniform1f(gpuProgram.GetLocation("U_LinearFactor"), 1, linearFactor);
glUniform1f(gpuProgram.GetLocation("U_ExpFactor"), 1, expFactor);
//fs
float attenuation = 1.0;
void main(){
//...
vec3 n = normalize(V_Normal);
vec3 L = U_LightPos.xyz - V_WorldPos;
float distance = length(L);
attenuation = 1.0/(U_ExpFactor*distance*distance + U_LinearFactor*distance + U_ConstantFactor);
float diffuseIntensity = max(0.0,dot(L,n));
vec4 diffuseColor = U_DiffuseLightColor*attenuation*diffuseIntensity;
//...
gl_FragColor=ambientColor+diffuseColor;
}
//...
float spotLightDirection[] = { 0.0f,-1.0f,0.0f,128.0f };
float spotLightCutoff = 15.0f;
glUniform1f(gpuProgram.GetLocation("U_Cutoff"), spotLightCutoff);
glUniform4fv(gpuProgram.GetLocation("U_LightDirection"), 1, spotLightDirection);
//...
//fs
float attenuation = 1.0;
void main(){
//...
float radianCutoff = U_Cutoff*3.14/180;
float cosThta = cos(radianCutoff);
vec3 spotLightDirection = normalize(U_LightDirection.xyz);
vec3 n = normalize(V_Normal);
vec3 L = U_LightPos.xyz - V_WorldPos;
float distance = length(L);
attenuation = 1.0/(U_ExpFactor*distance*distance + U_LinearFactor*distance + U_ConstantFactor);
float currentCosThta=max(0.0,dot(-L,spotLightDirection));
float diffuseIntensity = 0.0;
if(currentCosThta > cosThta)
{
if(dot(L,n) >0.0)
{
diffuseIntensity = pow(currentCosThta,U_LightDirection.w);
}
}
vec4 diffuseColor = U_DiffuseLightColor*attenuation*diffuseIntensity;
//...
gl_FragColor=ambientColor+diffuseColor;
}
关注我的微信公众号,获取更多优质内容
平行光
平行光我们已经写的轻车熟路了。它只需要一个光源方向就够了。通常我们会定义一个光源点,它与坐标轴原点的连线就是光线方向。//GL Codefloat lightPos[] = { 0.0f,1.5f,0.0f,0.0f };
float diffuseLightColor[] = { 1.0f,1.0f,1.0f,1.0f };
glUniformMatrix4fv(gpuProgram.GetLocation("M"), 1,GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(gpuProgram.GetLocation("V"), 1, GL_FALSE, identity);
glUniformMatrix4fv(gpuProgram.GetLocation("P"), 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glUniformMatrix4fv(gpuProgram.GetLocation("NM"), 1, GL_FALSE, glm::value_ptr(normalMatrix));
glUniform4fv(gpuProgram.GetLocation("U_LightPos"), 1, lightPos);
glUniform4fv(gpuProgram.GetLocation("U_DiffuseLightColor"), 1, diffuseLightColor);
//fs
void main(){
//...
vec3 n = normalize(V_Normal);
vec3 L = U_LightPos.xyz;
float diffuseIntensity=max(0.0,dot(L,n));
vec4 diffuseColor=U_DiffuseLightColor*diffuseIntensity;
//...
gl_FragColor=ambientColor+diffuseColor;
}
获取的光线方向直接与法线点乘,即为光照强度。
点光源
在平行光的基础上,根据模型与光源之间的距离进行衰减。衰减为与距离相关的二次函数。因此需要加入三个因数,分别为expFactor、
linearFactor、
constantFactor。//GL Code
float constantFactor = 1.0;
float linearFactor = 0.2;
float expFactor=0.0;
glUniform1f(gpuProgram.GetLocation("U_ConstantFactorn"), 1, constantFactor);
glUniform1f(gpuProgram.GetLocation("U_LinearFactor"), 1, linearFactor);
glUniform1f(gpuProgram.GetLocation("U_ExpFactor"), 1, expFactor);
//fs
float attenuation = 1.0;
void main(){
//...
vec3 n = normalize(V_Normal);
vec3 L = U_LightPos.xyz - V_WorldPos;
float distance = length(L);
attenuation = 1.0/(U_ExpFactor*distance*distance + U_LinearFactor*distance + U_ConstantFactor);
float diffuseIntensity = max(0.0,dot(L,n));
vec4 diffuseColor = U_DiffuseLightColor*attenuation*diffuseIntensity;
//...
gl_FragColor=ambientColor+diffuseColor;
}
聚光灯
在点光源的基础上,添加一个带角度的锥形区域的检测。只有在区域内的部分才有照亮处理。因此需要传入shader两个参数,分别为光照方向和范围角度。//GL Code//...
float spotLightDirection[] = { 0.0f,-1.0f,0.0f,128.0f };
float spotLightCutoff = 15.0f;
glUniform1f(gpuProgram.GetLocation("U_Cutoff"), spotLightCutoff);
glUniform4fv(gpuProgram.GetLocation("U_LightDirection"), 1, spotLightDirection);
//...
//fs
float attenuation = 1.0;
void main(){
//...
float radianCutoff = U_Cutoff*3.14/180;
float cosThta = cos(radianCutoff);
vec3 spotLightDirection = normalize(U_LightDirection.xyz);
vec3 n = normalize(V_Normal);
vec3 L = U_LightPos.xyz - V_WorldPos;
float distance = length(L);
attenuation = 1.0/(U_ExpFactor*distance*distance + U_LinearFactor*distance + U_ConstantFactor);
float currentCosThta=max(0.0,dot(-L,spotLightDirection));
float diffuseIntensity = 0.0;
if(currentCosThta > cosThta)
{
if(dot(L,n) >0.0)
{
diffuseIntensity = pow(currentCosThta,U_LightDirection.w);
}
}
vec4 diffuseColor = U_DiffuseLightColor*attenuation*diffuseIntensity;
//...
gl_FragColor=ambientColor+diffuseColor;
}
总结
以上为三种光源的OpenGL实现,可以看出,计算量最大的为聚光灯效果,而且为了让边缘柔和,需要pow的大量计算。移动端跑实时运算估计要优化算法了。关注我的微信公众号,获取更多优质内容
相关文章推荐
- OpenGL学习脚印:光源类型和使用多个光源(Light source and multiple lights)
- UnityShader入门精要学习笔记(十二):渲染路径与光源类型
- OpenGL 4.0 GLSL 用单光源 实现逐顶点 漫反射光照模型
- OpenGL学习脚印:光源类型和使用多个光源(Light source and multiple lights)
- OPENGL光源(shader部分)整体实现思想
- Redis源码剖析和注释(十二)--- 集合类型键实现(t_set)
- OpenGL学习: 光照系列3-光源类型和使用多个光源
- opengl对三种光源(方向光,点光源,聚光灯)进行特写并分屏渲染
- CSharpGL(13)用GLSL实现点光源(point light)和平行光源(directional light)的漫反射(diffuse reflection)
- opengl平行光光源,点光源,聚光灯光源同台出现
- Hibernate的自定义数据类型实现接口之一——UserType祥解
- 在SQL SERVER中实现日期类型的转换
- .Net/C# 实现真正的只读的 Hashtable 类型的属性 (ReadOnly Hashtable Property)
- 快速上手,使用 JS 配合XML-RPC(JSP)实现AJAX类型应用
- 利用OpenGL实现三维绘图
- 任何类型的文件下载时都会弹出文件保存框的实现
- 利用抽象工厂实现自定义多数据类型接口
- C#(文字类型转换)【下拉菜单->C#字体CodeBehind】附:【用C#实现生成PDF文档】
- 纹理滤波方式、光源:Jeff Molofee(NeHe) 的 OPENGL 教程-第七课
- 在Delphi中实现类型安全的容器,Delphi泛型库DGL引介(提供源码下载)