原文 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. hisi平台mii网络模式和rmii网络模式的uboot制作

    MII网络uboot编译说明 一:编译生成默认的uboot1. 进入到uboot目录a. cd /home/satan/Hi3518_SDK_V1.0.7.0/osdrv/uboot2. 新建临时文件 ...

  2. 音频PCM格式

    经常见到这样的描述: 44100HZ 16bit stereo 或者 22050HZ 8bit mono 等等. 44100HZ 16bit stereo: 每秒钟有 44100 次采样, 采样数据用 ...

  3. 【转】AVL

    #include <iostream> #include <ctime> #include <queue> #include <cassert> #in ...

  4. POJ 2159 Ancient Cipher

    题意:被题意杀了……orz……那个替换根本就不是ASCII码加几……就是随机的换成另一个字符…… 解法:只要统计每个字母的出现次数,然后把数组排序看相不相同就行了…… 代码: #include< ...

  5. hdu 1198 Farm Irrigation

    令人蛋疼的并查集…… 我居然做了大量的枚举,居然过了,我越来越佩服自己了 这个题有些像一个叫做“水管工”的游戏.给你一个m*n的图,每个单位可以有11种选择,然后相邻两个图只有都和对方连接,才判断他们 ...

  6. LXD 2.0 系列(二):安装与配置

    导读 简单来说,LXD是一个守护进程,为LXC容器的管理提供一组REST API.主要目标是提供一种类虚拟机的用户体验,是一种第三方的容器管理工具.下面呢,我们来介绍LXD 2.0 的安装与配置 安装 ...

  7. java ant 命令大全

    ANT命令总结 1 Ant是什么? Apache Ant 是一个基于 Java的生成工具.生成工具在软件开发中用来将源代码和其他输入文件转换为可执行文件的形式(也有可能转换为可安装的产品映像形式).随 ...

  8. android判断当前网络状态及跳转到设置界面

    今天,想做这个跳转到网络设置界面, 刚开始用 intent = new Intent(Settings.ACTION_WIRELESS_SETTINGS); 不料老是出现settings.Wirele ...

  9. Hadoop2.2.0(yarn)编译部署手册

    Created on 2014-3-30URL : http://www.cnblogs.com/zhxfl/p/3633919.html @author: zhxfl   Hadoop-2.2编译 ...

  10. 快速备份sqlserver2005以上版本数据库的方法-摘自网络

    使用优化参数的备份命令 BACKUP DATABASE [test]TO DISK = N'D:\test_FULL_20110311_050001_1.bak',DISK = N'D:\test_F ...