Pages: [1]
  Print  
Author Topic: [TUTO] Phong Shading - Spot Light (english)  (Read 3191 times)
0 Members and 1 Guest are viewing this topic.
JeGX
Global Moderator
Capo Bastone
*****
Posts: 1971



WWW
« on: February 19, 2006, 10:36:49 PM »

Here is a little tutorial that shows in detail the Phong shading model implementation using the GLSL. The spot light is described (finally!) and the double cones model (penumbra area) too.
The tutor is available here: Phong Tutorial.

The spot model with two cones comes from Direct3D. In this tutor, I've used a simple linear function to go from the lit area to the shadowed one.
Other functions (exp, quadratic, ...) could certainly improve the rendering.

Do not hesitate to do some tests and tuning and post your results!
« Last Edit: March 13, 2007, 04:54:42 PM by JeGX » Logged

Vyacheslav
Associate

Posts: 1


« Reply #1 on: March 02, 2006, 04:34:32 PM »

Here is optimised pixel shader for spot light(with two cones)
Code:

[Pixel_Shader]

varying vec3 normal, lightDir, eyeVec;

const float cos_outer_cone_angle = 0.8; // 36 degrees

void main (void)
{
    vec4 final_color =
        (gl_FrontLightModelProduct.sceneColor * gl_FrontMaterial.ambient) +
        (gl_LightSource[0].ambient * gl_FrontMaterial.ambient);

    vec3 L = normalize(lightDir);
    vec3 D = normalize(gl_LightSource[0].spotDirection);

    float cos_cur_angle = dot(-L, D);

    float cos_inner_cone_angle = gl_LightSource[0].spotCosCutoff;

    float cos_inner_minus_outer_angle =
        cos_inner_cone_angle - cos_outer_cone_angle;
    //Don't need dynamic branching, precompute falloff(i will call it spot)
    float spot = 0.0;
    if(cos_cur_angle > cos_outer_cone_angle)
        spot = clamp((cos_cur_angle - cos_outer_cone_angle) /
            cos_inner_minus_outer_angle, 0.0, 1.0);
    //
    vec3 N = normalize(normal);

    float lambertTerm = max( dot(N,L), 0.0);
    if(lambertTerm > 0.0)
    {
        final_color += gl_LightSource[0].diffuse *
            gl_FrontMaterial.diffuse *
            lambertTerm * spot;

        vec3 E = normalize(eyeVec);
        vec3 R = reflect(-L, N);

        float specular = pow( max(dot(R, E), 0.0),
            gl_FrontMaterial.shininess );

        final_color += gl_LightSource[0].specular *
            gl_FrontMaterial.specular *
            specular * spot;
    }
    gl_FragColor = final_color;
}
Logged
JeGX
Global Moderator
Capo Bastone
*****
Posts: 1971



WWW
« Reply #2 on: March 03, 2006, 12:38:15 AM »

Yeah nice optimization !
But we can do better by removing the if(cos_cur_angle > cos_outer_cone_angle) test. That works still fine without it.

I've done some tests with the original shader (s0), your shader (s1) and the improved version of your shader (s2). Here are the results on my 7800GT:

s0: 363 FPS
s1: 448 FPS
s2: 463 FPS

Conclusion: dynamic branching is still gpu-cycle-eater even on high-end graphics controller.

Good work Vyacheslav!
Logged

vexator
Associate

Posts: 2


« Reply #3 on: August 09, 2006, 06:04:14 PM »

hi! very good tutorial, i'm just adapting it for my renderer. but i don't want to use gl's internal uniform variables, so i'd like to replace gl_LightSource[0].spotDirection, gl_LightSource[0].spotCosCutoff etc with my own uniforms.

however, i don't understand how to define the spot radii then.. i thought that gl_LightSource[0].spotCosCutoff = cos(gl_LightSource[0].spotCutoff), but that does not seem to be the case.. i'd like to pass values in degrees for the radii, like 45° for the inner radius and 60° for the outer radius - how? (yep, i suck at maths)

thanks in advance! Cheesy
Logged
JeGX
Global Moderator
Capo Bastone
*****
Posts: 1971



WWW
« Reply #4 on: August 10, 2006, 08:03:56 PM »

hi man,
try to use your angles in radian rather than in degrees. I think that'll work better.
Logged

vexator
Associate

Posts: 2


« Reply #5 on: August 10, 2006, 08:22:53 PM »

d'oh! thank you, i'll give it a try! Cheesy
Logged
Pages: [1]
  Print  
 
Jump to: