Advancec Frustum Culling & fixes
This commit is contained in:
parent
11f004b582
commit
883dcbf168
14
.gitignore
vendored
14
.gitignore
vendored
@ -7,18 +7,18 @@ Debug/voxel_engine
|
||||
|
||||
/world
|
||||
/worlds/**/*
|
||||
/settings.toml
|
||||
|
||||
.vscode
|
||||
/.vs
|
||||
*.sln
|
||||
*.vcxproj
|
||||
*.filters
|
||||
*.user
|
||||
|
||||
.cache
|
||||
.settings
|
||||
.cproject
|
||||
.project
|
||||
.git
|
||||
/Default/
|
||||
/.vs
|
||||
/settings.toml
|
||||
/VoxelEngine-Cpp.sln
|
||||
/VoxelEngine-Cpp.vcxproj
|
||||
/VoxelEngine-Cpp.vcxproj.filters
|
||||
/VoxelEngine-Cpp.vcxproj.user
|
||||
/Default/
|
||||
@ -275,7 +275,7 @@ ImageData* _png_load(const char* file){
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *clr_type_str;
|
||||
const char *clr_type_str;
|
||||
if(ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE)
|
||||
clr_type_str = "grayscale";
|
||||
else if(ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR)
|
||||
|
||||
@ -50,15 +50,15 @@ HudRenderer::HudRenderer(Engine* engine, Level* level) : level(level), assets(en
|
||||
uicamera->perspective = false;
|
||||
uicamera->flipped = true;
|
||||
|
||||
Panel* panel = new Panel(vec2(200, 200), vec4(5.0f), 1.0f);
|
||||
Panel* panel = new Panel(vec2(250, 200), vec4(5.0f), 1.0f);
|
||||
panel->listenInterval(1.0f, [this]() {
|
||||
fpsString = std::to_wstring(fpsMax)+L" / "+std::to_wstring(fpsMin);
|
||||
fpsMin = fps;
|
||||
fpsMax = fps;
|
||||
});
|
||||
panel->setCoord(vec2(10, 10));
|
||||
panel->add(shared_ptr<Label>(create_label([this](){
|
||||
return L"chunks: "+std::to_wstring(this->level->chunks->chunksCount);
|
||||
panel->add(shared_ptr<Label>(create_label([this, level]() {
|
||||
return L"chunks: "+std::to_wstring(this->level->chunks->chunksCount)+L" visible: "+std::to_wstring(level->chunks->visible);
|
||||
})));
|
||||
panel->add(shared_ptr<Label>(create_label([this](){
|
||||
return L"fps: "+this->fpsString;
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "../objects/Player.h"
|
||||
#include "../assets/Assets.h"
|
||||
#include "../objects/player_control.h"
|
||||
#include "../maths/FrustumCulling.h"
|
||||
|
||||
using std::shared_ptr;
|
||||
|
||||
@ -28,6 +29,7 @@ WorldRenderer::WorldRenderer(Level* level, Assets* assets) : assets(assets), lev
|
||||
lineBatch = new LineBatch(4096);
|
||||
batch3d = new Batch3D(1024);
|
||||
renderer = new ChunksRenderer(level);
|
||||
frustumCulling = new Frustum();
|
||||
level->events->listen(EVT_CHUNK_HIDDEN, [this](lvl_event_type type, Chunk* chunk) {
|
||||
renderer->unload(chunk);
|
||||
});
|
||||
@ -37,6 +39,7 @@ WorldRenderer::~WorldRenderer() {
|
||||
delete batch3d;
|
||||
delete lineBatch;
|
||||
delete renderer;
|
||||
delete frustumCulling;
|
||||
}
|
||||
|
||||
bool WorldRenderer::drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion){
|
||||
@ -49,22 +52,15 @@ bool WorldRenderer::drawChunk(size_t index, Camera* camera, Shader* shader, bool
|
||||
|
||||
// Simple frustum culling
|
||||
if (occlusion){
|
||||
float y = camera->position.y+camera->front.y * CHUNK_H * 0.5f;
|
||||
if (y < 0.0f)
|
||||
y = 0.0f;
|
||||
if (y > CHUNK_H)
|
||||
y = CHUNK_H;
|
||||
vec3 v = vec3(chunk->x*CHUNK_W, y, chunk->z*CHUNK_D)-camera->position;
|
||||
if (v.x*v.x+v.z*v.z > (CHUNK_W*3)*(CHUNK_W*3)) {
|
||||
if (dot(camera->front, v) < 0.0f){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
glm::vec3 min = glm::vec3(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D);
|
||||
glm::vec3 max = glm::vec3(chunk->x * CHUNK_W + CHUNK_W, chunk->top, chunk->z * CHUNK_D + CHUNK_D);
|
||||
|
||||
if (!frustumCulling->IsBoxVisible(min, max)) return false;
|
||||
}
|
||||
mat4 model = glm::translate(mat4(1.0f), vec3(chunk->x*CHUNK_W, 0.0f, chunk->z*CHUNK_D+1));
|
||||
shader->uniformMatrix("u_model", model);
|
||||
mesh->draw(GL_TRIANGLES);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -120,10 +116,10 @@ void WorldRenderer::draw(Camera* camera, bool occlusion, float fogFactor, float
|
||||
(b->x + 0.5f - px)*(b->x + 0.5f - px) + (b->z + 0.5f - pz)*(b->z + 0.5f - pz));
|
||||
});
|
||||
|
||||
|
||||
int occludedChunks = 0;
|
||||
frustumCulling->update(camera->getProjection() * camera->getView());
|
||||
chunks->visible = 0;
|
||||
for (size_t i = 0; i < indices.size(); i++){
|
||||
occludedChunks += drawChunk(indices[i], camera, shader, occlusion);
|
||||
chunks->visible += drawChunk(indices[i], camera, shader, occlusion);
|
||||
}
|
||||
|
||||
shader->uniformMatrix("u_model", mat4(1.0f));
|
||||
@ -146,39 +142,26 @@ void WorldRenderer::draw(Camera* camera, bool occlusion, float fogFactor, float
|
||||
}
|
||||
|
||||
if (level->player->debug) {
|
||||
linesShader->use();
|
||||
linesShader->uniformMatrix("u_projview", camera->getProjection()*camera->getView());
|
||||
float lenght = 40.f;
|
||||
|
||||
vec3 point = vec3(camera->position.x+camera->front.x,
|
||||
camera->position.y+camera->front.y,
|
||||
camera->position.z+camera->front.z);
|
||||
linesShader->use();
|
||||
glm::mat4 model(1.0f);
|
||||
model = glm::translate(model, glm::vec3(Window::width >> 1, -static_cast<int>(Window::height) >> 1, 0.f));
|
||||
linesShader->uniformMatrix("u_projview", glm::ortho(0.f, static_cast<float>(Window::width), -static_cast<float>(Window::height), 0.f, -lenght, lenght) * model * glm::inverse(camera->rotation));
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glLineWidth(4.0f);
|
||||
lineBatch->line(point.x, point.y, point.z,
|
||||
point.x+0.1f, point.y, point.z,
|
||||
0, 0, 0, 1);
|
||||
lineBatch->line(point.x, point.y, point.z,
|
||||
point.x, point.y, point.z+0.1f,
|
||||
0, 0, 0, 1);
|
||||
lineBatch->line(point.x, point.y, point.z,
|
||||
point.x, point.y+0.1f, point.z,
|
||||
0, 0, 0, 1);
|
||||
lineBatch->line(0.f, 0.f, 0.f, lenght, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
lineBatch->line(0.f, 0.f, 0.f, 0.f, lenght, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, lenght, 0.f, 0.f, 0.f, 1.f);
|
||||
lineBatch->render();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glLineWidth(2.0f);
|
||||
lineBatch->line(point.x, point.y, point.z,
|
||||
point.x+0.1f, point.y, point.z,
|
||||
1, 0, 0, 1);
|
||||
lineBatch->line(point.x, point.y, point.z,
|
||||
point.x, point.y, point.z+0.1f,
|
||||
0, 0, 1, 1);
|
||||
lineBatch->line(point.x, point.y, point.z,
|
||||
point.x, point.y+0.1f, point.z,
|
||||
0, 1, 0, 1);
|
||||
lineBatch->line(0.f, 0.f, 0.f, lenght, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f);
|
||||
lineBatch->line(0.f, 0.f, 0.f, 0.f, lenght, 0.f, 0.f, 1.f, 0.f, 1.f);
|
||||
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, lenght, 0.f, 0.f, 1.f, 1.f);
|
||||
lineBatch->render();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,12 +20,13 @@ class ChunksRenderer;
|
||||
class Shader;
|
||||
class Texture;
|
||||
class Framebuffer;
|
||||
|
||||
class Frustum;
|
||||
|
||||
class WorldRenderer {
|
||||
Batch3D* batch3d;
|
||||
Assets* assets;
|
||||
Level* level;
|
||||
Frustum* frustumCulling;
|
||||
bool drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion);
|
||||
public:
|
||||
ChunksRenderer* renderer;
|
||||
|
||||
113
src/maths/FrustumCulling.h
Normal file
113
src/maths/FrustumCulling.h
Normal file
@ -0,0 +1,113 @@
|
||||
#include <glm/matrix.hpp>
|
||||
|
||||
class Frustum
|
||||
{
|
||||
public:
|
||||
Frustum() {};
|
||||
|
||||
void update(glm::mat4 projview);
|
||||
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 void Frustum::update(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);
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -157,7 +157,7 @@ void PlayerController::updateControls(float delta){
|
||||
float dt = min(1.0f, delta * ZOOM_SPEED);
|
||||
float zoomValue = 1.0f;
|
||||
if (crouch){
|
||||
cameraOffset += CROUCH_SHIFT_Y;
|
||||
cameraOffset += vec3(0.f, CROUCH_SHIFT_Y, 0.f);
|
||||
zoomValue = CROUCH_ZOOM;
|
||||
} else if (input.sprint){
|
||||
zoomValue = RUN_ZOOM;
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
#include "../lighting/Lightmap.h"
|
||||
|
||||
Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){
|
||||
bottom = 0;
|
||||
top = CHUNK_H;
|
||||
voxels = new voxel[CHUNK_VOL];
|
||||
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
||||
voxels[i].id = 2;
|
||||
@ -30,6 +32,22 @@ bool Chunk::isEmpty(){
|
||||
return true;
|
||||
}
|
||||
|
||||
void Chunk::updateHeights() {
|
||||
for (int i = 0; i < CHUNK_VOL; i++) {
|
||||
if (voxels[i].id != 0) {
|
||||
bottom = i / (CHUNK_D * CHUNK_W);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = CHUNK_VOL - 1; i > -1; i--) {
|
||||
if (voxels[i].id != 0) {
|
||||
top = i / (CHUNK_D * CHUNK_W) + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Chunk* Chunk::clone() const {
|
||||
Chunk* other = new Chunk(x,z);
|
||||
for (int i = 0; i < CHUNK_VOL; i++)
|
||||
|
||||
@ -26,6 +26,7 @@ struct RenderData {
|
||||
class Chunk {
|
||||
public:
|
||||
int x, z;
|
||||
int bottom, top;
|
||||
voxel* voxels;
|
||||
Lightmap* lightmap;
|
||||
int flags = 0;
|
||||
@ -37,6 +38,8 @@ public:
|
||||
|
||||
bool isEmpty();
|
||||
|
||||
void updateHeights();
|
||||
|
||||
Chunk* clone() const;
|
||||
|
||||
// flags getters/setters below
|
||||
|
||||
@ -139,6 +139,10 @@ void Chunks::set(int x, int y, int z, int id, uint8_t states){
|
||||
chunk->setUnsaved(true);
|
||||
chunk->setModified(true);
|
||||
|
||||
if (y < chunk->bottom) chunk->bottom = y;
|
||||
else if (y + 1 > chunk->top) chunk->top = y + 1;
|
||||
else if (id == 0) chunk->updateHeights();
|
||||
|
||||
if (lx == 0 && (chunk = getChunk(cx+ox-1, cz+oz))) chunk->setModified(true);
|
||||
if (lz == 0 && (chunk = getChunk(cx+ox, cz+oz-1))) chunk->setModified(true);
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ public:
|
||||
std::shared_ptr<Chunk>* chunksSecond;
|
||||
size_t volume;
|
||||
size_t chunksCount;
|
||||
size_t visible;
|
||||
int w,d;
|
||||
int ox,oz;
|
||||
WorldFiles* worldFiles;
|
||||
|
||||
@ -116,6 +116,8 @@ bool ChunksController::loadVisible(){
|
||||
chunk->setUnsaved(true);
|
||||
}
|
||||
|
||||
chunk->updateHeights();
|
||||
|
||||
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
||||
blockid_t id = chunk->voxels[i].id;
|
||||
if (Block::blocks[id] == nullptr) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user