Merge pull request #734 from MihailRis/visuals-restoration

Visuals restoration and optimizations
This commit is contained in:
MihailRis 2025-12-18 21:04:09 +03:00 • committed by GitHub
commit 024f9670eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 111 additions and 58 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 779 B

After

Width:  |  Height:  |  Size: 6.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Before After
Before After

View file

@ -30,7 +30,7 @@ void main() {
texColor.rgb = u_debugNormals ? (a_normal * 0.5 + 0.5) : vec3(1.0); texColor.rgb = u_debugNormals ? (a_normal * 0.5 + 0.5) : vec3(1.0);
f_color = texColor; f_color = texColor;
f_color.rgb *= min(vec3(1.0), a_torchLight.rgb + a_skyLight); f_color.rgb *= max(a_torchLight.rgb, a_skyLight);
#ifndef ADVANCED_RENDER #ifndef ADVANCED_RENDER
vec3 fogColor = texture(u_skybox, a_dir).rgb; vec3 fogColor = texture(u_skybox, a_dir).rgb;

View file

@ -485,6 +485,8 @@ ALAudio::ALAudio(ALCdevice* device, ALCcontext* context)
for (auto& name : inputDevices) { for (auto& name : inputDevices) {
logger.info() << " " << name; logger.info() << " " << name;
} }
alDopplerFactor(1.0 / 3.0);
} }
ALAudio::~ALAudio() { ALAudio::~ALAudio() {

View file

@ -28,10 +28,6 @@ BlocksRenderer::BlocksRenderer(
cache(cache), cache(cache),
settings(settings) settings(settings)
{ {
voxelsBuffer = std::make_unique<VoxelsVolume>(
CHUNK_W + voxelBufferPadding*2,
CHUNK_H,
CHUNK_D + voxelBufferPadding*2);
blockDefsCache = content.getIndices()->blocks.getDefs(); blockDefsCache = content.getIndices()->blocks.getDefs();
} }
@ -313,6 +309,7 @@ void BlocksRenderer::blockCustomModel(
overflow = true; overflow = true;
return; return;
} }
bool shading = mesh.shading && !block.shadeless;
for (int triangle = 0; triangle < mesh.vertices.size() / 3; triangle++) { for (int triangle = 0; triangle < mesh.vertices.size() / 3; triangle++) {
auto r = mesh.vertices[triangle * 3 + (triangle % 2) * 2].coord - auto r = mesh.vertices[triangle * 3 + (triangle % 2) * 2].coord -
mesh.vertices[triangle * 3 + 1].coord; mesh.vertices[triangle * 3 + 1].coord;
@ -329,7 +326,9 @@ void BlocksRenderer::blockCustomModel(
0.5f; 0.5f;
vp = vp.x * X + vp.y * Y + vp.z * Z; vp = vp.x * X + vp.y * Y + vp.z * Z;
if (!isOpen(glm::floor(coord + vp + 0.5f + n * 1e-3f), block, variant) && is_aligned(n)) { if (!block.rt.extended
&& !isOpen(glm::floor(coord + vp + 0.5f + n * 1e-3f), block, variant)
&& is_aligned(n)) {
continue; continue;
} }
@ -342,22 +341,29 @@ void BlocksRenderer::blockCustomModel(
const auto& vcoord = vertex.coord - 0.5f; const auto& vcoord = vertex.coord - 0.5f;
glm::vec4 aoColor {1.0f, 1.0f, 1.0f, 1.0f}; glm::vec4 aoColor {1.0f, 1.0f, 1.0f, 1.0f};
if (mesh.shading && ao) { if (shading && ao) {
const float eps = 0.05f; const float eps = 0.05f;
auto p = coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z + auto p = coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z +
r * 0.5f + t * 0.5f + n * eps; r * 0.5f + t * 0.5f + n * eps;
auto p1 = p + n * eps; auto p1 = p + n * eps;
auto p2 = p + n * 0.5f; auto p2 = p + n * 0.5f;
aoColor = pickSoftLight(p1.x, p1.y, p1.z, glm::ivec3(r), glm::ivec3(t)); aoColor = pickSoftLight(p1.x, p1.y, p1.z, glm::ivec3(r), glm::ivec3(t));
aoColor = glm::max(aoColor, pickSoftLight(p2.x, p2.y, p2.z, glm::ivec3(r), glm::ivec3(t))); if (!block.lightPassing) {
aoColor = glm::max(
aoColor,
pickSoftLight(
p2.x, p2.y, p2.z, glm::ivec3(r), glm::ivec3(t)
)
);
}
} }
this->vertex( this->vertex(
coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z, coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z,
vertex.uv.x, vertex.uv.x,
vertex.uv.y, vertex.uv.y,
mesh.shading ? (glm::vec4(d, d, d, d) * aoColor) : glm::vec4(1, 1, 1, d), shading ? (glm::vec4(d, d, d, d) * aoColor) : glm::vec4(1, 1, 1, d),
n, n,
mesh.shading ? 0.0f : 1.0 shading ? 0.0f : 1.0
); );
indexBuffer[indexCount++] = vertexOffset++; indexBuffer[indexCount++] = vertexOffset++;
} }
@ -691,13 +697,9 @@ SortingMeshData BlocksRenderer::renderTranslucent(
return sortingMesh; return sortingMesh;
} }
void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { void BlocksRenderer::build(const Chunk* chunk, const VoxelsVolume& volume) {
this->chunk = chunk; this->chunk = chunk;
voxelsBuffer->setPosition( this->voxelsBuffer = &volume;
chunk->x * CHUNK_W - voxelBufferPadding, 0,
chunk->z * CHUNK_D - voxelBufferPadding);
chunks->getVoxels(*voxelsBuffer, settings.graphics.backlight.get());
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) {
@ -738,7 +740,7 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {
indexCount = 0; indexCount = 0;
denseIndexCount = 0; denseIndexCount = 0;
denseRender = false; //settings.graphics.denseRender.get(); denseRender = false;
densePass = false; densePass = false;
render(voxels, beginEnds); render(voxels, beginEnds);
@ -767,15 +769,18 @@ ChunkMeshData BlocksRenderer::createMesh() {
util::Buffer(denseIndexBuffer.get(), denseIndexCount), util::Buffer(denseIndexBuffer.get(), denseIndexCount),
}, },
util::Buffer( util::Buffer(
ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute) ChunkVertex::ATTRIBUTES,
sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute)
) )
), ),
std::move(sortingMesh) std::move(sortingMesh)
}; };
} }
ChunkMesh BlocksRenderer::render(const Chunk *chunk, const Chunks *chunks) { ChunkMesh BlocksRenderer::render(
build(chunk, chunks); const Chunk* chunk, const VoxelsVolume& volume
) {
build(chunk, volume);
return ChunkMesh{std::make_unique<Mesh<ChunkVertex>>( return ChunkMesh{std::make_unique<Mesh<ChunkVertex>>(
vertexBuffer.get(), vertexCount, vertexBuffer.get(), vertexCount,
@ -786,11 +791,6 @@ ChunkMesh BlocksRenderer::render(const Chunk *chunk, const Chunks *chunks) {
), std::move(sortingMesh)}; ), std::move(sortingMesh)};
} }
VoxelsVolume* BlocksRenderer::getVoxelsBuffer() const {
return voxelsBuffer.get();
}
size_t BlocksRenderer::getMemoryConsumption() const { size_t BlocksRenderer::getMemoryConsumption() const {
size_t volume = voxelsBuffer->getW() * voxelsBuffer->getH() * voxelsBuffer->getD(); return capacity * (sizeof(ChunkVertex) + sizeof(uint32_t) * 2);
return capacity * (sizeof(ChunkVertex) + sizeof(uint32_t) * 2) + volume * (sizeof(voxel) + sizeof(light_t));
} }

View file

@ -32,13 +32,12 @@ class BlocksRenderer {
size_t indexCount; size_t indexCount;
size_t denseIndexCount; size_t denseIndexCount;
size_t capacity; size_t capacity;
int voxelBufferPadding = 2;
bool overflow = false; bool overflow = false;
bool cancelled = false; bool cancelled = false;
bool densePass = false; bool densePass = false;
bool denseRender = false; bool denseRender = false;
const Chunk* chunk = nullptr; const Chunk* chunk = nullptr;
std::unique_ptr<VoxelsVolume> voxelsBuffer; const VoxelsVolume* voxelsBuffer = nullptr;
const Block* const* blockDefsCache; const Block* const* blockDefsCache;
const ContentGfxCache& cache; const ContentGfxCache& cache;
@ -152,9 +151,13 @@ class BlocksRenderer {
glm::vec4 pickLight(int x, int y, int z) const; glm::vec4 pickLight(int x, int y, int z) const;
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(
glm::vec4 pickSoftLight(float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up) const; 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;
void render(const voxel* voxels, const int beginEnds[256][2]); void render(const voxel* voxels, const int beginEnds[256][2]);
SortingMeshData renderTranslucent(const voxel* voxels, int beginEnds[256][2]); SortingMeshData renderTranslucent(const voxel* voxels, int beginEnds[256][2]);
public: public:
@ -166,10 +169,11 @@ public:
); );
virtual ~BlocksRenderer(); virtual ~BlocksRenderer();
void build(const Chunk* chunk, const Chunks* chunks); void build(const Chunk* chunk, const VoxelsVolume& volume);
ChunkMesh render(const Chunk* chunk, const Chunks* chunks); ChunkMesh render(
const Chunk* chunk, const VoxelsVolume& volume
);
ChunkMeshData createMesh(); ChunkMeshData createMesh();
VoxelsVolume* getVoxelsBuffer() const;
size_t getMemoryConsumption() const; size_t getMemoryConsumption() const;

View file

@ -12,24 +12,22 @@
#include "window/Camera.hpp" #include "window/Camera.hpp"
#include "maths/FrustumCulling.hpp" #include "maths/FrustumCulling.hpp"
#include "util/listutil.hpp" #include "util/listutil.hpp"
#include "util/ObjectsPool.hpp"
#include "settings.hpp" #include "settings.hpp"
static debug::Logger logger("chunks-render"); static debug::Logger logger("chunks-render");
size_t ChunksRenderer::visibleChunks = 0; size_t ChunksRenderer::visibleChunks = 0;
class RendererWorker : public util::Worker<std::shared_ptr<Chunk>, RendererResult> { class RendererWorker : public util::Worker<RendererJob, RendererResult> {
const Chunks& chunks;
BlocksRenderer renderer; BlocksRenderer renderer;
public: public:
RendererWorker( RendererWorker(
const Level& level, const Level& level,
const Chunks& chunks,
const ContentGfxCache& cache, const ContentGfxCache& cache,
const EngineSettings& settings const EngineSettings& settings
) )
: chunks(chunks), : renderer(
renderer(
settings.graphics.denseRender.get() settings.graphics.denseRender.get()
? settings.graphics.chunkMaxVerticesDense.get() ? settings.graphics.chunkMaxVerticesDense.get()
: settings.graphics.chunkMaxVertices.get(), : settings.graphics.chunkMaxVertices.get(),
@ -39,8 +37,10 @@ public:
) { ) {
} }
RendererResult operator()(const std::shared_ptr<Chunk>& chunk) override { RendererResult operator()(const RendererJob& job) override {
renderer.build(chunk.get(), &chunks); auto chunk = job.chunk;
auto volume = job.volume;
renderer.build(chunk.get(), *volume);
if (renderer.isCancelled()) { if (renderer.isCancelled()) {
return RendererResult { return RendererResult {
glm::ivec2(chunk->x, chunk->z), true, ChunkMeshData {}}; glm::ivec2(chunk->x, chunk->z), true, ChunkMeshData {}};
@ -51,6 +51,9 @@ public:
} }
}; };
static util::ObjectsPool<VoxelsVolume> voxelsVolumesPool {};
static inline const int VOXELS_BUFFER_PADDING = 2;
ChunksRenderer::ChunksRenderer( ChunksRenderer::ChunksRenderer(
const Level* level, const Level* level,
const Chunks& chunks, const Chunks& chunks,
@ -67,7 +70,7 @@ ChunksRenderer::ChunksRenderer(
"chunks-render-pool", "chunks-render-pool",
[&]() { [&]() {
return std::make_shared<RendererWorker>( return std::make_shared<RendererWorker>(
*level, chunks, cache, settings *level, cache, settings
); );
}, },
[&](RendererResult& result) { [&](RendererResult& result) {
@ -87,30 +90,61 @@ ChunksRenderer::ChunksRenderer(
level->content, cache, settings level->content, cache, settings
); );
logger.info() << "created " << threadPool.getWorkersCount() << " workers"; logger.info() << "created " << threadPool.getWorkersCount() << " workers";
logger.info() << "memory consumption is " logger.info() << "memory consumption is "
<< renderer->getMemoryConsumption() * threadPool.getWorkersCount() << renderer->getMemoryConsumption() *
<< " B"; threadPool.getWorkersCount() +
voxelsVolumesPool.countTotal() *
(sizeof(VoxelsVolume) +
(CHUNK_W + VOXELS_BUFFER_PADDING * 2) * CHUNK_H *
(CHUNK_D + VOXELS_BUFFER_PADDING * 2) *
(sizeof(voxel) + sizeof(light_t)))
<< " B";
} }
ChunksRenderer::~ChunksRenderer() = default; ChunksRenderer::~ChunksRenderer() = default;
std::shared_ptr<VoxelsVolume> ChunksRenderer::prepareVoxelsVolume(
const Chunk& chunk
) {
auto voxelsBuffer = voxelsVolumesPool.create(
CHUNK_W + VOXELS_BUFFER_PADDING * 2,
CHUNK_H,
CHUNK_D + VOXELS_BUFFER_PADDING * 2
);
voxelsBuffer->setPosition(
chunk.x * CHUNK_W - VOXELS_BUFFER_PADDING, 0,
chunk.z * CHUNK_D - VOXELS_BUFFER_PADDING
);
chunks.getVoxels(
*voxelsBuffer, settings.graphics.backlight.get(), chunk.top + 1
);
return voxelsBuffer;
}
const Mesh<ChunkVertex>* ChunksRenderer::render( const Mesh<ChunkVertex>* ChunksRenderer::render(
const std::shared_ptr<Chunk>& chunk, bool important const std::shared_ptr<Chunk>& chunk, bool important
) { ) {
glm::ivec2 key(chunk->x, chunk->z);
chunk->flags.modified = false; chunk->flags.modified = false;
if (important) { if (important) {
auto mesh = renderer->render(chunk.get(), &chunks); auto voxelsBuffer = prepareVoxelsVolume(*chunk);
meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh { inwork[key] = true;
std::move(mesh.mesh), std::move(mesh.sortingMeshData)
}; auto mesh = renderer->render(chunk.get(), *voxelsBuffer);
meshes[glm::ivec2(chunk->x, chunk->z)] =
ChunkMesh {std::move(mesh.mesh), std::move(mesh.sortingMeshData)};
return meshes[glm::ivec2(chunk->x, chunk->z)].mesh.get(); return meshes[glm::ivec2(chunk->x, chunk->z)].mesh.get();
} }
glm::ivec2 key(chunk->x, chunk->z);
if (inwork.find(key) != inwork.end()) { if (inwork.find(key) != inwork.end()) {
return nullptr; return nullptr;
} }
auto voxelsBuffer = prepareVoxelsVolume(*chunk);
inwork[key] = true; inwork[key] = true;
threadPool.enqueueJob(chunk); chunks.getVoxels(
*voxelsBuffer, settings.graphics.backlight.get(), chunk->top + 1
);
threadPool.enqueueJob({chunk, std::move(voxelsBuffer)});
return nullptr; return nullptr;
} }

View file

@ -21,6 +21,7 @@ class Chunks;
class Frustum; class Frustum;
class BlocksRenderer; class BlocksRenderer;
class ContentGfxCache; class ContentGfxCache;
class VoxelsVolume;
struct EngineSettings; struct EngineSettings;
struct ChunksSortEntry { struct ChunksSortEntry {
@ -38,6 +39,11 @@ struct RendererResult {
ChunkMeshData meshData; ChunkMeshData meshData;
}; };
struct RendererJob {
std::shared_ptr<Chunk> chunk;
std::shared_ptr<VoxelsVolume> volume;
};
class ChunksRenderer { class ChunksRenderer {
const Chunks& chunks; const Chunks& chunks;
const Assets& assets; const Assets& assets;
@ -48,10 +54,11 @@ class ChunksRenderer {
std::unordered_map<glm::ivec2, ChunkMesh> 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<RendererJob, RendererResult> threadPool;
const Mesh<ChunkVertex>* retrieveChunk( const Mesh<ChunkVertex>* retrieveChunk(
size_t index, const Camera& camera, bool culling size_t index, const Camera& camera, bool culling
); );
std::shared_ptr<VoxelsVolume> prepareVoxelsVolume(const Chunk& chunk);
public: public:
ChunksRenderer( ChunksRenderer(
const Level* level, const Level* level,

View file

@ -126,7 +126,7 @@ void Emitter::update(
} }
void Emitter::stop() { void Emitter::stop() {
count = 0; this->count = 0;
} }
bool Emitter::isDead() const { bool Emitter::isDead() const {
@ -138,7 +138,7 @@ bool Emitter::isReferred() const {
} }
const EmitterOrigin& Emitter::getOrigin() const { const EmitterOrigin& Emitter::getOrigin() const {
return origin; return this->origin;
} }
void Emitter::setOrigin(const EmitterOrigin& origin) { void Emitter::setOrigin(const EmitterOrigin& origin) {

View file

@ -149,7 +149,7 @@ void PrecipitationRenderer::render(
glm::cross(glm::vec3(0, 1, 0), face.right), glm::cross(glm::vec3(0, 1, 0), face.right),
FACE_SIZE, FACE_SIZE,
light_at(chunks, pos.x, y, pos.z), light_at(chunks, pos.x, y, pos.z),
glm::vec3(2.0f), glm::vec3(3.0f),
calc_uv(pos, face.right, timer, weather) calc_uv(pos, face.right, timer, weather)
); );
} }

View file

@ -46,6 +46,10 @@ namespace util {
freeObjects.push(ptr); freeObjects.push(ptr);
}); });
} }
size_t countTotal() const {
return objects.size();
}
private: private:
std::vector<std::unique_ptr<void, AlignedDeleter>> objects; std::vector<std::unique_ptr<void, AlignedDeleter>> objects;
std::queue<void*> freeObjects; std::queue<void*> freeObjects;

View file

@ -334,7 +334,8 @@ bool Chunks::putChunk(const std::shared_ptr<Chunk>& chunk) {
// reduce nesting on next modification // reduce nesting on next modification
// 25.06.2024: not now // 25.06.2024: not now
// 11.11.2024: not now // 11.11.2024: not now
void Chunks::getVoxels(VoxelsVolume& volume, bool backlight) const { // 12.12.2025: not now
void Chunks::getVoxels(VoxelsVolume& volume, bool backlight, int top) const {
voxel* voxels = volume.getVoxels(); voxel* voxels = volume.getVoxels();
light_t* lights = volume.getLights(); light_t* lights = volume.getLights();
int x = volume.getX(); int x = volume.getX();
@ -342,7 +343,7 @@ void Chunks::getVoxels(VoxelsVolume& volume, bool backlight) const {
int z = volume.getZ(); int z = volume.getZ();
int w = volume.getW(); int w = volume.getW();
int h = volume.getH(); int h = std::min<int>(volume.getH(), top);
int d = volume.getD(); int d = volume.getD();
int scx = floordiv<CHUNK_W>(x); int scx = floordiv<CHUNK_W>(x);

View file

@ -9,6 +9,7 @@
#include "typedefs.hpp" #include "typedefs.hpp"
#include "voxel.hpp" #include "voxel.hpp"
#include "constants.hpp"
#include "util/AreaMap2D.hpp" #include "util/AreaMap2D.hpp"
class VoxelRenderer; class VoxelRenderer;
@ -126,7 +127,7 @@ public:
bool isReplaceableBlock(int32_t x, int32_t y, int32_t z); bool isReplaceableBlock(int32_t x, int32_t y, int32_t z);
bool isObstacleBlock(int32_t x, int32_t y, int32_t z); bool isObstacleBlock(int32_t x, int32_t y, int32_t z);
void getVoxels(VoxelsVolume& volume, bool backlight = false) const; void getVoxels(VoxelsVolume& volume, bool backlight = false, int top = CHUNK_H) const;
void setCenter(int32_t x, int32_t z); void setCenter(int32_t x, int32_t z);
void resize(uint32_t newW, uint32_t newD); void resize(uint32_t newW, uint32_t newD);