1
votes

I am trying to render a square plane mesh, 255 x 255 resolution, 128 world units -- read floats -- in size on screen.

Allocating and filling this mesh in RAM, uploading it to V-RAM, binding to attributes and indices buffers, calling glDrawElements correctly on it has not been a problem, the object is drawing as expected.

It is a water surface sim I'm working on and the vertex heights get calculated and uploaded every frame. When a click is registered "on" the water surface, a disturbance is produced, then water flow is calculated and normals are updated (considering bottom-to-top left-to-right flow).

My problem is that in some portions of the mesh I get the rendering you can see in pictures below (the third sans culling).

**THIS** **THIS** **THIS (sans culling)**

Noticeable it is, in that last picture mostly, that the effect appears to start somewhere on the far left side of the ViewPort, continuing for another half width towards right. This effect is visible only when the camera is panned to the left, in some positions relative to the mesh, but not others and camera's forward direction or ViewMatrix seems to have no effect on the artifact. If I slide the camera from side to side, I can notice the artifact's point of origin moving along with the camera. This origin seems to be in center of ViewPort, and has a height equal to that of the ViewPort, but only a ~4th of its width at times, other times can go up to half. As I said before, camera's forward direction / look at vectors have no influence on the rendering. Even when rendering from a "bird's eye" view, the effect can still be observed.

It seems that there is an issue with the camera position interfering with the gl_Position = mat4_ModelViewProjection * position; bit in my shader, or it might be that in the vertex color calculation, float dot = dot(N, V); needs some kind of (monster) validation?

Here is some of my code:

vertex shader

"attribute vec2 pos;"
"attribute vec2 normal;"
"attribute float height;"

"uniform vec3 sunColor;"
"uniform float ax;"

"varying PRECISION_MEDIUM vec4 waterColor_;"
"varying PRECISION_LOW vec2 tex_coord;"

"const vec3 g_WaterBlue  = vec3( 0.05, 0.25, 0.3 );"
"const vec3 g_WaterGreen = vec3( 0.05, 0.3, 0.2 );"

"vec3 CalculateWaterColor(vec3 V, vec3 N)"
"{"
    "float dot = dot(N, V);"

    "vec3 waterColor = mix(g_WaterGreen, g_WaterBlue, dot);"
    "waterColor = mix(sunColor, waterColor, dot);"
    "waterColor = mix(waterColor, g_WaterBlue, dot);"

    "return waterColor;"
"}"

"void main()"
"{"
    "vec4 position = vec4(pos.x, height, pos.y, 1.0);"

    "vec3 V = camera_pos.xyz + camera_forward.xyz - position.xyz;"
    "V = normalize(V);"

    "vec3 N = vec3(normal.x, 1, normal.y);"
    "N = normalize(N);"

    "waterColor_.xyz = CalculateWaterColor(V, N);"
    "waterColor_.w = 1.0;"//ax * 18 / length(camera_pos.xyz - position.xyz);"

    "gl_Position = mat4_ModelViewProjection * position;"
"}"

plane mesh vertex generation

// set accelerators
accel1 = Size / static_cast<float>(Resolution - 1);
accel2 = -Size / 2.0f;

x = accel2;
y = accel2;
z = 1.0f;
// ..

// fill the vertex buffer
p_data = reinterpret_cast<float*>(buf_vertex->DataPointer) - 1;
for (index1 = 0; index1 < Resolution; ++index1)
{
    for (index2 = 0; index2 < Resolution; ++index2)
    {
        *++p_data = x;
        *++p_data = y;

        if (buf_vertex->Dimension == 3)
        {
            *++p_data = z;
        }

        x += accel1;
    }

    x = accel2; // Size / 2
    y += accel1;
}
// ..

plane mesh index generator

// LEFT to RIGHT, BOTTOM to TOP
for (index1 = 0; index1 < (Resolution - 1); ++index1)
{
    for (index2 = 0; index2 < (Resolution - 1); ++index2)
    {
        // CLOCKWISE
        *++p_data = index2      + index1        * Resolution;
        *++p_data = index2      + (index1 + 1)  * Resolution;
        *++p_data = index2 + 1  + (index1 + 1)  * Resolution;

        *++p_data = index2      + index1        * Resolution;
        *++p_data = index2 + 1  + (index1 + 1)  * Resolution;
        *++p_data = index2 + 1  + index1        * Resolution;

        // COUNTER-CLOCKWISE
        //*++p_data = index2 +     (index1 + 1) * Resolution;
        //*++p_data = index2 +     index1       * Resolution;
        //*++p_data = index2 + 1 + index1       * Resolution;

        //*++p_data = index2 + 1 + index1       * Resolution;
        //*++p_data = index2 + 1 + (index1 + 1) * Resolution;
        //*++p_data = index2 +     (index1 + 1) * Resolution;
        // ..
    }
}

Things I have tried:

  • Enabling/Disabling depth testing
  • Setting a bigger value to depth buffer size (tried 16, 32, 8 -- same results on all values)
  • Playing with culling
  • Playing with alpha blending
  • Depth sorting -- useless, not doing blending anyway...
  • Setting a huge world size to mesh (10000.0f) so as to avoid rounding errors in the millionths of a world unit (1.0f)
  • Using different index buffers, rendering vertices in different orders, top to bottom, left to right and their respective inverses -- no influence whatsoever in attenuating or aggravating the artifact rendering.
1
Do you have MSAA enabled?Luka Jacobowitz
What happens when you enable it?Luka Jacobowitz
Will have to get back to you on that, since I haven't put in the effort of implementing anything beyond a bare metal win OpenGL context -- can be done, but will take some time -- suspect effect with remain...where are you going with this?Bebe Carabina
To check that I understand from the code: 2d position and height are separate attributes but are just attributes (height isn't sampled from a texture, so sampling errors are out); changing the manner in which you generate the indices has no effect (so index generation probably isn't to blame)? What happens if you replace your on-CPU water simulation to output a flat surface or one that's something simple like a sinusoid? To what extent have you ruled out the actual water simulation rather than its display?Tommy
1. 2d position and height, straight transfer to V-RAM -- yes, you got that 2. Yes, changing the indices' vertex order doesn't affect the artifact. 3. Good point -- thinking to export height data to a file/onscreen buffer for analysis. Have kind of ruled out simulation -- mainly because the effect is visible only from certain offsets from the mesh position. it is visible from 2 of the 4 sides of the mesh, and the two sides are opposing eachotherBebe Carabina

1 Answers

0
votes

The problem is NOT in the code that's been posted -- that's all correct!

Problem is this:

    // enable blending
    glEnable(GL_BLEND);
    // ..

    glBlendFunc
    (
        GL_SRC_ALPHA,
        GL_ONE_MINUS_SRC_ALPHA
    );

GL_ONE_MINUS_SRC_ALPHA should be GL_ONE to avoid painting with such artifacts.

Here are some examples to better understaind how glBlendFunc works.

  1. http://www.quake-1.com/docs/blending.jpg
  2. http://www.andersriggelsen.dk/glblendfunc.php

Also, importantly enough you should remember to glDisable(GL_DEPTH_TEST) when doing blending.