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