Realistic Water Reflection with CubeMaps?

Started by
4 comments, last by wis 22 years, 1 month ago
Hello, this is my first post so far... My question: is it possible to do a realistic (means non distorted) reflection on a planar water surface (one quad, no waves) with a CubeMap. Water Surface and sourrounding terrain is static, camera changes position. Background: I''m experimenting with landscape rendering and want my mountains to be reflected in a lake (without rerendering upside down and stenceling if possible). Here is a screenshot of my landscape engine with the lake, the lake is 25% transparent and is drawn using a 2D-Texture.

------------------------------------------------------------"Well, that's somewhat unstable by definition..."
Advertisement
> My question: is it possible to do a realistic (means non distorted) reflection on a planar water surface (one quad, no waves) with a CubeMap

Fast answer: No.

Complex answer: a cubemap is the full solution of the light incidence equation of a single point over a discrete sample range. It just hasn''t got enough information to do a planar reflection. You would need one full cubemap per fragment to get that...

The way to do it: treat your water surface as a flat mirror surface. Mirror your geometry around it and render it to a texture. Now, when drawing the water, apply this view depended reflection texture to the water surface using projective mapping and some kind of more or less fancy combiner equation. Especially, if you include the fresnel effect (can be nicely done using a 1D texture on a second or third texture unit), the result looks extremely convincing. You can even add waves to the water, resulting in distorted reflection, that looks totally awesome !
Thanks for your answer!

I''m not that experienced, but if I understood you right, the reflection isn''t precomputed (or is it?).
Isn''t there a way to precompute the reflection, e.g. have a texture with the reflection an map it perspectively to the water surface during runtime?
The reflection texture can be a approximation, I think nobody will recognize the approximation if I add waves (or wavy distortion).

Any answers are appreciated.
------------------------------------------------------------"Well, that's somewhat unstable by definition..."
Well, the problem with reflections (and also refractions) is that they are viewpoint depended. That simply means, that the content of the reflection texture changes, as the viewpoint moves. Imagine the following scenario: You have a reflective plane with a red cyclinder standing on it. A little blue box is behind the cylinder. Now your camera is positioned in such a way, that it looks on the front of the cylinder, you don''t see the little blue box, since it''s hidden behind it. What will you see in the reflection ? A red cylinder, no blue box. Now turn the camera around, so that the box becomes visible. It will also become visible in the reflection. But using your previous reflection map, no information about the blue box was included, and the reflection will be ''weird'', to say the least. This is simply, because the viewpoint has changed, but the reflection information was not updated.

So you have to update the reflection map, as the viewpoint moves. Or you could calculate every possible reflection map for every possible viewpoint... We are talking about billions of texture maps, even if a high quantization is used, and it will still look crappy.

The reason why a cubemap works is easy: it is actually a precalc of all possible viewpoints with respect to a point. Since a point has no space dimension, the exact viewpoint position is not needed, only the view direction. A cubemap does exactly that: it stores light incidence information only for variing light *directions*, but not position. But it only works on points. For doing that with a 2D surface, you would need to tesselate it with point-cubemaps, all over the surface, so that viewpoint position is taken into account. Here again, we''re talking about hundreds of thousands of cubemaps, and resolution still won''t be good.
You can actually fake a precalculated planar reflection, but this will only work with very far objects, such as the sky or the clouds reflecting in the water. It won''t work with near/local objects, such as mountains, boats, and whatever else is floating on the water. The only way to do real local reflections on a planar surface is recaculating them, if the viewpoint changes. But don''t worry, this isn''t slow. It actually is pretty fast, if your geometry is not too complex.

Thanks for your reply YannL!

Wasn''t home for a few days...
I see now, precalculation isn''t possible with realisitc reflections.
So i gotta, rerender upside down (unfortunately my geometry is fairly complex...).
Now, another question:
How to add wavy distortion?
- I think this would be possible with pixel shaders, unfortunately I don''t have a GeForce3, so I''m searching for another way...
-Is "Rendering to a texture each frame, or every second, third frame, then add wavy distortion to texture" the right way?

would be nice if YannL, or somebody else would answer!
------------------------------------------------------------"Well, that's somewhat unstable by definition..."
> So i gotta, rerender upside down (unfortunately my geometry is fairly complex...).

You could reduce the level of detail of your geometry in the reflection. If it is distorted, noone will ever see the difference.

quote:
How to add wavy distortion?
- I think this would be possible with pixel shaders, unfortunately I don''t have a GeForce3, so I''m searching for another way...
-Is "Rendering to a texture each frame, or every second, third frame, then add wavy distortion to texture" the right way?


Hmm. There are several ways. You don''t necessarily need vertex shaders, but they can speed up the whole thing. You can also do it on the CPU alone, it''s still fairly fast.

You need to distort the projected texture coordinates. One possibility is to project them on the CPU, getting s and t projected (in screen space), then displace them in 2D by an amount corresponding to the height of your water heightfield at that pixel position. Easy to code, but it''s ugly (IMO, looks very fake), and you don''t take advantage of hardware T&L. Not good.

Second (better) option: you transfer the 3D coordinates of every water mesh vertex as s,t,r 3D texture coordinates, and load your projection matrix into the texture matrix. Hardware accelerated projective texture mapping, very fast. Now for the distortion, that''s a bit more complicated. You trace a ray from each water mesh vertex along it''s normal (in object space) and intersect it with a virtual plane, floating a few cm over the water surface. Calculate the intersection point in 3D. Load it as s,t,r coordinates, and process them through the projective texture matrix. Here you go, extremely realistic distorted reflections, without pixel/vertex shaders ! And they are very fast. You can change the amount of distortion by adjusting the height of the virtual plane.

This screenshot uses the described technique, OK the geometry is trash (I''m a *very* bad modeller ), but the reflection is rather realistic. Though, it also uses an additional fresnel modulation on a second texture unit. The water surface is calculated in realtime by a 2D Navier Stokes solver.

http://www.geocities.com/jonalomb/dis/water1.jpg

Now, I know that''s rather complex stuff, so if you have questions, just ask

This topic is closed to new replies.

Advertisement