原文 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. JS调试必备的5个debug技巧

    我一直使用printf调试程序,一般来说都是比较顺利,但有时候,你会发现需要更好的方法.下面几个JavaScript技巧相信你一定会觉得十分有用   1. debugger; 我以前也说过,你可以在J ...

  2. 位图引起的内存溢出OutOfMemory解决方案

    一.问题描述:Android下的相机在独自使用时,拍照没有问题,通过我们的代码调用时,也正常,但是更换了不同厂商的平板,ROM由Android4.0变成了Android4.1后,拍照出现了OutOfM ...

  3. C#常用格式输出

    ylbtech- .NET-Basic:C#常用格式输出 C#常用格式输出 1.A,相关概念返回顶部 using System; namespace Test { class Formating { ...

  4. Storm-6 Storm的并行度、Grouping策略以及消息可靠处理机制简介

    概念: 配置并行度 动态的改变并行度 流分组策略----Stream Grouping 消息的可靠处理机制 概念: Workers (JVMs): 在一个节点上可以运行一个或多个独立的JVM 进程.一 ...

  5. 【Python】python读取文件操作mysql

    尾大不掉,前阵子做检索测试时,总是因为需要业务端操作db和一些其他服务,这就使得检索测试对环境和数据依赖性特别高,极大提高了测试成本. Mock服务和mysql可以很好的解决这个问题,所以那阵子做了两 ...

  6. Corn Fields(POJ 3254状压dp)

    题意: n*m网格1能放0不能放 放的格子不能相邻 求一共多少种可放的方案. 分析: dp[i][j]第i行可行状态j的的最大方案数,枚举当前行和前一行的所有状态转移就行了(不放牛也算一种情况) #i ...

  7. bzoj 3732 Network(最短路+倍增 | LCT)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3732 [题意] 给定一个无向图,处理若干询问:uv路径上最长的边最小是多少? [思路一 ...

  8. php pdo

    定义:PDO(PHP Data Object)是PHP5才支持的扩展,它为PHP访问各种数据库定义了一个轻量级的.一致性的接口. PDO是PHP5中的一个重大功能,PHP6中将只默认使用PDO来处理数 ...

  9. Lucene学习笔记:一,全文检索的基本原理

    一.总论 根据http://lucene.apache.org/java/docs/index.html定义: Lucene是一个高效的,基于Java的全文检索库. 所以在了解Lucene之前要费一番 ...

  10. JSP学习笔记(一)

    注释: 1.单行注释<!-- -->或者// <%@ page language="java" import="java.util.*" co ...