3D bump mapping of 3D object using 3D bump map

Started by
8 comments, last by Matthew Doucette 17 years, 6 months ago
Anyone implemented 3D bump mapping (bump mapping using a 3D bump map)? I'm just curious what algorithm you use. It seems a lot of renderers are using simple "hacks" that look really good but are not quite correct. I am using a most simple hack: 1) Take the x-value of the normal vector and subtract the gradient in x of the bump map of that same dimension. 2) Repeat for y and z. 3) Normalize the resultant vector. [EDIT] Let me rephrase that. I could barely understand what I wrote coming back to it. I am taking the derivative of the bump map function and all three direction (x,y,z) and subtracting those values from the original smooth surface normal. I normalize the resulting normal, which gives me the bump mapped surface normal. [/EDIT] This gives the bump mapped surface normal, but can easily be "broken" whenever the gradients I have researched Blinn's 1978 method, but it seems to be designed for 2D bump maps. I have an idea of how to make it work for my 3D bump maps, as any 2D slice of my 3D bump map immediately becomes a 2D bump map, and then it's just a matter of choosing a properly aligned coordinate system to calculate the u and v derivatives. But all this seems too complicated, and I was hoping for a more elegant solution. Please, share your methods if you do not mind. [Edited by - Matthew Doucette on October 5, 2006 6:04:33 PM]

Matthew Doucette, Xona Games

Advertisement
what is a 3D bump map?
The kind of "bump mapping" that uses a black and white heightmap and creates a normal based on the gradients is not something that's seriously used anywhere today. Using a normal map (a texture that stores a normal in each texel) is not only more correct and better looking, but a lot easier and faster to implement too. Many games nowadays use normal maps generated from a detailed multi-million polygon version of the model it's applied on, so they're as physically correct as you can get (considering the actual rendered model is low-poly).

I'm not sure what exactly you're trying to do with a 3D texture, but it's certainly possible to store normals in one. Since a normal has no meaning anywhere else than the surface of an object, I assume you're using procedurally generated data and just trying to give an overall "bumpy" texture to objects of arbitrary shapes like one might in a ray-tracer (e.g. You slice the object in half, and the cut surface remains bumpy).

You could fill the 3D texture with "normal offset" values where each texel determines which direction the surface normal will be perturbed in at that point (red channel is X offset, green is Y and blue is Z). Then in a pixel shader, you add together the actual normal of the polygon and the offset from the texture, and re-normalize before light calculations.

It'd be fairly simple to render (no worse than 2D normal mapping), but I wouldn't know how to generate the data... Perhaps you could use the gradients between neighboring texels in a 3D scalar map the way you use the 2D gradients in the "old-fashioned" bumpmapping. So make a 3D scalar map, then for each texel calculate the 3 gradients and store them into the 3D normal map.
A 3D bump map is the same as a 2D bump map, with an extra dimension. That take be taken in various ways, so let me explain:

A 2D bump map is a 2D array of 1D height values.
A 3D bump map is a 3D array of 1D height values.

Any 2D slice (a 2D plane "sample") of a 3D bump map is a 2D bump map.

If I were to do 2D bump mapping, I could sample my 3D bump map in only x & y, and leave z at 0.0, and I would have a 2D height-based bump map.

Why 3D? With 3D there is no "mapping" from the bump map space to the object space (I am thinking of an object that does not move, like ground.) If I want a bump map height value at (10.0, 15.4, 4.5), then I can sample the bump map at (10.0, 15.4, 4.5). If you were to think of bump mapping a sphere, a 3D bump map is excellent where a 2D bump map is not, due to the mapping of the texture space to the object space. (Try wallpapering a sphere with a wood-like wallpaper in real life [2D] versus carving out a sphere out of a block of wood [3D])

The problem I have is the height value is not enough. I need to know the rate of change to perturb the original smooth surface normal.

I am getting ahead of myself. I was just curiuos to know what they "typical" solution is.

...

My 3D bump map is generated via noise functions (similar to and based upon Ken Perlin's gradient noise, aka Perlin Noise, function).

My function returns -1.0..1.0 values. I use me 3D noise functions for many different things in my renderer, and one of the things I use it for is to generate bump maps. So I cannot use a normal map!

I can see normal mapping being used when pre-storing is available, but my renderer cannot make use of pre-stored arrays. (It can, but it is very limited as we are watching our memory usage.)

Surely ray tracers that use 3D noise functions to generate their bump maps must also not use normal maps? Am I wrong?

Matthew Doucette, Xona Games

I dont have a clue as to what your are talking about, but the accepted method to acheive "bump mapping" in real time 3d is to use normal mapping. A normal map just stores per-pixel normal data in either world or tangent space.

However, there are ways to improve this effect, such as parallax mapping, relief mapping, etc.
I should have stated that this was not real-time rendering (seeing that I am on a game dev board)... sorry.

Matthew Doucette, Xona Games

Well I think the same thing applies to offline rendering.. normal mapping is still the way to go even then, but of course you can also do raytracing and such..
I cannot do normal mapping because my 3D bump maps are 3D textures that return a value from a -1.0..1.0 range. They are not pre-stored, and I cannot pre-store a normal map. Everything is procedural.

But I do not doubt that it is faster (using normal maps instead of height-based bump maps), as it removes the step of calculating the normal.

[Edited by - Matthew Doucette on October 5, 2006 6:12:34 PM]

Matthew Doucette, Xona Games

OK, now I get what you're doing... Anyway what I said about the 3D normal mapping still applies except you need to generate the "normal offset" per-pixel instead of storing it in a normal map. The easiest way would be to use the gradients.

Say your "texture" is a function f(X,Y,Z) that returns a value from -1 to 1. For any point, you can generate the offset vector V from the gradients like this:
V.x = (f(X-d, Y, Z) - f(X+d, Y, Z))/d
V.y = (f(X, Y-d, Z) - f(X, Y+d, Z))/d
V.z = (f(X, Y, Z-d) - f(X, Y, Z+d))/d

(This creates a vector which points "away" from areas of higher f(), so those areas will appear raised. d determines the accuracy, smaller d == mode accurate if your noise function generates small details, but could introduce floating point accuracy errors if too small)

Then, assuming you know the surface normal N, you want a modified surface normal N' that is something like:

N' = normalize(N + V*bumpscale)

where normalize() is a function that returns a unit vector, and bumpscale is the "strength" of your bump mapping, probably between 0 and 0.5.

Edit: Hrm, looking at your original post again this sounds like what you're already doing. Really the only difference is the accuracy and bump scale parameters which allow tweaking the appearance of the bump mapping. Nevertheless I believe ray-tracers like POV-ray use a very similar method.

[Edited by - Fingers_ on October 5, 2006 3:17:51 PM]
That is exactly what I am already doing.

(I rephrased my explanation of what I was doing in my first post, as I could barely understand it myself! Also, there's a small bug in your formula, as you should be dividing by 2*d, not d, as 2*d = width between sample points.)

I actually implemented an optimization trick, which allows only using four samples, which is to use the sample of f(x,y,z) for all three directions, and then only sample once in x, once in y, and once in z, to obtain the derivatives. (Ken Perlin takes credit for that one.)

I'm getting off track though, as I know about this method but was assuming there was another, more typical, 3d bump mapping method. I know how I can use Blinn's 1978 formula for a 3D bump map (his was for a 2D one), but I've yet to see any examples or usages of it on the boards. By the way, Blinn's method is 100% accurate, and the hack method I am using is not. I can give examples to show how it can be broken if anyone wishes...

Matthew Doucette, Xona Games

This topic is closed to new replies.

Advertisement