Commit 91e8c1a6 authored by Shu's avatar Shu 🍠
Browse files

Frustum & Fog

parent 77d10611
......@@ -13,6 +13,7 @@
- [x] Render triangle
- [x] Avoid texture noise
- [x] MipMap LOD
- [x] Fog
- [ ] SRGB
- [ ] Skybox
- [ ] Better cheap planar
......@@ -24,5 +25,5 @@
- [ ] Dual MC
- [ ] Collision
- [ ] Render with glBufferSubData
- [ ] Frustum Culling
- [x] Frustum Culling
- [ ] Occlusion Culling
\ No newline at end of file
......@@ -8,6 +8,7 @@ uniform sampler2DArray NormalAtlas;
uniform sampler2DArray HOSAtlas;
uniform mat4 View;
uniform vec3 FogColor;
in VertexData {
vec3 Position_worldspace;
......@@ -18,6 +19,9 @@ in VertexData {
vec3 EyeDirection_cameraspace;
vec3 LightDirection_cameraspace;
#endif
#ifdef FOG
float Depth;
#endif
} vs;
vec3 expand(vec3 v) {
......@@ -140,4 +144,8 @@ void main() {
#else
color = tex;
#endif
#if FOG
float ratio = exp(vs.Depth * 0.69)-1;
color = mix(color, FogColor, clamp(ratio, 0, 1));
#endif
}
\ No newline at end of file
......@@ -13,6 +13,9 @@ out VertexData {
vec3 EyeDirection_cameraspace;
vec3 LightDirection_cameraspace;
#endif
#ifdef FOG
float Depth;
#endif
} vs;
uniform mat4 MVP;
......@@ -20,10 +23,15 @@ uniform mat4 Model;
uniform mat4 View;
uniform vec3 LightInvDirection_worldspace;
uniform float FogDepth;
void main(){
gl_Position = MVP * vec4(Position_modelspace, 1);
vs.Position_worldspace = Position_modelspace;
vs.Position_worldspace = (Model * vec4(Position_modelspace,1)).xyz;
#ifdef FOG
vs.Depth = length((View * vec4(vs.Position_worldspace,1)).xyz) / FogDepth;
#endif
vs.Material = float(Material_model);
......
......@@ -3,13 +3,13 @@
#include <glm/gtc/matrix_transform.hpp>
#include "../render/window.hpp"
Camera::Camera(GLFWwindow *window, const InputMap& inputs): window(window), inputs(inputs) {
Camera::Camera(GLFWwindow *window, const InputMap& inputs, const Camera::options& opt): window(window), inputs(inputs), o(opt) {
updateProjection();
}
Camera::~Camera() { }
void Camera::updateProjection() {
ProjectionMatrix = glm::perspective(FoV, RATIO, Near, Far);
ProjectionMatrix = glm::perspective(o.fov, RATIO, o.near, o.far);
}
void Camera::update(bool captureMouse, bool captureKeys) {
......@@ -29,8 +29,8 @@ void Camera::update(bool captureMouse, bool captureKeys) {
glfwGetCursorPos(window, &xPos, &yPos);
// Compute new orientation
HorizontalAngle += Sensibility * 0.0001f * float(viewportX / 2 - xPos);
VerticalAngle += Sensibility * 0.0001f * float(viewportY / 2 - yPos);
HorizontalAngle += o.sensibility * 0.0001f * float(viewportX / 2 - xPos);
VerticalAngle += o.sensibility * 0.0001f * float(viewportY / 2 - yPos);
} else {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
capturingMouse = true;
......@@ -57,27 +57,27 @@ void Camera::update(bool captureMouse, bool captureKeys) {
if(captureKeys) {
// Move forward
if (inputs.isDown(Input::Forward)) {
Position += direction * deltaTime * Speed;
Position += direction * deltaTime * o.speed;
}
// Move backward
if (inputs.isDown(Input::Backward)) {
Position -= direction * deltaTime * Speed;
Position -= direction * deltaTime * o.speed;
}
// Strafe right
if (inputs.isDown(Input::Right)) {
Position += right * deltaTime * Speed;
Position += right * deltaTime * o.speed;
}
// Strafe left
if (inputs.isDown(Input::Left)) {
Position -= right * deltaTime * Speed;
Position -= right * deltaTime * o.speed;
}
// Move up
if (inputs.isDown(Input::Up)) {
Position += up * deltaTime * Speed;
Position += up * deltaTime * o.speed;
}
// Move down
if (inputs.isDown(Input::Down)) {
Position -= up * deltaTime * Speed;
Position -= up * deltaTime * o.speed;
}
}
......
......@@ -5,11 +5,21 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "../data/glm.hpp"
#include "../data/geometry/Frustum.hpp"
/// Moving perspective camera
class Camera {
public:
Camera(GLFWwindow*, const InputMap&);
struct options {
float fov = glm::radians(70.f);
float near = 0.1;
float far = 64;
float speed = 5.0f;
int sensibility = 50;
};
Camera(GLFWwindow*, const InputMap&, const options&);
Camera(Camera &&) = default;
Camera(const Camera &) = default;
Camera &operator=(Camera &&) = default;
......@@ -17,20 +27,18 @@ public:
~Camera();
void update(bool captureMouse, bool captureKeys);
void updateProjection();
void setOptions(const options &options) {
o = options;
updateProjection();
}
glm::vec3 getDirection() const { return glm::vec3(cos(VerticalAngle) * sin(HorizontalAngle), sin(VerticalAngle), cos(VerticalAngle) * cos(HorizontalAngle)); }
inline Frustum getFrustum() const { return Frustum(ViewMatrix, ProjectionMatrix); }
glm::mat4 getViewMatrix() const { return ViewMatrix; }
glm::mat4 getProjectionMatrix() const { return ProjectionMatrix; }
camera_pos getPosition() const { return Position; }
float FoV = glm::radians(70.f);
float Near = 0.1;
float Far = 64;
float Speed = 5.0f;
int Sensibility = 50;
float getDepth() const { return o.far; }
private:
GLFWwindow *window;
......@@ -38,6 +46,7 @@ private:
glm::mat4 ViewMatrix;
glm::mat4 ProjectionMatrix;
void updateProjection();
camera_pos Position = glm::vec3(0, 0, 5);
......@@ -45,4 +54,5 @@ private:
float VerticalAngle = 0.0f;
bool capturingMouse = false;
options o;
};
#pragma once
#include <glm/glm.hpp>
#include <iostream>
/// Axis Aligned Floating Box
struct Box {
enum class ContainmentType {
Disjoint = false, Intersects, Contains
};
Box(glm::vec3 min, glm::vec3 max): Min(min), Max(max) {
assert(("Min > Max", max.x >= min.x && max.y >= min.y && max.z >= min.z));
}
inline static Box fromCenter(glm::vec3 center, float radius) { return Box(center - radius, center + radius); }
inline static Box fromMin(glm::vec3 min, glm::vec3 size) { return Box(min, min + size); }
glm::vec3 Min;
glm::vec3 Max;
ContainmentType contains(const Box& box) const {
//test if all corner is in the same side of a face by just checking min and max
if (box.Max.x < Min.x
|| box.Min.x > Max.x
|| box.Max.y < Min.y
|| box.Min.y > Max.y
|| box.Max.z < Min.z
|| box.Min.z > Max.z)
return ContainmentType::Disjoint;
if (box.Min.x >= Min.x
&& box.Max.x <= Max.x
&& box.Min.y >= Min.y
&& box.Max.y <= Max.y
&& box.Min.z >= Min.z
&& box.Max.z <= Max.z)
return ContainmentType::Contains;
return ContainmentType::Intersects;
}
};
#pragma once
#include "Box.hpp"
/// Bounding frustum
struct Frustum {
glm::vec4 planes[6];
enum FrustumSide
{
RIGHT = 0, // The RIGHT side of the frustum
LEFT = 1, // The LEFT side of the frustum
BOTTOM = 2, // The BOTTOM side of the frustum
TOP = 3, // The TOP side of the frustum
BACK = 4, // The BACK side of the frustum
FRONT = 5 // The FRONT side of the frustum
};
void normalize(glm::vec4 &plane) {
plane /= (float)sqrt(plane.x * plane.x + plane.y * plane.y + plane.z * plane.z);
}
Frustum(const glm::mat4& view_matrix, const glm::mat4& proj_matrix) {
const float *proj = &proj_matrix[0][0];
const float *modl = &view_matrix[0][0];
float clip[16]; //clipping planes
clip[0] = modl[0] * proj[0] + modl[1] * proj[4] + modl[2] * proj[8] + modl[3] * proj[12];
clip[1] = modl[0] * proj[1] + modl[1] * proj[5] + modl[2] * proj[9] + modl[3] * proj[13];
clip[2] = modl[0] * proj[2] + modl[1] * proj[6] + modl[2] * proj[10] + modl[3] * proj[14];
clip[3] = modl[0] * proj[3] + modl[1] * proj[7] + modl[2] * proj[11] + modl[3] * proj[15];
clip[4] = modl[4] * proj[0] + modl[5] * proj[4] + modl[6] * proj[8] + modl[7] * proj[12];
clip[5] = modl[4] * proj[1] + modl[5] * proj[5] + modl[6] * proj[9] + modl[7] * proj[13];
clip[6] = modl[4] * proj[2] + modl[5] * proj[6] + modl[6] * proj[10] + modl[7] * proj[14];
clip[7] = modl[4] * proj[3] + modl[5] * proj[7] + modl[6] * proj[11] + modl[7] * proj[15];
clip[8] = modl[8] * proj[0] + modl[9] * proj[4] + modl[10] * proj[8] + modl[11] * proj[12];
clip[9] = modl[8] * proj[1] + modl[9] * proj[5] + modl[10] * proj[9] + modl[11] * proj[13];
clip[10] = modl[8] * proj[2] + modl[9] * proj[6] + modl[10] * proj[10] + modl[11] * proj[14];
clip[11] = modl[8] * proj[3] + modl[9] * proj[7] + modl[10] * proj[11] + modl[11] * proj[15];
clip[12] = modl[12] * proj[0] + modl[13] * proj[4] + modl[14] * proj[8] + modl[15] * proj[12];
clip[13] = modl[12] * proj[1] + modl[13] * proj[5] + modl[14] * proj[9] + modl[15] * proj[13];
clip[14] = modl[12] * proj[2] + modl[13] * proj[6] + modl[14] * proj[10] + modl[15] * proj[14];
clip[15] = modl[12] * proj[3] + modl[13] * proj[7] + modl[14] * proj[11] + modl[15] * proj[15];
planes[RIGHT] = glm::vec4(clip[3] - clip[0], clip[7] - clip[4], clip[11] - clip[8], clip[15] - clip[12]);
normalize(planes[RIGHT]);
planes[LEFT] = glm::vec4(clip[3] + clip[0], clip[7] + clip[4], clip[11] + clip[8], clip[15] + clip[12]);
normalize(planes[LEFT]);
planes[BOTTOM] = glm::vec4(clip[3] + clip[1], clip[7] + clip[5], clip[11] + clip[9], clip[15] + clip[13]);
normalize(planes[BOTTOM]);
planes[TOP] = glm::vec4(clip[3] - clip[1], clip[7] - clip[5], clip[11] - clip[9], clip[15] - clip[13]);
normalize(planes[TOP]);
planes[BACK] = glm::vec4(clip[3] - clip[2], clip[7] - clip[6], clip[11] - clip[10], clip[15] - clip[14]);
normalize(planes[BACK]);
planes[FRONT] = glm::vec4(clip[3] + clip[2], clip[7] + clip[6], clip[11] + clip[10], clip[15] + clip[14]);
normalize(planes[FRONT]);
}
/// Check if box is contained
inline bool contains(const Box &box) const {
bool inside = true;
//test all 6 frustum planes
for (int i = 0; i<6; i++) {
//pick closest point to plane and check if it behind the plane
//if yes - object outside frustum
float d = std::max(box.Min.x * planes[i].x, box.Max.x * planes[i].x)
+ std::max(box.Min.y * planes[i].y, box.Max.y * planes[i].y)
+ std::max(box.Min.z * planes[i].z, box.Max.z * planes[i].z)
+ planes[i].w;
inside &= d > 0;
//return false; //with flag works faster
}
return inside;
}
};
......@@ -10,6 +10,7 @@
#include "circular_buffer.hpp"
#include "../render/Renderer.hpp"
#include "../world/World.hpp"
#include "../control/Camera.hpp"
/// Savable game options
struct options {
......@@ -25,12 +26,13 @@ struct options {
bool show_debug_world = false;
World::options world;
float voxelSize = 1;
float voxel_size = 1;
bool show_debug_contouring = false;
int contouring_idx = 0;
bool show_debug_controls = false;
Camera::options camera;
bool show_overlay = true;
int overlay_corner = 0;
......@@ -42,7 +44,8 @@ struct options {
/// Live state
struct state {
bool capture_mouse = true;
//std::optional<std::pair<voxel_pos, Voxel>> look_at = {};
camera_pos position;
std::optional<std::pair<voxel_pos, Voxel>> look_at = {};
char console_buffer[256];
};
......
......@@ -37,14 +37,13 @@ int main(int, char *[]){
glfwSwapInterval(options.target_fps < MIN_FPS);
InputMap inputs(window);
Camera camera(window, inputs);
Camera camera(window, inputs, options.camera);
Renderer *renderer = new Renderer(options.renderer);
UI::setup(window);
GLuint aimTexture = Program::loadTexture("ui/Aim", false);
const auto model = glm::scale(glm::mat4(1), glm::vec3(2));
renderer->LightInvDir = glm::vec3(-0.5f, 2, -2);
World world = World(options.world);
......@@ -59,6 +58,7 @@ int main(int, char *[]){
camera.update(state.capture_mouse, !UI::isFocus());
renderer->lookFrom(camera);
state.position = camera.getPosition();
/*look_at = world.raycast(camera.getViewRay() / scale);
if (capture_mouse && look_at.has_value()) {
if (inputs.isPressing(Mouse::Left))
......@@ -66,7 +66,7 @@ int main(int, char *[]){
else if (inputs.isPressing(Mouse::Right))
world.setCube(look_at.value().first, 2, Voxel{2, 1});
}*/
world.update(camera.getPosition() / options.voxelSize, reports.world);
world.update(state.position / options.voxel_size, reports.world);
inputs.saveKeys();
reports.main.update.push((glfwGetTime() - partTime) * 1000);
}
......@@ -95,9 +95,13 @@ int main(int, char *[]){
if(actions && UI::Actions::RendererTextures) {
renderer->reloadTextures(options.renderer.textures, options.renderer.mipMapLOD);
}
renderer->FogColor = glm::vec3(options.clear_color.x, options.clear_color.y, options.clear_color.z);
if(actions && UI::Actions::World) {
world.setOptions(options.world);
}
if(actions && UI::Actions::Camera) {
camera.setOptions(options.camera);
}
}
{ // Rendering
const double partTime = glfwGetTime();
......@@ -105,7 +109,11 @@ int main(int, char *[]){
pass.start();
std::vector<std::pair<glm::mat4, Buffer *>> models;
world.getModels(models, options.voxelSize);
if(options.culling) {
world.getModels(models, options.voxel_size, camera.getFrustum());
} else {
world.getModels(models, options.voxel_size);
}
reports.main.models_count = 0;
reports.main.tris_count = 0;
for (auto [model, buffer] : models) {
......
......@@ -49,4 +49,5 @@ void Renderer::loadTextures(const std::string& texturePath, float mipMapLOD) {
void Renderer::lookFrom(const Camera& camera) {
ProjectionMatrix = camera.getProjectionMatrix();
ViewMatrix = camera.getViewMatrix();
FogDepth = camera.getDepth();
}
\ No newline at end of file
......@@ -23,6 +23,8 @@ public:
~Renderer();
glm::vec3 LightInvDir = glm::vec3(0.5f, 2, 2);
glm::vec3 FogColor;
GLfloat FogDepth;
glm::mat4 getProjectionMatrix() const {
return ProjectionMatrix;
......
......@@ -68,6 +68,8 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
changeRenderer |= ImGui::Checkbox("PBR", &options.renderer.main.pbr);
ImGui::SameLine();
changeRenderer |= ImGui::Checkbox("Triplanar", &options.renderer.main.triplanar);
ImGui::SameLine();
changeRenderer |= ImGui::Checkbox("Fog", &options.renderer.main.fog);
if (changeRenderer) {
actions = actions | Actions::RendererSharders;
}
......@@ -91,7 +93,13 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
if (ImGui::SliderInt("Load distance", &options.world.loadDistance, 1, options.world.keepDistance) |
ImGui::SliderInt("Keep distance", &options.world.keepDistance, options.world.loadDistance + 1, 21)) {
actions = actions | Actions::World;
const auto far = std::clamp(options.camera.far, (options.world.loadDistance - 1.5f) * CHUNK_LENGTH * options.voxel_size, (options.world.keepDistance + .5f) * CHUNK_LENGTH * options.voxel_size);
if(far != options.camera.far) {
options.camera.far = far;
actions = actions | Actions::Camera;
}
}
ImGui::SliderFloat("Voxel size", &options.voxel_size, .1, 2);
ImGui::End();
}
......@@ -106,29 +114,29 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
ImGui::End();
}*/
/*if (options.show_debug_controls) {
if (options.show_debug_controls) {
ImGui::Begin("Debug: Controls", &options.show_debug_controls, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::Text("Position: (%.3f, %.3f, %.3f)", camera.getPosition().x, camera.getPosition().y, camera.getPosition().z);
if (look_at.has_value()) {
ImGui::Text("Look at: (%d, %d, %d) (%d, %.1f)", look_at.value().first.x, look_at.value().first.y, look_at.value().first.z, look_at.value().second.Material, look_at.value().second.Density); // TODO: printf array
ImGui::Text("(%.3f, %.3f, %.3f)", look_at.value().first.x * scale, look_at.value().first.y * scale, look_at.value().first.z * scale); // TODO: printf array
ImGui::Text("Position: (%.3f, %.3f, %.3f)", state.position.x, state.position.y, state.position.z);
if (state.look_at.has_value()) {
ImGui::Text("Look at: (%lld, %lld, %lld) (%d, %.1f)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, state.look_at.value().second.Material, state.look_at.value().second.Density / UCHAR_MAX);
ImGui::Text("(%.3f, %.3f, %.3f)", state.look_at.value().first.x * options.voxel_size, state.look_at.value().first.y * options.voxel_size, state.look_at.value().first.z * options.voxel_size);
} else {
ImGui::Text("Look at: none");
}
ImGui::Separator();
{
bool changePerspective = false;
changePerspective |= ImGui::SliderAngle("FoV", &camera.FoV, 30, 110);
changePerspective |= ImGui::SliderFloat("Near", &camera.Near, 0.01, 10);
changePerspective |= ImGui::SliderFloat("Far", &camera.Far, (world.getContouring()->getViewDistance() - 1.5) * CHUNK_LENGTH * scale, (world.getContouring()->getViewDistance() + .5) * CHUNK_LENGTH * scale);
changePerspective |= ImGui::SliderAngle("FoV", &options.camera.fov, 30, 110);
changePerspective |= ImGui::SliderFloat("Near", &options.camera.near, 0.01, 10);
changePerspective |= ImGui::SliderFloat("Far", &options.camera.far, (options.world.loadDistance - 1.5) * CHUNK_LENGTH * options.voxel_size, (options.world.keepDistance + .5) * CHUNK_LENGTH * options.voxel_size);
changePerspective |= ImGui::SliderFloat("Move speed", &options.camera.speed, 0.1, 50);
changePerspective |= ImGui::SliderInt("Sensibility", &options.camera.sensibility, 1, 100, "%d%%");
if(changePerspective) {
camera.updateProjection();
actions = actions | Actions::Camera;
}
}
ImGui::SliderFloat("Move speed", &camera.Speed, 0.1, 50);
ImGui::SliderInt("Sensibility", &camera.Sensibility, 1, 100, "%d%%");
ImGui::End();
}*/
}
/*if (show_console) {
ImGui::SetNextWindowPos(ImVec2(UI_MARGIN, 500), ImGuiCond_FirstUseEver);
......@@ -189,7 +197,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
ImGui::End();
}
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x / 2, io.DisplaySize.y / 2), ImGuiCond_Always, ImVec2(.5f, .5f));
ImGui::Begin("Aim", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground);
ImGui::Begin("Aim", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoInputs);
ImGui::Image((void *)(intptr_t)aim, ImVec2(32, 32));
ImGui::Render();
return actions;
......
......@@ -14,6 +14,7 @@ namespace UI {
RendererSharders = 1 << 3,
RendererTextures = 1 << 4,
World = 1 << 5,
Camera = 1 << 6,
};
inline Actions operator|(Actions a, Actions b) {
return static_cast<Actions>(static_cast<int>(a) | static_cast<int>(b));
......
......@@ -9,6 +9,8 @@ MainProgram::MainProgram(const MainProgram::options& opts): Program() {
flags.push_back("PBR");
if(opts.triplanar)
flags.push_back("TRIPLANAR");
if (opts.fog)
flags.push_back("FOG");
std::vector<Shader*> shaders;
shaders.push_back(loadShader(GL_VERTEX_SHADER, flags));
......@@ -24,6 +26,9 @@ MainProgram::MainProgram(const MainProgram::options& opts): Program() {
HOSID = glGetUniformLocation(ProgramID, "HOSAtlas");
LightInvDirID = glGetUniformLocation(ProgramID, "LightInvDirection_worldspace");
FogDepthID = glGetUniformLocation(ProgramID, "FogDepth");
FogColorID = glGetUniformLocation(ProgramID, "FogColor");
}
MainProgram::~MainProgram() { }
......@@ -36,6 +41,7 @@ void MainProgram::start(Renderer *renderer) {
bindNormal(renderer->getNormalAtlas());
bindHOS(renderer->getHOSAtlas());
setLightInvDir(&renderer->LightInvDir[0]);
setFog(&renderer->FogColor[0], renderer->FogDepth);
}
Buffer::params MainProgram::setup(Renderer *renderer, glm::mat4 modelMatrix) {
setModel(&modelMatrix[0][0]);
......@@ -73,4 +79,8 @@ void MainProgram::bindHOS(GLuint textureID) {
void MainProgram::setLightInvDir(const GLfloat *pos) {
glUniform3fv(LightInvDirID, 1, pos);
}
void MainProgram::setFog(const GLfloat *color, const GLfloat depth) {
glUniform3fv(FogColorID, 1, color);
glUniform1f(FogDepthID, depth);
}
\ No newline at end of file
......@@ -9,7 +9,7 @@ public:
bool pbr = true;
bool triplanar = false;
//TODO: bool blend = false;
//TODO: bool fog = true;
bool fog = true;
};
MainProgram(const options &opts);
......@@ -28,6 +28,7 @@ public:
void bindHOS(const GLuint textureID);
void setLightInvDir(const GLfloat *pos);
void setFog(const GLfloat *color, GLfloat depth);
private:
GLuint MVPMatrixID;
......@@ -39,4 +40,6 @@ private:
GLuint HOSID;
GLuint LightInvDirID;
GLuint FogDepthID;
GLuint FogColorID;
};
......@@ -64,7 +64,7 @@ void World::update(const camera_pos& pos, World::report& rep) {
rep.chunk_load.push(loadQueue.size());
// Load chunks
for (size_t i = 0; i < 2 && !loadQueue.empty(); i++) {
for (size_t i = 0; i < 8 && !loadQueue.empty(); i++) {
const auto pos = loadQueue.pop();
const auto chunk = std::make_shared<Chunk>(pos, generator);
chunks.insert({pos, chunk});
......@@ -83,3 +83,10 @@ void World::getModels(std::vector<std::pair<glm::mat4, Buffer*>> &out, float sca
out.push_back({glm::translate(scaling, glm::vec3(pos) * glm::vec3(CHUNK_LENGTH)), chunk->buffer});
}
}
void World::getModels(std::vector<std::pair<glm::mat4, Buffer*>> &out, float scale, const Frustum& frustum) const {
const auto scaling = glm::scale(glm::mat4(1), glm::vec3(scale));
for(const auto [pos, chunk]: chunks) {
if(chunk->buffer != NULL && frustum.contains(Box::fromMin(scale * glm::vec3(pos) * glm::vec3(CHUNK_LENGTH), scale * glm::vec3(CHUNK_LENGTH))))
out.push_back({glm::translate(scaling, glm::vec3(pos) * glm::vec3(CHUNK_LENGTH)), chunk->buffer});
}
}