使用GLSL实现更多数量的局部光照

来源:互联网 发布:电信apn设置4g最快网络 编辑:程序博客网 时间:2024/06/05 19:47

原文 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的,因此与固定管线的效果是一致的。

原创粉丝点击