PDA

View Full Version : Problem with GLSL bump mapping



Kaleidoscope
09-26-2006, 10:51 PM
Hi all, this is my first post here and like almost all first posts the reason for this is a problem I had.
This is my first attempt to use GLSL, I was trying to obtain some bump mapping using shaders. After reading a lot of tutorials I decided that it was time to start writing something.

Unluckily my first attempt wasn't that good :( the problem as you might see from the image below is that I am able to light only the world ( the textured quad ;) forget about the box in the middle ) that lies under the light source (the white dot) and only one corner of it (the lower left on the pic). I don't really know what I'm doing wrong.

http://img.photobucket.com/albums/v70/_kali_/BumpMapping.jpg

here is my vertex program:

varying vec3 LightDir; //The transformed light direction, to pass to the fragment shader
varying vec2 TexCoords;

attribute vec3 Tangent;

void main()
{
gl_Position = ftransform();

vec3 n = normalize ( gl_NormalMatrix * gl_Normal);
vec3 t = normalize ( gl_NormalMatrix * Tangent);
vec3 b = cross (n, t);

vec3 lPos = gl_LightSource[0].position.xyz - vec3(gl_ModelViewMatrix * gl_Vertex);
lPos = normalize( lPos );

//Rotate the light into tangent space
vec3 v;
v.x = dot ( lPos , t);
v.y = dot ( lPos , b);
v.z = dot ( lPos , n);
LightDir = normalize( v );

TexCoords = gl_MultiTexCoord1.xy;
}and my fragment program:

uniform sampler2D Texture_Normal; //The bump-map
uniform sampler2D Texture_Color; //The texture

varying vec3 LightDir;
varying vec2 TexCoords;

void main()
{
vec3 lDir = normalize ( LightDir );
vec3 BumpNorm = vec3(texture2D(Texture_Normal, TexCoords));
vec3 DecalCol = vec3(texture2D(Texture_Color, TexCoords));

//Expand the bump-map into a normalized unsigned vector float
BumpNorm = (BumpNorm -0.5) * 2.0;

//Find the dot product between the light direction and the normal
float NdotL = max(dot(BumpNorm, lDir), 0.0);

vec3 diffuse = NdotL * vec3(1.0) * DecalCol;
//Set the color of the fragment...
gl_FragColor = vec4(diffuse, 1.0);
}Any hint will be really appreciated.


Edit:
solved... looks like there was a problem with my normal map :( Thank you for your help

sqrt[-1]
09-27-2006, 02:31 AM
If you can upload a .exe and post a link, I will take a look. (I don't need source if you don't want to give it)

That is, if someone else does not spot an error first.

Kaleidoscope
09-27-2006, 04:40 AM
Thank you very much sqrt[-1].
you can download the .exe at http://download.yousendit.com/118C9B6A4B91EE33

Extract it in a folder and edit the config.cfg file so that the paths are correct.

You can find the shaders in the data\ folder.

Thank you again, let me know if you have problems running it.

sqrt[-1]
09-27-2006, 06:07 PM
Looking at the results and usage, it seems that you are not setting up the textures correctly.
(This is not to say that the shaders are correct, but the texture binding needs to be fixed before I can look at that)

The draw call looks like this (from GLIntercept):
Tex stage 0 = Diffuse Texture (OK)
Tex stage 1 = White texture?
Tex stage 2 = Heightmap?
Tex stage 3 = White texture?
Tex stage 4 = White texture?

So it seems you are binding a lot of un-necessary textures and not loading/binding the normal map into stage 1.

Kaleidoscope
09-28-2006, 03:43 AM
The problem was exactly that, I was binding the wrong texture.
Thank you sqrt! Its time to learn to use GLIntercept ;)

Here is the current situation in all its parallax mapped splendour :)

http://img.photobucket.com/albums/v70/_kali_/screen.jpg

Just another question, sorry if I abuse again of your kindness.
While calculating the specular factor is it correct to assume that the eye direction is x=0.0 , y=0.0 , z=-1.0 since I am doing my calculations in eye space?

abrodersen
09-28-2006, 04:00 AM
Also, you should transform the tangent in your vertex program by the modelview matrix, not the normal matrix, which should be used only to transform the normal.
Transforming the tangent by the normal matrix and then normalizing will give you the correct result though, until you start using non uniform scaling.

sqrt[-1]
09-28-2006, 05:40 PM
Originally posted by Kaleidoscope:

Just another question, sorry if I abuse again of your kindness.
While calculating the specular factor is it correct to assume that the eye direction is x=0.0 , y=0.0 , z=-1.0 since I am doing my calculations in eye space? Yeah, it will be 0,0,-1 ( or 0,0,1 depending on what you are doing).

Also, just looking at your screen shot, it seems there may be other problems as it looks a little funny.

Kaleidoscope
09-28-2006, 11:37 PM
Thank you abrodersen and sqrt for your replies.

@abrodersen:
Thanks for the info, will save me some headaches when (and if) I'll have to work with non uniform scaling :)

@sqrt:
I know there's something wrong but I cannot tell you what... Maybe is the kind of perspective, maybe that texture fits better with a vertical plane. Or maybe my shaders are wrong ( this theory is far more reliable ).

btw here is my code:
vp:

varying vec3 LightDir;
varying vec3 EyeDir;
varying vec3 HalfVector;
varying float LightDistance;
varying vec2 TexCoords;

attribute vec3 Tangent;



//////////////////////////////////////////////////////////////////////////////
// Transforms a vector from eye space to tangent space
// Parameters:
// t -> Tangent to the vertex
// b -> Binormal to the vertex
// n -> Normal to the vertex
// vector -> Vector to transform (will be normalized)
// Output:
// Vector in tangent space
vec3 TransformToTangentSpace( in vec3 t , in vec3 b , in vec3 n , in vec3 vector )
{
vec3 v;
vec3 temp = normalize( vector );
v.x = dot ( vector , t);
v.y = dot ( vector , b);
v.z = dot ( vector , n);
return normalize(v);
}


void main()
{
vec3 lPos; // Light position ( eye space )
vec3 halfVec; // Light half vector
vec3 vertPos; // Vertex position ( eye space )

vec3 eyePosition = vec3( 0.0 , 0.0 , 0.0 );
vec3 eyeDirection = vec3( 0.0 , 0.0 , -1.0 );

//Put the vertex in the position passed
gl_Position = ftransform();


vec3 n = normalize ( gl_NormalMatrix * gl_Normal);
vec3 t = normalize ( gl_NormalMatrix * Tangent );
vec3 b = cross (n, t);


vertPos = vec3( gl_ModelViewMatrix * gl_Vertex );


lPos = gl_LightSource[0].position.xyz - vertPos;
LightDistance = length( lPos );
LightDir = TransformToTangentSpace( t , b, n , lPos );


halfVec = gl_LightSource[0].halfVector.xyz;
HalfVector = TransformToTangentSpace( t , b, n , halfVec );


EyeDir = TransformToTangentSpace( t , b, n , eyeDirection );


TexCoords = gl_MultiTexCoord1.xy;
}fp:

uniform sampler2D Texture_Normal;
uniform sampler2D Texture_Color;
uniform sampler2D Texture_HeightMap;
varying vec3 HalfVector;
varying vec3 EyeDir;
varying vec3 LightDir;
varying vec2 TexCoords;
varying float LightDistance;

const float specularCoeff = 0.6;

//////////////////////////////////////////////////////////////////////////////
// Computes the diffuse coefficent for the current light
// Parameters:
// lightIdx -> Index of the light to use
// d -> Distance form the light from the point ( interpolated from vp )
// Output:
// the diffuse coefficent for the current light
vec4 ComputeLightDiffuse( in int lightIdx , in float d)
{
float attenuation = 1.0 / ( gl_LightSource[ lightIdx ].constantAttenuation +
gl_LightSource[ lightIdx ].linearAttenuation * d +
gl_LightSource[ lightIdx ].quadraticAttenuation * d * d );
vec4 diffuse = gl_LightSource[ lightIdx ].diffuse * attenuation;

return diffuse;
}

//////////////////////////////////////////////////////////////////////////////////////////////
// Expands a normal read from the bumpmap texture into a normalized vector
// Parameters:
// packedNormal -> Bump normal value read from the bumpmap texture
// Output:
// Normal unpacked
vec3 UnpackNormal( in vec4 packedNormal )
{
return ( vec3( packedNormal ) - 0.5) * 2.0;
}




void main()
{
vec3 lDir; // Normalized light direction in tangent space
vec3 eDir; // Normalized eye direction in tangent space
vec3 hVec; // Light half vector
vec2 uvCoord; // Texture coords
float height; // height offset for parallax mapping
vec3 bumpNorm; // normal to the pixel ( read from the normal map )
vec4 decalCol; // decal color ( read from color map )
vec4 diffuse; // Light diffuse coefficent
float nDotL; // Dot product between the light direction in tangent space and the pixel normal
float spec; // Specular factor
vec3 finalCol; // Final fragment color after the computations


lDir = normalize ( LightDir );
eDir = normalize ( EyeDir );
hVec = normalize ( HalfVector );


uvCoord = TexCoords;


// Parallax mapping...
height = texture2D (Texture_HeightMap, uvCoord ).r;
height = height * 0.04 - 0.02;

uvCoord = uvCoord + ( eDir.xy * height );


bumpNorm = UnpackNormal( texture2D( Texture_Normal, uvCoord ) );
decalCol = texture2D( Texture_Color, uvCoord );


// compute distance between the surface and the light position
diffuse = ComputeLightDiffuse( 0 , LightDistance );


//Find the dot product between the light direction and the normal
nDotL = max( dot( bumpNorm, lDir ), 0.0 );


// Specular factor
spec = max( dot( HalfVector , bumpNorm ), 0.0) ;
spec = pow( spec, 128.0 ) * specularCoeff;


finalCol = nDotL * decalCol.rgb;
finalCol = min( finalCol + spec , 1.0 );


gl_FragColor = vec4( finalCol , decalCol.a ) * diffuse;
}if you want to try the .exe you can download the latest version from http://download.yousendit.com/A6D8DCFD26C2FF4F

Extract it in a folder and edit the config.cfg file so that the paths are correct.

You can find the shaders in the data\ folder.

Thank you

Komat
09-29-2006, 06:46 AM
The eyeDirection is calculated incorrectly. Use


vec3 eyeDirection = eyePosition - vertPos ;instead.
The direction can not be constant unless nonlocal viewer is used. This was speedup hack for calculation of specular on older hw and probably not the thing you wish to use with per pixel lighting since it degenerates quality of the specular. For nonlocal viewer your also need to modify the half vector calculation equations.

The paralax mapping is highly dependent on proper direction to work believably so any attempt to use the nonlocal viewer will break that.

Komat
09-29-2006, 06:51 AM
The paralax mapping demo in ATI sdk also contains a slightly modified paralax mapping (uses two combined samples from height map, the second sample is taken on offset calculated from first sample) that works much better on sharp edges inside the high map.

Komat
09-29-2006, 08:10 AM
When the light is moving above the surface, the lit area is incorrect. This is caused by normalizing the directional vectors within the vertex shader before the interpolation.

Kaleidoscope
10-02-2006, 10:29 PM
Thank you for your help Komat (and sorry for the delay), it looks much better now :)
Just another question, the ati sdk you were talking about it the one located at http://www.ati.com/developer/radeonSDK.html (Radeon SDK March 2006)? I want to give that method a try but before downloading 400 m I want to be sure that the download is correct :)

Komat
10-03-2006, 04:36 AM
Originally posted by Kaleidoscope:
Just another question, the ati sdk you were talking about it the one located at http://www.ati.com/developer/radeonSDK.html (Radeon SDK March 2006)?Yes, that is the correct sdk. In this latest sdk version the paralax mapping paper and example contains even more variants of the paralax mapping (the modification I was talking about previously is called Paralax mapping with refining in that example).