• Advertisement
Sign in to follow this  

Strange Bug in Projected-Grid Rendering

This topic is 594 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Edited by multifractal

Share this post


Link to post
Share on other sites
Advertisement

Looks like the top row of vertices has bad positions.  It's getting clipped in the first screenshot, so it doesn't show.  My guess is the bad positions come from bad indices and the bad indices come from an off-by-one error when generating indices (probably on the loop bounds).

Share this post


Link to post
Share on other sites

In the second image there you can definitely see that some of the indices are incorrect because there is lines going straight through the model in a lot of places. I'd re-check your indices and the way they are being calculated.

Share this post


Link to post
Share on other sites

Looks like the top row of vertices has bad positions.  It's getting clipped in the first screenshot, so it doesn't show.  My guess is the bad positions come from bad indices and the bad indices come from an off-by-one error when generating indices (probably on the loop bounds).

 

In the second image there you can definitely see that some of the indices are incorrect because there is lines going straight through the model in a lot of places. I'd re-check your indices and the way they are being calculated.

I too thought the indices were the problem but I tried drawing the vertices without doing all of the projections and no problem was seen with the polygon construction:

 

[attachment=33167:angle_problem4.png]

 

this mesh is created with the same indices and vertices that the projected grid in the original post uses.

Share this post


Link to post
Share on other sites

 

Looks like the top row of vertices has bad positions.  It's getting clipped in the first screenshot, so it doesn't show.  My guess is the bad positions come from bad indices and the bad indices come from an off-by-one error when generating indices (probably on the loop bounds).

 

In the second image there you can definitely see that some of the indices are incorrect because there is lines going straight through the model in a lot of places. I'd re-check your indices and the way they are being calculated.

I too thought the indices were the problem but I tried drawing the vertices without doing all of the projections and no problem was seen with the polygon construction:

 

attachicon.gifangle_problem4.png

 

this mesh is created with the same indices and vertices that the projected grid in the original post uses.

 

 I feel like the code you wrote is too messy to easily debug it and picture what is going on here.

Share this post


Link to post
Share on other sites

 

I feel like the code you wrote is too messy to easily debug it and picture what is going on here.

Can I clear something up for you then? Do you not understand the bounds of the loop?

Share this post


Link to post
Share on other sites

Maybe it's division by zero or near zero in ocean_pos()

Wow, a quick test of that yielded the attached image. Upside down, but with the problem resolved. Thanks for your help!

[attachment=33184:Screenshot 2016-09-07 04.59.37.png]

 

EDIT: In the case that anyone is interested in the fix:

 

the glitch happens whenever 'world_dir.y'  from

float t = -ocean_camera_pos.y / world_dir.y;
return ocean_camera_pos.xz + (t) * world_dir.xz;

became positive making 't' become negative. Setting the variable like:

float t = -ocean_camera_pos.y / (min(world_dir.y, -0.001));

generally resolves the problem.

Edited by multifractal

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement