I’m looking for a solution to a problem I have when I’m trying to render water over my terrain in OpenGL. Water is basically a big blue square going through a terrain.
The results are pretty ugly. Edges are rough and pixelated.
The water also looks horrible when viewed from a distance.
I would appreciate any help.
It looks horrible mainly because of the colour.
the pixellation could be reduced by using MSAA.
The issues in the second picture may be related to inadequate depth precision; ensure that your near plane isn’t too close.
GClements, color is not a problem, it suppose to be like that for now.
I tried to put the water polygon way below the ground, but still the water can occasionally be seen through the ground.
Now I’m sure that depth precision is the problem.
Is it possible that the same depth value is assigned to both water and ground fragments when they are to close to each other and to far away from the camera during the depth test? If so, how do I make it work properly?
The simplest way is to increase the distance to the near plane.
As a rough guide, the -Z range between N times the near distance and the far distance gets 1/N of the depth range.
The near distance is what dictates depth resolution; it’s actually possible to set the far distance to infinity without having much effect upon the depth resolution for most of the scene.
If you can’t increase the near distance without clipping near terrain, you need to consider using either:
Multi-pass rendering (render everything more than a short distance from the viewpoint, clear the depth buffer, render anything close to the viewpoint) so that the first pass can use a higher near distance and the second pass covers a much smaller Z range.
An inverted floating-point depth buffer, where the depth is zero at the far plane, so that the increased precision of floating point values close to zero compensate for the reduced depth scaling at the far plane.
The latter requires constructing the appropriate projection matrix directly; you can’t use e.g. gluPerspective() and glDepthRange(1, 0), because the intermediate representation loses precision. For similar reasons, it also requires glClipControl(GL_ZERO_TO_ONE) to use NDC Z values in the range 0…1 directly rather than using -1…1 as an intermediate representation. See this thread for more information.
GClements, thank you so much for your help.
It turns out that i had stupidly small near distance (0.001) and unnecessarily large far distance(100k).
Now i can get satisfactory results without multi-pass rendering or an inverted floating-point depth buffer, but those are methods I’ll definitely have to learn to use.