diff --git a/src/kekengine/cpp/common/engine.cpp b/src/kekengine/cpp/common/engine.cpp index 1c2628b..b6ff748 100644 --- a/src/kekengine/cpp/common/engine.cpp +++ b/src/kekengine/cpp/common/engine.cpp @@ -198,7 +198,7 @@ int start() { glm::mat4 view = kekData.activeCamera->transformationMatrix(); glm::mat4 projection; - projection = glm::perspective(glm::radians(90.0f), kekData.screenWidth / (float) kekData.screenHeight, KEK_CAMERA_NEAR, KEK_CAMERA_FAR); + projection = glm::perspective(glm::radians(KEK_CAMERA_FOV), kekData.screenWidth / (float) kekData.screenHeight, KEK_CAMERA_NEAR, KEK_CAMERA_FAR); glm::vec3 position = kekData.activeCamera->getPosition(); @@ -279,7 +279,10 @@ int start() { } Timer drawTimer; - kekData.activeScene->draw(kekData.shader); + + Frustum frustum = getActiveCamera()->getFrustum((float) kekData.screenHeight / kekData.screenWidth); + + kekData.activeScene->draw(kekData.shader, frustum); timings.renderTime = drawTimer.elapsedSeconds(); } @@ -292,7 +295,7 @@ int start() { int time = (int) (glfwGetTime() * 10); if(time != prevTime) { int fps = (int) floor(1.0f / kekData.lastTimings.frameTime); - std::string str = "FPS: " + std::to_string(fps) + " (" + formatSeconds(kekData.lastTimings.frameTime) + ")" + " | Physics: " + formatSeconds(kekData.lastTimings.physicsTime) + ", Lighting: " + formatSeconds(kekData.lastTimings.lightingTime) + ", Render: " + formatSeconds(kekData.lastTimings.renderTime) + ", Idle: " + formatSeconds(kekData.lastTimings.idleTime); + std::string str = "FPS: " + std::to_string(fps) + " (" + formatSeconds(kekData.lastTimings.frameTime) + ")" + " | Physics: " + formatSeconds(kekData.lastTimings.physicsTime) + ", Lighting: " + formatSeconds(kekData.lastTimings.lightingTime) + ", Render: " + formatSeconds(kekData.lastTimings.renderTime) + ", Swap: " + formatSeconds(kekData.lastTimings.swapTime); fpsText->setText(str); } prevTime = time; @@ -305,11 +308,11 @@ int start() { glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); - Timer idleTimer; + Timer swapTimer; // Swap buffers and poll window events glfwSwapBuffers(kekData.window); glfwPollEvents(); - timings.idleTime = idleTimer.elapsedSeconds(); + timings.swapTime = swapTimer.elapsedSeconds(); timings.frameTime = frameTimer.elapsedSeconds(); kekData.lastTimings = timings; diff --git a/src/kekengine/cpp/object/gameobject.cpp b/src/kekengine/cpp/object/gameobject.cpp index 9fb6425..5bb83ba 100644 --- a/src/kekengine/cpp/object/gameobject.cpp +++ b/src/kekengine/cpp/object/gameobject.cpp @@ -11,6 +11,7 @@ namespace kek { GameObject::GameObject() { this->physics = nullptr; + this->boundingVolume = nullptr; } GameObject::~GameObject() { @@ -21,9 +22,12 @@ GameObject::~GameObject() { void GameObject::addMesh(Mesh *mesh) { meshes.push_back(mesh); + boundingVolume = mesh->createBoundingVolume(); // TODO: move somewhere else } -void GameObject::draw(Shader *shader) { +void GameObject::draw(Shader *shader, const Frustum &frustum) { + if(boundingVolume && !boundingVolume->isContained(frustum, getPosition(), getRotation())) return; + glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, getPosition()) * glm::mat4_cast(getRotation()); glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "model"), 1, GL_FALSE, glm::value_ptr(model)); diff --git a/src/kekengine/cpp/object/scene.cpp b/src/kekengine/cpp/object/scene.cpp index 6651b1e..98fce2b 100644 --- a/src/kekengine/cpp/object/scene.cpp +++ b/src/kekengine/cpp/object/scene.cpp @@ -26,9 +26,9 @@ void Scene::removeObject(GameObject *object) { } } -void Scene::draw(Shader *shader) { +void Scene::draw(Shader *shader, const Frustum &frustum) { for(GameObject *obj : objects) { - obj->draw(shader); + obj->draw(shader, frustum); } } diff --git a/src/kekengine/cpp/render/camera.cpp b/src/kekengine/cpp/render/camera.cpp index be5bd75..be46f83 100644 --- a/src/kekengine/cpp/render/camera.cpp +++ b/src/kekengine/cpp/render/camera.cpp @@ -8,11 +8,25 @@ #include #include +#include "constants.h" #include "object.h" #include "utils.h" namespace kek { +float Plane::getDistance(glm::vec3 point) const { + return glm::dot(point, normal) - distance; +} + +bool Frustum::contains(glm::vec3 point) const { + return near.getDistance(point) >= 0 && far.getDistance(point) >= 0 && left.getDistance(point) >= 0 && right.getDistance(point) >= 0 && top.getDistance(point) >= 0 && bottom.getDistance(point) >= 0; +} + +bool SphereBoundingVolume::isContained(const Frustum &frustum, glm::vec3 position, glm::quat rotation) { + glm::vec3 point = position + offset; + return frustum.near.getDistance(point) >= -radius && frustum.far.getDistance(point) >= -radius && frustum.left.getDistance(point) >= -radius && frustum.right.getDistance(point) >= -radius && frustum.top.getDistance(point) >= -radius && frustum.bottom.getDistance(point) >= -radius; +} + Camera::Camera() { this->position = glm::vec3(0.0f, 0.0f, 0.0f); this->direction = glm::vec3(0.0f, 0.0f, -1.0f); @@ -125,4 +139,25 @@ void Camera::applyEuler(glm::vec3 euler) { roll = euler.z; } -} \ No newline at end of file +Frustum Camera::getFrustum(float aspect) { + float halfW = KEK_CAMERA_FAR * tanf(glm::radians(KEK_CAMERA_FOV * 0.5f)); + float halfH = halfW * aspect; + glm::vec3 farPoint = KEK_CAMERA_FAR * direction; + + float rollRad = glm::radians(roll); + float x = sin(rollRad); + float y = cos(rollRad); + glm::vec3 up = glm::vec3(x, y, 0.0f); + glm::vec3 cameraRight = glm::normalize(glm::cross(direction, up)); + glm::vec3 cameraUp = glm::normalize(glm::cross(cameraRight, direction)); + + Plane near = Plane(position + KEK_CAMERA_NEAR * direction, direction); + Plane far = Plane(position + farPoint, -direction); + Plane left = Plane(position, glm::cross(farPoint + cameraRight * -halfW, cameraUp)); + Plane right = Plane(position, glm::cross(cameraUp, farPoint + cameraRight * halfW)); + Plane top = Plane(position, glm::cross(farPoint + cameraUp * halfH, cameraRight)); + Plane bottom = Plane(position, glm::cross(cameraRight, farPoint + cameraUp * -halfH)); + return Frustum(near, far, top, bottom, left, right); +} + +} diff --git a/src/kekengine/cpp/render/mesh.cpp b/src/kekengine/cpp/render/mesh.cpp index f1641b8..9acf7ce 100644 --- a/src/kekengine/cpp/render/mesh.cpp +++ b/src/kekengine/cpp/render/mesh.cpp @@ -1,5 +1,6 @@ #include "mesh.h" +#include "camera.h" #include "constants.h" #include @@ -90,4 +91,12 @@ void Mesh::draw(Shader *shader) { glBindVertexArray(0); } +BoundingVolume *Mesh::createBoundingVolume() { + float maxDist = 0; + for(Vertex v : vertices) { + maxDist = glm::max(maxDist, glm::length(glm::vec3(v.pos.x, v.pos.y, v.pos.z))); + } + return new SphereBoundingVolume(glm::vec3(0), maxDist); +} + } diff --git a/src/kekengine/include/camera.h b/src/kekengine/include/camera.h index 5fe0591..5bfd960 100644 --- a/src/kekengine/include/camera.h +++ b/src/kekengine/include/camera.h @@ -2,10 +2,64 @@ #include +#include "glm/geometric.hpp" #include "object.h" namespace kek { +class Plane { + glm::vec3 normal; + float distance; + + public: + Plane(glm::vec3 normal, float distance) + : normal(glm::normalize(normal)), + distance(distance){}; + + Plane(glm::vec3 point, glm::vec3 normal) + : normal(glm::normalize(normal)), + distance(glm::dot(this->normal, point)){}; + + float getDistance(glm::vec3 point) const; +}; + +struct Frustum { + const Plane near; + const Plane far; + const Plane top; + const Plane bottom; + const Plane left; + const Plane right; + + Frustum(Plane near, Plane far, Plane top, Plane bottom, Plane left, Plane right) + : near(near), + far(far), + top(top), + bottom(bottom), + left(left), + right(right){}; + + bool contains(glm::vec3 point) const; +}; + +class BoundingVolume { + public: + virtual bool isContained(const Frustum &frustum, glm::vec3 position, glm::quat rotation) = 0; +}; + +class SphereBoundingVolume: public BoundingVolume { + private: + glm::vec3 offset; + float radius; + + public: + SphereBoundingVolume(glm::vec3 offset, float radius) + : offset(offset), + radius(radius) {} + + virtual bool isContained(const Frustum &frustum, glm::vec3 position, glm::quat rotation); +}; + class Camera: public DefaultObject { public: @@ -38,6 +92,8 @@ class Camera: public DefaultObject { glm::vec3 eulerAngles(); void applyEuler(glm::vec3 euler); + + Frustum getFrustum(float aspect); }; -} \ No newline at end of file +} diff --git a/src/kekengine/include/constants.h b/src/kekengine/include/constants.h index d57cbd6..0eee88b 100644 --- a/src/kekengine/include/constants.h +++ b/src/kekengine/include/constants.h @@ -20,6 +20,7 @@ #define KEK_NOCLIP_SPEED 10.0f +#define KEK_CAMERA_FOV 90.0f #define KEK_CAMERA_NEAR 0.1f #define KEK_CAMERA_FAR 100.0f diff --git a/src/kekengine/include/gameobject.h b/src/kekengine/include/gameobject.h index a557eee..9dc4372 100644 --- a/src/kekengine/include/gameobject.h +++ b/src/kekengine/include/gameobject.h @@ -1,5 +1,6 @@ #pragma once +#include "camera.h" #include "mesh.h" #include "object.h" #include "physics.h" @@ -12,6 +13,7 @@ class GameObject: public DefaultRotateableObject { protected: std::vector meshes; + BoundingVolume *boundingVolume; public: PhysicsObjectData *physics; @@ -23,7 +25,7 @@ class GameObject: public DefaultRotateableObject { // Adds a mesh to the GameObject. The GameObject takes ownership of the Mesh, so don't use Meshes in multiple GameObjects void addMesh(Mesh *mesh); - void draw(Shader *shader); + void draw(Shader *shader, const Frustum &frustum); void addPhysics(btCollisionShape *shape, float mass, int collisionFlags = 0); diff --git a/src/kekengine/include/mesh.h b/src/kekengine/include/mesh.h index 7e1e7e4..65d4284 100644 --- a/src/kekengine/include/mesh.h +++ b/src/kekengine/include/mesh.h @@ -6,6 +6,7 @@ #include #include +#include "camera.h" #include "shader.h" #include "texture.h" @@ -44,6 +45,8 @@ class Mesh { ~Mesh(); void draw(Shader *shader); + + BoundingVolume *createBoundingVolume(); }; } diff --git a/src/kekengine/include/scene.h b/src/kekengine/include/scene.h index 5e31446..bd405c1 100644 --- a/src/kekengine/include/scene.h +++ b/src/kekengine/include/scene.h @@ -2,6 +2,7 @@ #include +#include "camera.h" #include "gameobject.h" #include "light.h" @@ -24,7 +25,7 @@ class Scene { void removeObject(GameObject *object); // Draws the scene - void draw(Shader *shader); + void draw(Shader *shader, const Frustum &frustum); }; } diff --git a/src/kekengine/include/timings.h b/src/kekengine/include/timings.h index 4b33835..b911d39 100644 --- a/src/kekengine/include/timings.h +++ b/src/kekengine/include/timings.h @@ -12,7 +12,7 @@ struct Timings { float physicsTime = 0; float lightingTime = 0; float renderTime = 0; - float idleTime = 0; + float swapTime = 0; }; class Timer {