Home » Community » Forums » Graphics Programming and Theory » Water Reflection and Refraction with normal map with out pixel shaders
  Intel sponsors gamedev.net search:   
[Control Panel] [Register] [Bookmarks] [Who's Online] [Active Topics] [Stats] [FAQ] [Search]

Add Forum to Favorites |  Send Topic To a Friend | View Forum FAQ | Track this topic

Page:   1 2 »»

 Last Thread Next Thread 
 Water Reflection and Refraction with normal map with out pixel shaders
Post New Topic  Post Reply 
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.

 User Rating: 1033   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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).


 User Rating: 1996   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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

 User Rating: 1598   |  Rate This User  Send Private MessageView ProfileView Journal Report this Post to a Moderator | Link

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]

 User Rating: 1996   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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.

 User Rating: 1033   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Yeah, in that case, you'll have to do the environment mapping per-vertex.

 User Rating: 1996   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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

 User Rating: 1598   |  Rate This User  Send Private MessageView ProfileView Journal Report this Post to a Moderator | Link

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?



 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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 offset

float dofs = VIRTUAL_PLANE_HEIGHT * N->z;

// Displace the texcoords (vertex position) by the offset, in the direction of the normal

TC->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]

 User Rating: 1996   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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?

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Doesn't really matter, you can do it in world or in eye space. Just make sure to stay consistent in your coordinate frames, ie. if you do the distortion computations in eye space, make sure to displace the eye space texcoords.

I would suggest doing the distortion in world space, and doing the world->eye->screenspace transforms and projections with a single texture matrix, in a vertex shader.


 User Rating: 1996   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

quote:
Original post by Yann L
Doesn't really matter, you can do it in world or in eye space. Just make sure to stay consistent in your coordinate frames, ie. if you do the distortion computations in eye space, make sure to displace the eye space texcoords.

I would suggest doing the distortion in world space, and doing the world->eye->screenspace transforms and projections with a single texture matrix, in a vertex shader.



I calculate the vertex texcoords(u,v) is base on view space(x.y),because use reflection/refraction map.
If use the vertex normal in view space to calculate distortion,the problem is on the "calm" water surface the vertex normal(view space)'s x,y is possible unequal to zero.
But the fact is when on ripple on the water surface,the vertex texcoords(u,v) shouldn't be distort,because the reflection map produced by the "calm" water surface flip.

If calculate in world space,how to get the correct relation of the normal-x,y,z and texcoords-u,v? The texcoords(u,v) get from vertex position in view space.

sorry for my poor english.


 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

OK, let's start from the beginning.

You have your reflection map in unit 0. Now, you need projective texcoords to adress unit0, so that the texture reprojects the same way into screencoords that it had been 'captured' before.

The reflection texture was rendered from the camera viewpoint, through the camera transform and projection matrix. To reproject the texture the same way onto the screen (and the water mesh), you need to perform the exact same computations again, only with the texture coordinates.

So, for each water mesh vertex you render, loads it's 3D position also into a 3D texture coordinate set:

TC.u = P.x, TC.v = P.y, TC.w = P.z (Eg.1)

Now, the texcoords equal the 3D worldspace position of the water mesh vertex. Now you apply the same camera view and camera projection matrices to those texcoords, as you previously did to render the reflected geometry (except for the reflection matrix, of course). The easiest way to accomplish that, is to load the combined camera/projection matrix into the texture matrix.

If you do that, without any further processing, you will get a perfectly calm reflective water surface. Now, consider Eq. 1 above: if you displace the texture coordinates TC (in worldspace here !) with the worldspace normal, before transforming them by the camera view and projection matrix, then you will get correct behaviour.

Example: in worldspace, a normal of (0,0,1) (assuming z pointing up) denotes a calm surface. Let's also assume, that the virtual plane is at 5 units above the surface:

dofs = 5 * N->z = 5

TC->x += dofs*0 == TC->x += 0
TC->y += dofs*0 == TC->y += 0
TC->z += dofs*1 == TC->z += 5

TC->z -= 5

As you can see, no changes are done to the coordinates. That is correct behaviour for calm surfaces. Note that, depending on your worldspace coordinate frame orientation, you might have to flip the sign of the virtual surface distance.


BTW, I'm planning to give an IRC lecture about realistic realtime water rendering shortly (exact date/time confirmation pending). You might want to drop in.


 User Rating: 1996   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Now I'm missing a step before this, How would I get good animated normals for my vertexes?

 User Rating: 1033   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Depends on your wave-model. Normally, you first compute the vertex heights using a model such as Fourier synthesis (FFT), Perlin noise, or the Navier Stokes equations (NSE). Your water surface is nothing but a heightmap. Then, once you have your heights, compute the normals by using finite differencing.


 User Rating: 1996   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

quote:
Original post by Yann L
OK, let's start from the beginning.

You have your reflection map in unit 0. Now, you need projective texcoords to adress unit0, so that the texture reprojects the same way into screencoords that it had been 'captured' before.

The reflection texture was rendered from the camera viewpoint, through the camera transform and projection matrix. To reproject the texture the same way onto the screen (and the water mesh), you need to perform the exact same computations again, only with the texture coordinates.

So, for each water mesh vertex you render, loads it's 3D position also into a 3D texture coordinate set:

TC.u = P.x, TC.v = P.y, TC.w = P.z (Eg.1)

Now, the texcoords equal the 3D worldspace position of the water mesh vertex. Now you apply the same camera view and camera projection matrices to those texcoords, as you previously did to render the reflected geometry (except for the reflection matrix, of course). The easiest way to accomplish that, is to load the combined camera/projection matrix into the texture matrix.

If you do that, without any further processing, you will get a perfectly calm reflective water surface. Now, consider Eq. 1 above: if you displace the texture coordinates TC (in worldspace here !) with the worldspace normal, before transforming them by the camera view and projection matrix, then you will get correct behaviour.

Example: in worldspace, a normal of (0,0,1) (assuming z pointing up) denotes a calm surface. Let's also assume, that the virtual plane is at 5 units above the surface:

dofs = 5 * N->z = 5

TC->x += dofs*0 == TC->x += 0
TC->y += dofs*0 == TC->y += 0
TC->z += dofs*1 == TC->z += 5

TC->z -= 5

As you can see, no changes are done to the coordinates. That is correct behaviour for calm surfaces. Note that, depending on your worldspace coordinate frame orientation, you might have to flip the sign of the virtual surface distance.


BTW, I'm planning to give an IRC lecture about realistic realtime water rendering shortly (exact date/time confirmation pending). You might want to drop in.



Thanks for your help!I have understood.
I'II expect your lecture.




 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Calculate the refraction offset(in world space):
The water plane is XY plane.
1 Calculate the view vector
2 Calculate the refraction vector per-vertex
3 Use the virtual plane(below the water plane) to intersect the refraction vector.
4 offset the u,v
TC->x -= ( intersected refraction vector ).x
TC->y -= ( intersected refraction vector ).y

the steps above is correct?

[edited by - sevecol on April 13, 2003 2:28:38 PM]

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

I just had interesting idea if I'm using a flat plane reflection, I'm wondering if I can use a series of animated texture offset bump maps tiled over the waters surface, normaly that wouldn't look right but I'm wondering if its possible to modulate the offset values by like a diffuse color value. Something that can be generated by the vertex shader so that I can make the offsets perspective correct (well as least make them shrink as they get farther from the camera), Is that possible?

 User Rating: 1033   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

I am trying to implement this also, but I can't get the reflection part working. I am not sure how exactly to setup my OpenGL viewmatrix to reflect the scene.

I found the DirectX function D3DXMatrixReflect and tried to convert it to OpenGL but that failed. Can someone show me the correct way?

 User Rating: 1015    Report this Post to a Moderator | Link

(For future reference: I'd prefer that you start a new topic and link to the old one, rather than pulling up a year-old thread, please.)

 User Rating: 2119   |  Rate This User  Send Private MessageView ProfileView JournalView GD Showcase Entries Report this Post to a Moderator | Link

ah the memories...

the easiest way I can think of is to multiply your view matrix by
0,0,-1,2*WaterHeight
0,0,-1,2*WaterHeight
0,0,-1,2*WaterHeight
0,0,-1,2*WaterHeight
or at least thats what I think it should be in opengl format and well I'm up at 3:00 in the morning.

this is as good an excuse as any to post a link to some screens of my game that I've apparently been working on over a year http://host67.ipowerweb.com/~reveriee/forums/viewtopic.php?t=176

 User Rating: 1033   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Ok, changed it, but now I have a real strange artifact. When I render the face, it looks likes it's being split as you can see in a simle screenshot.

http://members.lycos.nl/fransis123/screen1.JPG

On that shot you can clearly see (please ignore the incorrect mirroring..) that the mirror is split in 2. Any clue what that can be?

What I do it re-rendering the scene to texture with the WGL_ARB_render_texture extention. Then I project it to the screen like Yann explained above.

 User Rating: 1086   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Holy Hell JHL that looks like an amazing game! The soft shadows from the trees and the "model grass mat" looking grass effect is top notch, I can't wait to see it play.

 User Rating: 1101   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

thanks maniac,
jeroenb it looks like maybe the texture coordinates on those reflection triangles are wrong

 User Rating: 1033   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Ok, I will have a look at it again. I fixed the reflection already, so that part is at least working. Though I dont supply the texture coordinates: opengl generates them with texgen (eye linear). I wouldn't know how I can change the generated texture coords. Maybe I could adjust the texture matrix a little.

At the moment it also looks like it has something to do with the near plane. As when I am far enough away from the reflection plane there is no distortion anymore. But when I zoom in to that plane, the line comes back.

ps. Great screenshots! I hope my game will comes to 1/10'th of that

 User Rating: 1086   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link
Page:   1 2 »»
All times are ET (US)

Post Reply
 Last Thread Next Thread 
Forum Rules:
You may not post new threads
You may post replies
You may not edit your posts
You may not use HTML in your posts
Jump To:
Administrative Options: