Bump mapping technique repository

Hi everyone!

The main idea of engine I’m crafting is: create several execution paths for (almost) any hadware. So, I’ve got several bump mapping paths:

  1. NVidia Vertex Program path (works, cool result!).
  2. NVidia Register combiners (? but also works).
  3. Fixed function (TexEnv, everyone knows… nice result).
  4. !!!MISSING!!!SOS!!! ARB vertex program path! can’t find any example of bump maps through ARB vp1.0 !

So… if anyone has the code - please post!
Or - send: kh_dmitry2001@mail.ru

Thanx everyone!

[This message has been edited by Freelancer (edited 12-22-2003).]

A while ago I wrote a little bump mapping demo that used ARB_vertex_program and ARB_fragment_program. . . I lost the source code, but still have the demo itself and its shader programs.


PARAM	mvp[4] = {state.matrix.mvp};
PARAM	light1pos = state.light[1].position;
PARAM	light2pos = state.light[2].position;
#PARAM	light2pos = {-2.5, 2.5, -2.5, 1.0};
PARAM	one = {1.0, 1.0, 1.0, 1.0};
PARAM	lightradius = {0.125, 0.125, 0.125, 1.0};

ATTRIB	normal = vertex.normal;
ATTRIB	binormal = vertex.attrib[9];
ATTRIB	tangent = vertex.attrib[10];

TEMP	light1vector, light1ts;
TEMP	light2vector, light2ts;
TEMP	temp;

#	Light 1
SUB		light1vector, light1pos, vertex.position;

DP3		light1ts.x, light1vector, tangent;
DP3		light1ts.y, light1vector, binormal;
DP3		light1ts.z, light1vector, normal;
MOV		light1ts.w, one;

DP3		temp, light1ts, light1ts;
RSQ		temp, temp.x;
MUL		light1ts, light1ts, temp;

MOV		result.texcoord[1], light1ts;
MUL		result.texcoord[2], light1vector, lightradius;

#	Light 2
SUB		light2vector, light2pos, vertex.position;

DP3		light2ts.x, light2vector, tangent;
DP3		light2ts.y, light2vector, binormal;
DP3		light2ts.z, light2vector, normal;
MOV		light2ts.w, one;

DP3		temp, light2ts, light2ts;
RSQ		temp, temp.x;
MUL		light2ts, light2ts, temp;

MOV		result.texcoord[3], light2ts;
MUL		result.texcoord[4], light2vector, lightradius;

#	Output everything else
MOV		result.color, vertex.color;

DP4		result.position.x, mvp[0], vertex.position;
DP4		result.position.y, mvp[1], vertex.position;
DP4		result.position.z, mvp[2], vertex.position;
DP4		result.position.w, mvp[3], vertex.position;

MOV		result.texcoord[0], vertex.texcoord[0];


OUTPUT	final = result.color;
TEMP	base, normal, temp, bump, total;
TEMP	light1, atten1;
TEMP	light2, atten2;

PARAM	light0colour = state.light[0].ambient;
#PARAM	light1colour = state.light[1].diffuse;
PARAM	light1colour = {0.0, 1.0, 0.0, 1.0};
#PARAM	light2colour = state.light[2].diffuse;
PARAM	light2colour = {1.0, 0.0, 0.0, 1.0};

TEX		base,	fragment.texcoord[0],	texture[1],	2D;
TEX		normal,	fragment.texcoord[0],	texture[0],	2D;

#	remove scale and bias from the normal map
SUB		normal,	normal,	0.5;
MUL		normal, normal, 2.0;

#	normalize the normal map
DP3		temp,	normal,	normal;
RSQ		temp,	temp.r;
MUL		normal,	normal,	temp;

normalize the light1 vector

DP3 temp, fragment.texcoord[1], fragment.texcoord[1];
RSQ temp, temp.x;
MUL light1, fragment.texcoord[1], temp;


DP3 bump, normal, light1;

calculate and add attenuation

DP3_SAT atten1, fragment.texcoord[2], fragment.texcoord[2];
SUB atten1, 1.0, atten1;
MUL bump, bump, atten1;

add colour

MUL total, bump, light1colour;

normalize the light2 vector

DP3 temp, fragment.texcoord[3], fragment.texcoord[3];
RSQ temp, temp.x;
MUL light2, fragment.texcoord[3], temp;


DP3 bump, normal, light2;

calculate and add attenuation

DP3_SAT atten2, fragment.texcoord[4], fragment.texcoord[4];
SUB atten2, 1.0, atten2;
MUL bump, bump, atten2;

add colour and add to the total

MAD_SAT total, bump, light2colour, total;

add ambient lighting

ADD_SAT total, total, light0colour;

MUL_SAT total, base, total;

MOV final, total;

#MOV final, bump;


Grand Thanx!

…but… without fragment programs?
For GeForce1/2/3 ?

Just Vertex_Program + setup?

Seems like everyone is posting things about bump mapping at the moment .

your paths seem weird to me:

whats the point with 1. and 2.? How can you do bump mapping with vertex programs, but without RC? I think RC and VP are not alternatives, but other parts of the same things, use VP for geometry setup and RC for the dot3 stuff!?

  1. Fixed function (TexEnv, everyone knows… nice result).

Do you mean the ARB texture combine mode extension?

My path suggestions would be:

  • ARB extensions only
  • NV RC
  • the ati thing that is equivalent to NV RC (I do not own a radeon)
  • fragment prorams (gf fx/radeon and up).

I would do any of them with vp if vp is availabe, otherwise there’s a problem anyway (I think) because when not having vp, you cannot use display lists/vbo, and this will slow down everyhing.

Or am I getting something wrong?

The point about your SOS call: I think Vertex Progam are not the right things for bump mapping, they are just a way of doing the geometry transformation (tangent space), the heart of bump mapping is that you need something that can do a dot product for each fragment, and THIS is where the rendering paths should/would be different.


Yeah, ARB_vertex_program and NV_vertex_program are very close. Also, I think that every card that supports NV_vp also supports ARB_vp (with some limitations, perhaps). As such, the only issue there is what to use for fragment processing. The basic things you have to do are:

  1. normalize the light vector,
  2. convert the normalmap data from the range [0,1] to [-1,1],
  3. take the dot3 product of the normalmap and light vector,
  4. and modulate with the material colour or texture.

Attenuation can be done, too, but I’m not all that sure if I did it right in my posted example. . . It looked good at the time, so I kept it. Light colour may also be something you want to take into account, but that may be considered extra. The above steps are the basic elements of per-pixel dot3 bumpmapping.

The only difficult part with the fragment processing is in the method and the graphics card’s capabilities. If you only have two texture units, for example, you’ll need two passes per light using ARB_texture_env_combine (and related extensions) – one pass if you have more texture units. Using ATI_fragment_shader, ARB_fragment_program, or NV_fragment_program only a single pass is needed, of course. I’m not sure about other NVidia fragment processing extensions, though, since I’ve never had the oportunity to learn them.

On another note, without vertex programs you can still do bump-mapping, but you must then use immediate mode or standard vertex arrays if you want the object and/or the light to be dynamic (moving). If they’re both static, then you can set the appropriate attributes once and then toss the data into whatever static vertex storage method you want (display lists, VBO). Of course, bump mapping is really best and most noticable when the lighting is dynamic.

I disagree about the possibility of precomputing everything for static lights, so you can use display lists without having to use VP. Of course you can do so for the diffuse part, but for specular hightlights, you need the half vector, and this is dynamic even with static lights, as the eye position is taken into account, and this of course is dynamic (if not, do not use OpenGL but something like paintshop ).

You pretty much can’t do good specular bump on 2-texture-unit hardware. There just isn’t enough math power on the chip; there aren’t even dependent reads.

You can do regular specular (using REFLECTION_MAP) in one pass, and bumped diffuse (using object-space normal maps) in one pass. Assuming the lights are infinite. Something like:

Pass 1:
Calculate (ObjNormal DOT LightVector) TIMES DiffuseColor
Pass 2:
Add specular based on REFLECTION_MAP look-up in cube map

I’m not sure you can even get ambient into this situation with regular, plain TexEnv(); you might need a third pass for that (after pass 1).

JanHH - you’ve posted the thing I wanted, thank you!

But… again that BUT!

Do you (or anyone else) have the vertex programs for lighting (lighting only!).
I think that LIGHTING in OpenGL is a vertex-based thing…

…so the idea is to offload all lighting to the video hardware.

What I need is:

  1. direction light
  2. point omni light
  3. spot light

vertex programs. Diffuse/specular/etc components appreciated…

No I do not have any vertex program examples, vp will be one of the next things I’m going to learn. I would suggest with reading the specs of ARB_vertex_program, there are also some examples there, and first try to get the standard geometry transformations done with vp (modelview and projection), so that it looks like before. I am quite sure that once you got that so far and understand how it works, the maths for bump mapping are quite simple (but I am not sure about that, just guessing).

My plan is to rework my terrain engine to do the whole lighting with ARB_texture_env_combine, using one pass for diffuse and one pass for specular (with gloss map). The gloss map has an alpha channel so you later even can add reflections blended by destination alpha (so that it looks like puddles on the street, for example). As the data is inside of display lists, I’m going to use ARB_vertex_program. I am quite sure about getting good results in a two pass process (there is only one light in the scene which is an infinite light, no spot light).

for spoint+point lights I suggest you read ron frazier’s papers.