Implement frustum culling (WIP)

This commit is contained in:
MrLetsplay 2023-12-25 17:39:54 +01:00
parent 3051fbd3b9
commit 5691afe59b
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
11 changed files with 127 additions and 13 deletions

View File

@ -198,7 +198,7 @@ int start() {
glm::mat4 view = kekData.activeCamera->transformationMatrix(); glm::mat4 view = kekData.activeCamera->transformationMatrix();
glm::mat4 projection; 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(); glm::vec3 position = kekData.activeCamera->getPosition();
@ -279,7 +279,10 @@ int start() {
} }
Timer drawTimer; 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(); timings.renderTime = drawTimer.elapsedSeconds();
} }
@ -292,7 +295,7 @@ int start() {
int time = (int) (glfwGetTime() * 10); int time = (int) (glfwGetTime() * 10);
if(time != prevTime) { if(time != prevTime) {
int fps = (int) floor(1.0f / kekData.lastTimings.frameTime); 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); fpsText->setText(str);
} }
prevTime = time; prevTime = time;
@ -305,11 +308,11 @@ int start() {
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
Timer idleTimer; Timer swapTimer;
// Swap buffers and poll window events // Swap buffers and poll window events
glfwSwapBuffers(kekData.window); glfwSwapBuffers(kekData.window);
glfwPollEvents(); glfwPollEvents();
timings.idleTime = idleTimer.elapsedSeconds(); timings.swapTime = swapTimer.elapsedSeconds();
timings.frameTime = frameTimer.elapsedSeconds(); timings.frameTime = frameTimer.elapsedSeconds();
kekData.lastTimings = timings; kekData.lastTimings = timings;

View File

@ -11,6 +11,7 @@ namespace kek {
GameObject::GameObject() { GameObject::GameObject() {
this->physics = nullptr; this->physics = nullptr;
this->boundingVolume = nullptr;
} }
GameObject::~GameObject() { GameObject::~GameObject() {
@ -21,9 +22,12 @@ GameObject::~GameObject() {
void GameObject::addMesh(Mesh *mesh) { void GameObject::addMesh(Mesh *mesh) {
meshes.push_back(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); glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, getPosition()) * glm::mat4_cast(getRotation()); model = glm::translate(model, getPosition()) * glm::mat4_cast(getRotation());
glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "model"), 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "model"), 1, GL_FALSE, glm::value_ptr(model));

View File

@ -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) { for(GameObject *obj : objects) {
obj->draw(shader); obj->draw(shader, frustum);
} }
} }

View File

@ -8,11 +8,25 @@
#include <glm/gtx/matrix_decompose.hpp> #include <glm/gtx/matrix_decompose.hpp>
#include <math.h> #include <math.h>
#include "constants.h"
#include "object.h" #include "object.h"
#include "utils.h" #include "utils.h"
namespace kek { 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() { Camera::Camera() {
this->position = glm::vec3(0.0f, 0.0f, 0.0f); this->position = glm::vec3(0.0f, 0.0f, 0.0f);
this->direction = glm::vec3(0.0f, 0.0f, -1.0f); this->direction = glm::vec3(0.0f, 0.0f, -1.0f);
@ -125,4 +139,25 @@ void Camera::applyEuler(glm::vec3 euler) {
roll = euler.z; roll = euler.z;
} }
} 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);
}
}

View File

@ -1,5 +1,6 @@
#include "mesh.h" #include "mesh.h"
#include "camera.h"
#include "constants.h" #include "constants.h"
#include <GL/glew.h> #include <GL/glew.h>
@ -90,4 +91,12 @@ void Mesh::draw(Shader *shader) {
glBindVertexArray(0); 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);
}
} }

View File

@ -2,10 +2,64 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "glm/geometric.hpp"
#include "object.h" #include "object.h"
namespace kek { 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 { class Camera: public DefaultObject {
public: public:
@ -38,6 +92,8 @@ class Camera: public DefaultObject {
glm::vec3 eulerAngles(); glm::vec3 eulerAngles();
void applyEuler(glm::vec3 euler); void applyEuler(glm::vec3 euler);
Frustum getFrustum(float aspect);
}; };
} }

View File

@ -20,6 +20,7 @@
#define KEK_NOCLIP_SPEED 10.0f #define KEK_NOCLIP_SPEED 10.0f
#define KEK_CAMERA_FOV 90.0f
#define KEK_CAMERA_NEAR 0.1f #define KEK_CAMERA_NEAR 0.1f
#define KEK_CAMERA_FAR 100.0f #define KEK_CAMERA_FAR 100.0f

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "camera.h"
#include "mesh.h" #include "mesh.h"
#include "object.h" #include "object.h"
#include "physics.h" #include "physics.h"
@ -12,6 +13,7 @@ class GameObject: public DefaultRotateableObject {
protected: protected:
std::vector<Mesh *> meshes; std::vector<Mesh *> meshes;
BoundingVolume *boundingVolume;
public: public:
PhysicsObjectData *physics; 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 // 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 addMesh(Mesh *mesh);
void draw(Shader *shader); void draw(Shader *shader, const Frustum &frustum);
void addPhysics(btCollisionShape *shape, float mass, int collisionFlags = 0); void addPhysics(btCollisionShape *shape, float mass, int collisionFlags = 0);

View File

@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "camera.h"
#include "shader.h" #include "shader.h"
#include "texture.h" #include "texture.h"
@ -44,6 +45,8 @@ class Mesh {
~Mesh(); ~Mesh();
void draw(Shader *shader); void draw(Shader *shader);
BoundingVolume *createBoundingVolume();
}; };
} }

View File

@ -2,6 +2,7 @@
#include <vector> #include <vector>
#include "camera.h"
#include "gameobject.h" #include "gameobject.h"
#include "light.h" #include "light.h"
@ -24,7 +25,7 @@ class Scene {
void removeObject(GameObject *object); void removeObject(GameObject *object);
// Draws the scene // Draws the scene
void draw(Shader *shader); void draw(Shader *shader, const Frustum &frustum);
}; };
} }

View File

@ -12,7 +12,7 @@ struct Timings {
float physicsTime = 0; float physicsTime = 0;
float lightingTime = 0; float lightingTime = 0;
float renderTime = 0; float renderTime = 0;
float idleTime = 0; float swapTime = 0;
}; };
class Timer { class Timer {