Water Reflection and Refraction with normal map with out pixel shaders

Started by
26 comments, last by JHL 20 years, 2 months ago
I understand more or less how to do this with pixels shaders and a cubemap and such. But with out pixel shaders how can I generate coordinates into a cube map? I''m also considering it might be possible use some sort of 2d texture for the reflections sence water will never reflect down.
Advertisement
Depends on your definition of ''pixelshader''. If you want per-pixel indexing into a cubemap (ie. real EMBM), then you''ll need a GF3 minimum, as it requires a 3x3 matrix transform per pixel.

Below that minimum, there is no way to get per-pixel indexing into a cubemap. You can still do it per-vertex, though, and interpolate over the surface. It generally looks OK, although you won''t get per-pixel reflection, obviously. The same can be done using a 2D spheremap, instead of the cubemap: old style spherical environment mapping.

And then, there is still another method of doing water reflections (the best looking, IMO): by computing the real flat geometric reflection on the water plane (just as with standard stencil reflections, rendered into a texture). And perspectively projecting it back onto the water surface, while distorting the texcoords. Here again, you can either do it per-vertex (the distortion will only be influenced by the vertex normals) or per-pixel (the distortion will be influence by a bump-map, needs pixelshaders).
I tried rendering all the reflections into a texture, and then render it (as a flat plane), on the water surface, but it looked ugly.
By ugly, I mean that, whenever you moved the camera, the texture was flickering a LOT, nastly. That happened with a 256x256 texture. I treid with a 512x512 texture, and it did look a little better, but it was much slower...


Height Map Editor | Eternal Lands | Fast User Directory
You should use a texture with the same size as the screensize projection of your water surface. Usually, a 1024² texture is OK. The speed obviously depends on your hardware.

But even with lower resolution textures, it shouldn't flicker - it will only look blurred (which isn't that bad either). If it flickers, then you have a precision problem (rounding error) in your texture projection.

Here is an older shot of a simple water test. It uses the basic reflection model mentioned above (no refraction, Fresnel or other fancy effects, just raw reflection). The projected texture resolution is 256². There is no flickering, just a slight blurriness in the reflection (yeah, I know the 3D scene sucks, I suck at Maya...).


[edited by - Yann L on April 12, 2003 4:35:35 PM]
Well I have to do the planar reflections any ways for local objects like ships and such (its an rts) but I was hoping for more ocean look I think I''ll have to settle for pervertex.
Yeah, in that case, you''ll have to do the environment mapping per-vertex.
Yann, mine flicker because most of my plants use alpha testing. So, they have this tendency to flicker anyway, but they don''t flicker that bad. However, when they flicker in a 256 texture, that flickering is greatly amplified, especially in high resolutions...
And your water screenshot rulez, yet again
Why can''t I get similar results? But then again, I''d have to see it animated....

Height Map Editor | Eternal Lands | Fast User Directory
quote:Original post by Yann L
And perspectively projecting it back onto the water surface, while distorting the texcoords. Here again, you can either do it per-vertex (the distortion will only be influenced by the vertex normals) or per-pixel (the distortion will be influence by a bump-map, needs pixelshaders).


How to distorting the texcoords,per-vertex?
Use the View Space vertex normal.x and normal.y?

quote:
Yann, mine flicker because most of my plants use alpha testing. So, they have this tendency to flicker anyway, but they don't flicker that bad. However, when they flicker in a 256 texture, that flickering is greatly amplified, especially in high resolutions...

Ah OK, I see. Yes, that can of course lead to annoying artifacts. The only ways to solve that would either be a higher resolution projective texture, or alpha blending instead of alpha testing.

quote:
Why can't I get similar results? But then again, I'd have to see it animated....

Hey, this one is really easy, you should definitely be able to get similar results. Render the reflection into a texture, project it back while distorting the texcoords. That's it. Try the distortion method I explain below.

quote:
How to distorting the texcoords,per-vertex?
Use the View Space vertex normal.x and normal.y?

Different methods of varying complexity exist. Here is a very simple one, kind of hackish, but looks nice (the shot above uses that technique).

You displace the 3D texcoords prior to projection (ie. before they went through the texture matrix). You can do that in a vertex shader, if you want. First, we don't need to take the eye position into account, this is already done by the camera + texture back projection matrix. So we are left with the vertex position and normal (coming from the water mesh). Consider an imaginary plane floating slightly above the undisturbed water surface. The distance between that plane and the surface will change the strength of the distortion, you'll have to experiment a little. Now, let's assume that the water surface is on the XY plane, with a z-height of 0. The imaginary plane floats slightely above it, still in the XY plane. Now, imagine the normals sticking out of the vertices on the water surface. Compute the intersection distance between the water vertex and the virtual plane above, in the direction of the normal. That is you displacement offset. You can approximate, if you want, the exact distance is not needed.

Now, go back to your real (non-flat) water surface. Displace the 3D projective texcoords of the vertex by the displacement offset, along the normal. Now project as usual. Done.

Little code snippet:

    // N is the vertex normal, TC the 3D projective texcoords (ie. the vertex position, that gets projected to screenspace texcoords)// get the displacement offsetfloat dofs = VIRTUAL_PLANE_HEIGHT * N->z;// Displace the texcoords (vertex position) by the offset, in the direction of the normalTC->x += dofs*N->x;TC->y += dofs*N->y;TC->z += dofs*N->z;// The projective texcoords are now floating above the surface, on the virtual plane.// We don't want that. Correct the height. Little hackish, but works.TC->z -= VIRTUAL_PLANE_HEIGHT;// Now you can feed the texcoords TC to the projective matrix (in the texture matrix), and render the surface with the projective texture.// ...    



[edited by - Yann L on April 13, 2003 7:28:52 AM]
Yann,Thank you.

I have a question about the Normal.
"TC->x += dofs*N->x;
TC->y += dofs*N->y;
TC->z += dofs*N->z;"
the N is the vertex normal in world space or in view space?

This topic is closed to new replies.

Advertisement