mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-07 12:01:50 +00:00
Merge pull request #852 from MihailRis/refactor-world-renderer
update world renderer (part 1)
This commit is contained in:
commit
33053f07ed
45 changed files with 737 additions and 593 deletions
|
|
@ -372,7 +372,7 @@ void Batch2D::sprite(
|
|||
void Batch2D::flush() {
|
||||
if (index == 0)
|
||||
return;
|
||||
mesh->reload(buffer.get(), index);
|
||||
mesh->reload(buffer.get(), index, true);
|
||||
mesh->draw(gl::to_glenum(primitive));
|
||||
index = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,13 +292,13 @@ void Batch3D::point(const glm::vec3& coord, const glm::vec4& tint) {
|
|||
}
|
||||
|
||||
void Batch3D::flush() {
|
||||
mesh->reload(buffer.get(), index);
|
||||
mesh->reload(buffer.get(), index, true);
|
||||
mesh->draw();
|
||||
index = 0;
|
||||
}
|
||||
|
||||
void Batch3D::flushPoints() {
|
||||
mesh->reload(buffer.get(), index);
|
||||
mesh->reload(buffer.get(), index, true);
|
||||
mesh->draw(GL_POINTS);
|
||||
index = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ void LineBatch::box(float x, float y, float z, float w, float h, float d,
|
|||
void LineBatch::flush(){
|
||||
if (index == 0)
|
||||
return;
|
||||
mesh->reload(buffer.get(), index);
|
||||
mesh->reload(buffer.get(), index, true);
|
||||
mesh->draw(GL_LINES);
|
||||
index = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,12 +47,15 @@ public:
|
|||
void reload(
|
||||
const VertexStructure* vertexBuffer,
|
||||
size_t vertexCount,
|
||||
const std::vector<IndexBufferData>& indices
|
||||
const std::vector<IndexBufferData>& indices,
|
||||
bool streaming
|
||||
);
|
||||
|
||||
void reload(const VertexStructure* vertexBuffer, size_t vertexCount) {
|
||||
void reload(
|
||||
const VertexStructure* vertexBuffer, size_t vertexCount, bool streaming
|
||||
) {
|
||||
static const std::vector<IndexBufferData> indices {};
|
||||
reload(vertexBuffer, vertexCount, indices);
|
||||
reload(vertexBuffer, vertexCount, indices, streaming);
|
||||
}
|
||||
|
||||
/// @brief Draw mesh with specified primitives type
|
||||
|
|
@ -61,6 +64,8 @@ public:
|
|||
|
||||
/// @brief Draw mesh as triangles
|
||||
void draw() const;
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#include "graphics/core/Mesh.inl"
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@ Mesh<VertexStructure>::Mesh(
|
|||
glGenVertexArrays(1, &vao);
|
||||
glGenBuffers(1, &vbo);
|
||||
|
||||
reload(vertexBuffer, vertices, std::move(indices));
|
||||
|
||||
glBindVertexArray(vao);
|
||||
reload(vertexBuffer, vertices, std::move(indices), false);
|
||||
|
||||
// attributes
|
||||
int offset = 0;
|
||||
for (int i = 0; attrs[i].count; i++) {
|
||||
|
|
@ -82,20 +82,22 @@ template <typename VertexStructure>
|
|||
void Mesh<VertexStructure>::reload(
|
||||
const VertexStructure* vertexBuffer,
|
||||
size_t vertexCount,
|
||||
const std::vector<IndexBufferData>& indices
|
||||
const std::vector<IndexBufferData>& indices,
|
||||
bool streaming
|
||||
) {
|
||||
this->vertexCount = vertexCount;
|
||||
glBindVertexArray(vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
if (vertexBuffer != nullptr && vertexCount != 0) {
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
vertexCount * sizeof(VertexStructure),
|
||||
vertexBuffer,
|
||||
GL_STREAM_DRAW
|
||||
streaming ? GL_STREAM_DRAW : GL_STATIC_DRAW
|
||||
);
|
||||
} else {
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER, 0, {}, streaming ? GL_STREAM_DRAW : GL_STATIC_DRAW
|
||||
);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ibos.size(); i++) {
|
||||
|
|
@ -116,7 +118,6 @@ void Mesh<VertexStructure>::reload(
|
|||
GL_STATIC_DRAW
|
||||
);
|
||||
}
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
template <typename VertexStructure>
|
||||
|
|
|
|||
|
|
@ -186,7 +186,8 @@ void Shader::recompile(const std::vector<std::string>& defines) {
|
|||
glDeleteProgram(id);
|
||||
id = newProgram;
|
||||
uniformLocations.clear();
|
||||
logger.info() << "shader " << id << " has been recompiled";
|
||||
logger.debug() << "shader program (" << vertexSource.file << ", "
|
||||
<< fragmentSource.file << ") has been recompiled";
|
||||
}
|
||||
|
||||
std::unique_ptr<Shader> Shader::create(
|
||||
|
|
|
|||
|
|
@ -99,8 +99,8 @@ void Shadows::setup(Shader& shader, const Weather& weather) {
|
|||
if (!shadows) {
|
||||
return;
|
||||
}
|
||||
const auto& worldInfo = level.getWorld()->getInfo();
|
||||
float cloudsIntensity = glm::max(worldInfo.fog, weather.clouds());
|
||||
const auto& worldInfo = level.getWorld().getInfo();
|
||||
float cloudsIntensity = weather.clouds();
|
||||
float shadowsOpacity = 1.0f - cloudsIntensity;
|
||||
shadowsOpacity *= glm::sqrt(glm::abs(
|
||||
glm::mod((worldInfo.daytime + 0.5f) * 2.0f, 1.0f) * 2.0f - 1.0f
|
||||
|
|
@ -158,8 +158,8 @@ void Shadows::generateShadowsMap(
|
|||
float scale,
|
||||
const std::function<void(Camera&)>& renderShadowPass
|
||||
) {
|
||||
auto world = level.getWorld();
|
||||
const auto& worldInfo = world->getInfo();
|
||||
const auto& world = level.getWorld();
|
||||
const auto& worldInfo = world.getInfo();
|
||||
|
||||
int resolution = shadowMap.getResolution();
|
||||
float shadowMapScale = 0.32f / (1 << glm::max(0, quality)) * scale;
|
||||
|
|
|
|||
|
|
@ -10,15 +10,14 @@
|
|||
#include "frontend/ContentGfxCache.hpp"
|
||||
|
||||
const glm::vec3 BlocksRenderer::SUN_VECTOR(0.528265, 0.833149, -0.163704);
|
||||
const float DIRECTIONAL_LIGHT_FACTOR = 0.3f;
|
||||
constexpr float DIRECTIONAL_LIGHT_FACTOR = 0.3f;
|
||||
|
||||
BlocksRenderer::BlocksRenderer(
|
||||
size_t capacity,
|
||||
const Content& content,
|
||||
const Block* const* blockDefs,
|
||||
const ContentGfxCache& cache,
|
||||
const EngineSettings& settings
|
||||
) : content(content),
|
||||
vertexBuffer(std::make_unique<ChunkVertex[]>(capacity)),
|
||||
) : vertexBuffer(std::make_unique<ChunkVertex[]>(capacity)),
|
||||
indexBuffer(std::make_unique<uint32_t[]>(capacity)),
|
||||
denseIndexBuffer(std::make_unique<uint32_t[]>(capacity)),
|
||||
vertexCount(0),
|
||||
|
|
@ -28,7 +27,7 @@ BlocksRenderer::BlocksRenderer(
|
|||
cache(cache),
|
||||
settings(settings)
|
||||
{
|
||||
blockDefsCache = content.getIndices()->blocks.getDefs();
|
||||
blockDefsCache = blockDefs;
|
||||
}
|
||||
|
||||
BlocksRenderer::~BlocksRenderer() = default;
|
||||
|
|
@ -482,83 +481,78 @@ glm::vec4 BlocksRenderer::pickSoftLight(
|
|||
}
|
||||
|
||||
void BlocksRenderer::render(
|
||||
const voxel* voxels, const int beginEnds[256][2]
|
||||
const voxel* voxels, int totalBegin, int totalEnd
|
||||
) {
|
||||
bool denseRender = this->denseRender;
|
||||
bool densePass = this->densePass;
|
||||
bool enableAO = settings.graphics.softLighting.get();
|
||||
for (const auto drawGroup : *content.drawGroups) {
|
||||
int begin = beginEnds[drawGroup][0];
|
||||
if (begin == 0) {
|
||||
|
||||
for (int i = totalBegin; i < totalEnd; i++) {
|
||||
const voxel& vox = voxels[i];
|
||||
blockid_t id = vox.id;
|
||||
blockstate state = vox.state;
|
||||
const auto& def = *blockDefsCache[id];
|
||||
uint8_t variantId = def.getVariantIndex(state.userbits);
|
||||
const auto& variant = def.getVariant(variantId);
|
||||
if (id == 0 || state.segment) {
|
||||
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];
|
||||
uint8_t variantId = def.getVariantIndex(state.userbits);
|
||||
const auto& variant = def.getVariant(variantId);
|
||||
if (id == 0 || variant.drawGroup != drawGroup || state.segment) {
|
||||
continue;
|
||||
if (denseRender != (variant.culling == CullingMode::OPTIONAL)) {
|
||||
continue;
|
||||
}
|
||||
if (def.translucent) {
|
||||
continue;
|
||||
}
|
||||
const UVRegion texfaces[6] {
|
||||
cache.getRegion(id, variantId, 0, densePass),
|
||||
cache.getRegion(id, variantId, 1, densePass),
|
||||
cache.getRegion(id, variantId, 2, densePass),
|
||||
cache.getRegion(id, variantId, 3, densePass),
|
||||
cache.getRegion(id, variantId, 4, densePass),
|
||||
cache.getRegion(id, variantId, 5, densePass)
|
||||
};
|
||||
int x = i % CHUNK_W;
|
||||
int y = i / (CHUNK_D * CHUNK_W);
|
||||
int z = (i / CHUNK_D) % CHUNK_W;
|
||||
|
||||
switch (def.getModel(state.userbits).type) {
|
||||
case BlockModelType::BLOCK:
|
||||
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
|
||||
def.ambientOcclusion && enableAO);
|
||||
break;
|
||||
case BlockModelType::XSPRITE: {
|
||||
if (!denseRender)
|
||||
blockXSprite(x, y, z, glm::vec3(1.0f),
|
||||
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
|
||||
break;
|
||||
}
|
||||
if (denseRender != (variant.culling == CullingMode::OPTIONAL)) {
|
||||
continue;
|
||||
case BlockModelType::AABB: {
|
||||
if (!denseRender)
|
||||
blockAABB({x, y, z}, texfaces, &def, vox.state.rotation,
|
||||
!def.shadeless, def.ambientOcclusion && enableAO);
|
||||
break;
|
||||
}
|
||||
if (def.translucent) {
|
||||
continue;
|
||||
}
|
||||
const UVRegion texfaces[6] {
|
||||
cache.getRegion(id, variantId, 0, densePass),
|
||||
cache.getRegion(id, variantId, 1, densePass),
|
||||
cache.getRegion(id, variantId, 2, densePass),
|
||||
cache.getRegion(id, variantId, 3, densePass),
|
||||
cache.getRegion(id, variantId, 4, densePass),
|
||||
cache.getRegion(id, variantId, 5, densePass)
|
||||
};
|
||||
int x = i % CHUNK_W;
|
||||
int y = i / (CHUNK_D * CHUNK_W);
|
||||
int z = (i / CHUNK_D) % CHUNK_W;
|
||||
switch (def.getModel(state.userbits).type) {
|
||||
case BlockModelType::BLOCK:
|
||||
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
|
||||
def.ambientOcclusion && enableAO);
|
||||
break;
|
||||
case BlockModelType::XSPRITE: {
|
||||
if (!denseRender)
|
||||
blockXSprite(x, y, z, glm::vec3(1.0f),
|
||||
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
|
||||
break;
|
||||
}
|
||||
case BlockModelType::AABB: {
|
||||
if (!denseRender)
|
||||
blockAABB({x, y, z}, texfaces, &def, vox.state.rotation,
|
||||
!def.shadeless, def.ambientOcclusion && enableAO);
|
||||
break;
|
||||
}
|
||||
case BlockModelType::CUSTOM: {
|
||||
blockCustomModel(
|
||||
{x, y, z},
|
||||
def,
|
||||
vox.state,
|
||||
!def.shadeless,
|
||||
def.ambientOcclusion && enableAO
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (overflow) {
|
||||
return;
|
||||
case BlockModelType::CUSTOM: {
|
||||
blockCustomModel(
|
||||
{x, y, z},
|
||||
def,
|
||||
vox.state,
|
||||
!def.shadeless,
|
||||
def.ambientOcclusion && enableAO
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (overflow) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SortingMeshData BlocksRenderer::renderTranslucent(
|
||||
const voxel* voxels, int beginEnds[256][2]
|
||||
const voxel* voxels, int totalBegin, int totalEnd
|
||||
) {
|
||||
SortingMeshData sortingMesh {{}};
|
||||
|
||||
|
|
@ -568,106 +562,98 @@ SortingMeshData BlocksRenderer::renderTranslucent(
|
|||
|
||||
bool densePass = this->densePass;
|
||||
bool enableAO = settings.graphics.softLighting.get();
|
||||
for (const auto drawGroup : *content.drawGroups) {
|
||||
int begin = beginEnds[drawGroup][0];
|
||||
if (begin == 0) {
|
||||
for (int i = totalBegin; i < totalEnd; i++) {
|
||||
const voxel& vox = voxels[i];
|
||||
blockid_t id = vox.id;
|
||||
blockstate state = vox.state;
|
||||
const auto& def = *blockDefsCache[id];
|
||||
uint8_t variantId = def.getVariantIndex(state.userbits);
|
||||
if (id == 0 || state.segment) {
|
||||
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];
|
||||
uint8_t variantId = def.getVariantIndex(state.userbits);
|
||||
const auto& variant = def.getVariant(variantId);
|
||||
if (id == 0 || variant.drawGroup != drawGroup || state.segment) {
|
||||
continue;
|
||||
}
|
||||
if (!def.translucent) {
|
||||
continue;
|
||||
}
|
||||
const UVRegion texfaces[6] {
|
||||
cache.getRegion(id, variantId, 0, densePass),
|
||||
cache.getRegion(id, variantId, 1, densePass),
|
||||
cache.getRegion(id, variantId, 2, densePass),
|
||||
cache.getRegion(id, variantId, 3, densePass),
|
||||
cache.getRegion(id, variantId, 4, densePass),
|
||||
cache.getRegion(id, variantId, 5, densePass)
|
||||
};
|
||||
int x = i % CHUNK_W;
|
||||
int y = i / (CHUNK_D * CHUNK_W);
|
||||
int z = (i / CHUNK_D) % CHUNK_W;
|
||||
switch (def.getModel(state.userbits).type) {
|
||||
case BlockModelType::BLOCK:
|
||||
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
|
||||
def.ambientOcclusion && enableAO);
|
||||
break;
|
||||
case BlockModelType::XSPRITE: {
|
||||
blockXSprite(x, y, z, glm::vec3(1.0f),
|
||||
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
|
||||
break;
|
||||
}
|
||||
case BlockModelType::AABB: {
|
||||
blockAABB(
|
||||
{x, y, z},
|
||||
texfaces,
|
||||
&def,
|
||||
vox.state.rotation,
|
||||
!def.shadeless,
|
||||
def.ambientOcclusion && enableAO
|
||||
);
|
||||
break;
|
||||
}
|
||||
case BlockModelType::CUSTOM: {
|
||||
blockCustomModel(
|
||||
{x, y, z},
|
||||
def,
|
||||
vox.state,
|
||||
!def.shadeless,
|
||||
def.ambientOcclusion && enableAO
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (vertexCount == 0) {
|
||||
continue;
|
||||
}
|
||||
SortingMeshEntry entry {
|
||||
glm::vec3(
|
||||
x + chunk->x * CHUNK_W + 0.5f,
|
||||
y + 0.5f,
|
||||
z + chunk->z * CHUNK_D + 0.5f
|
||||
),
|
||||
util::Buffer<ChunkVertex>(indexCount), 0};
|
||||
|
||||
totalSize += entry.vertexData.size();
|
||||
|
||||
for (int j = 0; j < indexCount; j++) {
|
||||
std::memcpy(
|
||||
entry.vertexData.data() + j,
|
||||
vertexBuffer.get() + indexBuffer[j],
|
||||
sizeof(ChunkVertex)
|
||||
);
|
||||
ChunkVertex& vertex = entry.vertexData[j];
|
||||
|
||||
if (!aabbInit) {
|
||||
aabbInit = true;
|
||||
aabb.a = aabb.b = vertex.position;
|
||||
} else {
|
||||
aabb.addPoint(vertex.position);
|
||||
}
|
||||
|
||||
vertex.position.x += chunk->x * CHUNK_W + 0.5f;
|
||||
vertex.position.y += 0.5f;
|
||||
vertex.position.z += chunk->z * CHUNK_D + 0.5f;
|
||||
}
|
||||
sortingMesh.entries.push_back(std::move(entry));
|
||||
vertexCount = 0;
|
||||
vertexOffset = indexCount = 0;
|
||||
if (!def.translucent) {
|
||||
continue;
|
||||
}
|
||||
const UVRegion texfaces[6] {
|
||||
cache.getRegion(id, variantId, 0, densePass),
|
||||
cache.getRegion(id, variantId, 1, densePass),
|
||||
cache.getRegion(id, variantId, 2, densePass),
|
||||
cache.getRegion(id, variantId, 3, densePass),
|
||||
cache.getRegion(id, variantId, 4, densePass),
|
||||
cache.getRegion(id, variantId, 5, densePass)
|
||||
};
|
||||
int x = i % CHUNK_W;
|
||||
int y = i / (CHUNK_D * CHUNK_W);
|
||||
int z = (i / CHUNK_D) % CHUNK_W;
|
||||
switch (def.getModel(state.userbits).type) {
|
||||
case BlockModelType::BLOCK:
|
||||
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
|
||||
def.ambientOcclusion && enableAO);
|
||||
break;
|
||||
case BlockModelType::XSPRITE: {
|
||||
blockXSprite(x, y, z, glm::vec3(1.0f),
|
||||
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
|
||||
break;
|
||||
}
|
||||
case BlockModelType::AABB: {
|
||||
blockAABB(
|
||||
{x, y, z},
|
||||
texfaces,
|
||||
&def,
|
||||
vox.state.rotation,
|
||||
!def.shadeless,
|
||||
def.ambientOcclusion && enableAO
|
||||
);
|
||||
break;
|
||||
}
|
||||
case BlockModelType::CUSTOM: {
|
||||
blockCustomModel(
|
||||
{x, y, z},
|
||||
def,
|
||||
vox.state,
|
||||
!def.shadeless,
|
||||
def.ambientOcclusion && enableAO
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (vertexCount == 0) {
|
||||
continue;
|
||||
}
|
||||
SortingMeshEntry entry {
|
||||
glm::vec3(
|
||||
x + chunk->x * CHUNK_W + 0.5f,
|
||||
y + 0.5f,
|
||||
z + chunk->z * CHUNK_D + 0.5f
|
||||
),
|
||||
util::Buffer<ChunkVertex>(indexCount), 0};
|
||||
|
||||
totalSize += entry.vertexData.size();
|
||||
|
||||
for (int j = 0; j < indexCount; j++) {
|
||||
std::memcpy(
|
||||
entry.vertexData.data() + j,
|
||||
vertexBuffer.get() + indexBuffer[j],
|
||||
sizeof(ChunkVertex)
|
||||
);
|
||||
ChunkVertex& vertex = entry.vertexData[j];
|
||||
|
||||
if (!aabbInit) {
|
||||
aabbInit = true;
|
||||
aabb.a = aabb.b = vertex.position;
|
||||
} else {
|
||||
aabb.addPoint(vertex.position);
|
||||
}
|
||||
|
||||
vertex.position.x += chunk->x * CHUNK_W + 0.5f;
|
||||
vertex.position.y += 0.5f;
|
||||
vertex.position.z += chunk->z * CHUNK_D + 0.5f;
|
||||
}
|
||||
sortingMesh.entries.push_back(std::move(entry));
|
||||
vertexCount = 0;
|
||||
vertexOffset = indexCount = 0;
|
||||
}
|
||||
|
||||
// additional powerful optimization
|
||||
|
|
@ -709,19 +695,16 @@ void BlocksRenderer::build(
|
|||
|
||||
int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D);
|
||||
int totalEnd = chunk->top * (CHUNK_W * CHUNK_D);
|
||||
|
||||
bool hasTranslucent = false;
|
||||
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];
|
||||
const auto& variant = def.getVariantByBits(vox.state.userbits);
|
||||
hasTranslucent = def.translucent || hasTranslucent;
|
||||
|
||||
if (beginEnds[variant.drawGroup][0] == 0) {
|
||||
beginEnds[variant.drawGroup][0] = i + 1;
|
||||
if (def.translucent) {
|
||||
hasTranslucent = true;
|
||||
break;
|
||||
}
|
||||
beginEnds[variant.drawGroup][1] = i;
|
||||
}
|
||||
cancelled = false;
|
||||
|
||||
|
|
@ -733,7 +716,7 @@ void BlocksRenderer::build(
|
|||
densePass = false;
|
||||
|
||||
if (hasTranslucent) {
|
||||
sortingMesh = renderTranslucent(voxels, beginEnds);
|
||||
sortingMesh = renderTranslucent(voxels, totalBegin, totalEnd);
|
||||
} else {
|
||||
sortingMesh = {};
|
||||
}
|
||||
|
|
@ -746,13 +729,13 @@ void BlocksRenderer::build(
|
|||
|
||||
denseRender = false;
|
||||
densePass = false;
|
||||
render(voxels, beginEnds);
|
||||
render(voxels, totalBegin, totalEnd);
|
||||
|
||||
size_t endIndex = indexCount;
|
||||
|
||||
denseRender = true;
|
||||
densePass = settings.graphics.denseRender.get();
|
||||
render(voxels, beginEnds);
|
||||
render(voxels, totalBegin, totalEnd);
|
||||
|
||||
denseIndexCount = indexCount;
|
||||
for (size_t i = 0; i < denseIndexCount; i++) {
|
||||
|
|
@ -761,7 +744,7 @@ void BlocksRenderer::build(
|
|||
|
||||
indexCount = endIndex;
|
||||
densePass = false;
|
||||
render(voxels, beginEnds);
|
||||
render(voxels, totalBegin, totalEnd);
|
||||
}
|
||||
|
||||
ChunkMeshData BlocksRenderer::createMesh() {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class BlocksRenderer final {
|
|||
public:
|
||||
BlocksRenderer(
|
||||
size_t capacity,
|
||||
const Content& content,
|
||||
const Block* const* blockDefs,
|
||||
const ContentGfxCache& cache,
|
||||
const EngineSettings& settings
|
||||
);
|
||||
|
|
@ -44,7 +44,6 @@ public:
|
|||
}
|
||||
private:
|
||||
static const glm::vec3 SUN_VECTOR;
|
||||
const Content& content;
|
||||
std::unique_ptr<ChunkVertex[]> vertexBuffer;
|
||||
std::unique_ptr<uint32_t[]> indexBuffer;
|
||||
std::unique_ptr<uint32_t[]> denseIndexBuffer;
|
||||
|
|
@ -145,13 +144,16 @@ private:
|
|||
);
|
||||
|
||||
// Does block allow to see other blocks sides (is it transparent)
|
||||
inline bool isOpen(const glm::ivec3& pos, const Block& def, const Variant& variant) const {
|
||||
bool isOpen(const glm::ivec3& pos, const Block& def, const Variant& variant) const {
|
||||
const auto& vox = voxelsBuffer->pickBlock(
|
||||
chunk->x * CHUNK_W + pos.x, pos.y, chunk->z * CHUNK_D + pos.z
|
||||
);
|
||||
if (vox.id == BLOCK_VOID) {
|
||||
return false;
|
||||
}
|
||||
if (def.rt.id == vox.id && def.rt.solid && variant.culling == CullingMode::DEFAULT) {
|
||||
return false;
|
||||
}
|
||||
const auto& block = *blockDefsCache[vox.id];
|
||||
const auto& blockVariant = block.getVariantByBits(vox.state.userbits);
|
||||
uint8_t otherDrawGroup = blockVariant.drawGroup;
|
||||
|
|
@ -178,6 +180,6 @@ private:
|
|||
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]);
|
||||
SortingMeshData renderTranslucent(const voxel* voxels, int beginEnds[256][2]);
|
||||
void render(const voxel* voxels, int totalBegin, int totalEnd);
|
||||
SortingMeshData renderTranslucent(const voxel* voxels, int totalBegin, int totalEnd);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,9 +11,12 @@
|
|||
#include "world/Level.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "maths/FrustumCulling.hpp"
|
||||
#include "maths/util.hpp"
|
||||
#include "util/listutil.hpp"
|
||||
#include "util/ObjectsPool.hpp"
|
||||
#include "util/timeutil.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "content/Content.hpp"
|
||||
|
||||
static debug::Logger logger("chunks-render");
|
||||
|
||||
|
|
@ -33,7 +36,7 @@ public:
|
|||
settings.graphics.denseRender.get()
|
||||
? settings.graphics.chunkMaxVerticesDense.get()
|
||||
: settings.graphics.chunkMaxVertices.get(),
|
||||
level.content,
|
||||
level.content.getIndices()->blocks.getDefs(),
|
||||
cache,
|
||||
settings
|
||||
) {
|
||||
|
|
@ -92,7 +95,7 @@ ChunksRenderer::ChunksRenderer(
|
|||
threadPool.setStopOnFail(false);
|
||||
renderer = std::make_unique<BlocksRenderer>(
|
||||
settings.graphics.chunkMaxVertices.get(),
|
||||
level.content, cache, settings
|
||||
level.content.getIndices()->blocks.getDefs(), cache, settings
|
||||
);
|
||||
logger.info() << "created " << threadPool.getWorkersCount() << " workers";
|
||||
logger.info() << "memory consumption is "
|
||||
|
|
@ -122,30 +125,30 @@ std::shared_ptr<VoxelsRenderVolume> ChunksRenderer::prepareVoxelsVolume(
|
|||
return voxelsBuffer;
|
||||
}
|
||||
|
||||
const ChunkMesh* ChunksRenderer::render(
|
||||
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
|
||||
void ChunksRenderer::renderBlocking(const std::shared_ptr<Chunk>& chunk) {
|
||||
glm::ivec2 key(chunk->x, chunk->z);
|
||||
ChunkMesh mesh {};
|
||||
auto voxelsBuffer = prepareVoxelsVolume(*chunk);
|
||||
mesh = renderer->render(chunk.get(), *voxelsBuffer);
|
||||
meshes[key] = std::move(mesh);
|
||||
chunk->flags.modified = false;
|
||||
}
|
||||
|
||||
void ChunksRenderer::render(
|
||||
const std::shared_ptr<Chunk>& chunk, bool lowPriority
|
||||
) {
|
||||
glm::ivec2 key(chunk->x, chunk->z);
|
||||
if (important) {
|
||||
ChunkMesh mesh {};
|
||||
auto voxelsBuffer = prepareVoxelsVolume(*chunk);
|
||||
mesh = renderer->render(chunk.get(), *voxelsBuffer);
|
||||
meshes[key] = std::move(mesh);
|
||||
chunk->flags.modified = false;
|
||||
return &meshes[key];
|
||||
}
|
||||
if (inwork.find(key) != inwork.end() ||
|
||||
((inwork.size() >= threadPool.getWorkersCount() ||
|
||||
enqueuedInFrame >= MAX_CHUNKS_ENQUEUED_IN_FRAME) &&
|
||||
lowPriority)) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
chunk->flags.modified = false;
|
||||
enqueuedInFrame++;
|
||||
auto voxelsBuffer = prepareVoxelsVolume(*chunk);
|
||||
threadPool.enqueueJob({chunk, std::move(voxelsBuffer)});
|
||||
inwork[key] = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ChunksRenderer::unload(const Chunk* chunk) {
|
||||
|
|
@ -161,76 +164,69 @@ void ChunksRenderer::clear() {
|
|||
threadPool.clearQueue();
|
||||
}
|
||||
|
||||
const ChunkMesh* ChunksRenderer::getOrRender(
|
||||
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
|
||||
) {
|
||||
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
|
||||
if (found == meshes.end()) {
|
||||
return render(chunk, important, lowPriority);
|
||||
}
|
||||
if (chunk->flags.modified && chunk->flags.lighted) {
|
||||
render(chunk, important, lowPriority);
|
||||
}
|
||||
return &found->second;
|
||||
}
|
||||
|
||||
void ChunksRenderer::update() {
|
||||
threadPool.pullResults();
|
||||
enqueuedInFrame = 0;
|
||||
}
|
||||
|
||||
const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
||||
size_t index, const Camera& camera, bool culling
|
||||
) {
|
||||
auto chunk = chunks.getChunks()[index];
|
||||
if (chunk == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!chunk->flags.lighted) {
|
||||
const auto& found = meshes.find({chunk->x, chunk->z});
|
||||
if (found == meshes.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return found->second.mesh.get();
|
||||
int width = chunks.getWidth();
|
||||
int halfWidth = width / 2;
|
||||
int halfHeight = chunks.getHeight() / 2;
|
||||
int centerX = chunks.getOffsetX() + halfWidth;
|
||||
int centerY = chunks.getOffsetY() + halfHeight;
|
||||
|
||||
meshBuildQueue.clear();
|
||||
auto& chunksArray = chunks.getChunks();
|
||||
for (int index = 0; index < chunks.getVolume(); index++) {
|
||||
const auto& chunk = chunks.getChunks()[index];
|
||||
if (chunk == nullptr || !chunk->flags.lighted) {
|
||||
continue;
|
||||
}
|
||||
int x = chunk->x;
|
||||
int z = chunk->z;
|
||||
if (chunk->flags.modified || meshes.find({x, z}) == meshes.end()) {
|
||||
meshBuildQueue.emplace_back(x - centerX, z - centerY);
|
||||
}
|
||||
}
|
||||
float distance = glm::distance(
|
||||
camera.position,
|
||||
glm::vec3(
|
||||
(chunk->x + 0.5f) * CHUNK_W,
|
||||
camera.position.y,
|
||||
(chunk->z + 0.5f) * CHUNK_D
|
||||
)
|
||||
std::sort(
|
||||
meshBuildQueue.begin(),
|
||||
meshBuildQueue.end(),
|
||||
[](const glm::ivec2& a, const glm::ivec2& b) {
|
||||
return util::length2(a) < util::length2(b);
|
||||
}
|
||||
);
|
||||
auto mesh = getOrRender(
|
||||
chunk,
|
||||
distance < CHUNK_W * 1.5f,
|
||||
distance > CHUNK_W * settings.chunks.loadDistance.get() * 0.5
|
||||
);
|
||||
if (mesh == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (chunk->flags.dirtyHeights) {
|
||||
chunk->updateHeights();
|
||||
}
|
||||
if (culling) {
|
||||
const auto& meshAABB = mesh->meshAABB;
|
||||
auto aabbMin = meshAABB.min();
|
||||
auto aabbMax = meshAABB.max();
|
||||
glm::vec3 min(
|
||||
chunk->x * CHUNK_W + std::min(0.0f, aabbMin.x),
|
||||
chunk->bottom,
|
||||
chunk->z * CHUNK_D + std::min(0.0f, aabbMin.z)
|
||||
);
|
||||
glm::vec3 max(
|
||||
chunk->x * CHUNK_W + aabbMax.x,
|
||||
chunk->top,
|
||||
chunk->z * CHUNK_D + aabbMax.z
|
||||
);
|
||||
|
||||
if (!frustum.isBoxVisible(min, max)) return nullptr;
|
||||
int loadDistance = settings.chunks.loadDistance.get();
|
||||
|
||||
const int topN = 10;
|
||||
int top = std::min<int>(meshBuildQueue.size(), topN);
|
||||
for (int i = 0; i < top; i++) {
|
||||
glm::ivec2 offset = meshBuildQueue[i];
|
||||
size_t index =
|
||||
(offset.y + halfHeight) * width + offset.x + halfWidth;
|
||||
|
||||
auto& chunk = chunksArray[index];
|
||||
assert(chunk != nullptr);
|
||||
|
||||
float distance = glm::distance(
|
||||
glm::vec3 (centerX, 0.0f, centerY),
|
||||
glm::vec3(
|
||||
(chunk->x + 0.5f) * CHUNK_W,
|
||||
0,
|
||||
(chunk->z + 0.5f) * CHUNK_D
|
||||
)
|
||||
);
|
||||
bool important = distance < CHUNK_W * 1.5f;
|
||||
bool lowPriority = distance > CHUNK_W * loadDistance * 0.5;
|
||||
|
||||
if (chunk->flags.dirtyHeights) {
|
||||
chunk->updateHeights();
|
||||
}
|
||||
if (important) {
|
||||
renderBlocking(chunk);
|
||||
} else {
|
||||
render(chunk, lowPriority);
|
||||
}
|
||||
}
|
||||
return mesh->mesh.get();
|
||||
}
|
||||
|
||||
void ChunksRenderer::drawShadowsPass(
|
||||
|
|
@ -317,16 +313,43 @@ void ChunksRenderer::drawChunks(
|
|||
// TODO: minimize draw calls number
|
||||
for (int i = indices.size()-1; i >= 0; i--) {
|
||||
auto& chunk = chunks.getChunks()[indices[i].index];
|
||||
auto mesh = retrieveChunk(indices[i].index, camera, culling);
|
||||
if (mesh == nullptr) {
|
||||
if (chunk == nullptr) {
|
||||
continue;
|
||||
}
|
||||
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
|
||||
if (found == meshes.end()) {
|
||||
continue;
|
||||
}
|
||||
auto& mesh = found->second;
|
||||
if (mesh.mesh == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (culling) {
|
||||
const auto& meshAABB = mesh.meshAABB;
|
||||
auto aabbMin = meshAABB.min();
|
||||
auto aabbMax = meshAABB.max();
|
||||
glm::vec3 min(
|
||||
chunk->x * CHUNK_W + std::min(0.0f, aabbMin.x),
|
||||
chunk->bottom,
|
||||
chunk->z * CHUNK_D + std::min(0.0f, aabbMin.z)
|
||||
);
|
||||
glm::vec3 max(
|
||||
chunk->x * CHUNK_W + aabbMax.x,
|
||||
chunk->top,
|
||||
chunk->z * CHUNK_D + aabbMax.z
|
||||
);
|
||||
|
||||
if (!frustum.isBoxVisible(min, max)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 coord(
|
||||
chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f
|
||||
);
|
||||
glm::mat4 model = glm::translate(glm::mat4(1.0f), coord);
|
||||
shader.uniformMatrix("u_model", model);
|
||||
mesh->draw(GL_TRIANGLES, glm::distance2(camera.position * glm::vec3(1, 0, 1),
|
||||
mesh.mesh->draw(GL_TRIANGLES, glm::distance2(camera.position * glm::vec3(1, 0, 1),
|
||||
(coord + glm::vec3(CHUNK_W * 0.5f, 0.0f, CHUNK_D * 0.5f))) < denseDistance2);
|
||||
visibleChunks++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
|
||||
#include "util/ThreadPool.hpp"
|
||||
#include "commons.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/gtx/hash.hpp>
|
||||
|
||||
#include "util/ThreadPool.hpp"
|
||||
#include "commons.hpp"
|
||||
|
||||
template<typename VertexStructure> class Mesh;
|
||||
class Chunk;
|
||||
class Level;
|
||||
|
|
@ -44,22 +45,6 @@ struct RendererJob {
|
|||
};
|
||||
|
||||
class ChunksRenderer {
|
||||
const Chunks& chunks;
|
||||
const Assets& assets;
|
||||
const Frustum& frustum;
|
||||
const EngineSettings& settings;
|
||||
|
||||
std::unique_ptr<BlocksRenderer> renderer;
|
||||
std::unordered_map<glm::ivec2, ChunkMesh> meshes;
|
||||
std::unordered_map<glm::ivec2, bool> inwork;
|
||||
std::vector<ChunksSortEntry> indices;
|
||||
util::ThreadPool<RendererJob, RendererResult> threadPool;
|
||||
const Mesh<ChunkVertex>* retrieveChunk(
|
||||
size_t index, const Camera& camera, bool culling
|
||||
);
|
||||
std::shared_ptr<VoxelsRenderVolume> prepareVoxelsVolume(const Chunk& chunk);
|
||||
|
||||
size_t enqueuedInFrame = 0;
|
||||
public:
|
||||
ChunksRenderer(
|
||||
const Level& level,
|
||||
|
|
@ -69,18 +54,11 @@ public:
|
|||
const ContentGfxCache& cache,
|
||||
const EngineSettings& settings
|
||||
);
|
||||
virtual ~ChunksRenderer();
|
||||
~ChunksRenderer();
|
||||
|
||||
const ChunkMesh* render(
|
||||
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
|
||||
);
|
||||
void unload(const Chunk* chunk);
|
||||
void clear();
|
||||
|
||||
const ChunkMesh* getOrRender(
|
||||
const std::shared_ptr<Chunk>& chunk, bool important, bool lowPriority
|
||||
);
|
||||
|
||||
void drawShadowsPass(
|
||||
const Camera& camera, Shader& shader, const Camera& playerCamera
|
||||
);
|
||||
|
|
@ -92,4 +70,25 @@ public:
|
|||
void update();
|
||||
|
||||
static size_t visibleChunks;
|
||||
|
||||
private:
|
||||
const Chunks& chunks;
|
||||
const Assets& assets;
|
||||
const Frustum& frustum;
|
||||
const EngineSettings& settings;
|
||||
|
||||
std::unique_ptr<BlocksRenderer> renderer;
|
||||
std::unordered_map<glm::ivec2, ChunkMesh> meshes;
|
||||
std::unordered_map<glm::ivec2, bool> inwork;
|
||||
std::vector<ChunksSortEntry> indices;
|
||||
util::ThreadPool<RendererJob, RendererResult> threadPool;
|
||||
std::vector<glm::ivec2> meshBuildQueue;
|
||||
|
||||
size_t enqueuedInFrame = 0;
|
||||
|
||||
std::shared_ptr<VoxelsRenderVolume> prepareVoxelsVolume(const Chunk& chunk);
|
||||
|
||||
void render(const std::shared_ptr<Chunk>& chunk, bool lowPriority);
|
||||
|
||||
void renderBlocking(const std::shared_ptr<Chunk>& chunk);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ void CloudsRenderer::draw(
|
|||
|
||||
shader.uniform4f("u_tint", glm::vec4(weather.cloudsTint(), 1.0f));
|
||||
shader.uniform1f("u_fogFactor", fogFactor * 0.03f);
|
||||
shader.uniform1f("u_fogCurve", 0.7f - 0.3f);
|
||||
shader.uniform1f("u_fogCurve", 0.4f);
|
||||
|
||||
for (int i = 0; i < std::min<int>(quality, layers.size()); i++) {
|
||||
draw(layers[i], frustum, shader, camera, timer, i);
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ void DebugLinesRenderer::drawCoordSystem(
|
|||
}
|
||||
|
||||
void DebugLinesRenderer::render(
|
||||
DrawContext& pctx,
|
||||
const DrawContext& pctx,
|
||||
const Camera& camera,
|
||||
LineBatch& linesBatch,
|
||||
Shader& linesShader,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public:
|
|||
/// @param linesShader Shader used for rendering lines
|
||||
/// @param showChunkBorders Whether to show chunk borders
|
||||
void render(
|
||||
DrawContext& ctx,
|
||||
const DrawContext& ctx,
|
||||
const Camera& camera,
|
||||
LineBatch& linesBatch,
|
||||
Shader& linesShader,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "voxels/blocks_agent.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "world/Weather.hpp"
|
||||
#include "WorldRenderer.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ void MainBatch::flush() {
|
|||
texture = blank.get();
|
||||
}
|
||||
texture->bind();
|
||||
mesh->reload(buffer.get(), index);
|
||||
mesh->reload(buffer.get(), index, true);
|
||||
mesh->draw();
|
||||
index = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@
|
|||
#include "window/Window.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "world/LevelEvents.hpp"
|
||||
#include "world/Weather.hpp"
|
||||
#include "world/World.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
|
|
@ -62,9 +64,20 @@
|
|||
inline constexpr size_t BATCH3D_CAPACITY = 4096;
|
||||
inline constexpr size_t MODEL_BATCH_CAPACITY = 20'000;
|
||||
|
||||
static debug::Logger logger("world-renderer");
|
||||
|
||||
bool WorldRenderer::showChunkBorders = false;
|
||||
bool WorldRenderer::showEntitiesDebug = false;
|
||||
|
||||
template <typename T>
|
||||
static ObserverHandler observe_setting(
|
||||
ObservableSetting<T>& setting, bool& dirtySettings
|
||||
) {
|
||||
return setting.observe([&dirtySettings](auto const&) {
|
||||
dirtySettings = true;
|
||||
});
|
||||
}
|
||||
|
||||
WorldRenderer::WorldRenderer(
|
||||
Engine& engine, LevelFrontend& frontend, Player& player
|
||||
)
|
||||
|
|
@ -72,6 +85,7 @@ WorldRenderer::WorldRenderer(
|
|||
level(frontend.getLevel()),
|
||||
player(player),
|
||||
assets(*engine.getAssets()),
|
||||
weather(frontend.getWeather()),
|
||||
frustumCulling(std::make_unique<Frustum>()),
|
||||
lineBatch(std::make_unique<LineBatch>()),
|
||||
batch3d(std::make_unique<Batch3D>(BATCH3D_CAPACITY)),
|
||||
|
|
@ -120,10 +134,41 @@ WorldRenderer::WorldRenderer(
|
|||
shadowMapping = std::make_unique<Shadows>(level);
|
||||
debugLines = std::make_unique<DebugLinesRenderer>(level);
|
||||
cloudsRenderer = std::make_unique<CloudsRenderer>();
|
||||
|
||||
keepAlive(observe_setting(settings.graphics.advancedRender, dirtySettings));
|
||||
keepAlive(observe_setting(settings.graphics.shadowsQuality, dirtySettings));
|
||||
keepAlive(observe_setting(settings.graphics.ssao, dirtySettings));
|
||||
}
|
||||
|
||||
WorldRenderer::~WorldRenderer() = default;
|
||||
|
||||
void WorldRenderer::refreshSettings() {
|
||||
Shader* affectedShaders[] {
|
||||
&assets.require<Shader>("main"),
|
||||
&assets.require<Shader>("entity"),
|
||||
&assets.require<Shader>("clouds"),
|
||||
&assets.require<Shader>("translucent"),
|
||||
&assets.require<PostEffect>("deferred_lighting").getShader(),
|
||||
nullptr
|
||||
};
|
||||
|
||||
const auto& graphics = engine.getSettings().graphics;
|
||||
gbufferPipeline = graphics.advancedRender.get();
|
||||
|
||||
int shadowsQuality = graphics.shadowsQuality.get() * gbufferPipeline;
|
||||
shadowMapping->setQuality(shadowsQuality);
|
||||
|
||||
std::vector<std::string> defines;
|
||||
if (shadowsQuality != 0) defines.emplace_back("ENABLE_SHADOWS");
|
||||
if (graphics.ssao.get()) defines.emplace_back("ENABLE_SSAO");
|
||||
if (gbufferPipeline) defines.emplace_back("ADVANCED_RENDER");
|
||||
|
||||
logger.info() << "recompiling shaders due to settings change";
|
||||
for (size_t i = 0; affectedShaders[i]; i++) {
|
||||
affectedShaders[i]->recompile(defines);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_weather(Shader& shader, const Weather& weather) {
|
||||
shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity());
|
||||
shader.uniform1f("u_weatherFogDencity", weather.fogDencity());
|
||||
|
|
@ -156,7 +201,7 @@ void WorldRenderer::setupWorldShader(
|
|||
shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get());
|
||||
shader.uniform1i("u_debugLights", lightsDebug);
|
||||
shader.uniform1i("u_debugNormals", false);
|
||||
shader.uniform1f("u_dayTime", level.getWorld()->getInfo().daytime);
|
||||
shader.uniform1f("u_dayTime", level.getWorld().getInfo().daytime);
|
||||
shader.uniform2f("u_lightDir", skybox->getLightDir());
|
||||
shader.uniform1i("u_skybox", advanced_pipeline::TARGET_SKYBOX);
|
||||
|
||||
|
|
@ -188,8 +233,6 @@ void WorldRenderer::renderOpaque(
|
|||
const EngineSettings& settings,
|
||||
bool hudVisible
|
||||
) {
|
||||
texts->render(ctx, camera, settings, hudVisible, false);
|
||||
|
||||
float fogFactor = calcFogFactor();
|
||||
|
||||
auto& entityShader = assets.require<Shader>("entity");
|
||||
|
|
@ -212,12 +255,12 @@ void WorldRenderer::renderOpaque(
|
|||
modelBatch->render();
|
||||
particles->render(camera);
|
||||
|
||||
auto& shader = assets.require<Shader>("main");
|
||||
auto& mainShader = assets.require<Shader>("main");
|
||||
auto& cloudsShader = assets.require<Shader>("clouds");
|
||||
|
||||
setupWorldShader(shader, camera, settings, fogFactor);
|
||||
setupWorldShader(mainShader, camera, settings, fogFactor);
|
||||
|
||||
chunksRenderer->drawChunks(camera, shader);
|
||||
chunksRenderer->drawChunks(camera, mainShader);
|
||||
blockWraps->draw(ctx);
|
||||
|
||||
if (level.environment.sky.clouds) {
|
||||
|
|
@ -232,7 +275,7 @@ void WorldRenderer::renderOpaque(
|
|||
|
||||
if (hudVisible) {
|
||||
auto& linesShader = assets.require<Shader>("lines");
|
||||
renderLines(camera, linesShader, ctx);
|
||||
renderInWorldLines(camera, linesShader, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,7 +308,7 @@ void WorldRenderer::renderBlockSelection() {
|
|||
lineBatch->flush();
|
||||
}
|
||||
|
||||
void WorldRenderer::renderLines(
|
||||
void WorldRenderer::renderInWorldLines(
|
||||
const Camera& camera, Shader& linesShader, const DrawContext& pctx
|
||||
) {
|
||||
linesShader.use();
|
||||
|
|
@ -282,193 +325,144 @@ void WorldRenderer::renderLines(
|
|||
}
|
||||
}
|
||||
|
||||
void WorldRenderer::refreshSettings(Shader** shaders) {
|
||||
const auto& graphics = engine.getSettings().graphics;
|
||||
gbufferPipeline = graphics.advancedRender.get();
|
||||
|
||||
int shadowsQuality = graphics.shadowsQuality.get() * gbufferPipeline;
|
||||
shadowMapping->setQuality(shadowsQuality);
|
||||
|
||||
CompileTimeShaderSettings currentSettings {
|
||||
gbufferPipeline,
|
||||
shadowsQuality != 0,
|
||||
graphics.ssao.get() && gbufferPipeline};
|
||||
if (prevCTShaderSettings.advancedRender != currentSettings.advancedRender ||
|
||||
prevCTShaderSettings.shadows != currentSettings.shadows ||
|
||||
prevCTShaderSettings.ssao != currentSettings.ssao) {
|
||||
std::vector<std::string> defines;
|
||||
if (currentSettings.shadows) defines.emplace_back("ENABLE_SHADOWS");
|
||||
if (currentSettings.ssao) defines.emplace_back("ENABLE_SSAO");
|
||||
if (currentSettings.advancedRender)
|
||||
defines.emplace_back("ADVANCED_RENDER");
|
||||
|
||||
for (size_t i = 0; shaders[i]; i++) {
|
||||
shaders[i]->recompile(defines);
|
||||
}
|
||||
prevCTShaderSettings = currentSettings;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldRenderer::update(const Camera& camera, float delta) {
|
||||
timer += delta;
|
||||
chunksRenderer->update();
|
||||
weather.update(delta);
|
||||
precipitation->update(delta);
|
||||
particles->update(camera, delta);
|
||||
}
|
||||
|
||||
void WorldRenderer::renderFrameClassic(
|
||||
const DrawContext& pctx,
|
||||
Camera& camera,
|
||||
bool hudVisible,
|
||||
PostProcessing& postProcessing
|
||||
) {
|
||||
const auto& settings = engine.getSettings();
|
||||
const auto& worldInfo = level.getWorld().getInfo();
|
||||
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
ctx.setFramebuffer(postProcessing.getFramebuffer());
|
||||
|
||||
skybox->draw(
|
||||
level.environment, ctx, camera, worldInfo.daytime, weather.clouds()
|
||||
);
|
||||
texts->render(ctx, camera, settings, hudVisible, false);
|
||||
|
||||
if (debug && hudVisible) {
|
||||
renderDebugLines(ctx, camera);
|
||||
}
|
||||
|
||||
DrawContext wctx = ctx.sub();
|
||||
wctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap());
|
||||
wctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
// Translucent blocks
|
||||
{
|
||||
const auto& settings = engine.getSettings();
|
||||
auto& translucentShader = assets.require<Shader>("translucent");
|
||||
auto sctx = wctx.sub();
|
||||
sctx.setCullFace(true);
|
||||
translucentShader.use();
|
||||
setupWorldShader(translucentShader, camera, settings, calcFogFactor());
|
||||
chunksRenderer->drawSortedMeshes(camera, translucentShader);
|
||||
}
|
||||
|
||||
renderWeatherEffects(camera);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void WorldRenderer::renderFrameAdvanced(
|
||||
const DrawContext& pctx,
|
||||
Camera& camera,
|
||||
bool hudVisible,
|
||||
PostProcessing& postProcessing
|
||||
) {
|
||||
const auto& settings = engine.getSettings();
|
||||
const auto& worldInfo = level.getWorld().getInfo();
|
||||
float fogFactor = calcFogFactor();
|
||||
|
||||
shadowMapping->refresh(camera, pctx, [this, &camera](Camera& shadowCamera) {
|
||||
auto& shader = assets.require<Shader>("shadows");
|
||||
setupWorldShader(shader, shadowCamera, engine.getSettings(), 0.0f);
|
||||
chunksRenderer->drawShadowsPass(shadowCamera, shader, camera);
|
||||
});
|
||||
|
||||
auto& deferredShader =
|
||||
assets.require<PostEffect>("deferred_lighting").getShader();
|
||||
deferredShader.use();
|
||||
setupWorldShader(deferredShader, camera, settings, fogFactor);
|
||||
postProcessing.renderDeferredShading(pctx, assets, timer, camera);
|
||||
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
|
||||
postProcessing.bindDepthBuffer();
|
||||
skybox->draw(
|
||||
level.environment, ctx, camera, worldInfo.daytime, weather.clouds()
|
||||
);
|
||||
texts->render(ctx, camera, settings, hudVisible, false);
|
||||
if (debug && hudVisible) {
|
||||
renderDebugLines(ctx, camera);
|
||||
}
|
||||
|
||||
DrawContext wctx = ctx.sub();
|
||||
wctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap());
|
||||
wctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
// Translucent blocks
|
||||
{
|
||||
const auto& settings = engine.getSettings();
|
||||
auto& translucentShader = assets.require<Shader>("translucent");
|
||||
auto sctx = wctx.sub();
|
||||
sctx.setCullFace(true);
|
||||
translucentShader.use();
|
||||
setupWorldShader(translucentShader, camera, settings, fogFactor);
|
||||
chunksRenderer->drawSortedMeshes(camera, translucentShader);
|
||||
}
|
||||
|
||||
renderWeatherEffects(camera);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void WorldRenderer::renderFrame(
|
||||
const DrawContext& pctx,
|
||||
Camera& camera,
|
||||
bool hudVisible,
|
||||
PostProcessing& postProcessing
|
||||
) {
|
||||
auto projView = camera.getProjView();
|
||||
auto world = level.getWorld();
|
||||
|
||||
const auto& vp = pctx.getViewport();
|
||||
camera.setAspectRatio(vp.x / static_cast<float>(vp.y));
|
||||
if (dirtySettings) {
|
||||
refreshSettings();
|
||||
dirtySettings = false;
|
||||
}
|
||||
|
||||
auto& mainShader = assets.require<Shader>("main");
|
||||
auto& entityShader = assets.require<Shader>("entity");
|
||||
auto& cloudsShader = assets.require<Shader>("clouds");
|
||||
auto& translucentShader = assets.require<Shader>("translucent");
|
||||
auto& deferredShader =
|
||||
assets.require<PostEffect>("deferred_lighting").getShader();
|
||||
|
||||
const auto& settings = engine.getSettings();
|
||||
|
||||
Shader* affectedShaders[] {
|
||||
&mainShader,
|
||||
&entityShader,
|
||||
&cloudsShader,
|
||||
&translucentShader,
|
||||
&deferredShader,
|
||||
nullptr};
|
||||
|
||||
refreshSettings(affectedShaders);
|
||||
|
||||
const auto& worldInfo = world->getInfo();
|
||||
|
||||
const auto& worldInfo = level.getWorld().getInfo();
|
||||
float clouds = weather.clouds();
|
||||
clouds = glm::max(worldInfo.fog, clouds);
|
||||
float mie = 1.0f + glm::max(worldInfo.fog, clouds * 0.5f) * 2.0f;
|
||||
|
||||
float random = rand() / static_cast<float>(RAND_MAX);
|
||||
skybox->refresh(
|
||||
level.environment,
|
||||
pctx,
|
||||
worldInfo.daytime,
|
||||
mie,
|
||||
1.0f + clouds,
|
||||
weather.skyTint(),
|
||||
weather.highlight * random,
|
||||
4
|
||||
);
|
||||
|
||||
chunksRenderer->update();
|
||||
|
||||
shadowMapping->refresh(camera, pctx, [this, &camera](Camera& shadowCamera) {
|
||||
auto& shader = assets.require<Shader>("shadows");
|
||||
setupWorldShader(shader, shadowCamera, engine.getSettings(), 0.0f);
|
||||
chunksRenderer->drawShadowsPass(shadowCamera, shader, camera);
|
||||
});
|
||||
{
|
||||
DrawContext wctx = pctx.sub();
|
||||
postProcessing.use(wctx, gbufferPipeline);
|
||||
display::clearDepth();
|
||||
|
||||
/* Main opaque pass (GBuffer pass) */ {
|
||||
DrawContext ctx = wctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
ctx.setCullFace(true);
|
||||
ctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap());
|
||||
ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
renderOpaque(ctx, camera, settings, hudVisible);
|
||||
}
|
||||
texts->render(pctx, camera, settings, hudVisible, true);
|
||||
}
|
||||
float fogFactor = calcFogFactor();
|
||||
renderOpaquePass(pctx, camera, hudVisible, postProcessing);
|
||||
if (gbufferPipeline) {
|
||||
deferredShader.use();
|
||||
setupWorldShader(deferredShader, camera, settings, fogFactor);
|
||||
postProcessing.renderDeferredShading(pctx, assets, timer, camera);
|
||||
}
|
||||
{
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
|
||||
if (gbufferPipeline) {
|
||||
postProcessing.bindDepthBuffer();
|
||||
} else {
|
||||
ctx.setFramebuffer(postProcessing.getFramebuffer());
|
||||
}
|
||||
|
||||
// Background sky plane
|
||||
skybox->draw(
|
||||
level.environment, ctx, camera, worldInfo.daytime, clouds
|
||||
);
|
||||
|
||||
auto& linesShader = assets.require<Shader>("lines");
|
||||
linesShader.use();
|
||||
if (debug && hudVisible) {
|
||||
debugLines->render(
|
||||
ctx, camera, *lineBatch, linesShader, showChunkBorders
|
||||
);
|
||||
}
|
||||
linesShader.uniformMatrix("u_projview", projView);
|
||||
lineBatch->flush();
|
||||
|
||||
DrawContext wctx = ctx.sub();
|
||||
wctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap());
|
||||
wctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
// Translucent blocks
|
||||
{
|
||||
auto sctx = wctx.sub();
|
||||
sctx.setCullFace(true);
|
||||
translucentShader.use();
|
||||
setupWorldShader(translucentShader, camera, settings, fogFactor);
|
||||
chunksRenderer->drawSortedMeshes(camera, translucentShader);
|
||||
}
|
||||
|
||||
// Weather effects
|
||||
entityShader.use();
|
||||
setupWorldShader(entityShader, camera, settings, fogFactor);
|
||||
|
||||
std::array<const WeatherPreset*, 2> weatherInstances {
|
||||
&weather.a, &weather.b};
|
||||
for (const auto& weather : weatherInstances) {
|
||||
float maxIntensity = weather->fall.maxIntensity;
|
||||
float zero = weather->fall.minOpacity;
|
||||
float one = weather->fall.maxOpacity;
|
||||
float t = (weather->intensity * (one - zero)) * maxIntensity + zero;
|
||||
entityShader.uniform1i("u_alphaClip", weather->fall.opaque);
|
||||
entityShader.uniform1f(
|
||||
"u_opacity", weather->fall.opaque ? t * t : t
|
||||
);
|
||||
if (weather->intensity > 1.e-3f && !weather->fall.texture.empty()) {
|
||||
precipitation->render(camera, *weather);
|
||||
}
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
renderFrameAdvanced(pctx, camera, hudVisible, postProcessing);
|
||||
} else {
|
||||
renderFrameClassic(pctx, camera, hudVisible, postProcessing);
|
||||
}
|
||||
postProcessing.render(pctx, assets, timer, camera);
|
||||
|
||||
if (player.currentCamera == player.fpCamera) {
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
ctx.setCullFace(true);
|
||||
ctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap());
|
||||
ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
display::clearDepth();
|
||||
|
||||
// prepare modified HUD camera
|
||||
Camera hudcam = camera;
|
||||
hudcam.far = 10.0f;
|
||||
hudcam.setFov(0.9f);
|
||||
hudcam.position = {};
|
||||
|
||||
setupWorldShader(entityShader, hudcam, engine.getSettings(), 0.0f);
|
||||
hands->render(camera);
|
||||
renderHandsPass(pctx, camera);
|
||||
}
|
||||
{
|
||||
auto bctx = pctx.sub();
|
||||
|
|
@ -478,6 +472,83 @@ void WorldRenderer::renderFrame(
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
|
||||
void WorldRenderer::renderOpaquePass(
|
||||
const DrawContext& pctx,
|
||||
Camera& camera,
|
||||
bool hudVisible,
|
||||
PostProcessing& postProcessing
|
||||
) {
|
||||
const auto& settings = engine.getSettings();
|
||||
|
||||
DrawContext wctx = pctx.sub();
|
||||
postProcessing.use(wctx, gbufferPipeline);
|
||||
display::clearDepth();
|
||||
|
||||
/* Main opaque pass (GBuffer pass) */ {
|
||||
DrawContext ctx = wctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
ctx.setCullFace(true);
|
||||
ctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap());
|
||||
ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
renderOpaque(ctx, camera, settings, hudVisible);
|
||||
}
|
||||
texts->render(wctx, camera, settings, hudVisible, true);
|
||||
}
|
||||
|
||||
void WorldRenderer::renderWeatherEffects(Camera& camera) {
|
||||
const auto& settings = engine.getSettings();
|
||||
auto& entityShader = assets.require<Shader>("entity");
|
||||
entityShader.use();
|
||||
setupWorldShader(entityShader, camera, settings, calcFogFactor());
|
||||
|
||||
std::array<const WeatherPreset*, 2> weatherInstances {
|
||||
&weather.a, &weather.b};
|
||||
for (const auto& weather : weatherInstances) {
|
||||
float maxIntensity = weather->fall.maxIntensity;
|
||||
float zero = weather->fall.minOpacity;
|
||||
float one = weather->fall.maxOpacity;
|
||||
float t = (weather->intensity * (one - zero)) * maxIntensity + zero;
|
||||
entityShader.uniform1i("u_alphaClip", weather->fall.opaque);
|
||||
entityShader.uniform1f(
|
||||
"u_opacity", weather->fall.opaque ? t * t : t
|
||||
);
|
||||
if (weather->intensity > 1.e-3f && !weather->fall.texture.empty()) {
|
||||
precipitation->render(camera, *weather);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldRenderer::renderDebugLines(const DrawContext& ctx, Camera& camera) {
|
||||
auto& linesShader = assets.require<Shader>("lines");
|
||||
linesShader.use();
|
||||
debugLines->render(
|
||||
ctx, camera, *lineBatch, linesShader, showChunkBorders
|
||||
);
|
||||
linesShader.uniformMatrix("u_projview", camera.getProjView());
|
||||
lineBatch->flush();
|
||||
}
|
||||
|
||||
void WorldRenderer::renderHandsPass(const DrawContext& pctx, Camera& camera) {
|
||||
auto& entityShader = assets.require<Shader>("entity");
|
||||
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
ctx.setCullFace(true);
|
||||
ctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap());
|
||||
ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr);
|
||||
display::clearDepth();
|
||||
|
||||
// prepare modified HUD camera
|
||||
Camera hudcam = camera;
|
||||
hudcam.far = 10.0f;
|
||||
hudcam.setFov(0.9f);
|
||||
hudcam.position = {};
|
||||
|
||||
setupWorldShader(entityShader, hudcam, engine.getSettings(), 0.0f);
|
||||
hands->render(camera);
|
||||
}
|
||||
|
||||
void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) {
|
||||
int x = std::floor(player.currentCamera->position.x);
|
||||
int y = std::floor(player.currentCamera->position.y);
|
||||
|
|
@ -523,7 +594,7 @@ void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) {
|
|||
batch3d->flush();
|
||||
}
|
||||
|
||||
void WorldRenderer::clear() {
|
||||
void WorldRenderer::resetCache() {
|
||||
chunksRenderer->clear();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@
|
|||
#include "typedefs.hpp"
|
||||
|
||||
#include "presets/WeatherPreset.hpp"
|
||||
#include "world/Weather.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "util/ObjectsKeeper.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
class Assets;
|
||||
|
|
@ -36,18 +35,38 @@ class Skybox;
|
|||
class TextsRenderer;
|
||||
class CloudsRenderer;
|
||||
struct EngineSettings;
|
||||
struct Weather;
|
||||
|
||||
struct CompileTimeShaderSettings {
|
||||
bool advancedRender = false;
|
||||
bool shadows = false;
|
||||
bool ssao = false;
|
||||
};
|
||||
class WorldRenderer final : public util::ObjectsKeeper {
|
||||
public:
|
||||
static bool showChunkBorders;
|
||||
static bool showEntitiesDebug;
|
||||
|
||||
class WorldRenderer {
|
||||
WorldRenderer(Engine& engine, LevelFrontend& frontend, Player& player);
|
||||
~WorldRenderer();
|
||||
|
||||
void update(const Camera& camera, float delta);
|
||||
|
||||
void renderFrame(
|
||||
const DrawContext& context,
|
||||
Camera& camera,
|
||||
bool hudVisible,
|
||||
PostProcessing& postProcessing
|
||||
);
|
||||
|
||||
void resetCache();
|
||||
|
||||
void setDebug(bool flag);
|
||||
|
||||
void toggleLightsDebug();
|
||||
|
||||
Weather& getWeather();
|
||||
private:
|
||||
Engine& engine;
|
||||
const Level& level;
|
||||
Player& player;
|
||||
const Assets& assets;
|
||||
Weather& weather;
|
||||
std::unique_ptr<Frustum> frustumCulling;
|
||||
std::unique_ptr<LineBatch> lineBatch;
|
||||
std::unique_ptr<Batch3D> batch3d;
|
||||
|
|
@ -59,14 +78,12 @@ class WorldRenderer {
|
|||
std::unique_ptr<DebugLinesRenderer> debugLines;
|
||||
std::unique_ptr<PrecipitationRenderer> precipitation;
|
||||
std::unique_ptr<CloudsRenderer> cloudsRenderer;
|
||||
Weather weather {};
|
||||
|
||||
float timer = 0.0f;
|
||||
bool debug = false;
|
||||
bool lightsDebug = false;
|
||||
bool gbufferPipeline = false;
|
||||
|
||||
CompileTimeShaderSettings prevCTShaderSettings {};
|
||||
bool dirtySettings = true;
|
||||
|
||||
/// @brief Render block selection lines
|
||||
void renderBlockSelection();
|
||||
|
|
@ -74,7 +91,7 @@ class WorldRenderer {
|
|||
/// @brief Render lines (selection and debug)
|
||||
/// @param camera active camera
|
||||
/// @param linesShader shader used
|
||||
void renderLines(
|
||||
void renderInWorldLines(
|
||||
const Camera& camera, Shader& linesShader, const DrawContext& pctx
|
||||
);
|
||||
|
||||
|
|
@ -98,7 +115,34 @@ class WorldRenderer {
|
|||
bool hudVisible
|
||||
);
|
||||
|
||||
void refreshSettings(Shader** shaders);
|
||||
void renderOpaquePass(
|
||||
const DrawContext& context,
|
||||
Camera& camera,
|
||||
bool hudVisible,
|
||||
PostProcessing& postProcessing
|
||||
);
|
||||
|
||||
void renderWeatherEffects(Camera& camera);
|
||||
|
||||
void renderHandsPass(const DrawContext& pctx, Camera& camera);
|
||||
|
||||
void renderDebugLines(const DrawContext& context, Camera& camera);
|
||||
|
||||
void renderFrameClassic(
|
||||
const DrawContext& context,
|
||||
Camera& camera,
|
||||
bool hudVisible,
|
||||
PostProcessing& postProcessing
|
||||
);
|
||||
|
||||
void renderFrameAdvanced(
|
||||
const DrawContext& context,
|
||||
Camera& camera,
|
||||
bool hudVisible,
|
||||
PostProcessing& postProcessing
|
||||
);
|
||||
|
||||
void refreshSettings();
|
||||
|
||||
float calcFogFactor() const;
|
||||
public:
|
||||
|
|
@ -106,27 +150,4 @@ public:
|
|||
std::unique_ptr<TextsRenderer> texts;
|
||||
std::unique_ptr<BlockWrapsRenderer> blockWraps;
|
||||
std::unique_ptr<NamedSkeletons> skeletons;
|
||||
|
||||
static bool showChunkBorders;
|
||||
static bool showEntitiesDebug;
|
||||
|
||||
WorldRenderer(Engine& engine, LevelFrontend& frontend, Player& player);
|
||||
~WorldRenderer();
|
||||
|
||||
void update(const Camera& camera, float delta);
|
||||
|
||||
void renderFrame(
|
||||
const DrawContext& context,
|
||||
Camera& camera,
|
||||
bool hudVisible,
|
||||
PostProcessing& postProcessing
|
||||
);
|
||||
|
||||
void clear();
|
||||
|
||||
void setDebug(bool flag);
|
||||
|
||||
void toggleLightsDebug();
|
||||
|
||||
Weather& getWeather();
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue