zoukankan      html  css  js  c++  java
  • 使用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(001.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(0001.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*+ 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*+ 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的,因此与固定管线的效果是一致的。

  • 相关阅读:
    SpringCloud学习(二)---Eureka
    【Jmeter源码解读】001——目录结构
    TCP连接可能出现的异常总结
    TCP的socket连接
    soap-ws获取ws中的所有的接口方法
    webservice的hello world
    【环境搭建】Angular (含Hello World)
    使用Spring-boot-admin对Spring boot的服务进行监控
    idea的配置文件------application.properties和application.yml
    Spring Boot常用的注解以及含义<持续更新>
  • 原文地址:https://www.cnblogs.com/mazhenyu/p/3806634.html
Copyright © 2011-2022 走看看