使用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的,因此与固定管线的效果是一致的。
众所周知,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实现更多数量的局部光照
- 使用GLSL实现更多数量的局部光照 【转】
- 使用GLSL实现对光照的模拟(二)
- 使用GLSL实现对光照的模拟(一)
- 使用GLSL实现对光照的模拟(一)
- 使用updatepanel局部刷新实现注册时对用户名的检测示例
- pulltorefresh(一)使用介绍,实现下拉刷新上拉加载更多
- 使用XML实现页面的局部刷新
- OpenGL 4.0 GLSL 用单光源 实现逐顶点 漫反射光照模型
- GLSL-使用Uniform Block实现着色器的数据共享
- 使用JQUERY实现局部页面定时刷新
- 使用 AJAX,局部刷新 GridView 进行数据绑定的简单实现
- 使用ajax与jQuery实现局部修改信息
- .NET使用js制作百度搜索下拉提示效果(不是局部刷新)实现思路
- 使用SwipeRefreshLayout和RecyclerView实现仿“简书”下拉刷新和上拉加载更多
- 使用turbolinks实现局部页面刷新
- 使用SwipeRefreshLayout和RecyclerView实现仿“简书”下拉刷新和上拉加载更多
- 使用vue.js 在移动端简单实现的下拉加载更多 和一些常用的js/jq操作和vueFilter,v-if和v-show运用
- 【SSH网上商城项目实战28】使用Ajax技术局部更新商品数量和总价