--- /dev/null
+#include <glm/matrix.hpp>
+
+class Frustum
+{
+public:
+ Frustum() {}
+
+ // m = ProjectionMatrix * ViewMatrix
+ Frustum(glm::mat4 m);
+
+ // http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm
+ bool IsBoxVisible(const glm::vec3& minp, const glm::vec3& maxp) const;
+
+private:
+ enum Planes
+ {
+ Left = 0,
+ Right,
+ Bottom,
+ Top,
+ Near,
+ Far,
+ Count,
+ Combinations = Count * (Count - 1) / 2
+ };
+
+ template<Planes i, Planes j>
+ struct ij2k
+ {
+ enum { k = i * (9 - i) / 2 + j - 1 };
+ };
+
+ template<Planes a, Planes b, Planes c>
+ glm::vec3 intersection(const glm::vec3* crosses) const;
+
+ glm::vec4 m_planes[Count];
+ glm::vec3 m_points[8];
+};
+
+inline Frustum::Frustum(glm::mat4 m)
+{
+ m = glm::transpose(m);
+ m_planes[Left] = m[3] + m[0];
+ m_planes[Right] = m[3] - m[0];
+ m_planes[Bottom] = m[3] + m[1];
+ m_planes[Top] = m[3] - m[1];
+ m_planes[Near] = m[3] + m[2];
+ m_planes[Far] = m[3] - m[2];
+
+ glm::vec3 crosses[Combinations] = {
+ glm::cross(glm::vec3(m_planes[Left]), glm::vec3(m_planes[Right])),
+ glm::cross(glm::vec3(m_planes[Left]), glm::vec3(m_planes[Bottom])),
+ glm::cross(glm::vec3(m_planes[Left]), glm::vec3(m_planes[Top])),
+ glm::cross(glm::vec3(m_planes[Left]), glm::vec3(m_planes[Near])),
+ glm::cross(glm::vec3(m_planes[Left]), glm::vec3(m_planes[Far])),
+ glm::cross(glm::vec3(m_planes[Right]), glm::vec3(m_planes[Bottom])),
+ glm::cross(glm::vec3(m_planes[Right]), glm::vec3(m_planes[Top])),
+ glm::cross(glm::vec3(m_planes[Right]), glm::vec3(m_planes[Near])),
+ glm::cross(glm::vec3(m_planes[Right]), glm::vec3(m_planes[Far])),
+ glm::cross(glm::vec3(m_planes[Bottom]), glm::vec3(m_planes[Top])),
+ glm::cross(glm::vec3(m_planes[Bottom]), glm::vec3(m_planes[Near])),
+ glm::cross(glm::vec3(m_planes[Bottom]), glm::vec3(m_planes[Far])),
+ glm::cross(glm::vec3(m_planes[Top]), glm::vec3(m_planes[Near])),
+ glm::cross(glm::vec3(m_planes[Top]), glm::vec3(m_planes[Far])),
+ glm::cross(glm::vec3(m_planes[Near]), glm::vec3(m_planes[Far]))
+ };
+
+ m_points[0] = intersection<Left, Bottom, Near>(crosses);
+ m_points[1] = intersection<Left, Top, Near>(crosses);
+ m_points[2] = intersection<Right, Bottom, Near>(crosses);
+ m_points[3] = intersection<Right, Top, Near>(crosses);
+ m_points[4] = intersection<Left, Bottom, Far>(crosses);
+ m_points[5] = intersection<Left, Top, Far>(crosses);
+ m_points[6] = intersection<Right, Bottom, Far>(crosses);
+ m_points[7] = intersection<Right, Top, Far>(crosses);
+
+}
+
+// http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm
+inline bool Frustum::IsBoxVisible(const glm::vec3& minp, const glm::vec3& maxp) const
+{
+ // check box outside/inside of frustum
+ for (int i = 0; i < Count; i++)
+ {
+ if ((glm::dot(m_planes[i], glm::vec4(minp.x, minp.y, minp.z, 1.0f)) < 0.0) &&
+ (glm::dot(m_planes[i], glm::vec4(maxp.x, minp.y, minp.z, 1.0f)) < 0.0) &&
+ (glm::dot(m_planes[i], glm::vec4(minp.x, maxp.y, minp.z, 1.0f)) < 0.0) &&
+ (glm::dot(m_planes[i], glm::vec4(maxp.x, maxp.y, minp.z, 1.0f)) < 0.0) &&
+ (glm::dot(m_planes[i], glm::vec4(minp.x, minp.y, maxp.z, 1.0f)) < 0.0) &&
+ (glm::dot(m_planes[i], glm::vec4(maxp.x, minp.y, maxp.z, 1.0f)) < 0.0) &&
+ (glm::dot(m_planes[i], glm::vec4(minp.x, maxp.y, maxp.z, 1.0f)) < 0.0) &&
+ (glm::dot(m_planes[i], glm::vec4(maxp.x, maxp.y, maxp.z, 1.0f)) < 0.0))
+ {
+ return false;
+ }
+ }
+
+ // check frustum outside/inside box
+ int out;
+ out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].x > maxp.x) ? 1 : 0); if (out == 8) return false;
+ out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].x < minp.x) ? 1 : 0); if (out == 8) return false;
+ out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].y > maxp.y) ? 1 : 0); if (out == 8) return false;
+ out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].y < minp.y) ? 1 : 0); if (out == 8) return false;
+ out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].z > maxp.z) ? 1 : 0); if (out == 8) return false;
+ out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].z < minp.z) ? 1 : 0); if (out == 8) return false;
+
+ return true;
+}
+
+template<Frustum::Planes a, Frustum::Planes b, Frustum::Planes c>
+inline glm::vec3 Frustum::intersection(const glm::vec3* crosses) const
+{
+ float D = glm::dot(glm::vec3(m_planes[a]), crosses[ij2k<b, c>::k]);
+ glm::vec3 res = glm::mat3(crosses[ij2k<b, c>::k], -crosses[ij2k<a, c>::k], crosses[ij2k<a, b>::k]) *
+ glm::vec3(m_planes[a].w, m_planes[b].w, m_planes[c].w);
+ return res * (-1.0f / D);
+}
mesh = new Mesh(scene, &vertices[0], vertices.size() * sizeof(GLfloat));
mesh->pos = pos * SIZE + SIZE / 2;
+ mesh->minp = vec3(- SIZE / 2 - 1);
+ mesh->maxp = vec3(+ SIZE / 2 + 1);
mesh->textures = textures;
mesh->vertices_per_texture = 6;
if (! mesh_created_before) {
{
log("Initalizing...");
- Texture::mipmap = false;
+ Texture::mipmap = true;
Texture::bilinear_filter = false;
Texture::initArgs();
player = Player::createLocalplayer(render_engine->camera, render_engine->input_handler, map);
player->pitch_move = false;
- player->yaw = -90;
- player->pitch = -80;
+ player->yaw = 0;
+ player->pitch = 0;
player->speed = 10;
player->pos = vec3(8, 8, 8);
-0.5, +0.5, -0.5, +0.0, +1.0,
-0.5, -0.5, -0.5, +0.0, +0.0,
- -0.5, -0.5, +0.5, +0.0, +0.0,
- +0.5, -0.5, +0.5, +1.0, +0.0,
+ -0.5, -0.5, +0.5, +0.0, +0.0,
+0.5, +0.5, +0.5, +1.0, +1.0,
+ +0.5, -0.5, +0.5, +1.0, +0.0,
+0.5, +0.5, +0.5, +1.0, +1.0,
- -0.5, +0.5, +0.5, +0.0, +1.0,
-0.5, -0.5, +0.5, +0.0, +0.0,
+ -0.5, +0.5, +0.5, +0.0, +1.0,
-0.5, +0.5, +0.5, +1.0, +1.0,
- -0.5, +0.5, -0.5, +0.0, +1.0,
-0.5, -0.5, -0.5, +0.0, +0.0,
+ -0.5, +0.5, -0.5, +0.0, +1.0,
-0.5, -0.5, -0.5, +0.0, +0.0,
- -0.5, -0.5, +0.5, +1.0, +0.0,
-0.5, +0.5, +0.5, +1.0, +1.0,
+ -0.5, -0.5, +0.5, +1.0, +0.0,
- +0.5, +0.5, +0.5, +1.0, +1.0,
+ +0.5, +0.5, +0.5, +1.0, +1.0,
+0.5, +0.5, -0.5, +0.0, +1.0,
+0.5, -0.5, -0.5, +0.0, +0.0,
+0.5, -0.5, -0.5, +0.0, +0.0,
#include <cstring>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/constants.hpp>
+#include "FrustumCull.h"
#include "gldebug.hpp"
#include "mesh.hpp"
#include "scene.hpp"
}
}
-void Mesh::render(double dtime, ShaderProgram *shader_program)
+void Mesh::render(double dtime, ShaderProgram *shader_program, Frustum *frustum)
{
rendering = true;
mat4 model_matrix = animation.getModelMatrix(dtime, pos, size, rotation_axis, rotation_angle); CHECKERR
+ if (! frustum->IsBoxVisible(model_matrix * vec4(minp, 1.0), model_matrix * vec4(maxp, 1.0)))
+ return;
+
shader_program->set("model", model_matrix); CHECKERR
glBindVertexArray(VAO); CHECKERR
#include "gl.hpp"
#include "texture.hpp"
+class Frustum;
+
namespace dragonblocks
{
class Scene;
int vertices_per_texture;
glm::vec3 pos, size, rotation_axis;
+ glm::vec3 minp, maxp;
float rotation_angle = 0;
std::vector<Texture> textures;
Animation animation;
- void render(double dtime, ShaderProgram *);
+ void render(double dtime, ShaderProgram *, Frustum *);
bool isRendering();
void die();
#include <stdexcept>
#include <glm/gtc/matrix_transform.hpp>
+#include "FrustumCull.h"
#include "camera.hpp"
#include "gldebug.hpp"
#include "input_handler.hpp"
input_handler->processInput(dtime);
glEnable(GL_DEPTH_TEST); CHECKERR
+ glEnable(GL_CULL_FACE); CHECKERR
+ glCullFace(GL_BACK); CHECKERR
+ glFrontFace(GL_CW); CHECKERR
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); CHECKERR
updateViewMatrix(); CHECKERR
- scene->render(dtime, shader_program);
+ Frustum frustum(projection_matrix * view_matrix);
+
+ scene->render(dtime, shader_program, &frustum);
window->swapBuffers(); CHECKERR
glfwPollEvents(); CHECKERR
void RenderEngine::updateProjectionMatrix()
{
dvec2 bounds = window->getSize();
- mat4 projection_matrix = perspective(radians(fov), bounds.x / bounds.y, 0.01, render_distance);
+ projection_matrix = perspective(radians(fov), bounds.x / bounds.y, 0.01, render_distance);
shader_program->set("projection", projection_matrix); CHECKERR
}
void RenderEngine::updateViewMatrix()
{
- shader_program->set("view", camera->getViewMatrix()); CHECKERR
+ view_matrix = camera->getViewMatrix();
+ shader_program->set("view", view_matrix); CHECKERR
}
void RenderEngine::setSky(vec3 sky)
RenderEngine();
~RenderEngine();
- private:
+ private:
+ glm::mat4 view_matrix, projection_matrix;
double last_time;
double render_distance;
double fov;
meshes.erase(m);
}
-void Scene::render(double dtime, ShaderProgram *shader_program)
+void Scene::render(double dtime, ShaderProgram *shader_program, Frustum *frustum)
{
auto renderlist = meshes;
for (auto it = renderlist.begin(); it != renderlist.end(); it++) {
Mesh *mesh = *it;
- mesh->render(dtime, shader_program);
+ mesh->render(dtime, shader_program, frustum);
}
}
#include <set>
+class Frustum;
+
namespace dragonblocks
{
class Mesh;
public:
void add(Mesh *);
void remove(Mesh *);
- void render(double, ShaderProgram *);
+ void render(double, ShaderProgram *, Frustum *);
void clear();
void run();