]> git.lizzy.rs Git - dragonblocks3d.git/commitdiff
Frustum & Backface Culling
authorElias Fleckenstein <eliasfleckenstein@web.de>
Sun, 13 Sep 2020 14:53:05 +0000 (16:53 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Sun, 13 Sep 2020 14:53:05 +0000 (16:53 +0200)
lib/FrustumCull.h [new file with mode: 0644]
src/dragonblocks/chunk.cpp
src/dragonblocks/client.cpp
src/dragonblocks/cube.cpp
src/dragonblocks/mesh.cpp
src/dragonblocks/mesh.hpp
src/dragonblocks/render_engine.cpp
src/dragonblocks/render_engine.hpp
src/dragonblocks/scene.cpp
src/dragonblocks/scene.hpp

diff --git a/lib/FrustumCull.h b/lib/FrustumCull.h
new file mode 100644 (file)
index 0000000..ab97929
--- /dev/null
@@ -0,0 +1,117 @@
+#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);
+}
index 5c6433dfad9a118f7ff381f8906884e192442a3a..2100511ca836c3e6fb99f39b834826ba4b1aa7c7 100644 (file)
@@ -137,6 +137,8 @@ void Chunk::updateMesh()
        
        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) {
index c98cec344c39df8ef82cd40b98c780288cb7756c..c8fa8dbd28f658ec209de8c54beb4f00b84d72f8 100644 (file)
@@ -18,7 +18,7 @@ Client::Client()
 {
        log("Initalizing...");
        
-       Texture::mipmap = false;
+       Texture::mipmap = true;
        Texture::bilinear_filter = false;
        Texture::initArgs();
        
@@ -41,8 +41,8 @@ Client::Client()
        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);
        
index f506de5f37cb8c79c03becfee0d90f96cca9f079..e132b70e80e09d72640886db3129bf79722ffabd 100644 (file)
@@ -9,21 +9,21 @@ GLfloat dragonblocks::cube[DRAGONBLOCKS_CUBE_VERTEX_COUNT] = {
        -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,
index 2d077f3d0a558cb15b8b8fec0e20e5dd33893e90..e8741ac614adb391419478d0af364e0469ec52e5 100644 (file)
@@ -3,6 +3,7 @@
 #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"
@@ -76,7 +77,7 @@ Mesh::Animation::Animation(Mesh::Animation::Type t, void (*o)(void *), void *e)
        }
 }
 
-void Mesh::render(double dtime, ShaderProgram *shader_program)
+void Mesh::render(double dtime, ShaderProgram *shader_program, Frustum *frustum)
 {
        rendering = true;
        
@@ -95,6 +96,9 @@ void Mesh::render(double dtime, ShaderProgram *shader_program)
        
        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
index b603bc9e9f5596c8059b33a8940939099cbe5388..4dafcc92cf69ce1e762a7c2700de243cbcbe6415 100644 (file)
@@ -4,6 +4,8 @@
 #include "gl.hpp"
 #include "texture.hpp"
 
+class Frustum;
+
 namespace dragonblocks
 {
        class Scene;
@@ -44,11 +46,12 @@ namespace dragonblocks
                
                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();
                
index 5476bd106c7f71aab07bfe30c26baf58a197fcda..fb23d35179225aab5e5cd5d47307883d8becdb09 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdexcept>
 #include <glm/gtc/matrix_transform.hpp>
+#include "FrustumCull.h"
 #include "camera.hpp"
 #include "gldebug.hpp"
 #include "input_handler.hpp"
@@ -21,11 +22,16 @@ void RenderEngine::render()
        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
@@ -39,13 +45,14 @@ bool RenderEngine::running()
 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)
index fcf54749ffbc2c4580b9e5e21ae2ee2f46823e82..c1732c6fb2f14ec99dd738d5cfea5ec6dea4d93f 100644 (file)
@@ -34,7 +34,8 @@ namespace dragonblocks
                RenderEngine();
                ~RenderEngine();
                
-               private:                
+               private:
+               glm::mat4 view_matrix, projection_matrix;
                double last_time;
                double render_distance;
                double fov;
index fa230b5d6738ccce1b5967bd03c75423c45bf69d..2f74bb21aa3745d8a707ef495230d0c8644dd921 100644 (file)
@@ -14,12 +14,12 @@ void Scene::remove(Mesh *m)
        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);
        }
 }
 
index fdf0d860224ad41d2d8b8dd688bb10b84ffcf5cd..fc0f62dcc366aef55a0d354d2cd903dad259a095 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <set>
 
+class Frustum;
+
 namespace dragonblocks
 {
        class Mesh;
@@ -11,7 +13,7 @@ namespace dragonblocks
                public:
                void add(Mesh *);
                void remove(Mesh *);
-               void render(double, ShaderProgram *);
+               void render(double, ShaderProgram *, Frustum *);
                void clear();
                void run();