Merge pull request #370 from MihailRis/transparency-fix
Fix transparency
This commit is contained in:
commit
be9bd3e508
@ -39,6 +39,12 @@ Block model type from list:
|
|||||||
|
|
||||||
Integer specifying number of block draw group (render order). Used for semi-transparent blocks.
|
Integer specifying number of block draw group (render order). Used for semi-transparent blocks.
|
||||||
|
|
||||||
|
### *translucent*
|
||||||
|
|
||||||
|
Enables translucency support in block textures (examples: water, ice).
|
||||||
|
Should only be used when needed, as it impacts performance.
|
||||||
|
Not required for full transparency (grass, flowers).
|
||||||
|
|
||||||
### *rotation*
|
### *rotation*
|
||||||
|
|
||||||
Rotation profile (set of available block rotations and behaviour of placing block rotation) from list:
|
Rotation profile (set of available block rotations and behaviour of placing block rotation) from list:
|
||||||
|
|||||||
@ -40,6 +40,12 @@
|
|||||||
Целое число определяющее номер группы отрисовки данного блока.
|
Целое число определяющее номер группы отрисовки данного блока.
|
||||||
Актуально для полупрозрачных блоков - решает проблемы невидимых сторон блоков за этим блоком.
|
Актуально для полупрозрачных блоков - решает проблемы невидимых сторон блоков за этим блоком.
|
||||||
|
|
||||||
|
### Полупрозрачность - *translucent*
|
||||||
|
|
||||||
|
Включает поддержку полупрозрачности в текстурах блока (примеры: вода, лёд).
|
||||||
|
Следует использовать только при надобности, так как влияет на производительность.
|
||||||
|
Не требуется для полной прозрачности (трава, цветы).
|
||||||
|
|
||||||
### Вращение - *rotation*
|
### Вращение - *rotation*
|
||||||
|
|
||||||
Профиль вращения (набор положений, в которые можно установить блок) из списка:
|
Профиль вращения (набор положений, в которые можно установить блок) из списка:
|
||||||
|
|||||||
@ -3,5 +3,6 @@
|
|||||||
"material": "base:glass",
|
"material": "base:glass",
|
||||||
"draw-group": 2,
|
"draw-group": 2,
|
||||||
"light-passing": true,
|
"light-passing": true,
|
||||||
"sky-light-passing": true
|
"sky-light-passing": true,
|
||||||
|
"translucent": true
|
||||||
}
|
}
|
||||||
|
|||||||
7
res/content/base/blocks/ice.json
Normal file
7
res/content/base/blocks/ice.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"texture": "ice",
|
||||||
|
"material": "base:glass",
|
||||||
|
"draw-group": 4,
|
||||||
|
"light-passing": true,
|
||||||
|
"translucent": true
|
||||||
|
}
|
||||||
@ -6,5 +6,6 @@
|
|||||||
"sky-light-passing": false,
|
"sky-light-passing": false,
|
||||||
"obstacle": false,
|
"obstacle": false,
|
||||||
"selectable": false,
|
"selectable": false,
|
||||||
"replaceable": true
|
"replaceable": true,
|
||||||
|
"translucent": true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"items": [
|
"entities": [
|
||||||
"bazalt_breaker"
|
"drop",
|
||||||
|
"player",
|
||||||
|
"falling_block"
|
||||||
],
|
],
|
||||||
"blocks": [
|
"blocks": [
|
||||||
"dirt",
|
"dirt",
|
||||||
@ -27,11 +29,10 @@
|
|||||||
"lightbulb",
|
"lightbulb",
|
||||||
"torch",
|
"torch",
|
||||||
"wooden_door",
|
"wooden_door",
|
||||||
"coal_ore"
|
"coal_ore",
|
||||||
|
"ice"
|
||||||
],
|
],
|
||||||
"entities": [
|
"items": [
|
||||||
"drop",
|
"bazalt_breaker"
|
||||||
"player",
|
|
||||||
"falling_block"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
BIN
res/content/base/textures/blocks/ice.png
Normal file
BIN
res/content/base/textures/blocks/ice.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
@ -9,14 +9,14 @@ uniform samplerCube u_cubemap;
|
|||||||
uniform vec3 u_fogColor;
|
uniform vec3 u_fogColor;
|
||||||
uniform float u_fogFactor;
|
uniform float u_fogFactor;
|
||||||
uniform float u_fogCurve;
|
uniform float u_fogCurve;
|
||||||
|
uniform bool u_alphaClip;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 fogColor = texture(u_cubemap, a_dir).rgb;
|
vec3 fogColor = texture(u_cubemap, a_dir).rgb;
|
||||||
vec4 tex_color = texture(u_texture0, a_texCoord);
|
vec4 tex_color = texture(u_texture0, a_texCoord);
|
||||||
float depth = (a_distance/256.0);
|
float depth = (a_distance/256.0);
|
||||||
float alpha = a_color.a * tex_color.a;
|
float alpha = a_color.a * tex_color.a;
|
||||||
// anyway it's any alpha-test alternative required
|
if (u_alphaClip && alpha < 0.9f)
|
||||||
if (alpha < 0.3f)
|
|
||||||
discard;
|
discard;
|
||||||
f_color = mix(a_color * tex_color, vec4(fogColor,1.0),
|
f_color = mix(a_color * tex_color, vec4(fogColor,1.0),
|
||||||
min(1.0, pow(depth*u_fogFactor, u_fogCurve)));
|
min(1.0, pow(depth*u_fogFactor, u_fogCurve)));
|
||||||
|
|||||||
@ -35,9 +35,6 @@ inline constexpr int CHUNK_D = 16;
|
|||||||
inline constexpr uint VOXEL_USER_BITS = 8;
|
inline constexpr uint VOXEL_USER_BITS = 8;
|
||||||
inline constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS;
|
inline constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS;
|
||||||
|
|
||||||
/// @brief pixel size of an item inventory icon
|
|
||||||
inline constexpr int ITEM_ICON_SIZE = 48;
|
|
||||||
|
|
||||||
/// @brief chunk volume (count of voxels per Chunk)
|
/// @brief chunk volume (count of voxels per Chunk)
|
||||||
inline constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D);
|
inline constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D);
|
||||||
|
|
||||||
@ -53,6 +50,11 @@ inline constexpr uint vox_index(uint x, uint y, uint z, uint w=CHUNK_W, uint d=C
|
|||||||
return (y * d + z) * w + x;
|
return (y * d + z) * w + x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief pixel size of an item inventory icon
|
||||||
|
inline constexpr int ITEM_ICON_SIZE = 48;
|
||||||
|
|
||||||
|
inline constexpr int TRANSLUCENT_BLOCKS_SORT_INTERVAL = 8;
|
||||||
|
|
||||||
inline const std::string SHADERS_FOLDER = "shaders";
|
inline const std::string SHADERS_FOLDER = "shaders";
|
||||||
inline const std::string TEXTURES_FOLDER = "textures";
|
inline const std::string TEXTURES_FOLDER = "textures";
|
||||||
inline const std::string FONTS_FOLDER = "fonts";
|
inline const std::string FONTS_FOLDER = "fonts";
|
||||||
|
|||||||
@ -333,6 +333,7 @@ void ContentLoader::loadBlock(
|
|||||||
root.at("inventory-size").get(def.inventorySize);
|
root.at("inventory-size").get(def.inventorySize);
|
||||||
root.at("tick-interval").get(def.tickInterval);
|
root.at("tick-interval").get(def.tickInterval);
|
||||||
root.at("overlay-texture").get(def.overlayTexture);
|
root.at("overlay-texture").get(def.overlayTexture);
|
||||||
|
root.at("translucent").get(def.translucent);
|
||||||
|
|
||||||
if (root.has("fields")) {
|
if (root.has("fields")) {
|
||||||
def.dataStruct = std::make_unique<StructLayout>();
|
def.dataStruct = std::make_unique<StructLayout>();
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
inline constexpr uint B2D_VERTEX_SIZE = 8;
|
inline constexpr uint B2D_VERTEX_SIZE = 8;
|
||||||
|
|
||||||
Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
|
Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
|
||||||
const vattr attrs[] = {
|
const VertexAttribute attrs[] = {
|
||||||
{2}, {2}, {4}, {0}
|
{2}, {2}, {4}, {0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ inline constexpr uint B3D_VERTEX_SIZE = 9;
|
|||||||
|
|
||||||
Batch3D::Batch3D(size_t capacity)
|
Batch3D::Batch3D(size_t capacity)
|
||||||
: capacity(capacity) {
|
: capacity(capacity) {
|
||||||
const vattr attrs[] = {
|
const VertexAttribute attrs[] = {
|
||||||
{3}, {2}, {4}, {0}
|
{3}, {2}, {4}, {0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
inline constexpr uint LB_VERTEX_SIZE = (3+4);
|
inline constexpr uint LB_VERTEX_SIZE = (3+4);
|
||||||
|
|
||||||
LineBatch::LineBatch(size_t capacity) : capacity(capacity) {
|
LineBatch::LineBatch(size_t capacity) : capacity(capacity) {
|
||||||
const vattr attrs[] = { {3},{4}, {0} };
|
const VertexAttribute attrs[] = { {3},{4}, {0} };
|
||||||
buffer = std::make_unique<float[]>(capacity * LB_VERTEX_SIZE * 2);
|
buffer = std::make_unique<float[]>(capacity * LB_VERTEX_SIZE * 2);
|
||||||
mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs);
|
mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs);
|
||||||
index = 0;
|
index = 0;
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
int Mesh::meshesCount = 0;
|
int Mesh::meshesCount = 0;
|
||||||
int Mesh::drawCalls = 0;
|
int Mesh::drawCalls = 0;
|
||||||
|
|
||||||
inline size_t calc_vertex_size(const vattr* attrs) {
|
inline size_t calc_vertex_size(const VertexAttribute* attrs) {
|
||||||
size_t vertexSize = 0;
|
size_t vertexSize = 0;
|
||||||
for (int i = 0; attrs[i].size; i++) {
|
for (int i = 0; attrs[i].size; i++) {
|
||||||
vertexSize += attrs[i].size;
|
vertexSize += attrs[i].size;
|
||||||
@ -19,10 +19,10 @@ Mesh::Mesh(const MeshData& data)
|
|||||||
data.indices.size(),
|
data.indices.size(),
|
||||||
data.attrs.data()) {}
|
data.attrs.data()) {}
|
||||||
|
|
||||||
Mesh::Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const vattr* attrs) :
|
Mesh::Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const VertexAttribute* attrs) :
|
||||||
ibo(0),
|
ibo(0),
|
||||||
vertices(vertices),
|
vertices(0),
|
||||||
indices(indices)
|
indices(0)
|
||||||
{
|
{
|
||||||
meshesCount++;
|
meshesCount++;
|
||||||
vertexSize = 0;
|
vertexSize = 0;
|
||||||
@ -58,10 +58,9 @@ void Mesh::reload(const float* vertexBuffer, size_t vertices, const int* indexBu
|
|||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
if (vertexBuffer != nullptr && vertices != 0) {
|
if (vertexBuffer != nullptr && vertices != 0) {
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, vertexBuffer, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, vertexBuffer, GL_STREAM_DRAW);
|
||||||
}
|
} else {
|
||||||
else {
|
glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW);
|
||||||
glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STATIC_DRAW);
|
|
||||||
}
|
}
|
||||||
if (indexBuffer != nullptr && indices != 0) {
|
if (indexBuffer != nullptr && indices != 0) {
|
||||||
if (ibo == 0) glGenBuffers(1, &ibo);
|
if (ibo == 0) glGenBuffers(1, &ibo);
|
||||||
@ -75,7 +74,7 @@ void Mesh::reload(const float* vertexBuffer, size_t vertices, const int* indexBu
|
|||||||
this->indices = indices;
|
this->indices = indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::draw(unsigned int primitive){
|
void Mesh::draw(unsigned int primitive) const {
|
||||||
drawCalls++;
|
drawCalls++;
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
if (ibo != 0) {
|
if (ibo != 0) {
|
||||||
@ -87,6 +86,6 @@ void Mesh::draw(unsigned int primitive){
|
|||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::draw() {
|
void Mesh::draw() const {
|
||||||
draw(GL_TRIANGLES);
|
draw(GL_TRIANGLES);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,8 +14,8 @@ class Mesh {
|
|||||||
size_t vertexSize;
|
size_t vertexSize;
|
||||||
public:
|
public:
|
||||||
Mesh(const MeshData& data);
|
Mesh(const MeshData& data);
|
||||||
Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const vattr* attrs);
|
Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const VertexAttribute* attrs);
|
||||||
Mesh(const float* vertexBuffer, size_t vertices, const vattr* attrs) :
|
Mesh(const float* vertexBuffer, size_t vertices, const VertexAttribute* attrs) :
|
||||||
Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {};
|
Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {};
|
||||||
~Mesh();
|
~Mesh();
|
||||||
|
|
||||||
@ -28,10 +28,10 @@ public:
|
|||||||
|
|
||||||
/// @brief Draw mesh with specified primitives type
|
/// @brief Draw mesh with specified primitives type
|
||||||
/// @param primitive primitives type
|
/// @param primitive primitives type
|
||||||
void draw(unsigned int primitive);
|
void draw(unsigned int primitive) const;
|
||||||
|
|
||||||
/// @brief Draw mesh as triangles
|
/// @brief Draw mesh as triangles
|
||||||
void draw();
|
void draw() const;
|
||||||
|
|
||||||
/// @brief Total numbers of alive mesh objects
|
/// @brief Total numbers of alive mesh objects
|
||||||
static int meshesCount;
|
static int meshesCount;
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include "util/Buffer.hpp"
|
#include "util/Buffer.hpp"
|
||||||
|
|
||||||
/// @brief Vertex attribute info
|
/// @brief Vertex attribute info
|
||||||
struct vattr {
|
struct VertexAttribute {
|
||||||
ubyte size;
|
ubyte size;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ struct vattr {
|
|||||||
struct MeshData {
|
struct MeshData {
|
||||||
util::Buffer<float> vertices;
|
util::Buffer<float> vertices;
|
||||||
util::Buffer<int> indices;
|
util::Buffer<int> indices;
|
||||||
util::Buffer<vattr> attrs;
|
util::Buffer<VertexAttribute> attrs;
|
||||||
|
|
||||||
MeshData() = default;
|
MeshData() = default;
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ struct MeshData {
|
|||||||
MeshData(
|
MeshData(
|
||||||
util::Buffer<float> vertices,
|
util::Buffer<float> vertices,
|
||||||
util::Buffer<int> indices,
|
util::Buffer<int> indices,
|
||||||
util::Buffer<vattr> attrs
|
util::Buffer<VertexAttribute> attrs
|
||||||
) : vertices(std::move(vertices)),
|
) : vertices(std::move(vertices)),
|
||||||
indices(std::move(indices)),
|
indices(std::move(indices)),
|
||||||
attrs(std::move(attrs)) {}
|
attrs(std::move(attrs)) {}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ PostProcessing::PostProcessing() {
|
|||||||
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
|
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
|
||||||
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
|
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
|
||||||
};
|
};
|
||||||
vattr attrs[] {{2}, {0}};
|
VertexAttribute attrs[] {{2}, {0}};
|
||||||
quadMesh = std::make_unique<Mesh>(vertices, 6, attrs);
|
quadMesh = std::make_unique<Mesh>(vertices, 6, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
BlocksRenderer::BlocksRenderer(
|
BlocksRenderer::BlocksRenderer(
|
||||||
@ -21,7 +20,7 @@ BlocksRenderer::BlocksRenderer(
|
|||||||
const ContentGfxCache& cache,
|
const ContentGfxCache& cache,
|
||||||
const EngineSettings& settings
|
const EngineSettings& settings
|
||||||
) : content(content),
|
) : content(content),
|
||||||
vertexBuffer(std::make_unique<float[]>(capacity * VERTEX_SIZE)),
|
vertexBuffer(std::make_unique<float[]>(capacity * CHUNK_VERTEX_SIZE)),
|
||||||
indexBuffer(std::make_unique<int[]>(capacity)),
|
indexBuffer(std::make_unique<int[]>(capacity)),
|
||||||
vertexOffset(0),
|
vertexOffset(0),
|
||||||
indexOffset(0),
|
indexOffset(0),
|
||||||
@ -85,7 +84,7 @@ void BlocksRenderer::face(
|
|||||||
const glm::vec4(&lights)[4],
|
const glm::vec4(&lights)[4],
|
||||||
const glm::vec4& tint
|
const glm::vec4& tint
|
||||||
) {
|
) {
|
||||||
if (vertexOffset + BlocksRenderer::VERTEX_SIZE * 4 > capacity) {
|
if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) {
|
||||||
overflow = true;
|
overflow = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -125,7 +124,7 @@ void BlocksRenderer::faceAO(
|
|||||||
const UVRegion& region,
|
const UVRegion& region,
|
||||||
bool lights
|
bool lights
|
||||||
) {
|
) {
|
||||||
if (vertexOffset + BlocksRenderer::VERTEX_SIZE * 4 > capacity) {
|
if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) {
|
||||||
overflow = true;
|
overflow = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -163,7 +162,7 @@ void BlocksRenderer::face(
|
|||||||
glm::vec4 tint,
|
glm::vec4 tint,
|
||||||
bool lights
|
bool lights
|
||||||
) {
|
) {
|
||||||
if (vertexOffset + BlocksRenderer::VERTEX_SIZE * 4 > capacity) {
|
if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) {
|
||||||
overflow = true;
|
overflow = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -288,7 +287,7 @@ void BlocksRenderer::blockCustomModel(
|
|||||||
|
|
||||||
const auto& model = cache.getModel(block->rt.id);
|
const auto& model = cache.getModel(block->rt.id);
|
||||||
for (const auto& mesh : model.meshes) {
|
for (const auto& mesh : model.meshes) {
|
||||||
if (vertexOffset + BlocksRenderer::VERTEX_SIZE * mesh.vertices.size() > capacity) {
|
if (vertexOffset + CHUNK_VERTEX_SIZE * mesh.vertices.size() > capacity) {
|
||||||
overflow = true;
|
overflow = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -433,21 +432,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 +449,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 +490,185 @@ void BlocksRenderer::render(const voxel* voxels) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SortingMeshData BlocksRenderer::renderTranslucent(
|
||||||
|
const voxel* voxels, int beginEnds[256][2]
|
||||||
|
) {
|
||||||
|
SortingMeshData sortingMesh {{}};
|
||||||
|
|
||||||
|
AABB aabb {};
|
||||||
|
bool aabbInit = false;
|
||||||
|
size_t totalSize = 0;
|
||||||
|
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 + 0.5f,
|
||||||
|
y + 0.5f,
|
||||||
|
z + chunk->z * CHUNK_D + 0.5f
|
||||||
|
),
|
||||||
|
util::Buffer<float>(indexSize * CHUNK_VERTEX_SIZE)};
|
||||||
|
|
||||||
|
totalSize += entry.vertexData.size();
|
||||||
|
|
||||||
|
for (int j = 0; j < indexSize; j++) {
|
||||||
|
std::memcpy(
|
||||||
|
entry.vertexData.data() + j * CHUNK_VERTEX_SIZE,
|
||||||
|
vertexBuffer.get() + indexBuffer[j] * CHUNK_VERTEX_SIZE,
|
||||||
|
sizeof(float) * CHUNK_VERTEX_SIZE
|
||||||
|
);
|
||||||
|
float& vx = entry.vertexData[j * CHUNK_VERTEX_SIZE + 0];
|
||||||
|
float& vy = entry.vertexData[j * CHUNK_VERTEX_SIZE + 1];
|
||||||
|
float& vz = entry.vertexData[j * CHUNK_VERTEX_SIZE + 2];
|
||||||
|
|
||||||
|
if (!aabbInit) {
|
||||||
|
aabbInit = true;
|
||||||
|
aabb.a = aabb.b = {vx, vy, vz};
|
||||||
|
} else {
|
||||||
|
aabb.addPoint(glm::vec3(vx, vy, vz));
|
||||||
|
}
|
||||||
|
vx += chunk->x * CHUNK_W + 0.5f;
|
||||||
|
vy += 0.5f;
|
||||||
|
vz += chunk->z * CHUNK_D + 0.5f;
|
||||||
|
}
|
||||||
|
sortingMesh.entries.push_back(std::move(entry));
|
||||||
|
vertexOffset = 0;
|
||||||
|
indexOffset = indexSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// additional powerful optimization
|
||||||
|
auto size = aabb.size();
|
||||||
|
if ((size.y < 0.01f || size.x < 0.01f || size.z < 0.01f) &&
|
||||||
|
sortingMesh.entries.size() > 1) {
|
||||||
|
SortingMeshEntry newEntry {
|
||||||
|
sortingMesh.entries[0].position,
|
||||||
|
util::Buffer<float>(totalSize)
|
||||||
|
};
|
||||||
|
size_t offset = 0;
|
||||||
|
for (const auto& entry : sortingMesh.entries) {
|
||||||
|
std::memcpy(
|
||||||
|
newEntry.vertexData.data() + offset,
|
||||||
|
entry.vertexData.data(), entry.vertexData.size() * sizeof(float)
|
||||||
|
);
|
||||||
|
offset += entry.vertexData.size();
|
||||||
|
}
|
||||||
|
return SortingMeshData {{std::move(newEntry)}};
|
||||||
|
}
|
||||||
|
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} };
|
return ChunkMeshData {
|
||||||
return MeshData(
|
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<VertexAttribute>(
|
||||||
);
|
CHUNK_VATTRS, sizeof(CHUNK_VATTRS) / sizeof(VertexAttribute)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
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} };
|
size_t vcount = vertexOffset / CHUNK_VERTEX_SIZE;
|
||||||
size_t vcount = vertexOffset / BlocksRenderer::VERTEX_SIZE;
|
return ChunkMesh{std::make_unique<Mesh>(
|
||||||
return std::make_shared<Mesh>(
|
vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, CHUNK_VATTRS
|
||||||
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;
|
||||||
@ -26,7 +27,6 @@ struct UVRegion;
|
|||||||
|
|
||||||
class BlocksRenderer {
|
class BlocksRenderer {
|
||||||
static const glm::vec3 SUN_VECTOR;
|
static const glm::vec3 SUN_VECTOR;
|
||||||
static const uint VERTEX_SIZE;
|
|
||||||
const Content& content;
|
const Content& content;
|
||||||
std::unique_ptr<float[]> vertexBuffer;
|
std::unique_ptr<float[]> vertexBuffer;
|
||||||
std::unique_ptr<int[]> indexBuffer;
|
std::unique_ptr<int[]> indexBuffer;
|
||||||
@ -45,6 +45,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 +117,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 +136,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 +149,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 {
|
||||||
|
|||||||
@ -14,10 +14,6 @@
|
|||||||
#include "util/listutil.hpp"
|
#include "util/listutil.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <glm/ext.hpp>
|
|
||||||
|
|
||||||
static debug::Logger logger("chunks-render");
|
static debug::Logger logger("chunks-render");
|
||||||
|
|
||||||
size_t ChunksRenderer::visibleChunks = 0;
|
size_t ChunksRenderer::visibleChunks = 0;
|
||||||
@ -62,7 +58,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_unique<Mesh>(meshData.mesh),
|
||||||
|
std::move(meshData.sortingMesh)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
inwork.erase(result.key);
|
inwork.erase(result.key);
|
||||||
}, settings.graphics.chunkMaxRenderers.get())
|
}, settings.graphics.chunkMaxRenderers.get())
|
||||||
@ -78,12 +78,16 @@ ChunksRenderer::ChunksRenderer(
|
|||||||
ChunksRenderer::~ChunksRenderer() {
|
ChunksRenderer::~ChunksRenderer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Mesh> ChunksRenderer::render(const std::shared_ptr<Chunk>& chunk, bool important) {
|
const Mesh* ChunksRenderer::render(
|
||||||
|
const std::shared_ptr<Chunk>& chunk, bool important
|
||||||
|
) {
|
||||||
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.sortingMeshData)
|
||||||
|
};
|
||||||
|
return meshes[glm::ivec2(chunk->x, chunk->z)].mesh.get();
|
||||||
}
|
}
|
||||||
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()) {
|
||||||
@ -107,7 +111,9 @@ void ChunksRenderer::clear() {
|
|||||||
threadPool.clearQueue();
|
threadPool.clearQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Mesh> ChunksRenderer::getOrRender(const std::shared_ptr<Chunk>& chunk, bool important) {
|
const Mesh* ChunksRenderer::getOrRender(
|
||||||
|
const std::shared_ptr<Chunk>& chunk, bool important
|
||||||
|
) {
|
||||||
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
|
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
|
||||||
if (found == meshes.end()) {
|
if (found == meshes.end()) {
|
||||||
return render(chunk, important);
|
return render(chunk, important);
|
||||||
@ -115,19 +121,19 @@ 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.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunksRenderer::update() {
|
void ChunksRenderer::update() {
|
||||||
threadPool.update();
|
threadPool.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChunksRenderer::drawChunk(
|
const Mesh* ChunksRenderer::retrieveChunk(
|
||||||
size_t index, const Camera& camera, Shader& shader, bool culling
|
size_t index, const Camera& camera, Shader& shader, bool culling
|
||||||
) {
|
) {
|
||||||
auto chunk = level.chunks->getChunks()[index];
|
auto chunk = level.chunks->getChunks()[index];
|
||||||
if (chunk == nullptr || !chunk->flags.lighted) {
|
if (chunk == nullptr || !chunk->flags.lighted) {
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
float distance = glm::distance(
|
float distance = glm::distance(
|
||||||
camera.position,
|
camera.position,
|
||||||
@ -139,7 +145,7 @@ bool ChunksRenderer::drawChunk(
|
|||||||
);
|
);
|
||||||
auto mesh = getOrRender(chunk, distance < CHUNK_W * 1.5f);
|
auto mesh = getOrRender(chunk, distance < CHUNK_W * 1.5f);
|
||||||
if (mesh == nullptr) {
|
if (mesh == nullptr) {
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (culling) {
|
if (culling) {
|
||||||
glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D);
|
glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D);
|
||||||
@ -149,13 +155,9 @@ bool ChunksRenderer::drawChunk(
|
|||||||
chunk->z * CHUNK_D + CHUNK_D
|
chunk->z * CHUNK_D + CHUNK_D
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!frustum.isBoxVisible(min, max)) return false;
|
if (!frustum.isBoxVisible(min, max)) return nullptr;
|
||||||
}
|
}
|
||||||
glm::vec3 coord(chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f);
|
return mesh;
|
||||||
glm::mat4 model = glm::translate(glm::mat4(1.0f), coord);
|
|
||||||
shader.uniformMatrix("u_model", model);
|
|
||||||
mesh->draw();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunksRenderer::drawChunks(
|
void ChunksRenderer::drawChunks(
|
||||||
@ -191,11 +193,108 @@ void ChunksRenderer::drawChunks(
|
|||||||
bool culling = settings.graphics.frustumCulling.get();
|
bool culling = settings.graphics.frustumCulling.get();
|
||||||
|
|
||||||
visibleChunks = 0;
|
visibleChunks = 0;
|
||||||
//if (GLEW_ARB_multi_draw_indirect && false) {
|
shader.uniform1i("u_alphaClip", true);
|
||||||
// TODO: implement Multi Draw Indirect chunks draw
|
|
||||||
//} else {
|
// TODO: minimize draw calls number
|
||||||
for (size_t i = 0; i < indices.size(); i++) {
|
for (size_t i = 0; i < indices.size(); i++) {
|
||||||
visibleChunks += drawChunk(indices[i].index, camera, shader, culling);
|
auto chunk = chunks.getChunks()[indices[i].index];
|
||||||
|
auto mesh = retrieveChunk(indices[i].index, camera, shader, culling);
|
||||||
|
|
||||||
|
if (mesh) {
|
||||||
|
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();
|
||||||
|
visibleChunks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write_sorting_mesh_entries(
|
||||||
|
float* buffer, const std::vector<SortingMeshEntry>& chunkEntries
|
||||||
|
) {
|
||||||
|
for (const auto& entry : chunkEntries) {
|
||||||
|
const auto& vertexData = entry.vertexData;
|
||||||
|
std::memcpy(
|
||||||
|
buffer,
|
||||||
|
vertexData.data(),
|
||||||
|
vertexData.size() * sizeof(float)
|
||||||
|
);
|
||||||
|
buffer += vertexData.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) {
|
||||||
|
const int sortInterval = TRANSLUCENT_BLOCKS_SORT_INTERVAL;
|
||||||
|
static int frameid = 0;
|
||||||
|
frameid++;
|
||||||
|
|
||||||
|
bool culling = settings.graphics.frustumCulling.get();
|
||||||
|
const auto& chunks = level.chunks->getChunks();
|
||||||
|
const auto& cameraPos = camera.position;
|
||||||
|
const auto& atlas = assets.require<Atlas>("blocks");
|
||||||
|
|
||||||
|
atlas.getTexture()->bind();
|
||||||
|
shader.uniformMatrix("u_model", glm::mat4(1.0f));
|
||||||
|
shader.uniform1i("u_alphaClip", false);
|
||||||
|
|
||||||
|
for (const auto& index : indices) {
|
||||||
|
const auto& chunk = chunks[index.index];
|
||||||
|
if (chunk == nullptr || !chunk->flags.lighted) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto& found = meshes.find(glm::ivec2(chunk->x, chunk->z));
|
||||||
|
if (found == meshes.end() || found->second.sortingMeshData.entries.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D);
|
||||||
|
glm::vec3 max(
|
||||||
|
chunk->x * CHUNK_W + CHUNK_W,
|
||||||
|
chunk->top,
|
||||||
|
chunk->z * CHUNK_D + CHUNK_D
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!frustum.isBoxVisible(min, max)) continue;
|
||||||
|
|
||||||
|
auto& chunkEntries = found->second.sortingMeshData.entries;
|
||||||
|
|
||||||
|
if (chunkEntries.size() == 1) {
|
||||||
|
auto& entry = chunkEntries.at(0);
|
||||||
|
if (found->second.sortedMesh == nullptr) {
|
||||||
|
found->second.sortedMesh = std::make_unique<Mesh>(
|
||||||
|
entry.vertexData.data(),
|
||||||
|
entry.vertexData.size() / CHUNK_VERTEX_SIZE,
|
||||||
|
CHUNK_VATTRS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
found->second.sortedMesh->draw();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (auto& entry : chunkEntries) {
|
||||||
|
entry.distance = static_cast<long long>(
|
||||||
|
glm::distance2(entry.position, cameraPos)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (found->second.sortedMesh == nullptr ||
|
||||||
|
(frameid + chunk->x) % sortInterval == 0) {
|
||||||
|
std::sort(chunkEntries.begin(), chunkEntries.end());
|
||||||
|
size_t size = 0;
|
||||||
|
for (const auto& entry : chunkEntries) {
|
||||||
|
size += entry.vertexData.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
static util::Buffer<float> buffer;
|
||||||
|
if (buffer.size() < size) {
|
||||||
|
buffer = util::Buffer<float>(size);
|
||||||
|
}
|
||||||
|
write_sorting_mesh_entries(buffer.data(), chunkEntries);
|
||||||
|
found->second.sortedMesh = std::make_unique<Mesh>(
|
||||||
|
buffer.data(), size / CHUNK_VERTEX_SIZE, CHUNK_VATTRS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
found->second.sortedMesh->draw();
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,19 +4,21 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include <glm/gtx/hash.hpp>
|
||||||
|
|
||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.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;
|
||||||
class Level;
|
class Level;
|
||||||
class Camera;
|
class Camera;
|
||||||
class Shader;
|
class Shader;
|
||||||
class Chunks;
|
|
||||||
class Assets;
|
class Assets;
|
||||||
class Frustum;
|
class Frustum;
|
||||||
class BlocksRenderer;
|
class BlocksRenderer;
|
||||||
@ -35,7 +37,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,12 +47,11 @@ 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;
|
||||||
|
const Mesh* retrieveChunk(
|
||||||
bool drawChunk(
|
|
||||||
size_t index, const Camera& camera, Shader& shader, bool culling
|
size_t index, const Camera& camera, Shader& shader, bool culling
|
||||||
);
|
);
|
||||||
public:
|
public:
|
||||||
@ -63,17 +64,19 @@ public:
|
|||||||
);
|
);
|
||||||
virtual ~ChunksRenderer();
|
virtual ~ChunksRenderer();
|
||||||
|
|
||||||
std::shared_ptr<Mesh> render(
|
const Mesh* render(
|
||||||
const std::shared_ptr<Chunk>& chunk, bool important
|
const std::shared_ptr<Chunk>& chunk, bool important
|
||||||
);
|
);
|
||||||
void unload(const Chunk* chunk);
|
void unload(const Chunk* chunk);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
std::shared_ptr<Mesh> getOrRender(
|
const Mesh* getOrRender(
|
||||||
const std::shared_ptr<Chunk>& chunk, bool important
|
const std::shared_ptr<Chunk>& chunk, bool important
|
||||||
);
|
);
|
||||||
void drawChunks(const Camera& camera, Shader& shader);
|
void drawChunks(const Camera& camera, Shader& shader);
|
||||||
|
|
||||||
|
void drawSortedMeshes(const Camera& camera, Shader& shader);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
static size_t visibleChunks;
|
static size_t visibleChunks;
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include "voxels/Chunks.hpp"
|
#include "voxels/Chunks.hpp"
|
||||||
#include "voxels/Chunk.hpp"
|
#include "voxels/Chunk.hpp"
|
||||||
|
|
||||||
static const vattr attrs[] = {
|
static const VertexAttribute attrs[] = {
|
||||||
{3}, {2}, {3}, {1}, {0}
|
{3}, {2}, {3}, {1}, {0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,7 @@ Skybox::Skybox(uint size, Shader& shader)
|
|||||||
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
|
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
|
||||||
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
|
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
|
||||||
};
|
};
|
||||||
vattr attrs[] {{2}, {0}};
|
VertexAttribute attrs[] {{2}, {0}};
|
||||||
mesh = std::make_unique<Mesh>(vertices, 6, attrs);
|
mesh = std::make_unique<Mesh>(vertices, 6, attrs);
|
||||||
|
|
||||||
sprites.push_back(skysprite {
|
sprites.push_back(skysprite {
|
||||||
|
|||||||
@ -164,10 +164,18 @@ void WorldRenderer::renderLevel(
|
|||||||
particles->render(camera, delta * !pause);
|
particles->render(camera, delta * !pause);
|
||||||
|
|
||||||
auto& shader = assets.require<Shader>("main");
|
auto& shader = assets.require<Shader>("main");
|
||||||
|
auto& linesShader = assets.require<Shader>("lines");
|
||||||
|
|
||||||
setupWorldShader(shader, camera, settings, fogFactor);
|
setupWorldShader(shader, camera, settings, fogFactor);
|
||||||
|
|
||||||
chunks->drawChunks(camera, shader);
|
chunks->drawChunks(camera, shader);
|
||||||
|
|
||||||
|
if (hudVisible) {
|
||||||
|
renderLines(camera, linesShader, ctx);
|
||||||
|
}
|
||||||
|
shader.use();
|
||||||
|
chunks->drawSortedMeshes(camera, shader);
|
||||||
|
|
||||||
if (!pause) {
|
if (!pause) {
|
||||||
scripting::on_frontend_render();
|
scripting::on_frontend_render();
|
||||||
}
|
}
|
||||||
@ -326,7 +334,6 @@ void WorldRenderer::draw(
|
|||||||
ctx, camera, *lineBatch, linesShader, showChunkBorders
|
ctx, camera, *lineBatch, linesShader, showChunkBorders
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
renderLines(camera, linesShader, ctx);
|
|
||||||
if (player->currentCamera == player->fpCamera) {
|
if (player->currentCamera == player->fpCamera) {
|
||||||
renderHands(camera, delta * !pause);
|
renderHands(camera, delta * !pause);
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/graphics/render/commons.hpp
Normal file
40
src/graphics/render/commons.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <glm/vec3.hpp>
|
||||||
|
|
||||||
|
#include "graphics/core/MeshData.hpp"
|
||||||
|
#include "util/Buffer.hpp"
|
||||||
|
|
||||||
|
/// @brief Chunk mesh vertex attributes
|
||||||
|
inline const VertexAttribute CHUNK_VATTRS[]{ {3}, {2}, {1}, {0} };
|
||||||
|
/// @brief Chunk mesh vertex size divided by sizeof(float)
|
||||||
|
inline constexpr int CHUNK_VERTEX_SIZE = 6;
|
||||||
|
|
||||||
|
class Mesh;
|
||||||
|
|
||||||
|
struct SortingMeshEntry {
|
||||||
|
glm::vec3 position;
|
||||||
|
util::Buffer<float> vertexData;
|
||||||
|
long long distance;
|
||||||
|
|
||||||
|
inline bool operator<(const SortingMeshEntry& o) const noexcept {
|
||||||
|
return distance > o.distance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SortingMeshData {
|
||||||
|
std::vector<SortingMeshEntry> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChunkMeshData {
|
||||||
|
MeshData mesh;
|
||||||
|
SortingMeshData sortingMesh;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChunkMesh {
|
||||||
|
std::unique_ptr<Mesh> mesh;
|
||||||
|
SortingMeshData sortingMeshData;
|
||||||
|
std::unique_ptr<Mesh> sortedMesh = nullptr;
|
||||||
|
};
|
||||||
@ -140,6 +140,7 @@ void Block::cloneTo(Block& dst) {
|
|||||||
dst.inventorySize = inventorySize;
|
dst.inventorySize = inventorySize;
|
||||||
dst.tickInterval = tickInterval;
|
dst.tickInterval = tickInterval;
|
||||||
dst.overlayTexture = overlayTexture;
|
dst.overlayTexture = overlayTexture;
|
||||||
|
dst.translucent = translucent;
|
||||||
if (particles) {
|
if (particles) {
|
||||||
dst.particles = std::make_unique<ParticlesPreset>(*particles);
|
dst.particles = std::make_unique<ParticlesPreset>(*particles);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -172,6 +172,9 @@ public:
|
|||||||
/// @brief Turns off block item generation
|
/// @brief Turns off block item generation
|
||||||
bool hidden = false;
|
bool hidden = false;
|
||||||
|
|
||||||
|
/// @brief Block has semi-transparent texture
|
||||||
|
bool translucent = false;
|
||||||
|
|
||||||
/// @brief Set of block physical hitboxes
|
/// @brief Set of block physical hitboxes
|
||||||
std::vector<AABB> hitboxes;
|
std::vector<AABB> hitboxes;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user