【发布时间】:2012-04-04 13:44:04
【问题描述】:
基于像素的光照是许多 OpenGL 应用程序中的常见问题,因为标准的 OpenGL 光照质量很差。
我想使用 GLSL 程序在我的 OpenGL 程序中使用基于每个像素的照明,而不是每个顶点。只是漫反射照明,但至少有雾、纹理和纹理阿尔法。
我从this shader开始:
texture.vert:
varying vec3 position;
varying vec3 normal;
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_FrontColor = gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
normal = normalize(gl_NormalMatrix * gl_Normal);
position = vec3(gl_ModelViewMatrix * gl_Vertex);
}
texture.frag:
uniform sampler2D Texture0;
uniform int ActiveLights;
varying vec3 position;
varying vec3 normal;
void main(void)
{
vec3 lightDir;
float attenFactor;
vec3 eyeDir = normalize(-position); // camera is at (0,0,0) in ModelView space
vec4 lightAmbientDiffuse = vec4(0.0,0.0,0.0,0.0);
vec4 lightSpecular = vec4(0.0,0.0,0.0,0.0);
// iterate all lights
for (int i=0; i<ActiveLights; ++i)
{
// attenuation and light direction
if (gl_LightSource[i].position.w != 0.0)
{
// positional light source
float dist = distance(gl_LightSource[i].position.xyz, position);
attenFactor = 1.0/( gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * dist +
gl_LightSource[i].quadraticAttenuation * dist * dist );
lightDir = normalize(gl_LightSource[i].position.xyz - position);
}
else
{
// directional light source
attenFactor = 1.0;
lightDir = gl_LightSource[i].position.xyz;
}
// ambient + diffuse
lightAmbientDiffuse += gl_FrontLightProduct[i].ambient*attenFactor;
lightAmbientDiffuse += gl_FrontLightProduct[i].diffuse * max(dot(normal, lightDir), 0.0) * attenFactor;
// specular
vec3 r = normalize(reflect(-lightDir, normal));
lightSpecular += gl_FrontLightProduct[i].specular *
pow(max(dot(r, eyeDir), 0.0), gl_FrontMaterial.shininess) *
attenFactor;
}
// compute final color
vec4 texColor = gl_Color * texture2D(Texture0, gl_TexCoord[0].xy);
gl_FragColor = texColor * (gl_FrontLightModelProduct.sceneColor + lightAmbientDiffuse) + lightSpecular;
float fog = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale; // Intensität berechnen
fog = clamp(fog, 0.0, 1.0); // Beschneiden
gl_FragColor = mix(gl_Fog.color, gl_FragColor, fog); // Nebelfarbe einmischen
}
评论是德语,因为这是发布此代码的德语网站,抱歉。
但是这个着色器所做的只是让一切都变得很暗。根本没有光照效果——但是着色器代码可以编译。如果我只在片段着色器中使用 GL_LIGHT0,那么它似乎可以工作,但仅适用于面向相机的多边形并且我的地板多边形非常暗。具有 RGBA 纹理的四边形也没有透明的迹象。 我对模型视图矩阵使用标准 glRotate/Translate,对我的多边形使用 glVertex/Normal。 OpenGL 光照效果很好,除了它在非常大的表面上看起来很丑。我三次检查了我的法线,它们很好。
上面的代码有问题吗? 要么 告诉我为什么这个实际任务没有通用照明着色器(具有距离衰减的基于点的光:如果你愿意的话,可以使用蜡烛)——难道不应该只有一种正确的方法来做到这一点吗?我不想要凹凸/法线/视差/卡通/模糊/任何效果。我只是希望我的照明在使用更大的多边形时表现更好。
我发现的所有教程仅适用于在相机位于 0,0,0 并面向与对象正交时照亮单个对象。以上是唯一发现的至少看起来像我想做的事情。
【问题讨论】:
-
显而易见的第一件事:你绑定了一个采样器,你的纹理坐标和法线是否正确,如果你将 gl_FragColor 设置为固定颜色,它是否显示几何?使用着色器时,我发现通过一次使用和添加一些小功能更容易理解它们,因为我无法进入和追踪它们:p。
-
采样器是 TEXTURE_2D 并且它绑定了渲染的多边形。纹理坐标是正确的,因为正常的 OpenGL 光照表现完美。法线是完美的(如前所述)。是的,当将 gl_FragColor 设置为固定颜色或仅设置为 texColor 时,它会显示几何图形。
-
GLSL 没有通用函数或模板元编程,尽管有 a compiler 可以将 C++ 模板转换为 GLSL 函数。