Hello.
I have been attempting to implement a projected grid to test out some water related code I have written. In order to do this I implemented the projected grid created by Eric Bruneton in his ocean water/lighting paper (http://www-ljk.imag.fr/Publications/Basilic/com.lmc.publi.PUBLI_Article@125fe8a8322_1ac3379/article.pdf). I have essentially completed the implementation aside for one odd bug that remains unsolved. Whenever the pitch of the camera increases to above some angle, dependent on how the "horizon" of the grid is computed, the grid becomes to draw degenerate triangles and it seems like a projection problem but I can't really tell what about this angle causes the grid to spasm so severely. The code for grid generation is implemented as follows:
void generate_mesh(float camera_theta)
{
if (grid_vbo_size != 0) {
glDeleteVertexArrays(1, &grid_vao);
glDeleteBuffers(1, &grid_vbo);
glDeleteBuffers(1, &grid_ibo);
}
glGenVertexArrays(1, &grid_vao);
glBindVertexArray(grid_vao);
glGenBuffers(1, &grid_vbo);
glBindBuffer(GL_ARRAY_BUFFER, grid_vbo);
//was horizon = tan(camera_theta / 180 * M_PI);
float horizon = tan(45 / 180.0 * M_PI);
float s = std::min(1.1f, 0.5f + horizon * 0.50f);
std::cout << s << std::endl;
float vmargin = 0.1;
float hmargin = 0.1;
int size = int(ceil(HEIGHT * (s + vmargin) / grid_size) + 5) * int(ceil(WIDTH * (1.0 + 2.0 * hmargin) / grid_size) + 5);
glm::vec4 *data = new glm::vec4[int(ceil(HEIGHT * (s + vmargin) / grid_size) + 5) * int(ceil(WIDTH * (1.0 + 2.0 * hmargin) / grid_size) + 5)];
int n = 0;
int nx = 0;
for (float j = HEIGHT * s - 0.1; j > -HEIGHT * vmargin - grid_size; j -= grid_size) {
nx = 0;
for (float i = -WIDTH * hmargin; i < WIDTH * (1.0 + hmargin) + grid_size; i += grid_size) {
data[n++] = glm::vec4(-1.0 + 2.0 * i / WIDTH, -1.0 + 2.0 * j / HEIGHT, 0.0, 1.0);
nx++;
}
}
glBufferData(GL_ARRAY_BUFFER, n * 16, data, GL_STATIC_DRAW);
delete[] data;
glGenBuffers(1, &grid_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, grid_ibo);
grid_vbo_size = 0;
GLuint *indices = new GLuint[6 * int(ceil(HEIGHT * (s + vmargin) / grid_size) + 4) * int(ceil(WIDTH * (1.0 + 2.0 * hmargin) / grid_size) + 4)];
int nj = 0;
for (float j = HEIGHT * s - 0.1; j > -HEIGHT * vmargin; j -= grid_size) {
int ni = 0;
for (float i = -WIDTH * hmargin; i < WIDTH * (1.0 + hmargin); i += grid_size) {
indices[grid_vbo_size++] = ni + ((nj + 1) * nx);
indices[grid_vbo_size++] = (ni + 1) + ((nj + 1) * nx);
indices[grid_vbo_size++] = (ni + 1) + (nj * nx);
indices[grid_vbo_size++] = (ni + 1) + (nj * nx);
indices[grid_vbo_size++] = ni + ((nj + 1) * nx);
indices[grid_vbo_size++] = ni + nj * nx;
ni++;
}
nj++;
}
glBufferData(GL_ELEMENT_ARRAY_BUFFER, grid_vbo_size * sizeof(GLuint), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 4, GL_FLOAT, false, 4 * sizeof(GL_FLOAT), (GLvoid *)0);
glEnableVertexAttribArray(0);
delete[] indices;
glBindVertexArray(0);
}
As I mentioned above the following line:
float horizon = tan(45 / 180.0 * M_PI);
affects the angle at which the grid begins to become warped. In Bruneton's original code this angle was set to be the pitch of the camera but this still presents the bug (and other undesirable behavior.) The matrices used to project the grid are simply my standard projection and view matrices (along with their inverts) and seem to be set up correctly as they projected various other geometry as expected.
The actual grid is transformed like so in a shader:
vec2 ocean_pos(vec4 vertex)
{
vec3 camera_dir = normalize((screen_to_camera * vertex).xyz);
vec3 world_dir = (camera_to_world * vec4(camera_dir, 0.0)).xyz;
//was t = -world_camera.z / world_dir.z;
float t = -world_camera.y / world_dir.y;
return world_camera.xz + t * world_dir.xz;
}
void main()
{
vec2 u = ocean_pos(position);
float s = sin(u.x) * cos(u.y);
color = vec3(s);
gl_Position = world_to_screen * vec4(u.x, s, u.y, 1.0);
}
where world_to_screen = perspective matrix * view matrix, screen_to_camera = inverse perspective matrix, camera_to_world = inverse of view matrix, and world_camera is the position of the camera in world space.
In order to illustrate the problem further here is a screenshot of the grid with the camera pointed just under the problem angle:
[attachment=33137:angle_problem2.png]
And then when the camera is moved just above the angle:
[attachment=33138:angle_problem3.png]
Filled in:
[attachment=33139:angle_problem.png]
(the grid is being offset by sine functions to emphasize the bug but it is present in non offset grids.)
Has anyone who has implemented this encountered similar problems? Does anyone see if it's obvious why applying the aforementioned transformation would so warp a grid when the view is of a certain angle?
Thank you for your time.