使用GLSL实现更多数量的局部光照 【转】
原文 http://www.cnblogs.com/CGDeveloper/archive/2008/07/02/1233816.html
众所周知,OpenGL固定管线只提供了最多8盏灯光。如何使得自己的场景之中拥有更多的灯光效果呢?
这里提供一种使用GLSL shader实现更多数量的局部光照。
在GLSL里,首先建立光照参数数据结构:
struct myLightParams
{
bool enabled;
vec4 position;
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec3 spotDirection;
float spotCutoff;
float spotExponent;
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
};
然后,需要app传入的参数:
const int maxLightCount = 32;
uniform myLightParams light[maxLightCount];
uniform bool bLocalViewer;
uniform bool bSeperateSpecualr;
主函数:
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
vec4 pos = gl_ModelViewMatrix * gl_Vertex;
vec3 epos = vec3(pos)/pos.w;
vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
vec3 eye;
if (bLocalViewer)
eye = -normalize(epos);
else
eye = vec3(0, 0, 1.0);
vec4 amb = vec4(0);
vec4 diff = vec4(0);
vec4 spec = vec4(0);
for (int i=0; i<maxLightCount; i++)
{
if (light[i].enabled == false)
continue;
if (light[i].position.w == 0)
{
DirectionalLight(i, eye, epos, normal, amb, diff, spec);
}
else if (light[i].spotCutoff == 180.0)
{
PointLight(i, eye, epos, normal, amb, diff, spec);
}
else
{
SpotLight(i, eye, epos, normal, amb, diff, spec);
}
}
vec4 color = gl_FrontLightModelProduct.sceneColor +
amb * gl_FrontMaterial.ambient +
diff * gl_FrontMaterial.diffuse;
if (bSeperateSpecualr)
{
gl_FrontSecondaryColor = spec * gl_FrontMaterial.specular;
}
else
{
gl_FrontSecondaryColor = vec4(0, 0, 0, 1.0);
color += spec * gl_FrontMaterial.specular;
}
gl_FrontColor = color;
}
对于方向光源的计算:
void DirectionalLight(int i, vec3 eye, vec3 epos, vec3 normal,
inout vec4 amb, inout vec4 diff, inout vec4 spec)
{
float dotVP = max(0, dot(normal, normalize(vec3(light[i].position))));
float dotHV = max(0, dot(normal, normalize(eye+normalize(vec3(light[i].position)))));
amb += light[i].ambient;
diff += light[i].diffuse * dotVP;
spec += light[i].specular * pow(dotHV, gl_FrontMaterial.shininess);
}
对于点光源:
void PointLight(int i, vec3 eye, vec3 epos, vec3 normal,
inout vec4 amb, inout vec4 diff, inout vec4 spec)
{
vec3 VP = vec3(light[i].position) - epos;
float d = length(VP);
VP = normalize(VP);
float att = 1.0/(light[i].constantAttenuation + light[i].linearAttenuation*d + light[i].quadraticAttenuation*d*d);
vec3 h = normalize(VP+eye);
float dotVP = max(0, dot(normal, VP));
float dotHV = max(0, dot(normal, h));
amb += light[i].ambient * att;
diff += light[i].diffuse * dotVP * att;
spec += light[i].specular * pow(dotHV, gl_FrontMaterial.shininess) * att;
}
对于聚光灯:
void SpotLight(int i, vec3 eye, vec3 epos, vec3 normal,
inout vec4 amb, inout vec4 diff, inout vec4 spec)
{
vec3 VP = vec3(light[i].position) - epos;
float d = length(VP);
VP = normalize(VP);
float att = 1.0/(light[i].constantAttenuation + light[i].linearAttenuation*d + light[i].quadraticAttenuation*d*d);
float dotSpot = dot(-VP, normalize(light[i].spotDirection));
float cosCutoff = cos(light[i].spotCutoff*3.1415926/180.0);
float spotAtt = 0;
if (dotSpot < cosCutoff)
spotAtt = 0;
else
spotAtt = pow(dotSpot, light[i].spotExponent);
att *= spotAtt;
vec3 h = normalize(VP+eye);
float dotVP = max(0, dot(normal, VP));
float dotHV = max(0, dot(normal, h));
amb += light[i].ambient * att;
diff += light[i].diffuse * dotVP * att;
spec += light[i].specular * pow(dotHV, gl_FrontMaterial.shininess) * att;
}
这样,对于场景之中的任意对象,它所能够接受计算的光源就可以突破8个的限制了。
上述光照计算是遵循OpenGL spec的,因此与固定管线的效果是一致的。
使用GLSL实现更多数量的局部光照 【转】的更多相关文章
- Deferred Shading,延迟渲染(提高渲染效率,减少多余光照计算)【转】
Deferred Shading,看过<Gems2> 的应该都了解了.最近很火的星际2就是使用了Deferred Shading. 原帖位置: http://blog.csdn.net ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第八章:光照
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第八章:光照 代码工程地址: https://github.com/j ...
- Obj模型功能完善(物体材质,光照,法线贴图).Cg着色语言+OpenTK+F#实现.
这篇文章给大家讲Obj模型里一些基本功能的完善,包含Cg着色语言,矩阵转换,光照,多重纹理,法线贴图的运用. 在上篇中,我们用GLSL实现了基本的phong光照,这里用Cg着色语言来实现另一钟Blin ...
- JNI/NDK开发指南(十)——JNI局部引用、全局引用和弱全局引用
转自:http://blog.csdn.net/xyang81/article/details/44657385 这篇文章比较偏理论,详细介绍了在编写本地代码时三种引用的使用场景和注意事项.可能看 ...
- WebGL学习笔记(八):光照
局部光照与全局光照 局部光照 只考虑光源到模型表面的照射效果,运算量较小: 全局光照 考虑到环境中所有表面和光源相互作用的照射效果,即让没有直接受光照射的位置也会受周围反射光的影响,运算量较大: Ph ...
- 最大化 AIX 上的 Java 性能,第 3 部分: 更多就是更好
http://www.ibm.com/developerworks/cn/aix/library/es-Javaperf/es-Javaperf3.html 最大化 AIX 上的 Java 性能,第 ...
- 【翻译】Jay Kreps - 为何流处理中局部状态是必要的
译者注: 原文作者是 Jay Kreps,也是那篇著名的<The Log: What every software engineer should know about real-time da ...
- [Swift]LeetCode775. 全局倒置与局部倒置 | Global and Local Inversions
We have some permutation Aof [0, 1, ..., N - 1], where N is the length of A. The number of (global) ...
- matlab练习程序(局部加权线性回归)
通常我们使用的最小二乘都需要预先设定一个模型,然后通过最小二乘方法解出模型的系数. 而大多数情况是我们是不知道这个模型的,比如这篇博客中z=ax^2+by^2+cxy+dx+ey+f 这样的模型. 局 ...
随机推荐
- 是时候学习Android分屏开发了
今年Google发布了Android N,Android N新增了不少功能,最受关注的自然就是分屏了. 这一功能对国内的很多手机用户并不陌生,其实很多第三方系统早已经实现了这一功能,如EMUI,Fly ...
- Java 如何防止线程意外中止
Thread的run方法是不抛出任何检查型异常(checked exception)的,但是它自身却可能因为一个异常而被终止,导致这个线程的终结.最麻烦的是,在线程中抛出的异常即使使用try...ca ...
- POJ 2456 Aggressive cows
Aggressive cows Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11192 Accepted: 5492 ...
- Java SE 6 新特性: 对脚本语言的支持
2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马).跟 Tiger(Java SE 5)相比,Musta ...
- Linux基本命令(2)有关磁盘空间的命令
有关磁盘空间的命令 命令 功能 mount 挂载文件系统 umount 卸载已挂载上的文件系统 df 检查各个硬盘分区和已挂上来的文件系统的磁盘空间 du 显示文件目录和大小 fsck 主要是检查和修 ...
- 精雕细琢 35 套精美的 PSD 图标素材
设计师总是有独特的创意和精雕细琢的精湛技术,让我们值得去欣赏和借鉴,如梦想天空所表达的:非常感谢那些很有才华的设计师分享它们的劳动成果,让更多的人可以使用他们的创意设计.今天,本文与大家分享35套精美 ...
- 8个很有用的PHP安全函数,你知道几个?
原文:Useful functions to provide secure PHP application 译文:有用的PHP安全函数 译者:dwqs 安 全是编程非常重要的一个方面.在任何一种编程语 ...
- c++ Map使用
引入头文件: #include <map>1.初始化map<int, int> a, b;map<sting, int> a, b;2.添加数据 map<in ...
- Codeforces 377
简单说一下. A 搜索出任意一个剩余细胞个数的联通块.剩下的填X. B 二分加贪心加数据结构. /* * Problem: * Author: Shun Yao */ #include <str ...
- HDU 5805 NanoApe Loves Sequence (模拟)
NanoApe Loves Sequence 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5805 Description NanoApe, the ...