introduce ChunkMesh

This commit is contained in:
MihailRis 2024-11-16 04:13:00 +03:00
parent 5793c52ac6
commit 5b6256e0fa
5 changed files with 172 additions and 42 deletions

View File

@ -12,6 +12,8 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "util/timeutil.hpp"
const uint BlocksRenderer::VERTEX_SIZE = 6; const uint BlocksRenderer::VERTEX_SIZE = 6;
const glm::vec3 BlocksRenderer::SUN_VECTOR (0.411934f, 0.863868f, -0.279161f); const glm::vec3 BlocksRenderer::SUN_VECTOR (0.411934f, 0.863868f, -0.279161f);
@ -433,21 +435,9 @@ glm::vec4 BlocksRenderer::pickSoftLight(
right, up); right, up);
} }
void BlocksRenderer::render(const voxel* voxels) { void BlocksRenderer::render(
int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D); const voxel* voxels, int beginEnds[256][2]
int totalEnd = chunk->top * (CHUNK_W * CHUNK_D); ) {
int beginEnds[256][2] {};
for (int i = totalBegin; i < totalEnd; i++) {
const voxel& vox = voxels[i];
blockid_t id = vox.id;
const auto& def = *blockDefsCache[id];
if (beginEnds[def.drawGroup][0] == 0) {
beginEnds[def.drawGroup][0] = i+1;
}
beginEnds[def.drawGroup][1] = i;
}
for (const auto drawGroup : *content.drawGroups) { for (const auto drawGroup : *content.drawGroups) {
int begin = beginEnds[drawGroup][0]; int begin = beginEnds[drawGroup][0];
if (begin == 0) { if (begin == 0) {
@ -462,13 +452,13 @@ void BlocksRenderer::render(const voxel* voxels) {
if (id == 0 || def.drawGroup != drawGroup || state.segment) { if (id == 0 || def.drawGroup != drawGroup || state.segment) {
continue; continue;
} }
//if (def.translucent) {
// continue;
//}
const UVRegion texfaces[6] { const UVRegion texfaces[6] {
cache.getRegion(id, 0), cache.getRegion(id, 0), cache.getRegion(id, 1),
cache.getRegion(id, 1), cache.getRegion(id, 2), cache.getRegion(id, 3),
cache.getRegion(id, 2), cache.getRegion(id, 4), cache.getRegion(id, 5)
cache.getRegion(id, 3),
cache.getRegion(id, 4),
cache.getRegion(id, 5)
}; };
int x = i % CHUNK_W; int x = i % CHUNK_W;
int y = i / (CHUNK_D * CHUNK_W); int y = i / (CHUNK_D * CHUNK_W);
@ -503,43 +493,143 @@ void BlocksRenderer::render(const voxel* voxels) {
} }
} }
SortingMeshData BlocksRenderer::renderTranslucent(
const voxel* voxels, int beginEnds[256][2]
) {
timeutil::ScopeLogTimer log(555);
SortingMeshData sortingMesh {{}};
for (const auto drawGroup : *content.drawGroups) {
int begin = beginEnds[drawGroup][0];
if (begin == 0) {
continue;
}
int end = beginEnds[drawGroup][1];
for (int i = begin-1; i <= end; i++) {
const voxel& vox = voxels[i];
blockid_t id = vox.id;
blockstate state = vox.state;
const auto& def = *blockDefsCache[id];
if (id == 0 || def.drawGroup != drawGroup || state.segment) {
continue;
}
if (!def.translucent) {
continue;
}
const UVRegion texfaces[6] {
cache.getRegion(id, 0), cache.getRegion(id, 1),
cache.getRegion(id, 2), cache.getRegion(id, 3),
cache.getRegion(id, 4), cache.getRegion(id, 5)
};
int x = i % CHUNK_W;
int y = i / (CHUNK_D * CHUNK_W);
int z = (i / CHUNK_D) % CHUNK_W;
switch (def.model) {
case BlockModel::block:
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
def.ambientOcclusion);
break;
case BlockModel::xsprite: {
blockXSprite(x, y, z, glm::vec3(1.0f),
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
break;
}
case BlockModel::aabb: {
blockAABB({x, y, z}, texfaces, &def, vox.state.rotation,
!def.shadeless, def.ambientOcclusion);
break;
}
case BlockModel::custom: {
blockCustomModel({x, y, z}, &def, vox.state.rotation,
!def.shadeless, def.ambientOcclusion);
break;
}
default:
break;
}
if (vertexOffset == 0) {
continue;
}
SortingMeshEntry entry {glm::vec3(
x + chunk->x * CHUNK_W, y, z + chunk->z * CHUNK_D
), util::Buffer<float>(indexSize * VERTEX_SIZE)};
for (int j = 0; j < indexSize; j++) {
std::memcpy(
entry.vertexData.data(),
vertexBuffer.get() + indexBuffer[j] * VERTEX_SIZE,
sizeof(float) * VERTEX_SIZE
);
}
sortingMesh.entries.push_back(std::move(entry));
vertexOffset = 0;
indexOffset = indexSize = 0;
}
}
return sortingMesh;
}
void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {
this->chunk = chunk; this->chunk = chunk;
voxelsBuffer->setPosition( voxelsBuffer->setPosition(
chunk->x * CHUNK_W - voxelBufferPadding, 0, chunk->x * CHUNK_W - voxelBufferPadding, 0,
chunk->z * CHUNK_D - voxelBufferPadding); chunk->z * CHUNK_D - voxelBufferPadding);
chunks->getVoxels(voxelsBuffer.get(), settings.graphics.backlight.get()); chunks->getVoxels(voxelsBuffer.get(), settings.graphics.backlight.get());
overflow = false;
vertexOffset = 0;
indexOffset = indexSize = 0;
if (voxelsBuffer->pickBlockId( if (voxelsBuffer->pickBlockId(
chunk->x * CHUNK_W, 0, chunk->z * CHUNK_D chunk->x * CHUNK_W, 0, chunk->z * CHUNK_D
) == BLOCK_VOID) { ) == BLOCK_VOID) {
cancelled = true; cancelled = true;
return; return;
} }
cancelled = false;
const voxel* voxels = chunk->voxels; const voxel* voxels = chunk->voxels;
render(voxels);
int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D);
int totalEnd = chunk->top * (CHUNK_W * CHUNK_D);
int beginEnds[256][2] {};
for (int i = totalBegin; i < totalEnd; i++) {
const voxel& vox = voxels[i];
blockid_t id = vox.id;
const auto& def = *blockDefsCache[id];
if (beginEnds[def.drawGroup][0] == 0) {
beginEnds[def.drawGroup][0] = i+1;
}
beginEnds[def.drawGroup][1] = i;
}
cancelled = false;
overflow = false;
vertexOffset = 0;
indexOffset = indexSize = 0;
sortingMesh = std::move(renderTranslucent(voxels, beginEnds));
overflow = false;
vertexOffset = 0;
indexOffset = indexSize = 0;
render(voxels, beginEnds);
} }
MeshData BlocksRenderer::createMesh() { ChunkMeshData BlocksRenderer::createMesh() {
const vattr attrs[]{ {3}, {2}, {1}, {0} }; const vattr attrs[]{ {3}, {2}, {1}, {0} };
return MeshData( return ChunkMeshData{MeshData(
util::Buffer<float>(vertexBuffer.get(), vertexOffset), util::Buffer<float>(vertexBuffer.get(), vertexOffset),
util::Buffer<int>(indexBuffer.get(), indexSize), util::Buffer<int>(indexBuffer.get(), indexSize),
util::Buffer<vattr>({{3}, {2}, {1}, {0}}) util::Buffer<vattr>({{3}, {2}, {1}, {0}})
); ), std::move(sortingMesh)};
} }
std::shared_ptr<Mesh> BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { ChunkMesh BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) {
build(chunk, chunks); build(chunk, chunks);
const vattr attrs[]{ {3}, {2}, {1}, {0} }; const vattr attrs[]{ {3}, {2}, {1}, {0} };
size_t vcount = vertexOffset / BlocksRenderer::VERTEX_SIZE; size_t vcount = vertexOffset / BlocksRenderer::VERTEX_SIZE;
return std::make_shared<Mesh>( return ChunkMesh{std::make_shared<Mesh>(
vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, attrs vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, attrs
); ), std::move(sortingMesh)};
} }
VoxelsVolume* BlocksRenderer::getVoxelsBuffer() const { VoxelsVolume* BlocksRenderer::getVoxelsBuffer() const {

View File

@ -12,6 +12,7 @@
#include "voxels/VoxelsVolume.hpp" #include "voxels/VoxelsVolume.hpp"
#include "graphics/core/MeshData.hpp" #include "graphics/core/MeshData.hpp"
#include "maths/util.hpp" #include "maths/util.hpp"
#include "commons.hpp"
class Content; class Content;
class Mesh; class Mesh;
@ -45,6 +46,8 @@ class BlocksRenderer {
util::PseudoRandom randomizer; util::PseudoRandom randomizer;
SortingMeshData sortingMesh;
void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light); void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light);
void index(int a, int b, int c, int d, int e, int f); void index(int a, int b, int c, int d, int e, int f);
@ -115,7 +118,6 @@ class BlocksRenderer {
bool isOpenForLight(int x, int y, int z) const; bool isOpenForLight(int x, int y, int z) const;
// Does block allow to see other blocks sides (is it transparent) // Does block allow to see other blocks sides (is it transparent)
inline bool isOpen(const glm::ivec3& pos, ubyte group) const { inline bool isOpen(const glm::ivec3& pos, ubyte group) const {
auto id = voxelsBuffer->pickBlockId( auto id = voxelsBuffer->pickBlockId(
@ -135,7 +137,9 @@ class BlocksRenderer {
glm::vec4 pickLight(const glm::ivec3& coord) const; glm::vec4 pickLight(const glm::ivec3& coord) const;
glm::vec4 pickSoftLight(const glm::ivec3& coord, const glm::ivec3& right, const glm::ivec3& up) const; glm::vec4 pickSoftLight(const glm::ivec3& coord, const glm::ivec3& right, const glm::ivec3& up) const;
glm::vec4 pickSoftLight(float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up) const; glm::vec4 pickSoftLight(float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up) const;
void render(const voxel* voxels);
void render(const voxel* voxels, int beginEnds[256][2]);
SortingMeshData renderTranslucent(const voxel* voxels, int beginEnds[256][2]);
public: public:
BlocksRenderer( BlocksRenderer(
size_t capacity, size_t capacity,
@ -146,8 +150,8 @@ public:
virtual ~BlocksRenderer(); virtual ~BlocksRenderer();
void build(const Chunk* chunk, const Chunks* chunks); void build(const Chunk* chunk, const Chunks* chunks);
std::shared_ptr<Mesh> render(const Chunk* chunk, const Chunks* chunks); ChunkMesh render(const Chunk* chunk, const Chunks* chunks);
MeshData createMesh(); ChunkMeshData createMesh();
VoxelsVolume* getVoxelsBuffer() const; VoxelsVolume* getVoxelsBuffer() const;
bool isCancelled() const { bool isCancelled() const {

View File

@ -62,7 +62,11 @@ ChunksRenderer::ChunksRenderer(
[&](){return std::make_shared<RendererWorker>(*level, cache, settings);}, [&](){return std::make_shared<RendererWorker>(*level, cache, settings);},
[&](RendererResult& result){ [&](RendererResult& result){
if (!result.cancelled) { if (!result.cancelled) {
meshes[result.key] = std::make_shared<Mesh>(result.meshData); auto meshData = std::move(result.meshData);
meshes[result.key] = ChunkMesh {
std::make_shared<Mesh>(meshData.mesh),
std::move(meshData.sortingMesh)
};
} }
inwork.erase(result.key); inwork.erase(result.key);
}, settings.graphics.chunkMaxRenderers.get()) }, settings.graphics.chunkMaxRenderers.get())
@ -82,8 +86,10 @@ std::shared_ptr<Mesh> ChunksRenderer::render(const std::shared_ptr<Chunk>& chunk
chunk->flags.modified = false; chunk->flags.modified = false;
if (important) { if (important) {
auto mesh = renderer->render(chunk.get(), level.chunks.get()); auto mesh = renderer->render(chunk.get(), level.chunks.get());
meshes[glm::ivec2(chunk->x, chunk->z)] = mesh; meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh {
return mesh; std::move(mesh.mesh), std::move(mesh.sortingMesh)
};
return meshes[glm::ivec2(chunk->x, chunk->z)].mesh;
} }
glm::ivec2 key(chunk->x, chunk->z); glm::ivec2 key(chunk->x, chunk->z);
if (inwork.find(key) != inwork.end()) { if (inwork.find(key) != inwork.end()) {
@ -115,7 +121,7 @@ std::shared_ptr<Mesh> ChunksRenderer::getOrRender(const std::shared_ptr<Chunk>&
if (chunk->flags.modified) { if (chunk->flags.modified) {
render(chunk, important); render(chunk, important);
} }
return found->second; return found->second.mesh;
} }
void ChunksRenderer::update() { void ChunksRenderer::update() {

View File

@ -10,6 +10,7 @@
#include "voxels/ChunksStorage.hpp" #include "voxels/ChunksStorage.hpp"
#include "util/ThreadPool.hpp" #include "util/ThreadPool.hpp"
#include "graphics/core/MeshData.hpp" #include "graphics/core/MeshData.hpp"
#include "commons.hpp"
class Mesh; class Mesh;
class Chunk; class Chunk;
@ -35,7 +36,7 @@ struct ChunksSortEntry {
struct RendererResult { struct RendererResult {
glm::ivec2 key; glm::ivec2 key;
bool cancelled; bool cancelled;
MeshData meshData; ChunkMeshData meshData;
}; };
class ChunksRenderer { class ChunksRenderer {
@ -45,7 +46,7 @@ class ChunksRenderer {
const EngineSettings& settings; const EngineSettings& settings;
std::unique_ptr<BlocksRenderer> renderer; std::unique_ptr<BlocksRenderer> renderer;
std::unordered_map<glm::ivec2, std::shared_ptr<Mesh>> meshes; std::unordered_map<glm::ivec2, ChunkMesh> meshes;
std::unordered_map<glm::ivec2, bool> inwork; std::unordered_map<glm::ivec2, bool> inwork;
std::vector<ChunksSortEntry> indices; std::vector<ChunksSortEntry> indices;
util::ThreadPool<std::shared_ptr<Chunk>, RendererResult> threadPool; util::ThreadPool<std::shared_ptr<Chunk>, RendererResult> threadPool;

View File

@ -0,0 +1,29 @@
#pragma once
#include <vector>
#include <memory>
#include <glm/vec3.hpp>
#include "graphics/core/MeshData.hpp"
#include "util/Buffer.hpp"
class Mesh;
struct SortingMeshEntry {
glm::vec3 position;
util::Buffer<float> vertexData;
};
struct SortingMeshData {
std::vector<SortingMeshEntry> entries;
};
struct ChunkMeshData {
MeshData mesh;
SortingMeshData sortingMesh;
};
struct ChunkMesh {
std::shared_ptr<Mesh> mesh;
SortingMeshData sortingMesh;
};