# Parallax mapping

Why would parallax mapping be dependent on the light source direction? All the examples I have looked at tie it in with the light source.

I am using “radiosity bump mapping” which is a fancy way of saying I calculate a lightmap with a “light direction map” to tell the shader where light is coming from.

I don’t see why parallax mapping needs to be tied to a light source, since it is a function of the eye vector and the height at that texel.

It’s usually something like this:
float height = texture2D(heightmap,gl_TexCoord[0].st).a
height = height * 0.04 - 0.036;
newtexcoord = gl_TexCoord[0].st + height * normalize(halfvec).xy;

So I need the vector to multiply the height by. Why should this have anything to do with a light source?

I am not sure what your question is.
Can you describe the part light plays in your algorithm that doesn’t seem necessary to you?

I have bumpmapping implemented. It works perfectly, but it doesn’t use a single light source like most examples do.

Now parallax mapping simply takes the normal and the eye vector and skews the texcoords a little. So I want to do this independently of the bumpmapping or lighting.

the eye vector is independent from the light’s position… it only depends on the camera’a position/rotation.

Given one of his constants is called “halfvec”, I suppose he’s using the half vector between the eye vector and the light direction, hence the original question

Exactly. Every implementation I have seen uses a halfvec from a light source. They are probably merging some of their bumpmap / parallax mapping stuff, but there should be a way to do them separately. I mean, you should be able to do parallax mapping on a flat unlit texture with no bumpmap, just a heightmap.

We would need to see the code.
In the case of parallax mapping, the halfvec variable would need to be based on the polygon’s normal. It shouldn’t be based on light, I agree. The new texture coordinate shouldn’t be relative to the position of a light source. (Or the half-vector between them) That would cause the coordinate offset to move depending on your position relative to a light source.

Can you post the whole sample?

The important part is the parallax mapping section at the beginning, where basetexcoord is calculated. I am storing the heightmap in the colormap alpha channel (bumpmap alpha already gets used for specular level).

Thanks to Arne Reiners for his help with some of the bump stuff.

``````uniform sampler2D basetexture;
uniform sampler2D lightmap;
uniform sampler2D bumpmap;
uniform vec4 AmbientLight;
varying vec3 T,B,N;
varying vec3 ModelVertex;

void main(void) {

vec2 basetexcoord;
vec4 lightcolor;
vec4 bumpcolor;
float alpha=gl_Color.w;
vec3 lightdir;
vec3 normal;
vec4 basecolor;
float specular=0.0;

#ifdef LW_PARALLAX
vec3 h = normalize(halfVector);
float height = texture2D(heightMap,basetexcoord).r;
height = height * 0.04 - 0.036;
basetexcoord = gl_TexCoord[0].st + (height * h.xy);
#else
basetexcoord=gl_TexCoord[0].xy;
#endif

//======================================
// Light color
//======================================
#ifdef LW_LIGHTMAP
lightcolor = texture2D(lightmap,gl_TexCoord[1].st) * 2.0;

#ifdef LW_BUMPMAP
#endif
#else
lightcolor = gl_Color;
#endif

//======================================
// Bumpmap
//======================================
#ifdef LW_BUMPMAP

#ifdef LW_LIGHTMAP
lightdir = gl_NormalMatrix * ( ( texture2D(radiositymap,gl_TexCoord[1].st).xyz - 0.5 ));
#endif

vec3 halfvec = normalize(normalize(lightdir) + normalize(-ModelVertex));

bumpcolor = texture2D(bumpmap,basetexcoord);
normal = normalize(bumpcolor.xyz - 0.5);
normal = T * normal.x + B * normal.y + N * normal.z;

float diffuse = max(0.0,dot(normal,lightdir));
lightcolor = lightcolor * diffuse;
specular = pow(max(0.0, dot(halfvec,normal)),8.0) * bumpcolor.w;
#endif

//======================================
// Base color
//======================================
#ifdef LW_BASETEXTURE
basecolor = texture2D(basetexture,basetexcoord);// * gl_Color*2.0;
alpha *= basecolor.w;
#else
basecolor=vec4(0.5);
#endif

//======================================
// Mix final color
//======================================
gl_FragColor = basecolor * lightcolor;
#ifdef LW_BUMPMAP
gl_FragColor += specular * lightcolor * 2.0;
#endif
gl_FragColor += basecolor * AmbientLight;

//======================================
// Fog effect
//======================================
float fogeffect = clamp( 1.0 - (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale , 0.0, 1.0 ) * gl_Fog.color.w;
gl_FragColor = 	gl_FragColor * (1.0 - fogeffect) + gl_Fog.color * fogeffect;

gl_FragColor.w=alpha;
}
``````

But where does the halfVector come from?
It isn’t a global or a local variable.

Lumina has a good example showing simple relief mapping, without any nonsense:
http://lumina.sourceforge.net

I used that as an example, and it works now:

You are getting 1014 frames per second?!

What kind of video card you got there?

GE Force 8800.

Why should it be slow? This is the only parallax code in the frag shader:

``````		vec3 eye = normalize(EyeVec);
float height = texture2D(basetexture,basetexcoord).a;
height = height * 0.04 - 0.036;
basetexcoord = basetexcoord + (height * eye.xy);
``````

Well, I have a Geforce 6000-something and I can’t get it to render faster than 90 frames per second, if I don’t draw anything at all.

Are you sure your FPS calculations are correct?

1014 FPS seems pretty high.