Sign in to follow this  
jfdegbo

Water reflection edges artefacts (GLSL)

Recommended Posts

[EDIT : here is a video of the (temporary?) solution used, XViD codec.] Hello, i'm working on a water system, very HL2-like. in fact i use a 3 pass method 1- reflected scene (clipped) - clear frame and depth buffer 2- refracted scene (clipped) with volumetric fog 3- the water plane (using the refeflect and refract textures) & the upper world (clipped, again). The water is rendered using a normal map, and the vectors of this normal map are used to offset the texel reading in the to other maps. My problem is very common, but I didn't find information about how devs handle it. As you can see there are gasps at the edges. Image Hosted by ImageShack.us I think a lot about it and founded some solutions, some of them are not realistic in terms of perf. Others are introducing other errors. 1 - Calculate the Y value on a per fragment basis of the bump mapped water and clip per fragment the reflected scene (heavy cost) 2 - Offset the clipping plane by the maximum height of a wave in the water texture (in fact simulated height, as it is a plane), to try avoiding "to run out of reflect to show" (a few more reflect is drawn than necessary to fill the gasps. the second method works quite well to remove those artefact, but make some new ones a different stages. Indeed, the reflects are sometimes visible where it should not. Image Hosted by ImageShack.us To exaplain, i drawed a blue line where the cube intersect the water plane. No reflects of the cube should be seen above that line... this is unfortunately the case, and it is fairly logical... that is because i shifted the clipping plane of the reflected scene. Sorry for the legnth of the post. I would really apreciate help, or knowledge on how does devs handle this problem. Thanks in advance. [Edited by - jfdegbo on July 22, 2006 9:22:14 AM]

Share this post


Link to post
Share on other sites
Actually, Half-Life 2 has the same problem.
http://techreport.com/etc/2004q3/source-engine/5950-noreflect.jpg
It can't be solved because of the nature of the method you use.

Share this post


Link to post
Share on other sites
Well, I'm not sure of what I see in this screenshot, anyway, i didn't remember seeing a lot of artefact in the source engine on the "edges of the water".

But I noticed in their engine that the deformation is mostly X axis driven... Don't know exactly why.

No one ever did this water effect and got rid of those gasps ?

Thx

JFD

Share this post


Link to post
Share on other sites
yes Hydrael,

that is what I did, but there comes the second screenshot...
It's strange not to have more feedback, I think every one who wants to do water reflections (without cube map) falls onto the same problems.

Share this post


Link to post
Share on other sites
Oh, sorry jfdegbo - I've only read the first half of your first post, because I once had the same problem (regarding the artifacts).
Regarding the succeeding problem I can't help you, because I haven't had any situations within my engine yet, that would make such "wrong reflections" appear.

I guess you did try to play around with the clipping plane's offset a bit? Maybe there there is a value, that "minimizes" both problems.

Share this post


Link to post
Share on other sites
The problem is just logically unsolvable.
You're trying to access a position in the texture that doesn't exist, so it just wraps around.
Look more attentively at the screenshot I've posted.
You will notice the brown artefacts at the edges, just like in your screenshot.
Valve did two things to minimize the visibility of the artefacts in Source.
First of all, they use smaller waves. It obviously makes the gaps smaller.
They also make the color of the gaps close to the color of the ground to make it less noticeable.
If you doubt, run HL2 and play the 'd1_canals' maps.
It's extremely noticeable there.

Share this post


Link to post
Share on other sites
Hydrael : No problem, i'm pleased that you respond !
in fact, this would apear when you place your eyes near that plane ... very close to the surface... like when swimming with the head out of the water

mrbig : In fact no, there's no wrap, i think you misunderstood the problem. It comes from the fact that once cut, the geometry of the clipped reflections does have "holes" that is uncapped intersection with the clipping plane, i you see what I mean.

Share this post


Link to post
Share on other sites
Please excuse me for my ignorance, but no, I don't see what you mean.
Whether it wraps or not doesn't matter.
You're trying to draw something that doesn't exist, but it has to draw something, so that's what it does.
http://img91.imageshack.us/img91/6788/omggy2.jpg
The red line in the picture above is the refracted reflection of the shoreline, which I have marked green.
You see, the shoreline's reflection is over there, any further than that and it just draws the void inside your shore!
There's nothing there and there can't be, so it probably fills it with the clear color you set.

Share this post


Link to post
Share on other sites
I know, and I don't exclude changing of technique in any of the stages... but I have no clue to do it in another way in real time. That's why I'm asking commets / suggestions.

Thanks for your response anyway mrbig.

Share this post


Link to post
Share on other sites
Guess what?
In DX9 mode, Source uses a shader which reduces water refraction in areas with shallow water.
This way you could both smooth out the shorelines AND get rid of the artefacts!
The simplest way to implement something like that is using a texture.
Calculate the points where your water plane intersects the shores.
Save these points.
These points make up your water surface.
Now make a refraction amount texture, like this one: http://img291.imageshack.us/img291/3829/refractionmapvq6.png
Stretch it over your water surface using texture coordinates.
The (grayscale) texture contains values between 0 and 256 exclusive. (Black to white.)
For every fragment of your water surface, multiply the default refraction amount for the current fragment by the value in the texture (put it in range of 0 to 1 first).
This should do the trick nicely!

This is, of course, all in theory.
It shouldn't require DX9 and should be very cheap.

Share this post


Link to post
Share on other sites
Great !
I've just finished implemnting a new algorithm... works quite good !
Many many thanks mrbig ! I owe you one :-)

For those who are interested, I did not implement the method but got mine while reading mrbig's post.

I just kept the idea of fading the waves away on the shores. In fact computing intersections in real time and for each frame (I want the system to be fully flexible and dynamic) would have been too expensive (not speaking of the texture generation).

I just do one extra pass before the refraction, giving the fragment a shade of grey, the deeper, the lighter. I then redraw the real refracted scene, using the shaded Y-depth to attenuate the waves... Here is a vid showing it working, on the end you can see it is dyunamic with the object dynamically spawned on the water. This system has limitations to a certain type of shores pointing upwards, but as the advantage to be very, very fast.

Here is the vid : XViD codec.

Share this post


Link to post
Share on other sites
No, no, no, you got it all wrong!
You only need to calculate the intersection points and texture coordinates once.

[EDIT]

Oh, flexible and dynamic...
But why would you need to change your water surface in real time?

[EDIT]

You don't need to generate the texture at all.
You can just use the one in my previous post.

Share this post


Link to post
Share on other sites
But the intersection points and texture coordinates don't change. Nor does the refraction amount texture.

Share this post


Link to post
Share on other sites
I found a partial solution to this problem. I took the heightmap of the terrain and scaled it so that it was 0 at the shore, and 1 just a little further out. Then I used this to scale down the distortion of both the reflection and refraction near the shores, which gets rid of the glitch in most cases. You can also use this factor to introduce more refraction near the shores, like mrbig said. That way you can get rid of the hard shorelines. Here are the results:

hard edges
soft edges

If you want to see it in action try downloading my aQuaterra demo (click on the downloads tab)

I say partial solution because the way I did it only works on the terrain. But it could easily be extended to the rest of the scene, and the fadeout factor could be computed as a pre-process, making the performance optimal (a texture lookup and a multiply)

Also you might find this thread helpful.

Share this post


Link to post
Share on other sites
Quote:
Original post by jfdegbo
yes is does, at the actor's intersection with the water plane


Ooooh, you're right!

P.S:
Wow, James, that looks good! :D
The only problem is, your method is brilliant for terrains, but it won't work for dynamic models.

P.P.S:
Jfdegbo, how do you calculate the Y-depth?

Share this post


Link to post
Share on other sites
thanks for all this information james...

mrbig : i just interpolated it from vertex to fragments... but in viewspace. Maybe i'll figure out another solution, but as the shader is extremely simple and fast, it is not on the top of the todo list.

Share this post


Link to post
Share on other sites
Quote:
Original post by mrbig
I think I'm gonna spend some time today trying to figure a robust solution.


I stay tuned ;)

Share this post


Link to post
Share on other sites
I think I finally found a good solution!
I'll need to test it first, though.
If it really works as well as I expect, i'll post it here.

By the way, your engine is very impressive!
Better than what I've finished by now, that's for sure!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this