原文 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. 用ioctl获取无线网络信息 /usr//include/linux/wireless.h

    1.UNIX Network Programming环境搭建 Unix NetWork Programming――环境搭建(解决unp.h等源码编译问题) http://blog.csdn.net/a ...

  2. C# DataGridView的列对象属性探讨 (未完待续)

    比较难的几个属性的释义[1]:

  3. C# chart控件绘制曲线

    在.NET中以前经常用GDI去绘制,虽然效果也不错,自从.NET 4.0开始,专门为绘制图表而生的Chart控件出现了,有了它,就可以轻松的绘制你所需要的曲线图.柱状图什么的了. using Syst ...

  4. [Papers]NSE, $u_3$, Lebesgue space [Kukavica-Ziane, Nonlinearity, 2006]

    $$\bex u_3\in L^p(0,T;L^q(\bbR^3)),\quad \frac{2}{p}+\frac{3}{q}=\frac{5}{8},\quad \frac{24}{5}<q ...

  5. 按钮点击WIN8 磁贴效果

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  6. <译>Selenium Python Bindings 5 - Waits

    如今,大多数的Web应用程序使用AJAX技术.当页面加载到浏览器,页面中的元素也许在不同的时间间隔内加载.这使得元素很难定位,如果在DOM中的元素没有呈现,它将抛出ElementNotVisibleE ...

  7. bug报告-常用词汇中英对照表

  8. Jemeter对Oracle数据库性能测试方法

    下载Oracle的jdbc数据库驱动包,注意Oracle数据库的版本,这里使用的是:Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 ...

  9. NGUI的UIProgressBar使用裁剪方式而不是压缩方式的方法

    UIProgressBar默认的方式是压缩图片,而如果我们需要裁减图片,只需要将UIProgressBar的Foreground的UISprite的Type改为Filled就行了. 好几个“的”... ...

  10. Linux下用Intel编译器编译安装NetCDF-Fortan库(4.2以后版本)

    本来这个问题真的没必要写的,可是真的困扰我太久%>_<%,决定还是记录一下. 首先,最权威清晰的安装文档还是官方的: Building the NetCDF-4.2 and later F ...