From 0ce26f2a49fd6d64a690b84b1932126edfbfbee6 Mon Sep 17 00:00:00 2001 From: Mel Date: Tue, 11 Jul 2023 04:52:24 +0200 Subject: Add simple scrolling non-tiling 2D clouds --- CMakeLists.txt | 2 + src/GFX/Shading/Uniform.hpp | 2 + src/Math/MVP.hpp | 5 +- src/Math/Matrix.hpp | 9 ++++ src/Util/ImageViewer.cpp | 2 +- src/World/Clouds.cpp | 121 ++++++++++++++++++++++++++++++++++++++++++++ src/World/Clouds.hpp | 36 +++++++++++++ src/main.cpp | 18 +++++-- 8 files changed, 187 insertions(+), 8 deletions(-) create mode 100644 src/World/Clouds.cpp create mode 100644 src/World/Clouds.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e78f153..b58a94e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,8 @@ add_executable(meowcraft src/World/Generation/Decoration.hpp src/Math/Random.cpp src/Math/Random.hpp + src/World/Clouds.cpp + src/World/Clouds.hpp src/GFX/Util/MeshBuilder.hpp ) target_link_libraries(meowcraft glfw GLEW::GLEW) diff --git a/src/GFX/Shading/Uniform.hpp b/src/GFX/Shading/Uniform.hpp index 3ddbd4a..6edff7f 100644 --- a/src/GFX/Shading/Uniform.hpp +++ b/src/GFX/Shading/Uniform.hpp @@ -8,6 +8,8 @@ namespace MC::GFX::Shading { class Uniform { public: + Uniform() = default; + Uniform(std::string name, U32 index) : m_name(std::move(name)), m_index(index) {} diff --git a/src/Math/MVP.hpp b/src/Math/MVP.hpp index 4046a50..b7341a8 100644 --- a/src/Math/MVP.hpp +++ b/src/Math/MVP.hpp @@ -5,11 +5,12 @@ namespace Math::MVP { template -Matrix<4, 4, T> model(Vector<3> position, Rotation angles) { +Matrix<4, 4, T> model(Vector<3> position, Vector<3> size, Rotation angles) { auto transformation = Matrix<4, 4, T>::transformation(position); + auto scale = Matrix<4, 4, T>::scale(size); auto rotation = Matrix<4, 4, T>::rotation(angles); - return transformation * rotation; + return transformation * rotation * scale; } template diff --git a/src/Math/Matrix.hpp b/src/Math/Matrix.hpp index d51d171..41d3661 100644 --- a/src/Math/Matrix.hpp +++ b/src/Math/Matrix.hpp @@ -37,6 +37,15 @@ struct Matrix { }; } + static Matrix<4, 4, T> scale(Vector<3> factor) { + return { + factor.x(), 0.0, 0.0, 0.0, + 0.0, factor.y(), 0.0, 0.0, + 0.0, 0.0, factor.z(), 0.0, + 0.0, 0.0, 0.0, 1.0 + }; + } + static Matrix<4, 4, T> rotation(Rotation angles) { auto radians = angles.vector.map([](auto a) { return Math::radians(a); }); diff --git a/src/Util/ImageViewer.cpp b/src/Util/ImageViewer.cpp index 8ff8c57..6c88c78 100644 --- a/src/Util/ImageViewer.cpp +++ b/src/Util/ImageViewer.cpp @@ -18,7 +18,7 @@ ImageViewer::ImageViewer( auto view_uniform = m_program.uniform("view_matrix"); auto projection_uniform = m_program.uniform("projection_matrix"); - model_uniform.set(Math::MVP::model({}, {})); + model_uniform.set(Math::MVP::model({}, Vector<3>::one(), {})); view_uniform.set(Math::MVP::view({}, {})); projection_uniform.set(Math::MVP::orthographic_projection(view_size * window_aspect, view_size, 0.0f, 100.0f)); diff --git a/src/World/Clouds.cpp b/src/World/Clouds.cpp new file mode 100644 index 0000000..6c5dba3 --- /dev/null +++ b/src/World/Clouds.cpp @@ -0,0 +1,121 @@ +#include "Clouds.hpp" +#include "../Math/MVP.hpp" +#include "../Math/Perlin.hpp" +#include "../GFX/Util/MeshBuilder.hpp" +#include +#include + +namespace MC::World { + +Clouds::Clouds(Real ascept, Real fov, Real near, Real far, Vector<3, F32> sky_color) + : m_position(-1000, 120, -1000), + m_program( + {GFX::Shading::Shader::Type::Vertex, vertex}, + {GFX::Shading::Shader::Type::Fragment, fragment} + ), + m_mesh(GFX::Binder::load(create_mesh(create_cloud_matrix()))), + m_model_uniform(), m_view_uniform(), m_projection_uniform() { + m_program.bind(); + + m_model_uniform = m_program.uniform("model_matrix"); + m_view_uniform = m_program.uniform("view_matrix"); + m_projection_uniform = m_program.uniform("projection_matrix"); + auto sky_color_uniform = m_program.uniform("sky_color"); + + m_model_uniform.set(Math::MVP::model({}, {}, {})); + m_view_uniform.set(Math::MVP::view({}, {})); + m_projection_uniform.set(Math::MVP::perspective_projection(ascept, fov, near, far)); + sky_color_uniform.set(sky_color); + + m_program.unbind(); +} + +void Clouds::update(U64 time) { + m_position.x() += time / 5000.0; +} + +void Clouds::render(const GFX::Camera& camera) const { + m_program.bind(); + + m_view_uniform.set(Math::MVP::view(camera.position(), camera.angles())); + m_model_uniform.set(Math::MVP::model(m_position, Vector<3>{10.0}, {})); + + m_mesh.bind(); + glDrawElements(GL_TRIANGLES, m_mesh.size(), GL_UNSIGNED_INT, nullptr); + m_mesh.unbind(); + + m_program.unbind(); +} + +Clouds::CloudMatrix Clouds::create_cloud_matrix() { + Math::Perlin::Noise<2> noise{}; + + CloudMatrix clouds{false}; + for (Int x = 0; x < CloudMatrixSize; x++) { + for (Int y = 0; y < CloudMatrixSize; y++) { + if (noise.at({x, y * 2}) > 0.55) { + clouds(x, y) = true; + } + } + } + return clouds; +} + +GFX::Mesh Clouds::create_mesh(const CloudMatrix& cloud_matrix) { + GFX::Util::MeshBuilder builder{}; + + for (Int x = 0; x < CloudMatrixSize; x++) { + for (Int y = 0; y < CloudMatrixSize; y++) { + if (!cloud_matrix(x, y)) continue; + + U32 s = builder.vertex_count(); + std::array, 4> positions = {{{0, 0, 0}, {1, 0, 0}, {0, 0, 1}, {1, 0, 1}}}; + std::array indices = { s + 0, s + 1, s + 2, s + 1, s + 3, s + 2 }; + + for (auto& p : positions) p += {x, 0, y}; + + builder.positions(positions); + builder.indices(indices); + } + } + + return builder.mesh(); +} + +const Char* Clouds::vertex = R"v( +#version 330 core + +uniform mat4 model_matrix; +uniform mat4 view_matrix; +uniform mat4 projection_matrix; + +layout (location = 0) in vec3 position; + +out float depth; + +void main() { + vec4 world_position = model_matrix * vec4(position, 1.0); + vec4 view_position = view_matrix * world_position; + vec4 clip_position = projection_matrix * view_position; + + gl_Position = clip_position; + depth = clamp((length(view_position) - 75) / 125, 0.0, 1.0); +} +)v"; + +const Char* Clouds::fragment = R"f( +#version 330 core + +uniform vec3 sky_color; + +in float depth; +out vec4 color; + +void main() { + vec3 white = vec3(1.0, 1.0, 1.0); + + color = vec4(mix(sky_color, white, 1 - depth), 0.5); +} +)f"; + +} diff --git a/src/World/Clouds.hpp b/src/World/Clouds.hpp new file mode 100644 index 0000000..6a91901 --- /dev/null +++ b/src/World/Clouds.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "../GFX/Binder.hpp" +#include "../GFX/Shading/Program.hpp" +#include "../GFX/Shading/Uniform.hpp" +#include "../GFX/Camera.hpp" + +namespace MC::World { + +class Clouds { +public: + Clouds(Real ascept, Real fov, Real near, Real far, Vector<3, F32> sky_color); + + void update(U64 time); + void render(const GFX::Camera& camera) const; +private: + constexpr static U32 CloudMatrixSize = 128; + using CloudMatrix = Matrix; + + static CloudMatrix create_cloud_matrix(); + static GFX::Mesh create_mesh(const CloudMatrix& cloud_matrix); + + static const Char* vertex; + static const Char* fragment; + + Vector<3> m_position; + + GFX::Shading::Program m_program; + GFX::BindableMesh m_mesh; + + GFX::Shading::Uniform m_model_uniform; + GFX::Shading::Uniform m_view_uniform; + GFX::Shading::Uniform m_projection_uniform; +}; + +} diff --git a/src/main.cpp b/src/main.cpp index 3d193c2..1688dac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,7 @@ #include "GFX/Shading/Program.hpp" #include "GFX/Texture.hpp" #include "GFX/Image/PPMParser.hpp" +#include "World/Clouds.hpp" #include "World/World.hpp" #define APP_NAME "Meowcraft" @@ -80,6 +81,8 @@ void run() { Vector<3, F32> sky_color{0.85, 0.85, 0.85}; // #DBDBDB sky_color_uniform.set(sky_color); + MC::World::Clouds clouds{ASPECT, FOV, 0.1f, 1000.0f, sky_color}; + glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); @@ -100,27 +103,32 @@ void run() { #endif process_input(window, camera); + clouds.update(time); + + glClearColor(sky_color.x(), sky_color.y(), sky_color.z(), 1.0f); // #DBDBDB + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); program.bind(); auto view = Math::MVP::view(camera.position(), camera.angles()); view_uniform.set(view); - glClearColor(sky_color.x(), sky_color.y(), sky_color.z(), 1.0f); // #DBDBDB - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - for (auto chunk : world.get_visible_chunks(camera.position())) { mesh_alpha_uniform.set(1.0); - auto land_model = Math::MVP::model(chunk->chunk.value().position(), {}); + auto land_model = Math::MVP::model(chunk->chunk.value().position(), Vector<3>::one(), {}); model_uniform.set(land_model); render(chunk->land_mesh.value(), texture); mesh_alpha_uniform.set(0.4); - auto water_model = Math::MVP::model(chunk->chunk.value().position() - Vector<3>{0, 0.2, 0}, {}); + auto water_model = Math::MVP::model(chunk->chunk.value().position() - Vector<3>{0, 0.2, 0}, Vector<3>::one(), {}); model_uniform.set(water_model); render(chunk->water_mesh.value(), texture); } + program.unbind(); + + clouds.render(camera); + time++; } } -- cgit 1.4.1