Added bounding volume computation and frustum culling

dev
Shariq Shah 10 years ago
parent 69122f081d
commit 13465911d7
  1. 72
      src/bounding_volumes.c
  2. 41
      src/bounding_volumes.h
  3. 47
      src/camera.c
  4. 1
      src/camera.h
  5. 26
      src/game.c
  6. 45
      src/geometry.c
  7. 10
      src/geometry.h
  8. 7
      src/linmath.c
  9. 1
      src/linmath.h
  10. 2
      src/model.c
  11. 2
      src/renderer.c

@ -0,0 +1,72 @@
#include "bounding_volumes.h"
#include "transform.h"
#include <math.h>
int bv_intersect_frustum_box(vec4* frustum, struct Bounding_Box* box, struct Transform* transform)
{
vec3 min, max, size, center, half_ext, half_size;
vec3_add(&min, &box->min, &transform->position);
vec3_mul(&min, &min, &transform->scale);
vec3_add(&max, &box->max, &transform->position);
vec3_mul(&min, &min, &transform->scale);
vec3_sub(&size, &max, &min);
vec3_add(&center, &max, &min);
vec3_scale(&center, &center, (1.f/ 2.f));
vec3_assign(&half_ext, &size);
vec3_scale(&half_size, &size, (1.f / 2.f));
for(int i = 0; i < 6; i++)
{
vec3 normal = {frustum[i].x, frustum[i].y, frustum[i].z};
float distance = frustum[i].w;
float d = vec3_dot(&normal, &center);
vec3 abs_normal = {fabsf(normal.x), fabsf(normal.y), fabsf(normal.z)};
float r = vec3_dot(&half_ext, &abs_normal);
if(d + r < -distance)
{
return IT_OUTSIDE;
}
}
return IT_INSIDE;
}
int bv_intersect_frustum_sphere(vec4* frustum, struct Bounding_Sphere* sphere, struct Transform* transform)
{
int intersect_type = IT_INSIDE;
vec3 center;
vec3_add(&center, &sphere->center, &transform->position);
vec3_mul(&center, &center, &transform->scale);
for(int i = 0; i < 6; i++)
{
vec3 plane_normal = {frustum[i].x, frustum[i].y, frustum[i].z};
float distance = frustum[i].w;
float dot = vec3_dot(&plane_normal, &center) + distance;
if(dot < -sphere->radius)
{
intersect_type = IT_OUTSIDE;
return intersect_type;
}
if(fabsf(dot) < sphere->radius)
{
intersect_type = IT_INTERSECT;
return intersect_type;
}
}
return intersect_type;
}
int bv_intersect_frustum_point(vec4* frustum, const vec3* point)
{
int success = 1;
for(int i = 0; i < 6; i++)
{
if((frustum[i].x * point->x +
frustum[i].y * point->y +
frustum[i].z * point->z +
frustum[i].w) < 0 )
success = 0;
}
return success;
}

@ -0,0 +1,41 @@
#ifndef bounding_volumes_H
#define bounding_volumes_H
#include "linmath.h"
struct Transform;
struct Bounding_Box
{
vec3 min;
vec3 max;
};
struct Bounding_Sphere
{
vec3 center;
float radius;
};
enum Intersection_Type
{
IT_OUTSIDE = 0,
IT_INTERSECT,
IT_INSIDE,
};
enum Frustum_Planes
{
FP_LEFT = 0,
FP_RIGHT,
FP_BOTTOM,
FP_TOP,
FP_NEAR,
FP_FAR
};
int bv_intersect_frustum_box(vec4* frustum, struct Bounding_Box* box, struct Transform* transform);
int bv_intersect_frustum_sphere(vec4* frustum, struct Bounding_Sphere* sphere, struct Transform* transform);
int bv_intersect_frustum_point(vec4* frustum, const vec3* point);
#endif

@ -5,6 +5,7 @@
#include "array.h"
#include "framebuffer.h"
#include "texture.h"
#include "bounding_volumes.h"
#include "utils.h"
#include "log.h"
@ -16,6 +17,7 @@
static struct Camera* camera_list;
static int* empty_indices;
static int primary_camera_index;
static void update_frustum(struct Camera* camera);
struct Camera* camera_get(int index)
{
@ -91,6 +93,7 @@ int camera_create(int node, int width, int height)
void camera_update_view_proj(struct Camera* camera)
{
mat4_mul(&camera->view_proj_mat, &camera->proj_mat, &camera->view_mat);
update_frustum(camera);
}
void camera_update_view(struct Camera* camera)
@ -195,7 +198,6 @@ void camera_set_primary_viewer(struct Camera* camera)
if(camera_list[i].node == camera->node)
{
primary_camera_index = i;
log_message("Camera at index %d set as primary viewer", primary_camera_index);
break;
}
@ -210,3 +212,46 @@ struct Camera* camera_get_primary(void)
primary_camera = &camera_list[primary_camera_index];
return primary_camera;
}
static void update_frustum(struct Camera* camera)
{
assert(camera);
float* mvp = &camera->view_proj_mat.mat[0];
camera->frustum[FP_LEFT].x = mvp[3] + mvp[0];
camera->frustum[FP_LEFT].y = mvp[7] + mvp[4];
camera->frustum[FP_LEFT].z = mvp[11] + mvp[2];
camera->frustum[FP_LEFT].w = mvp[15] + mvp[12];
camera->frustum[FP_RIGHT].x = mvp[3] - mvp[0];
camera->frustum[FP_RIGHT].y = mvp[7] - mvp[4];
camera->frustum[FP_RIGHT].z = mvp[11] - mvp[8];
camera->frustum[FP_RIGHT].w = mvp[15] - mvp[12];
camera->frustum[FP_BOTTOM].x = mvp[3] + mvp[1];
camera->frustum[FP_BOTTOM].y = mvp[11] + mvp[5];
camera->frustum[FP_BOTTOM].z = mvp[11] + mvp[9];
camera->frustum[FP_BOTTOM].w = mvp[15] + mvp[13];
camera->frustum[FP_TOP].x = mvp[3] - mvp[1];
camera->frustum[FP_TOP].y = mvp[7] - mvp[5];
camera->frustum[FP_TOP].z = mvp[11] - mvp[9];
camera->frustum[FP_TOP].w = mvp[15] - mvp[13];
camera->frustum[FP_NEAR].x = mvp[3] + mvp[2];
camera->frustum[FP_NEAR].y = mvp[7] + mvp[6];
camera->frustum[FP_NEAR].z = mvp[11] + mvp[10];
camera->frustum[FP_NEAR].w = mvp[15] + mvp[14];
camera->frustum[FP_FAR].x = mvp[3] - mvp[2];
camera->frustum[FP_FAR].y = mvp[7] - mvp[6];
camera->frustum[FP_FAR].z = mvp[11] - mvp[10];
camera->frustum[FP_FAR].w = mvp[15] - mvp[14];
for(int i = 0; i < 6; i++)
{
vec3 plane_xyz = {camera->frustum[i].x, camera->frustum[i].y, camera->frustum[i].z};
float length = vec3_len(&plane_xyz);
vec4_scale(&camera->frustum[i], &camera->frustum[i], (1.f / length));
}
}

@ -18,6 +18,7 @@ struct Camera
int render_tex;
int depth_tex;
vec4 clear_color;
vec4 frustum[6];
};
struct Camera* camera_get(int index);

@ -83,6 +83,10 @@ void scene_setup(void)
player_node = player->node;
vec3 viewer_pos = {0, 0, 10};
struct Transform* viewer_tran = entity_component_get(player, C_TRANSFORM);
struct Model* player_model = entity_component_add(player, C_MODEL, "sphere.pamesh");
vec4 color = {0.f, 1.f, 1.f, 1.f };
model_set_material_param(player_model, "diffuse_color", &color);
vec4_fill(&color, 1.f, 1.f, 1.f, 1.f);
transform_set_position(viewer_tran, &viewer_pos);
int render_width, render_height;
render_width = 800;
@ -95,7 +99,6 @@ void scene_setup(void)
struct Entity* new_ent = scene_add_new("Model_Entity", NULL);
struct Transform* tran = entity_component_get(new_ent, C_TRANSFORM);
vec3 position = {0, 0, -5};
vec4 color = {1.f, 1.f, 1.f, 1.f };
transform_translate(tran, &position, TS_WORLD);
struct Model* box_model = entity_component_add(new_ent, C_MODEL, "default.pamesh");
model_set_material_param(box_model, "diffuse_color", &color);
@ -124,8 +127,7 @@ void scene_setup(void)
screen_model->geometry_index = geom_find("Quad");
struct Entity* screen_camera = scene_add_as_child("Screen_Camera", NULL, screen->node);
struct Transform* screen_camera_tran = entity_component_get(screen_camera, C_TRANSFORM);
vec3 screen_cam_tran = {0, -5, 5};
transform_translate(screen_camera_tran, &screen_camera_tran, TS_PARENT);
transform_rotate(screen_camera_tran, &UNIT_Y, 180.f, TS_WORLD);
struct Camera* cam = entity_component_add(screen_camera, C_CAMERA, 1024, 1024);
camera_attach_fbo(cam, 1024, 1024, 1, 1);
model_set_material_param(screen_model, "diffuse_color", &color);
@ -134,7 +136,10 @@ void scene_setup(void)
void debug(float dt)
{
struct Entity* entity = entity_get(player_node);
//struct Entity* entity = entity_get(player_node);
struct Entity* entity = !input_key_state_get('C', GLFW_PRESS) ? entity_get(player_node) : scene_find("Screen_Camera");
struct Camera* cam = entity_component_get(entity, C_CAMERA);
camera_set_primary_viewer(cam);
struct Transform* transform = entity_component_get(entity, C_TRANSFORM);
float move_speed = 5.f, turn_speed = 50.f;
vec3 offset = {0, 0, 0};
@ -248,6 +253,19 @@ void debug(float dt)
vec3 amount = {0, 0, 5 * dt};
transform_translate(mod_tran, &amount, TS_LOCAL);
}
/* if(input_key_state_get(GLFW_KEY_C, GLFW_PRESS)) */
/* { */
/* struct Entity* cam_ent = scene_find("Screen_Camera"); */
/* struct Camera* cam = entity_component_get(cam_ent, C_CAMERA); */
/* camera_set_primary_viewer(cam); */
/* } */
/* if(input_key_state_get(GLFW_KEY_V, GLFW_PRESS)) */
/* { */
/* struct Camera* cam = entity_component_get(entity, C_CAMERA); */
/* camera_set_primary_viewer(cam); */
/* } */
}
void run(void)

@ -4,6 +4,8 @@
#include "file_io.h"
#include "log.h"
#include "renderer.h"
#include "bounding_volumes.h"
#include "transform.h"
#include "GL/glew.h"
#include "GLFW/glfw3.h"
@ -12,6 +14,7 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
struct Geometry
{
@ -29,8 +32,8 @@ struct Geometry
vec3* normals;
vec2* uvs;
uint* indices;
/* BoundingBox boundingBox; */
/* BoundingSphere boundingSphere; */
struct Bounding_Box bounding_box;
struct Bounding_Sphere bounding_sphere;
};
@ -41,6 +44,7 @@ static int* empty_indices;
static int load_from_file(struct Geometry* geometry, const char* filename);
static void create_vao(struct Geometry* geometry);
static struct Geometry* generate_new_index(int* out_new_index);
static void generate_bounding_volume(int geomtry_index);
void geom_init(void)
{
@ -63,6 +67,29 @@ int geom_find(const char* filename)
return index;
}
static void generate_bounding_volume(int geometry_index)
{
struct Geometry* geometry = &geometry_list[geometry_index];
struct Bounding_Box* box = &geometry->bounding_box;
struct Bounding_Sphere* sphere = &geometry->bounding_sphere;
for(int i = 0; i < array_len(geometry->vertices); i++)
{
vec3* vertex = &geometry->vertices[i];
if(vertex->x > box->max.x) box->max.x = vertex->x;
if(vertex->y > box->max.y) box->max.y = vertex->y;
if(vertex->z > box->max.z) box->max.z = vertex->z;
if(vertex->x < box->min.x) box->min.x = vertex->x;
if(vertex->y < box->min.y) box->min.y = vertex->y;
if(vertex->z < box->min.z) box->min.z = vertex->z;
}
vec3_add(&sphere->center, &box->max, &box->min);
vec3_scale(&sphere->center, &sphere->center, (1.f / 2.f));
vec3 len_vec;
vec3_sub(&len_vec, &box->max, &sphere->center);
sphere->radius = fabs(vec3_len(&len_vec));
}
static struct Geometry* generate_new_index(int* out_new_index)
{
assert(out_new_index);
@ -97,7 +124,7 @@ int geom_create_from_file(const char* name)
if(load_from_file(new_geo, name))
{
create_vao(new_geo);
//generateBoundingBox(index);
generate_bounding_volume(index);
}
else
{
@ -320,3 +347,15 @@ void geom_render(int index)
glBindVertexArray(0);
}
void geom_render_in_frustum(int index, vec4* frustum, struct Transform* transform)
{
struct Geometry* geometry = &geometry_list[index];
int intersection = bv_intersect_frustum_sphere(frustum, &geometry->bounding_sphere, transform);
if(intersection == IT_INTERSECT || intersection == IT_INSIDE)
{
intersection = bv_intersect_frustum_box(frustum, &geometry->bounding_box, transform);
if(intersection == IT_INTERSECT || intersection == IT_INSIDE)
geom_render(index);
}
}

@ -4,12 +4,20 @@
#include "num_types.h"
#include "linmath.h"
struct Transform;
void geom_init(void);
int geom_create_from_file(const char* name);
int geom_create(const char* name, vec3* vertices, vec2* uvs, vec3* normals, uint* indices, vec3* vertex_colors);
int geom_find(const char* filename);
void geom_remove(int index);
void geom_cleanup(void);
void geom_render(int index);
void geom_render_in_frustum(int index, vec4* frustum, struct Transform* transform);
int geom_create(const char* name,
vec3* vertices,
vec2* uvs,
vec3* normals,
uint* indices,
vec3* vertex_colors);
#endif

@ -181,6 +181,13 @@ void vec3_transform_norm(vec3* res, const vec3* val, const mat4* mat)
res->z = v.z;
}
float vec3_dot(vec3* v1, vec3* v2)
{
return (v1->x * v2->x +
v1->y * v2->y +
v1->z * v2->z);
}
void vec4_fill(vec4* res, float x, float y, float z, float w)
{

@ -79,6 +79,7 @@ void vec3_scale(vec3* res, const vec3* val, float s);
void vec3_transform_norm(vec3* res, const vec3* val, const mat4* mat);
int vec3_equals(vec3* v1, vec3* v2);
float vec3_len(vec3* val);
float vec3_dot(vec3* v1, vec3* v2);
/* vec4 */
int vec4_equals(vec4* v1, vec4* v2);

@ -146,7 +146,7 @@ void model_render_all(struct Camera* camera)
}
}
/* Render the geometry */
geom_render(model->geometry_index);
geom_render_in_frustum(model->geometry_index, &camera->frustum, transform);
for(int k = 0; k < array_len(model->material_params); k++)
{

@ -25,6 +25,8 @@ void renderer_init(GLFWwindow* window)
glClearColor(0.3f, 0.6f, 0.9f, 1.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glfwSetFramebufferSizeCallback(window, on_framebuffer_size_change);
/* Quad geometry for final render */

Loading…
Cancel
Save