原文 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实现更多数量的局部光照 【转】的更多相关文章

  1. Deferred Shading,延迟渲染(提高渲染效率,减少多余光照计算)【转】

    Deferred Shading,看过<Gems2> 的应该都了解了.最近很火的星际2就是使用了Deferred Shading. 原帖位置:   http://blog.csdn.net ...

  2. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第八章:光照

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第八章:光照 代码工程地址: https://github.com/j ...

  3. Obj模型功能完善(物体材质,光照,法线贴图).Cg着色语言+OpenTK+F#实现.

    这篇文章给大家讲Obj模型里一些基本功能的完善,包含Cg着色语言,矩阵转换,光照,多重纹理,法线贴图的运用. 在上篇中,我们用GLSL实现了基本的phong光照,这里用Cg着色语言来实现另一钟Blin ...

  4. JNI/NDK开发指南(十)——JNI局部引用、全局引用和弱全局引用

    转自:http://blog.csdn.net/xyang81/article/details/44657385   这篇文章比较偏理论,详细介绍了在编写本地代码时三种引用的使用场景和注意事项.可能看 ...

  5. WebGL学习笔记(八):光照

    局部光照与全局光照 局部光照 只考虑光源到模型表面的照射效果,运算量较小: 全局光照 考虑到环境中所有表面和光源相互作用的照射效果,即让没有直接受光照射的位置也会受周围反射光的影响,运算量较大: Ph ...

  6. 最大化 AIX 上的 Java 性能,第 3 部分: 更多就是更好

    http://www.ibm.com/developerworks/cn/aix/library/es-Javaperf/es-Javaperf3.html 最大化 AIX 上的 Java 性能,第 ...

  7. 【翻译】Jay Kreps - 为何流处理中局部状态是必要的

    译者注: 原文作者是 Jay Kreps,也是那篇著名的<The Log: What every software engineer should know about real-time da ...

  8. [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) ...

  9. matlab练习程序(局部加权线性回归)

    通常我们使用的最小二乘都需要预先设定一个模型,然后通过最小二乘方法解出模型的系数. 而大多数情况是我们是不知道这个模型的,比如这篇博客中z=ax^2+by^2+cxy+dx+ey+f 这样的模型. 局 ...

随机推荐

  1. 是时候学习Android分屏开发了

    今年Google发布了Android N,Android N新增了不少功能,最受关注的自然就是分屏了. 这一功能对国内的很多手机用户并不陌生,其实很多第三方系统早已经实现了这一功能,如EMUI,Fly ...

  2. Java 如何防止线程意外中止

    Thread的run方法是不抛出任何检查型异常(checked exception)的,但是它自身却可能因为一个异常而被终止,导致这个线程的终结.最麻烦的是,在线程中抛出的异常即使使用try...ca ...

  3. POJ 2456 Aggressive cows

    Aggressive cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11192   Accepted: 5492 ...

  4. Java SE 6 新特性: 对脚本语言的支持

    2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马).跟 Tiger(Java SE 5)相比,Musta ...

  5. Linux基本命令(2)有关磁盘空间的命令

    有关磁盘空间的命令 命令 功能 mount 挂载文件系统 umount 卸载已挂载上的文件系统 df 检查各个硬盘分区和已挂上来的文件系统的磁盘空间 du 显示文件目录和大小 fsck 主要是检查和修 ...

  6. 精雕细琢 35 套精美的 PSD 图标素材

    设计师总是有独特的创意和精雕细琢的精湛技术,让我们值得去欣赏和借鉴,如梦想天空所表达的:非常感谢那些很有才华的设计师分享它们的劳动成果,让更多的人可以使用他们的创意设计.今天,本文与大家分享35套精美 ...

  7. 8个很有用的PHP安全函数,你知道几个?

    原文:Useful functions to provide secure PHP application 译文:有用的PHP安全函数 译者:dwqs 安 全是编程非常重要的一个方面.在任何一种编程语 ...

  8. c++ Map使用

    引入头文件: #include <map>1.初始化map<int, int> a, b;map<sting, int> a, b;2.添加数据 map<in ...

  9. Codeforces 377

    简单说一下. A 搜索出任意一个剩余细胞个数的联通块.剩下的填X. B 二分加贪心加数据结构. /* * Problem: * Author: Shun Yao */ #include <str ...

  10. HDU 5805 NanoApe Loves Sequence (模拟)

    NanoApe Loves Sequence 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5805 Description NanoApe, the ...