2012-03-20 26 views
16

La iluminación basada en píxeles es un problema común en muchas aplicaciones OpenGL, ya que la iluminación estándar de OpenGL tiene muy mala calidad.Generic GLSL Lighting Shader

Quiero utilizar un programa GLSL para tener iluminación basada en píxeles en mi programa OpenGL en lugar de por vértice. Solo iluminación difusa, pero con niebla, textura y textura alfa por lo menos.

Empecé con 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 
} 

Los comentarios son alemán porque es un sitio alemán donde fue publicada este código , lo siento.

Pero todo lo que hace este sombreador es hacer que todo sea muy oscuro. Sin efectos de iluminación en absoluto, sin embargo, los códigos de sombreado se compilan. Si solo uso GL_LIGHT0 en el sombreador de fragmentos, parece que funciona, pero solo es razonable para los polígonos que miran hacia la cámara y el polígono de mi piso es extremadamente oscuro. Además, los quads con texturas RGBA no muestran signos de transparencia. Uso glRotate/Translate estándar para la matriz Modelview y glVertex/Normal para mis polígonos. La iluminación OpenGL funciona bien, aparte del hecho de que se ve feo en superficies muy grandes. Comprobé tres veces mis normales, están bien.

¿Hay algún error en el código anterior? O Dime por qué no existe un Shader de iluminación genérico para esta tarea real (luz basada en puntos con caída de distancia: una vela si se quiere) - ¿no debería haber solo una forma correcta de hacerlo? No quiero los efectos de bache/normal/paralaje/toon/desenfoque/cualesquiera. Solo quiero que mi iluminación funcione mejor con polígonos más grandes.

Todos los tutoriales que encontré son útiles solo para iluminar un solo objeto cuando la cámara está a 0,0,0 de cara ortogonal al objeto. Lo anterior es el único que se encuentra que al menos se parece a lo que quiero hacer.

+1

Lo obvio primero: ¿ha enlazado una muestra, son correctos sus cordones de textura y normales, ¿muestra la geometría si establece gl_FragColor en un color fijo?Con los sombreadores me resulta más fácil entenderlos usando y agregando pequeñas características de una en una, a falta de poder entrar y rastrearlas: p. – Robinson

+0

La muestra es TEXTURE_2D y está ligada a las polis renderizadas. Los cordones de textura son correctos, ya que la iluminación de OpenGL normal funciona de manera impecable. Los normales son perfectos (como ya se dijo). Sí, muestra la Geometría al configurar gl_FragColor en un color fijo o solo en texColor. – Rock

Respuesta

10

Yo sugeriría fuertemente a leer this article para ver cómo el rayo ADS estándar se realiza dentro de GLSL.That es GL 4.0, pero no es un problema para ajustar a su versión:

también opera en la vista (cámara) por lo que el espacio DON "T negar el vector de ojos:

vec3 eyeDir = normalize(-position); 

tuve problemas muy similares a los suyos porque también negaba el vector de ojo olvidar que se transforma en la difusa vista space.Your y cálculos parecen ser especulares También está mal en el escenario actual. En su lugar, no usaría los datos de la tubería fija en absoluto, oth ¿cuál es el punto de hacerlo en un sombreador? Aquí es el método para calcular difusa y especular en el ADS punto por cada fragmento de un rayo:

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. 
} 

Además no se podría sugerir el uso de la ecuación de atenuación que tiene aquí, es difícil control.If desea agregar atenuación basada en el radio ligero there is this nice blog post: