introduce ChunkMesh
This commit is contained in:
parent
5793c52ac6
commit
5b6256e0fa
@ -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 {
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
29
src/graphics/render/commons.hpp
Normal file
29
src/graphics/render/commons.hpp
Normal 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;
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user