I have implemented frustum culling by using the plane extraction method explained in this article.
The article mentions that if the matrix is a projection matrix, then the planes will be in view-space. So I need to transform my AABB coordinates to view space to do the culling tests. However, this doesn't work.
But if extract the planes from view-projection matrix and test with AABB coordinates in model space, everything works fine.
The only change I've done is update the frustum planes using view-projection matrix with every camera motion, and transform AABB coordinates to model space instead of view space.
Here is the relevant code. The lines commented with "diff" are the only changes between two versions.
Code for projection matrix based frustum culling:
// called only at initialization
void camera_set_proj_matrix(camera *c, mat4 *proj_matrix)
{
c->proj_matrix = *proj_matrix;
// diff
extract_frustum_planes(&c->frustum_planes, &c->proj_matrix);
}
void camera_update_view_matrix(camera *c)
{
mat4_init_look(&c->view_matrix, &c->pos, &c->dir, &VEC3_UNIT_Y);
mat4_mul(&c->vp_matrix, &c->proj_matrix, &c->view_matrix);
// diff
}
void chunk_render(const chunk *c, chunk_pos pos, const camera *camera, GLuint mvp_matrix_location)
{
mat4 model_matrix;
block_pos bp = chunk_pos_to_block_pos(pos);
mat4_init_translation(&model_matrix, bp.x, bp.y, bp.z);
mat4 mv_matrix;
mat4_mul(&mv_matrix, &camera->view_matrix, &model_matrix);
vec4 min = {0, 0, 0, 1};
vec4 max = {CHUNK_SIDE, CHUNK_HEIGHT, CHUNK_SIDE, 1};
// diff: using model view matrix here
mat4_mul_vec4(&min, &mv_matrix, &min);
// diff: using model view matrix here
mat4_mul_vec4(&max, &mv_matrix, &max);
AABB aabb = {{min.x, min.y, min.z}, {max.x, max.y, max.z}};
if (AABB_outside_frustum(&aabb, &camera->frustum_planes)) return;
//draw
}
Looks like it's culling too much. Also note: This abnormal culling only happens when I'm looking at positive z direction.
Code for view-projection based culling:
void camera_set_proj_matrix(camera *c, mat4 *proj_matrix)
{
c->proj_matrix = *proj_matrix;
// diff
}
void camera_update_view_matrix(camera *c)
{
mat4_init_look(&c->view_matrix, &c->pos, &c->dir, &VEC3_UNIT_Y);
mat4_mul(&c->vp_matrix, &c->proj_matrix, &c->view_matrix);
// diff: update frustum planes based on view projection matrix now
extract_frustum_planes(&c->frustum_planes, &c->vp_matrix);
}
void chunk_render(const chunk *c, chunk_pos pos, const camera *camera, GLuint mvp_matrix_location)
{
mat4 model_matrix;
block_pos bp = chunk_pos_to_block_pos(pos);
mat4_init_translation(&model_matrix, bp.x, bp.y, bp.z);
mat4 mv_matrix;
mat4_mul(&mv_matrix, &camera->view_matrix, &model_matrix);
vec4 min = {0, 0, 0, 1};
vec4 max = {CHUNK_SIDE, CHUNK_HEIGHT, CHUNK_SIDE, 1};
// diff: using model matrix now
mat4_mul_vec4(&min, &model_matrix, &min);
// diff: using model matrix now
mat4_mul_vec4(&max, &model_matrix, &max);
AABB aabb = {{min.x, min.y, min.z}, {max.x, max.y, max.z}};
if (AABB_outside_frustum(&aabb, &camera->frustum_planes)) return;
// draw
}
I've no idea why projection only method would be working in a weird way when I'm transforming aabb appropriately :/