diff --git a/src/graphics/render/CloudsRenderer.cpp b/src/graphics/render/CloudsRenderer.cpp index 5253004f6..749986ae5 100755 --- a/src/graphics/render/CloudsRenderer.cpp +++ b/src/graphics/render/CloudsRenderer.cpp @@ -1,3 +1,4 @@ +#define GLM_ENABLE_EXPERIMENTAL #include "CloudsRenderer.hpp" #include "assets/Assets.hpp" @@ -10,11 +11,13 @@ #include "io/io.hpp" #include "lighting/Lightmap.hpp" #include "maths/FastNoiseLite.h" +#include "maths/voxmaths.hpp" #include "util/timeutil.hpp" #include "window/Camera.hpp" #include "world/Weather.hpp" #include +#include #include static debug::Logger logger("clouds-render"); @@ -70,7 +73,6 @@ public: return; } } - logger.info() << "layer vertices: " << offset; } MeshData createMesh() const { @@ -160,70 +162,137 @@ private: } }; -static inline constexpr int WIDTH = 256; -static inline constexpr int DEPTH = 256; +static inline constexpr int MAP_SIZE = 512; CloudsRenderer::CloudsRenderer() { - VolumeRenderer volumeRenderer(1024 * 1024); + VolumeRenderer volumeRenderer(1024 * 512); + + int diameter = 4; + int segmentSize = MAP_SIZE / diameter; + + for (int layerid = 0; layerid < 2; layerid++) { + auto& layer = layers[layerid]; + layer.diameter = diameter; + layer.segmentSize = segmentSize; - for (int layer = 0; layer < 2; layer++) { fnl_state state = fnlCreateState(); - const int w = WIDTH; + const int w = MAP_SIZE; const int h = 8; - const int d = DEPTH; + const int d = MAP_SIZE; const int dd = d * 1.5; - state.seed = 5265 + layer * 3521; + state.seed = 5265 + layerid * 3521; float pi2 = glm::two_pi(); - float heightmap[w * dd]; + auto heightmap = std::make_unique(w * dd); for (int lz = 0; lz < dd; lz++) { for (int lx = 0; lx < w; lx++) { float x = glm::sin(lx / static_cast(w) * pi2) * w / pi2; float y = -glm::cos(lx / static_cast(w) * pi2) * w / pi2; float z = lz; float s = 1.5f; - auto n = fnlGetNoise3D(&state, x * s, y * s, z * s); - n += fnlGetNoise3D(&state, x * s + fnlGetNoise2D(&state, x * s * 4 + 2, z * s * 4) * 0.25f, y * s, z * 3.0f) * 0.5f; + auto n = fnlGetNoise3D(&state, x * s * 0.7, y * s, z * s * 0.7); + n += fnlGetNoise3D(&state, x * s + fnlGetNoise2D(&state, x * s * 4 + 2, z * s * 4) * 2.0f, y * s, z * 3.0f) * 0.5f; n += fnlGetNoise3D(&state, x * s * 2, y * s * 2, z * s * 2) * 0.25f; n += fnlGetNoise3D(&state, x * s * 4, y * s * 4, z * s * 4) * 0.125f * 2; n += fnlGetNoise3D(&state, x * s * 8, y * s * 8, z * s * 8) * 0.125f * 0.5f * 2; n += fnlGetNoise3D(&state, x * s * 16, y * s * 16, z * s * 16) * 0.125f * 0.25f * 3; n = glm::max(0.0f, n); - // n = n * n * 2.0f; - n -= 0.2f + layer * 0.5f; - // n -= 0.5f; + n += -0.1f - layerid * 0.3f; heightmap[lz * w + lx] = n; } } - bool voxels[w * h * d]; - for (int y = 0; y < h; y++) { - for (int z = 0; z < d; z++) { - for (int x = 0; x < w; x++) { - float n = heightmap[z * w + x]; - if (z < d / 2) { - float t = z / static_cast(d / 2); - n = n * t + heightmap[(d + z) * w + x] * (1.0f - t); + bool voxels[segmentSize * h * segmentSize]; + for (int sz = 0; sz < diameter; sz++) { + for (int sx = 0; sx < diameter; sx++) { + for (int y = 0; y < h; y++) { + for (int z = 0; z < segmentSize; z++) { + for (int x = 0; x < segmentSize; x++) { + int gx = (sx * segmentSize) + x; + int gz = (sz * segmentSize) + z; + + float n = heightmap[gz * MAP_SIZE + gx]; + if (gz < MAP_SIZE / 2) { + float t = gz / static_cast(MAP_SIZE / 2); + n = n * t + heightmap[(MAP_SIZE + gz) * MAP_SIZE + gx] * (1.0f - t); + } + bool solid = y <= n * h && y >= (0.5f - n * 0.5f) * h; + voxels[vox_index(x, y, z, segmentSize, segmentSize)] = solid; + } } - bool solid = y <= n * h && y >= (0.5f - n * 0.5f) * h; - voxels[vox_index(x, y, z, w, d)] = solid; } + + CloudsMap map({segmentSize, h, segmentSize}, voxels); + + volumeRenderer.build(map); + layer.meshes.push_back(std::make_unique>( + volumeRenderer.createMesh() + )); } } - - CloudsMap map({w, h, d}, voxels); - - volumeRenderer.build(map); - meshes[layer] = std::make_unique>(volumeRenderer.createMesh()); } } CloudsRenderer::~CloudsRenderer() = default; +void CloudsRenderer::draw( + Shader& shader, + Layer& layer, + const Camera& camera, + float timer, + int layerId +) { + float scale = 8; + int totalDiameter = layer.segmentSize * scale; + + int gcellX = floordiv(camera.position.x, totalDiameter); + int gcellZ = floordiv(camera.position.z, totalDiameter); + + float speed = 4.0f; + float speedX = glm::sin(layerId * 0.3f + 0.4f) * speed / (layerId + 1); + float speedZ = -glm::cos(layerId * 0.3f + 0.4f) * speed / (layerId + 1); + + int radius = 4; + + for (int x = -radius; x <= radius; x++) { + for (int z = -radius; z <= radius; z++) { + int lcellX = gcellX - floordiv(glm::floor(timer * speedX), totalDiameter); + int lcellZ = gcellZ - floordiv(glm::floor(timer * speedZ), totalDiameter); + glm::vec3 position( + -128 * scale + (x + gcellX) * layer.segmentSize * scale + + glm::mod(timer * speedX, static_cast(totalDiameter)), + 250 + layerId * 200, + -128 * scale + (z + gcellZ) * layer.segmentSize * scale + + glm::mod(timer * speedZ, static_cast(totalDiameter)) + ); + if (glm::distance2( + glm::vec2( + position.x + totalDiameter * 0.5f, + position.z + totalDiameter * 0.5f + ), + glm::vec2(camera.position.x, camera.position.z) + ) > 4e6) { + continue; + } + auto matrix = glm::mat4(1.0f); + matrix = glm::translate(matrix, position); + matrix = glm::scale(matrix, glm::vec3(scale, scale, scale)); + shader.uniformMatrix("u_model", matrix); + + int lx = (x + radius + lcellX) % layer.diameter; + int lz = (z + radius + lcellZ) % layer.diameter; + if (lx < 0) lx += layer.diameter; + if (lz < 0) lz += layer.diameter; + + layer.meshes[lz * layer.diameter + lx]->draw(); + } + } +} + void CloudsRenderer::draw( Shader& shader, const Weather& weather, @@ -233,37 +302,10 @@ void CloudsRenderer::draw( int quality ) { 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); - float scale = 8; - float totalWidth = WIDTH * scale; - float totalDepth = DEPTH * scale; - - int cellX = glm::floor(camera.position.x / totalWidth + 0.5f); - int cellZ = glm::floor(camera.position.z / totalDepth + 0.5f); - - float speed = 4.0f; - for (int i = 0; i < std::min(quality, meshes.size()); i++) { - float speedX = glm::sin(i * 0.3f + 0.4f) * speed / (i + 1); - float speedZ = -glm::cos(i * 0.3f + 0.4f) * speed / (i + 1); - for (int x = -2; x <= 2; x++) { - for (int z = -2; z <= 2; z++) { - auto matrix = glm::mat4(1.0f); - matrix = glm::translate( - matrix, - glm::vec3( - -128 * scale + (x + cellX) * WIDTH * scale + - glm::mod(timer * speedX, totalWidth), - 250 + i * 200, - -128 * scale + (z + cellZ) * DEPTH * scale + - glm::mod(timer * speedZ, totalDepth) - ) - ); - matrix = glm::scale(matrix, glm::vec3(scale, scale, scale)); - shader.uniform1f("u_fogFactor", fogFactor * 0.03f); - shader.uniform1f("u_fogCurve", 0.7f - 0.3f); - shader.uniformMatrix("u_model", matrix); - meshes[i]->draw(); - } - } + for (int i = 0; i < std::min(quality, layers.size()); i++) { + draw(shader, layers[i], camera, timer, i); } } diff --git a/src/graphics/render/CloudsRenderer.hpp b/src/graphics/render/CloudsRenderer.hpp index 736acebd9..22ea73185 100755 --- a/src/graphics/render/CloudsRenderer.hpp +++ b/src/graphics/render/CloudsRenderer.hpp @@ -2,7 +2,9 @@ #include "commons.hpp" +#include #include +#include class Camera; class Shader; @@ -22,5 +24,19 @@ public: int quality ); private: - std::array>, 2> meshes; + struct Layer { + int diameter; + int segmentSize; + std::vector>> meshes; + }; + + std::array layers; + + void draw( + Shader& shader, + Layer& layer, + const Camera& camera, + float timer, + int layerId + ); };