您的位置:首页 > 其它

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

2009-08-09 13:13 399 查看
原文 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的,因此与固定管线的效果是一致的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: