通用的GLSL光照着色器

17

像素级光照在许多OpenGL应用程序中都是一个常见的问题,因为标准的OpenGL光照质量非常差。

我想使用GLSL程序,将我的OpenGL程序从顶点级别的光照改为像素级别的光照。至少需要有漫反射光照、雾、纹理和纹理透明度。

我从这个着色器开始:

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,面向物体的正交方向时照明单个对象有用。以上是唯一一个看起来像我想做的事情的东西。


1
首先要确认的是:您是否已绑定采样器,纹理坐标和法线是否正确,如果将gl_FragColor设置为固定颜色,是否显示几何图形?对于着色器,我发现通过逐步使用和添加小功能来更容易理解它们,在无法进入和跟踪它们的情况下:p。 - Robinson
Sampler是TEXTURE_2D,它绑定了渲染的多边形。纹理坐标是正确的,因为正常的OpenGL光照表现完美。法线是完美的(如已经说明)。当将gl_FragColor设置为固定颜色或仅为texColor时,它确实显示几何图形。 - Rock
GLSL没有通用函数或模板元编程,但是有一个编译器(https://github.com/seanbaxter/shaders)可以将C++模板转换为GLSL函数。 - Anderson Green
1个回答

12

我强烈建议你阅读这篇文章,了解GLSL中如何实现标准的ADS光照。虽然是针对GL 4.0编写的,但可以根据你使用的版本进行调整:

此外,你操作的是视图(相机)空间,因此不要取反眼睛向量:

    vec3 eyeDir  = normalize(-position); 

我遇到了与你类似的问题,因为我也否定了眼睛向量并忘记将其转换为视图空间。在当前情况下,您的漫反射和镜面反射计算似乎也是错误的。如果我处于您的位置,我根本不会使用来自固定管道的数据,否则着色器的意义何在?以下是按每个片段ADS点光照计算漫反射和镜面反射的方法:

void ads( int lightIndex,out vec3 ambAndDiff, out vec3 spec )
{


vec3 s =  vec3(lights[lightIndex].Position -  posOut) ;
vec3 v = normalize( posOut.xyz );
vec3 n = normalize(normOut); 
vec3 h = normalize(v+s) ;// half vector (read in the web on what it is )


    vec3 diffuse =  ((Ka+ lights[lightIndex].Ld) * Kd *  max( 0.0,dot(n, v) )) ;
     spec =  Ks *  pow( max(0.0, dot(n,h) ), Shininess ) ;  


 ambAndDiff =   diffuse ;

/// Ka-material ambient factor
/// Kd-material diffuse factor
/// Ks-material specular factor.
/// lights[lightIndex].Ld-lights diffuse factor;you may also add La and Ls if you want to have even more control of the light shading.
}

我不建议您使用此处提供的衰减方程,因为难以控制。如果您想要基于光半径进行衰减,可以参考这篇详细的博客文章:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接