Bump map flitering

On again with the same problem …

I use a bump map for my water rendering. this bump map is used for dependant texture lookup in a cubic map (bumped reflection or EMBM as some enjoy to call it).
I add a Fresnel term to have nice reflection (this term is the percentage between diffuse texture and reflection texture, the reflection texture is the cube map looked up via the bump map).

But … on the horizon, I get a full mirror of the skybox, because the normal coming from the bump map is filtered and points “up” everywhere around the texture. At this point, I use automatic mip map constructions and trilinear filtering.
How am I supposed to filter my bump map so that it does not give this nasty effect ?

For those who are about to answer “filter manually”, they did not understand the question that is, precisely, what kind of filtering do I have to manually set up ?

Screenshots at the same place : http://ffiw.succubus.fr
( this is my first web page :] )


When I look at water at a distance, all the tiny ripples tend to blend together to just make the reflection look blurry. Would it be possible to get opengl to index lower levels of your sky cubemap than it wants to. So, if the reflection would normally index the 4th mipmap level, you would force it to index the 8th or something like that. Or is this what you’re trying already?

No, I’m not trying to do that. I’m trying to get “varying normals” at horizon, instead of plain non bumped up vector everywhere.

I’m wondering if there is another to get this than “artist generated” …


To make it so that you can see bumps really far away (assuming that you’re just adding sine waves) the simplest thing to do is to make sure that one of your sine waves has a wavelength as long as two opposite corners on the texture and that that sine wave has a larger amplitude than all the others.

I think blurring should be the most correct way to simulate water in extreme cases. Once your eyepoint gets far enough away that a bump in the water shrinks down to one pixel on the screen, all the normals that that pixel represent will cover a 30 or 45 degree sweep. The only texels in the sky cubemap that would represent such a wide sweep would be in a very deep mipmap level.

1st, I’m not an expert at bump mapping in GL.

Would it be possible to take into account the length of the normals at the horizon, so that the reflection at the horizon gets slightly darkened? If the mipmaps are plain RGB normals, then the smallest automatically generated mipmaps should have “shorter” normals (i.e. approaching 0.64, in the case of randomly distiributed 1.0 length normals pointing in the range -90 to +90 degrees, where 0 degrees is up).

I’m not sure if this would look any better. In any case, I think the screenshots look very nice. The only problem seems to be that it’s difficult to see where the water stops and the sky starts (which should probably be solved by the above proposed solution).

mogumbo :
the bump (normal) map are artist generated, and I would prefer not to ask them to generate all the mip levels too. The texture is animated, so they would have to generate them for every animation step.

marcus :
I don’t need the normal to be normalized, as it only serves for a lookup in the skybox (cube map). Actually it gets normalized, to compute the fresnel term, that, by definition, makes the sea like a mirror at the horizon.

My problem is that I want the lowest level of the mipmaps of the normal map not uniformly “up”. Of course artist could generate by themselve these levels, but there may be a way to filter them differently that with the standard OGL gluBuild2DMipMaps that gives uniform color (0.5, 0.5, 1.0) at horizon.

Which way ?

[edit] just added a picture : the last screenshot on the page http://ffiw.succubus.fr shows this artifact very clearly. [/edit]
[edit2] the direct link to this picture is here [/edit2]


[This message has been edited by SeskaPeel (edited 01-13-2004).]

(is it the jpeg compression or the mipmaps are bilinear filtered ?? trilinear/anisotropic would be better)

To do the mipmaps yourself, maybe you can do that :

  • each level is done from level 0, to keep maximum information.
  • for any pixel : sample all the level 0 texels which are directly ‘above’, and find the average direction of the normal, as well as the variance. Then, modify randomly the direction depending on the variance.

Other method :

  • Try to use the median (is that the right word in english ? In french : médianne ) instead of the average of the direction, and randomize it slightly.

Well, I think that a statistical/histogram based solution mixed with a bit of randomness could do the trick.
Or as said earlier, instead of noise, add a low frequency sinusoïdal signal to the lower mipmaps.

[This message has been edited by ZbuffeR (edited 01-13-2004).]

This is an uncompressed TGA. Filtering is trilinear with anisotropy 2.

The texture is tiling, and must stay seamless, so adding a random in the filtering process doesn’t sound like a good idea.

I don’t know about all filtering methods, but I wonder if one could keep some details in the lowest mip level …


Originally posted by SeskaPeel:
…but I wonder if one could keep some details in the lowest mip level …

The lowest mip have only one pixel, no ? Perhaps it is possible to add a sine wave to the normal, based on world space position ?

BTW, at http://www.virtualskipper3-lejeu.com/ you may try the demo of VirtualSkipper 3, they have a very good looking water (even with my gf3). But they do exhibit glitches with reflected geometry near the horizon.

As said mogumbo, a good way to deal with that would be to make the reflection look blurry. Look at the real sea ! I’ve googled “sea horizon” and found those particularly interesting : http://www.mikejs.com/pics/scotland/skye_horizon.jpg http://www.r7.fws.gov/mmm/images/otter/soship.jpg http://www.louisvillescience.org/imgs/sea%20and%20desert.jpg

You’ll have to algorithmically generate you mipmaps yourself. Most cards implement SGIS_generate_mipmaps by just averaging 4 pixels together to create the new, filtered pixel. That is, they use a simple 2x2 box filter where every component of the filter is 0.25. Try using a larger filter with non-uniform weights. There is lots of material available on this subject in the library and on the web. Basically, you want a filter that preserves some of the high-frequency components of your data.

idr : thanks

Would a non 2x2 box filter do it (eg a 9x9) ?
What would give filtering all the mip levels from the base one, incrementing the number of sample pixels : level 0 unchanged, level 1 box filter 2x2, level 2 box filter 4x4, level 3 8x8, etc … ?

Should I use another filtering method than “box” ?


maybe you can restrict the lowest MipMap level to use by setting the GL_TEXTURE_MAX_LEVEL parameter of the texture object. So you can enforce thatthe smallest MipMap level that gets used is e.g. 16x16 pixel.

As ZBuffeR mentioned, the lowest level of your mip maps is going to be a 1x1 texture. No matter what you do that will always be uniformly something.

Even if you put a random variation in your second to last level (2x2) it will most likely look strange.

Maybe you should try it without mip-mapping?

Note that the signal processing kernels (Kaiser, Sinc, etc) don’t actually work right for images. The reason is that signal processing assumes that samples are instantaneous readings of a band-limited signal. However, most image capture equipment take summed-area readings of un-band-limited signals.

Wavelet transform is actually able to deal with things like that, so if you bone up on your algebra and formulate the right wavelet transform, you can create a better MIP mapping function. (Personally, my education was sadly lacking in wavelet theory)

Have you tried clamping the lowest MIP level? It will probably give you some aliasing, but it sounds like that is more or less what you’re after

The problem isn’t that the box filter is 2x2. The problem is the weights are uniform. As a couple other people also mentioned, clamping the min lod to not use the 1x1 mipmap will also help. I hadn’t thought about that before.

ScottManDeath :
yes, this is it. I’ll try, and if it gives good results, I’ll post screenshots.