glsl 1.3+ 中的点光/聚光灯衰减?
我一直在研究 OpenGL 的 Superbible(第五版)点光源示例。
我发现它们缺少集成到旧照明模型中的恒定、线性和二次衰减值,因此我根据此 食人魔指南。
结果非常奇怪。 如何才能在新的 glsl 上获得合理的光衰减?有衰减常数的GLSL表吗?
图片
距离99处的衰减 -球体为黑色,光为蓝色-
距离 50 处的衰减 - 球体为黑色,光为蓝色 -
距离 16 处的衰减 - 球体为黑色,光为蓝色 -
距离 2 处的衰减 - 球体为黑色,光为蓝色 -
示例顶点和片段程序:
顶点程序:
//point light per pixel vertex program
#version 130
// Incoming per vertex... position and normal
in vec4 vVertex;
in vec3 vNormal;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
// Color to fragment program
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;
out float dist;
out float constantAttenuation;
out float linearAttenuation;
out float quadraticAttenuation;
void main(void)
{
// Get surface normal in eye coordinates
vVaryingNormal = normalMatrix * vNormal;
// Get vertex position in eye coordinates
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
//get distance to light source
dist=length(vLightPosition-vPosition3);
//write proper attenuation values
if (dist<7.0){
constantAttenuation=1.0;
linearAttenuation=0.7;
quadraticAttenuation=1.8;
}
else if (dist<13.0){
constantAttenuation=1.0;
linearAttenuation=0.35;
quadraticAttenuation=0.44;
}
else if (dist<20.0){
constantAttenuation=1.0;
linearAttenuation=0.22;
quadraticAttenuation=0.20;
}
if (dist<32.0){
constantAttenuation=1.0;
linearAttenuation=0.14;
quadraticAttenuation=0.07;
}
if (dist<50.0){
constantAttenuation=1.0;
linearAttenuation=0.09;
quadraticAttenuation=0.32;
}
if (dist<65.0){
constantAttenuation=1.0;
linearAttenuation=0.07;
quadraticAttenuation=0.017;
}
if (dist<100.0){
constantAttenuation=1.0;
linearAttenuation=0.045;
quadraticAttenuation=0.0075;
}
// Get vector to light source
vVaryingLightDir = normalize(vLightPosition - vPosition3);
// Don't forget to transform the geometry!
gl_Position = mvpMatrix * vVertex;
}
片段程序:
//point light per pixel fragment program
#version 130
out vec4 vFragColor;
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;
in float dist;
in float constantAttenuation;
in float linearAttenuation;
in float quadraticAttenuation;
void main(void){
float att;
att = 1.0 / constantAttenuation + linearAttenuation*dist +quadraticAttenuation*dist*dist;
// Dot product gives us diffuse intensity
float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
// Multiply intensity by diffuse color, force alpha to 1.0
vFragColor = att*(diff * diffuseColor +ambientColor); // attenuation affects the diffuse component
// Specular Light
vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
if(diff != 0) {
float fSpec = pow(spec, 128.0);
vFragColor.rgb += (att*vec3 (fSpec, fSpec, fSpec)); // attenuation affects the specular component
}
}
I've been working OpenGL's Superbible (5th Edition) point light examples.
I found them missing the constant, linear and quadratic attenuation values integrated into the old lighting model, so I went and wrote a point light shader with attenuation values based on this ogre guide.
The results have been completely bizarre. What can be done to get a sensible light attenuation on the new glsl? Is there a glsl table for attenuation constants?
Pics
Attenuation at distance 99 -sphere is black, light is blue-
Attenuation at distance 50 -sphere is black, light is blue-
Attenuation at distance 16 -sphere is black, light is blue-
Attenuation at distance 2 -sphere is black, light is blue-
Sample vertex and fragment programs:
Vertex program:
//point light per pixel vertex program
#version 130
// Incoming per vertex... position and normal
in vec4 vVertex;
in vec3 vNormal;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
// Color to fragment program
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;
out float dist;
out float constantAttenuation;
out float linearAttenuation;
out float quadraticAttenuation;
void main(void)
{
// Get surface normal in eye coordinates
vVaryingNormal = normalMatrix * vNormal;
// Get vertex position in eye coordinates
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
//get distance to light source
dist=length(vLightPosition-vPosition3);
//write proper attenuation values
if (dist<7.0){
constantAttenuation=1.0;
linearAttenuation=0.7;
quadraticAttenuation=1.8;
}
else if (dist<13.0){
constantAttenuation=1.0;
linearAttenuation=0.35;
quadraticAttenuation=0.44;
}
else if (dist<20.0){
constantAttenuation=1.0;
linearAttenuation=0.22;
quadraticAttenuation=0.20;
}
if (dist<32.0){
constantAttenuation=1.0;
linearAttenuation=0.14;
quadraticAttenuation=0.07;
}
if (dist<50.0){
constantAttenuation=1.0;
linearAttenuation=0.09;
quadraticAttenuation=0.32;
}
if (dist<65.0){
constantAttenuation=1.0;
linearAttenuation=0.07;
quadraticAttenuation=0.017;
}
if (dist<100.0){
constantAttenuation=1.0;
linearAttenuation=0.045;
quadraticAttenuation=0.0075;
}
// Get vector to light source
vVaryingLightDir = normalize(vLightPosition - vPosition3);
// Don't forget to transform the geometry!
gl_Position = mvpMatrix * vVertex;
}
Fragment program:
//point light per pixel fragment program
#version 130
out vec4 vFragColor;
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;
in float dist;
in float constantAttenuation;
in float linearAttenuation;
in float quadraticAttenuation;
void main(void){
float att;
att = 1.0 / constantAttenuation + linearAttenuation*dist +quadraticAttenuation*dist*dist;
// Dot product gives us diffuse intensity
float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
// Multiply intensity by diffuse color, force alpha to 1.0
vFragColor = att*(diff * diffuseColor +ambientColor); // attenuation affects the diffuse component
// Specular Light
vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
if(diff != 0) {
float fSpec = pow(spec, 128.0);
vFragColor.rgb += (att*vec3 (fSpec, fSpec, fSpec)); // attenuation affects the specular component
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的衰减公式完全不正确:
应该改为:
这就是为什么当距离增加时球体会变轻的原因。尝试正确的公式并发布结果。
Your attenuation formula is completely incorrect:
Should be instead:
That's why you are getting the sphere lighter when the distance increases. Try the proper formula and post the result.
我最终只使用了这个衰减值,效果可以接受:
衰减除法上也缺少几个括号。
I ended up using just this attenuation values, the thing works acceptably:
There a couple of parenthesis missing on the attenuation division too.