Program Listing for File ViewFrustumCulling.cpp
↰ Return to documentation for file (Src/GraphicsEngineOpenGL/scene/ViewFrustumCulling.cpp
)
#include "scene/ViewFrustumCulling.hpp"
ViewFrustumCulling::ViewFrustumCulling()
:
VBO(-1), VAO(-1), EBO(-1), m_drawCount(0),
// we get that as input
near_plane(0.f), far_plane(0.f), fov(0.f), ratio(0.f),
// calculate as soon as we become params
tan(0.f), near_height(0.f), near_width(0.f), far_height(0.f), far_width(0.f), main_camera(),
dir(glm::vec3(0.f)), near_center(glm::vec3(0.f)), far_center(glm::vec3(0.f)),
near_top_left(glm::vec3(0.f)), near_top_right(glm::vec3(0.f)), near_bottom_left(glm::vec3(0.f)),
near_bottom_right(glm::vec3(0.f)),
far_top_left(glm::vec3(0.f)), far_top_right(glm::vec3(0.f)), far_bottom_left(glm::vec3(0.f)),
far_bottom_right(glm::vec3(0.f))
{}
bool ViewFrustumCulling::is_inside(GLfloat ratio,
std::shared_ptr<Camera> main_camera,
std::shared_ptr<AABB> bounding_box,
glm::mat4 model)
{
GLfloat near_plane = main_camera->get_near_plane();
GLfloat far_plane = main_camera->get_far_plane();
GLfloat fov = main_camera->get_fov();
update_frustum_param(near_plane, far_plane, fov, ratio, main_camera);
std::vector<glm::vec3> aabb_corners = bounding_box->get_corners(model);
// layout: [0]: near plane, [1] far plane, [2] up ,
// [3] bottom , [4]: left , [5]: right outcodes (binary) : 100000 , 010000 ,
// 000100 , 001000 , 000010, 000001 outcodes (dezi) : 32 , 16 , 4 , 8
// , 2 , 1
bool result = true;
GLint outcode_near_plane = 32;
GLint outcode_far_plane = 16;
GLint outcode_up = 4;
GLint outcode_bottom = 8;
GLint outcode_left = 2;
GLint outcode_right = 1;
// GLint outcode;
GLint outcodes_pattern[NUM_FRUSTUM_PLANES] = {
outcode_near_plane, outcode_far_plane, outcode_up, outcode_bottom, outcode_left, outcode_right
};
for (int i = 0; i < NUM_FRUSTUM_PLANES; i++) {
frustum_plane plane = frustum_planes[i];
if (corners_outside_plane(aabb_corners, plane, outcodes_pattern[i])) {
result = false;
break;
}
}
return result;
}
void ViewFrustumCulling::render_view_frustum()
{
// seeing as we only have a single VAO there's no need to bind it every time,
// but we'll do so to keep things a bit more organized
glBindVertexArray(VAO);
// glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawElements(GL_TRIANGLES, m_drawCount, GL_UNSIGNED_INT, 0);
// unbind all again
glBindVertexArray(0);
}
bool ViewFrustumCulling::corners_outside_plane(std::vector<glm::vec3> aabb_corners,
frustum_plane plane,
GLuint outcode_pattern)
{
GLint outcode = outcode_pattern;
for (int i = 0; i < static_cast<int>(aabb_corners.size()); i++) {
if (plane_point_distance(plane, aabb_corners[i]) < 0.0f) {
if (i == 0) {
outcode = outcode_pattern;
} else {
outcode = outcode & outcode_pattern;
}
} else {
if (i == 0) {
outcode = 0;
} else {
outcode = outcode & 0;
}
}
}
return (outcode != 0) ? true : false;
}
GLfloat ViewFrustumCulling::plane_point_distance(frustum_plane plane, glm::vec3 corner)
{
GLfloat result = 0.0f;
glm::vec3 plane_normal = plane.normal;
glm::vec3 plane_position = plane.position;
GLfloat d = glm::dot(plane_normal, plane_position);
result = (glm::dot(plane_normal, corner) - d) / glm::length(plane_normal);
return result;
}
void ViewFrustumCulling::update_frustum_param(GLfloat near_plane,
GLfloat far_plane,
GLfloat fov,
GLfloat ratio,
std::shared_ptr<Camera> main_camera)
{
this->near_plane = near_plane;
this->far_plane = far_plane;
this->fov = fov;
this->ratio = ratio;
tan = glm::tan(glm::radians(fov) * 0.5f);
near_height = near_plane * tan;
near_width = near_height * ratio;
far_height = far_plane * tan;
far_width = far_height * ratio;
this->main_camera = main_camera;
near_center = main_camera->get_camera_position() + main_camera->get_camera_direction() * near_plane;
far_center = main_camera->get_camera_position() + main_camera->get_camera_direction() * far_plane;
glm::vec3 aux_position, aux, aux_normal;
// layout: [0]: near plane
frustum_planes[0].normal = main_camera->get_camera_direction();
frustum_planes[0].position = near_center;
// [1] far plane
frustum_planes[1].normal = -main_camera->get_camera_direction();
frustum_planes[1].position = far_center;
aux_position = near_center + main_camera->get_up_axis() * near_height;
aux = aux_position - main_camera->get_camera_position();
aux = glm::normalize(aux);
aux_normal = glm::cross(aux, main_camera->get_right_axis());
// [2] top
frustum_planes[2].normal = normalize(aux_normal);
frustum_planes[2].position = aux_position;
aux_position = near_center - main_camera->get_up_axis() * near_height;
aux = aux_position - main_camera->get_camera_position();
aux = glm::normalize(aux);
aux_normal = glm::cross(main_camera->get_right_axis(), aux);
// [3] bottom
frustum_planes[3].normal = normalize(aux_normal);
frustum_planes[3].position = aux_position;
aux_position = near_center - main_camera->get_right_axis() * near_width;
aux = aux_position - main_camera->get_camera_position();
aux = glm::normalize(aux);
aux_normal = glm::cross(aux, main_camera->get_up_axis());
// [4]: left
frustum_planes[4].normal = normalize(aux_normal);
frustum_planes[4].position = aux_position;
aux_position = near_center + main_camera->get_right_axis() * near_width;
aux = aux_position - main_camera->get_camera_position();
aux = glm::normalize(aux);
aux_normal = glm::cross(main_camera->get_up_axis(), aux);
// [5]: right
frustum_planes[5].normal = normalize(aux_normal);
frustum_planes[5].position = aux_position;
std::vector<glm::vec3> frustum_corners;
// frustum_corners.push_back(near_center - main_camera->get_right_axis() *
// near_width -
// main_camera->get_up_axis() * near_height);// left bottom front
//
// frustum_corners.push_back(far_center - main_camera->get_right_axis() *
// far_width -
// main_camera->get_up_axis() * far_height);// left bottom back
//
// frustum_corners.push_back(near_center - main_camera->get_right_axis() *
// near_width +
// main_camera->get_up_axis() * near_height); // left top front
//
// frustum_corners.push_back(far_center - main_camera->get_right_axis() *
// far_width +
// main_camera->get_up_axis() * far_height);// left top back
//
// frustum_corners.push_back(near_center + main_camera->get_right_axis() *
// near_width -
// main_camera->get_up_axis() * near_height); // right bottom front
//
// frustum_corners.push_back(far_center + main_camera->get_right_axis() *
// far_width -
// main_camera->get_up_axis() * far_height);//right bottom back
//
// frustum_corners.push_back(near_center + main_camera->get_right_axis() *
// near_width +
// main_camera->get_up_axis() * near_height);//right top front
//
// frustum_corners.push_back(far_center + main_camera->get_right_axis() *
// far_width + main_camera->get_up_axis() * far_height);//right top back
// init(frustum_corners);
}
void ViewFrustumCulling::init(std::vector<glm::vec3> frustum_corner)
{
// unsigned int num_corners = 8;
m_drawCount = 36;// num_corners;
float vertices[] = {
frustum_corner[0].x,
frustum_corner[0].y,
frustum_corner[0].z,// left bottom front
frustum_corner[1].x,
frustum_corner[1].y,
frustum_corner[1].z,// left bottom back
frustum_corner[2].x,
frustum_corner[2].y,
frustum_corner[2].z,// left top front
frustum_corner[3].x,
frustum_corner[3].y,
frustum_corner[3].z,// left top back
frustum_corner[4].x,
frustum_corner[4].y,
frustum_corner[4].z,// right bottom front
frustum_corner[5].x,
frustum_corner[5].y,
frustum_corner[5].z,// right bottom back
frustum_corner[6].x,
frustum_corner[6].y,
frustum_corner[6].z,// right top front
frustum_corner[7].x,
frustum_corner[7].y,
frustum_corner[7].z// right top back
};
unsigned int indices[] = {
// note that we start from 0!
// left
0,
1,
3,
0,
2,
3,
// right
4,
5,
7,
4,
6,
7,
// top
3,
2,
7,
3,
2,
8,
// bottom
0,
1,
4,
0,
1,
5,
// back
1,
3,
5,
1,
3,
7,
// front
0,
2,
4,
0,
2,
6,
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and
// then configure vertex attributes(s).
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
// note that this is allowed, the call to glVertexAttribPointer registered VBO
// as the vertex attribute's bound vertex buffer object so afterwards we can
// safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// remember: do NOT unbind the EBO while a VAO is active as the bound element
// buffer object IS stored in the VAO; keep the EBO bound.
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally
// modify this VAO, but this rarely happens. Modifying other VAOs requires a
// call to glBindVertexArray anyways so we generally don't unbind VAOs (nor
// VBOs) when it's not directly necessary.
glBindVertexArray(0);
}
ViewFrustumCulling::~ViewFrustumCulling()
{
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}