Spot Light Per Pixel

 

Prev: Point Light Per PixelNext: Simple Texture
 

This tutorial is based on the previous tutorial as most of the code comes from there. The only thing new in a spot light, when compared to a point light, is that in the former the light rays are restricted to a cone of light where as in the latter the rays are emitted in all directions.

From an OpenGL application point of view the differences between the two are:

  • The spot light, besides the position has a direction, spotDirection, which represents the axis of the cone.
  • There is an angle of the cone. GLSL offers both the angle, as specified in the application, as well as the cosine which is a derived variable, spotCosCutoff.
  • Finally we have a rate of decay, spotExponent, i.e. a measure of how the light intensity decreases from the center to the walls of the cone.

The vertex shader is the same as in the point light. It’s in the fragment shader that we’re going to make some changes. The diffuse, specular and ambient components will only have an effect if the fragment being shaded is inside the light’s cone. Hence the first thing we must do is to check this.

The cosine of the angle between the light to vertex vector and the spot direction must be larger than spotCosCutofff otherwise the fragment is outside the cone and will only receive the global ambient term.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
n = normalize (normal);
 
/* compute the dot product between normal and ldir */
NdotL = max ( dot (n, normalize (lightDir)),0.0);
if (NdotL > 0.0) {
 
     spotEffect = dot ( normalize (gl_LightSource[0].spotDirection),
             normalize (-lightDir));
     if (spotEffect > gl_LightSource[0].spotCosCutoff) {
         /* compute the illumination in here */
 
     }
}
gl_FragColor = ...

The computation of the illumination is pretty much the same as in the point light case, the only difference being that the attenuation must be multiplied be the spotlight effect using the following equation:


where spotDirection is a field from the ligth state (see here), lightDir is the vector from the light source to the vertex, and spotExp is the spot rate of decay. This is also provided by the OpenGL state (see here), and controls how the lights intensity decays from the center of the cone it its borders. The larger the value the faster de decay, with zero meaning constant light within the light cone.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
spotEffect = pow (spotEffect, gl_LightSource[0].spotExponent);
att = spotEffect / (gl_LightSource[0].constantAttenuation +
         gl_LightSource[0].linearAttenuation * dist +
         gl_LightSource[0].quadraticAttenuation * dist * dist);
 
color += att * (diffuse * NdotL + ambient);
 
 
halfV = normalize (halfVector);
NdotHV = max ( dot (n,halfV),0.0);
color += att * gl_FrontMaterial.specular *
             gl_LightSource[0].specular *
             pow (NdotHV,gl_FrontMaterial.shininess);

The following images show the difference between a point light as computed by the fixed functionality, i.e. per vertex, and using the shader in this tutorial, i.e. per pixel. 

Fixed FunctionalityPer Pixel

The complete fragment shader is presented below.

varying vec4 diffuse,ambientGlobal, ambient, ecPos;
varying vec3 normal,halfVector;
varying float dist;
 
 
void main()
{
    vec3 n,halfV;
    float NdotL,NdotHV;
    vec4 color = ambientGlobal;
    float att,spotEffect;
     
    /* a fragment shader can't write a verying variable, hence we need
    a new variable to store the normalized interpolated normal */
    n = normalize(normal);
     
    // Compute the ligt direction
    lightDir = vec3(gl_LightSource[0].position-ecPos);
     
    /* compute the distance to the light source to a varying variable*/
    dist = length(lightDir);
 
    /* compute the dot product between normal and ldir */
    NdotL = max(dot(n,normalize(lightDir)),0.0);
 
    if (NdotL > 0.0) {
     
        spotEffect = dot(normalize(gl_LightSource[0].spotDirection), normalize(-lightDir));
        if (spotEffect > gl_LightSource[0].spotCosCutoff) {
            spotEffect = pow(spotEffect, gl_LightSource[0].spotExponent);
            att = spotEffect / (gl_LightSource[0].constantAttenuation +
                    gl_LightSource[0].linearAttenuation * dist +
                    gl_LightSource[0].quadraticAttenuation * dist * dist);
                 
            color += att * (diffuse * NdotL + ambient);
         
             
            halfV = normalize(halfVector);
            NdotHV = max(dot(n,halfV),0.0);
            color += att * gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV,gl_FrontMaterial.shininess);
        }
    }
 
    gl_FragColor = color;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值