A quick and dirty environment mapping and fake tangent space AO

4a93ba032c357d782afb0820f328d14e
0
zavie 101 Dec 19, 2010 at 09:00

10-12-17.jpg

Description
Hi,

It’s been years I haven’t been active here, and I suddenly decided I would try to make a contribution of some kind.

What you see here is a comparison of the same mesh textured a bit differently.

The mesh is completely flat, and any feeling of volume is only given by the good old parallax mapping and normal mapping (a shader fairly easy to write, cheap, and giving good results as long as you don’t get in the cases that screw it completely).

It is lit by a single light; the blue and orange tones are given by some simple environment mapping. Remember the usual equation albedo * (ambient + diffuse) ?
Usually ambient is a constant is lighting tutorials, but getting inspired by the spherical harmonics papers, I tested the generation of a simple square texture describing the color of the ambient light: longitude along x, and latitude along y.

In the shader it becomes :

vec4 getAmbient()
{
  float invPi = 1. / 3.14159265358979;

  vec3 wNormal = (vec4(nNormal, 0.) * cameraMatrix).xyz;
  vec2 uv = vec2(0.5 * invPi * atan(wNormal.x, wNormal.z), invPi * atan(length(wNormal.xz), wNormal.y));
  return vec4(vec3(texture2D(aMap, uv)), 1.);
}

* nNormal is the normal;
* cameraMatrix will allow us to get wNormal, the normal in world coordinates (otherwise the ambient light will seem to be attached to the camera);
* aMap is the texture the ambient map is bound onto.

Now the part being compared in the image is the fake ambient occlusion. Notice how edges look lighter and inner corners look darker on the right? Even the round parts look a bit darker than the flat ones. The effect is very faint, and you probably wouldn’t notice, but when you compare the images, there is a difference. The left one looks flatter, and somehow less interesting.

This is done very easily, during the normal map creation: the normal map is created thanks to a heightmap, and so is a fake AO map. Fake, because it doesn’t rely onto any math, just out of intuition. The idea is to consider that a higher element will to some extend prevent surrounding lower elements from being lit. So a fake shadow is generated from the heightmap with a convolution filter like this for example:
0 -1 0
-1 4 -1
0 -1 0

Also, the farther the elements, the softer the effect. Therefore this is done repeatedly, each time with a more blurry version of the heightmap, and with an increased distance for filter (well this is not a convolution anymore). This would probably work by reducing the size of the texture each time too; I haven’t tested.

Anyway this is all about a hack, and about having quickly a fairly interesting result. :-)

6 Replies

Please log in or register to post a reply.

6837d514b487de395be51432d9cdd078
0
TheNut 179 Dec 19, 2010 at 14:47

That convolution filter is quite close to a Laplace filter. I’m looking at this algorithm more as using edge detection to provide enhanced lighting detail around the edges, especially for specular materials. Interesting stuff.

It’s sort of funny when you look at your images. They can either appear bevelled in or bevelled out. The former looks interesting, the later does not :)

4a93ba032c357d782afb0820f328d14e
0
zavie 101 Dec 20, 2010 at 01:43

Well after all that filter is a derivative one, and ambient occlusion approximation is all about considering the local curvature of the surface.

Now that you mention the bevel thing, that’s true. I never noticed because I always had some visual clue (moving camera and dynamic light), which are not present here. :)

Also as an additional note, I discovered that the envmap trick doesn’t work with mip-mapping (or anisotropic filtering): the discontinuity introduced by the arctan results in some ugly pixelated artifacts. It works fine with simple linear interpolation though.

(edit: typo. Note to self: do not trust spell checker suggestions)

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Dec 20, 2010 at 04:26

You might try getting the ambient color from a cubemap lookup rather than the arctan stuff. That should mip well, and you will be able to use it on a surface of any orientation as it will encode indirect illumination from all directions.

Could you post a copy of the image in PNG or another lossless format? Unfortunately the site encodes these images in JPEG, which saves server space but introduces a lot of artifacts - not good for fine-detail graphics comparisons like this. :huh: Also, maybe you could post an image of the fake-AO component alone, without any lighting or normal map?

How much of an effect is there from the repetition with blurred heightmap / increased filter radius? Most of the differences I can see in the two images are quite fine. It seems almost an artistic effect, like a painter might use to bring out the edges. Anyway, it’s quite pretty. :)

F97e7248a82cc7e1e422eae96f425bfa
0
refleX 101 Dec 21, 2010 at 07:35

It looks beveled in if you focus your eyes on the inside then move outwards, but it looks beveled out if you focus your eyes on the outside and slowly move your focus across the edge towards the inside. It seems as if your brain takes the object you looking at first as having a greater depth. Could be because when you look at a room your eyes first focuses on the farthest wall, then it focuses on an object in the room which has a lesser depth.

Fd80f81596aa1cf809ceb1c2077e190b
0
rouncer 103 Dec 22, 2010 at 01:58

the cross is definitely pressed inwards, i can tell ive been looking at no parallax maps for bloody ages.

4a93ba032c357d782afb0820f328d14e
0
zavie 101 Dec 22, 2010 at 19:08

@Reedbeta

You might try getting the ambient color from a cubemap lookup rather than the arctan stuff. That should mip well, and you will be able to use it on a surface of any orientation as it will encode indirect illumination from all directions.

This is very likely. But the reason for using a simple square texture was to avoid the burden of setting up a cubemap.
@Reedbeta

Could you post a copy of the image in PNG or another lossless format? Unfortunately the site encodes these images in JPEG, which saves server space but introduces a lot of artifacts - not good for fine-detail graphics comparisons like this. :) Also, maybe you could post an image of the fake-AO component alone, without any lighting or normal map?

Here you go!
http://twitpic.com/3igb5n/full
http://twitpic.com/3igorx/full

Without AO on the left, with AO in the middle, and the AO map on the right.
I took those capture with more tilting, to show the effect of the parallax. Notice though how it introduces artifacts near the corners. Parallax mapping really don’t like discontinuities.

Also, don’t pay too much attention to the lightness. This is really done in a quick and dirty way, so the luminosity is a bit overlooked. :-) I adjusted the weights in the light equation afterwards.

Here is another example of AO map, with a different heightmap:
http://twitpic.com/34jc5h/full
@Reedbeta

How much of an effect is there from the repetition with blurred heightmap / increased filter radius? Most of the differences I can see in the two images are quite fine. It seems almost an artistic effect, like a painter might use to bring out the edges. Anyway, it’s quite pretty. :)

I haven’t compared too much the effect of different values, but this is sure something to test.
As you point out, it reminds the way artists enhance shapes.