karx11erx

01-18-2008, 09:18 AM

Obviously I am too dang stupid to figure something as simple as a spot light via pixel shader, so I am asking for help.

The light source can be anywhere in the view space, position and direction are given by lightPos and lightDir (lightDir is normalized).

I don't want to pass them via OpenGL's light stuff. Actually the shader can handle multiple spotlights, but I have simplified it here.

vEye is the view point.

aspect serves for making the headlight round.

cutOff is the opening angle, spotExp the rate of decay.

grAlpha is some global alpha (usually just 1.0)

The OpenGL transformation matrixes are all properly set up (or the renderer wouldn't work). Some scaling is involved, but that should be stuck in the model view matrix, or am I wrong?

Even if the viewer is the light source for the spotlight, the spotlight doesn't light the proper area right in front, but is off.

If I rotate the view, the spotlight wanders just somewhere, and I dunno what I am doing wrong.

//base texture and decal

uniform sampler2D btmTex, topTex;

varying vec3 vertPos;

uniform vec3 vEye, lightPos, lightDir;

uniform vec4 matColor;

uniform float grAlpha, aspect, cutOff, spotExp, brightness;

void main(void) {

vec4 btmColor = texture2D (btmTex, gl_TexCoord [0].xy);

vec4 topColor = texture2D (topTex, gl_TexCoord [1].xy);

vec3 lp, ld, lightVec, spotColor, v = vec3 (vertPos.x * aspect, vertPos.y, vertPos.z);

float spotEffect, lightDist, spotBrightness = 0.0;

lightPos -= vEye; //translate

//rotate the light dir by adding it to the light pos, rotating the result, rotating the light pos,

//then subtracting the rotated light pos from the rotated light dir (better way? Cannot figure)

lightDir = vec3 (gl_ModelViewMatrix * vec4 (lightPos + lightDir, 1.0));

lightPos = vec3 (gl_ModelViewMatrix * vec4 (lightPos, 1.0));

lightDir = normalize (lightDir - lightPos);

//this should be standard per pixel lighting fare ...

lightVec = v - lightPos;

lightDist = length (lightVec);

spotEffect = dot (lightDir, lightVec / lightDist);

if (spotEffect >= cutOff) {

float attenuation = min (brightness / lightDist, 1.0);

spotBrightness += pow (spotEffect * 1.1, spotExp) * attenuation;

}

//compute the final light (probably more noob stuff ...)

spotColor = vec3 (max (spotBrightness, gl_Color.r), max (spotBrightness, gl_Color.g), max (spotBrightness, gl_Color.b));

spotColor = vec3 (min (spotColor.r, matColor.r), min (spotColor.g, matColor.g), min (spotColor.b, matColor.b));

gl_FragColor = vec4 (vec3 (mix (btmColor, topColor, topColor.a)), (btmColor.a + topColor.a) * grAlpha) * vec4 (spotColor, gl_Color.a);

}

The vertex shader:

varying vec3 vertPos;

void main(void)

{

gl_TexCoord [0]=gl_MultiTexCoord0;

gl_TexCoord [1]=gl_MultiTexCoord1;

vertPos=vec3(gl_ModelViewMatrix * gl_Vertex);

gl_Position = ftransform();

gl_FrontColor=gl_Color;

}

Please be so kind and help me to get this going.

The light source can be anywhere in the view space, position and direction are given by lightPos and lightDir (lightDir is normalized).

I don't want to pass them via OpenGL's light stuff. Actually the shader can handle multiple spotlights, but I have simplified it here.

vEye is the view point.

aspect serves for making the headlight round.

cutOff is the opening angle, spotExp the rate of decay.

grAlpha is some global alpha (usually just 1.0)

The OpenGL transformation matrixes are all properly set up (or the renderer wouldn't work). Some scaling is involved, but that should be stuck in the model view matrix, or am I wrong?

Even if the viewer is the light source for the spotlight, the spotlight doesn't light the proper area right in front, but is off.

If I rotate the view, the spotlight wanders just somewhere, and I dunno what I am doing wrong.

//base texture and decal

uniform sampler2D btmTex, topTex;

varying vec3 vertPos;

uniform vec3 vEye, lightPos, lightDir;

uniform vec4 matColor;

uniform float grAlpha, aspect, cutOff, spotExp, brightness;

void main(void) {

vec4 btmColor = texture2D (btmTex, gl_TexCoord [0].xy);

vec4 topColor = texture2D (topTex, gl_TexCoord [1].xy);

vec3 lp, ld, lightVec, spotColor, v = vec3 (vertPos.x * aspect, vertPos.y, vertPos.z);

float spotEffect, lightDist, spotBrightness = 0.0;

lightPos -= vEye; //translate

//rotate the light dir by adding it to the light pos, rotating the result, rotating the light pos,

//then subtracting the rotated light pos from the rotated light dir (better way? Cannot figure)

lightDir = vec3 (gl_ModelViewMatrix * vec4 (lightPos + lightDir, 1.0));

lightPos = vec3 (gl_ModelViewMatrix * vec4 (lightPos, 1.0));

lightDir = normalize (lightDir - lightPos);

//this should be standard per pixel lighting fare ...

lightVec = v - lightPos;

lightDist = length (lightVec);

spotEffect = dot (lightDir, lightVec / lightDist);

if (spotEffect >= cutOff) {

float attenuation = min (brightness / lightDist, 1.0);

spotBrightness += pow (spotEffect * 1.1, spotExp) * attenuation;

}

//compute the final light (probably more noob stuff ...)

spotColor = vec3 (max (spotBrightness, gl_Color.r), max (spotBrightness, gl_Color.g), max (spotBrightness, gl_Color.b));

spotColor = vec3 (min (spotColor.r, matColor.r), min (spotColor.g, matColor.g), min (spotColor.b, matColor.b));

gl_FragColor = vec4 (vec3 (mix (btmColor, topColor, topColor.a)), (btmColor.a + topColor.a) * grAlpha) * vec4 (spotColor, gl_Color.a);

}

The vertex shader:

varying vec3 vertPos;

void main(void)

{

gl_TexCoord [0]=gl_MultiTexCoord0;

gl_TexCoord [1]=gl_MultiTexCoord1;

vertPos=vec3(gl_ModelViewMatrix * gl_Vertex);

gl_Position = ftransform();

gl_FrontColor=gl_Color;

}

Please be so kind and help me to get this going.