Wednesday, April 14, 2010

Depth texturing in OpenGL GLSL Shader Program

Depth Texturing in GLSL



This GLSL shader program is used to enable depth texturing. The depth texture is located under texture unit 5 as shown:


uniform sampler2DShadow texture_5;


Note we had to pass the light's translation matrix in gl_TextureMatrix element 0 as shown:

ShadowCoord = gl_TextureMatrix[0] * gl_Vertex;


Here are the shaders

Vertex Program



varying vec4 diffuse,ambient;
varying vec3 normal,lightDir,halfVector;
varying vec4 ShadowCoord;

void main()
{
ShadowCoord = gl_TextureMatrix[0] * gl_Vertex;

/* first transform the normal into eye space and
normalize the result */
normal = normalize(gl_NormalMatrix * gl_Normal);

/* now normalize the light's direction. Note that
according to the OpenGL specification, the light
is stored in eye space. Also since we're talking about
a directional light, the position field is actually direction */
lightDir = normalize(vec3(gl_LightSource[0].position));

/* Normalize the halfVector to pass it to the fragment shader */
halfVector = normalize(gl_LightSource[0].halfVector.xyz);

/* Compute the diffuse, ambient and globalAmbient terms */
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
ambient += gl_LightModel.ambient * gl_FrontMaterial.ambient;

gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}


Fragment Program



varying vec4 diffuse,ambient;
varying vec3 normal,lightDir,halfVector;
varying vec4 ShadowCoord;
uniform sampler2D texture_0;
uniform sampler2DShadow texture_5;

void main()
{
vec3 n,halfV;
float NdotL,NdotHV;
diffuse = texture2D(texture_0, gl_TexCoord[0].xy);
ambient = vec4(0.0, 0.0, 0.0, 0.0);


vec4 shadowCoordinateWdivide = ShadowCoord / ShadowCoord.w;
shadowCoordinateWdivide.z += 0.0001;
float distanceFromLight = shadow2DProj(texture_5, shadowCoordinateWdivide).a;

vec4 tc = shadowCoordinateWdivide;
/*
MultiSample depth texture
float s = 0.00005;
//float s = 1.0 / 10.0;
//float d = distanceFromLight;
float d1 = shadow2DProj(texture_5, vec4(tc.r+s, tc.g+s, tc.b, tc.a)).a;
float d2 = shadow2DProj(texture_5, vec4(tc.r+s, tc.g-s, tc.b, tc.a)).a;
float d3 = shadow2DProj(texture_5, vec4(tc.r-s, tc.g+s, tc.b, tc.a)).a;
float d4 = shadow2DProj(texture_5, vec4(tc.r-s, tc.g-s, tc.b, tc.a)).a;
float d5 = shadow2DProj(texture_5, vec4(tc.r+s, tc.g, tc.b, tc.a)).a;
float d6 = shadow2DProj(texture_5, vec4(tc.r+s, tc.g, tc.b, tc.a)).a;
float d7 = shadow2DProj(texture_5, vec4(tc.r-s, tc.g, tc.b, tc.a)).a;
float d8 = shadow2DProj(texture_5, vec4(tc.r-s, tc.g, tc.b, tc.a)).a;*/

/* The ambient term will always be present */
vec4 color = ambient;

/* a fragment shader can't write a varying variable, hence we need
a new variable to store the normalized interpolated normal */
n = normalize(normal);

/* compute the dot product between normal and ldir */
NdotL = max(dot(n,lightDir),0.0);

if (NdotL > 0.0) {
color += diffuse * NdotL;
halfV = normalize(halfVector);
NdotHV = max(dot(n,halfV),0.0);
color += gl_FrontMaterial.specular *
gl_LightSource[0].specular *
pow(NdotHV, gl_FrontMaterial.shininess);
}

gl_FragColor = color;
gl_FragColor.a = diffuse.a;

float shadow = 1.0;
if(ShadowCoord.w > 0.0) {
shadow = distanceFromLight < shadowCoordinateWdivide.z ? 0.2 : 1.0 ;
}

gl_FragColor.rgb = shadow * gl_FragColor.rgb;

}

1 comment: