diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/GFX/Util/MeshBuilder.hpp | 13 | ||||
| -rw-r--r-- | src/GFX/Util/Primitives.cpp | 107 | ||||
| -rw-r--r-- | src/GFX/Util/Primitives.hpp | 47 | ||||
| -rw-r--r-- | src/Math/AABB.hpp | 10 | ||||
| -rw-r--r-- | src/World/Clouds.cpp | 74 | ||||
| -rw-r--r-- | src/World/Clouds.hpp | 10 | ||||
| -rw-r--r-- | src/main.cpp | 2 |
7 files changed, 241 insertions, 22 deletions
diff --git a/src/GFX/Util/MeshBuilder.hpp b/src/GFX/Util/MeshBuilder.hpp index e3caa8c..c174b8c 100644 --- a/src/GFX/Util/MeshBuilder.hpp +++ b/src/GFX/Util/MeshBuilder.hpp @@ -2,6 +2,7 @@ #include "../../Common/Sizes.hpp" #include "../../Math/Common.hpp" +#include "Primitives.hpp" #include <vector> namespace MC::GFX::Util { @@ -53,6 +54,18 @@ public: m_indices.insert(m_indices.end(), from.begin(), from.end()); } + template<uint PN> + void primitive(const Primitives::Primitive<PN>& primitive) { + decltype(primitive.indices) relativized_indices{}; + for (Int i = 0; i < primitive.indices.size(); i++) { + relativized_indices[i] = primitive.indices[i] + m_positions.size(); + } + + positions(primitive.positions); + attributes<0>(primitive.normals); + indices(relativized_indices); + } + Mesh mesh() { return mesh(std::make_index_sequence<AttributesN>{}); } diff --git a/src/GFX/Util/Primitives.cpp b/src/GFX/Util/Primitives.cpp new file mode 100644 index 0000000..d2c3690 --- /dev/null +++ b/src/GFX/Util/Primitives.cpp @@ -0,0 +1,107 @@ +#include "Primitives.hpp" + +namespace MC::GFX::Util::Primitives { + +PlanePrimitive plane(Math::AABB aabb, FaceSet face) { + decltype(PlanePrimitive::positions) positions; + auto [min, max] = aabb; + + switch (face) { + case FaceSet::Front: + positions = {{ + {min.x(), min.y(), min.z()}, {min.x(), max.y(), min.z()}, + {max.x(), max.y(), min.z()}, {max.x(), min.y(), min.z()} + }}; + break; + case FaceSet::Back: + positions = {{ + {min.x(), min.y(), max.z()}, {max.x(), min.y(), max.z()}, + {max.x(), max.y(), max.z()}, {min.x(), max.y(), max.z()} + }}; + break; + case FaceSet::Top: + positions = {{ + {min.x(), max.y(), min.z()}, {min.x(), max.y(), max.z()}, + {max.x(), max.y(), max.z()}, {max.x(), max.y(), min.z()} + }}; + break; + case FaceSet::Bottom: + positions = {{ + {min.x(), min.y(), min.z()}, {max.x(), min.y(), min.z()}, + {max.x(), min.y(), max.z()}, {min.x(), min.y(), max.z()} + }}; + break; + case FaceSet::Right: + positions = {{ + {max.x(), min.y(), min.z()}, {max.x(), max.y(), min.z()}, + {max.x(), max.y(), max.z()}, {max.x(), min.y(), max.z()} + }}; + break; + case FaceSet::Left: + positions = {{ + {min.x(), min.y(), min.z()}, {min.x(), min.y(), max.z()}, + {min.x(), max.y(), max.z()}, {min.x(), max.y(), min.z()} + }}; + break; + } + + auto is_side = [=](FaceSet f) -> I8 { return f == face; }; + Vector<3, F32> normal = { + is_side(FaceSet::Right) - is_side(FaceSet::Left), + is_side(FaceSet::Top) - is_side(FaceSet::Bottom), + is_side(FaceSet::Front) - is_side(FaceSet::Back), + }; + + return {positions, {normal, normal, normal, normal}, {0, 1, 2, 2, 3, 0}}; +} + +BoxPrimitive box(Math::AABB aabb, FaceSet faces) { + BoxPrimitive box{}; + auto [min, max] = aabb; + + UInt set_faces = 0; + U8 face_value = 1; + for (UInt face_index = 0; face_index < FaceSet::Size; face_index++, face_value <<= 1) { + FaceSet face = (FaceSet::Value)face_value; + if ((faces & face) == 0) continue; + + Math::AABB face_aabb; + switch (face) { + case FaceSet::Front: + face_aabb = {min, {max.x(), max.y(), min.z()}}; + break; + case FaceSet::Back: + face_aabb = {{min.x(), min.y(), max.z()}, max}; + break; + case FaceSet::Top: + face_aabb = {{min.x(), max.y(), min.z()}, {max.x(), max.y(), max.z()}}; + break; + case FaceSet::Bottom: + face_aabb = {min, {max.x(), min.y(), max.z()}}; + break; + case FaceSet::Right: + face_aabb = {{max.x(), min.y(), min.z()}, max}; + break; + case FaceSet::Left: + face_aabb = {min, {min.x(), max.y(), max.z()}}; + break; + } + + auto p = plane(face_aabb, face); + + for (UInt i = 0; i < p.positions.size(); i++) { + box.positions[set_faces * 4 + i] = p.positions[i]; + } + for (UInt i = 0; i < p.normals.size(); i++) { + box.normals[set_faces * 4 + i] = p.normals[i]; + } + for (UInt i = 0; i < p.indices.size(); i++) { + box.indices[set_faces * 6 + i] = p.indices[i] + set_faces * 4; + } + set_faces++; + } + + return box; +} + +} \ No newline at end of file diff --git a/src/GFX/Util/Primitives.hpp b/src/GFX/Util/Primitives.hpp new file mode 100644 index 0000000..b96bc00 --- /dev/null +++ b/src/GFX/Util/Primitives.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "../../Common/Sizes.hpp" +#include "../../Math/AABB.hpp" +#include <array> + +namespace MC::GFX::Util::Primitives { + +class FaceSet { +public: + enum Value : U8 { + Front = 1 << 0, + Back = 1 << 1, + Top = 1 << 2, + Bottom = 1 << 3, + Right = 1 << 4, + Left = 1 << 5, + }; + + static constexpr UInt Size = 6; + + FaceSet() = default; + FaceSet(const Value set) : m_set(set) {} + + operator Value() const { return m_set; } + + static FaceSet all() { + return static_cast<Value>(Front | Back | Top | Bottom | Right | Left); + } +private: + Value m_set; +}; + +template <uint N> +struct Primitive { + std::array<Vector<3, F32>, N> positions; + std::array<Vector<3, F32>, N> normals; + std::array<U32, N + N / 2> indices; +}; + +using PlanePrimitive = Primitive<4>; +PlanePrimitive plane(Math::AABB aabb, FaceSet face); + +using BoxPrimitive = Primitive<4 * 6>; +BoxPrimitive box(Math::AABB aabb, FaceSet faces = FaceSet::all()); + +} diff --git a/src/Math/AABB.hpp b/src/Math/AABB.hpp new file mode 100644 index 0000000..2c02abf --- /dev/null +++ b/src/Math/AABB.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "Vector.hpp" + +namespace Math { + +struct AABB { + Vector<3> min, max; +}; + +} diff --git a/src/World/Clouds.cpp b/src/World/Clouds.cpp index 6c5dba3..36f2441 100644 --- a/src/World/Clouds.cpp +++ b/src/World/Clouds.cpp @@ -1,15 +1,16 @@ #include "Clouds.hpp" #include "../Math/MVP.hpp" #include "../Math/Perlin.hpp" +#include "../Math/AABB.hpp" +#include "../GFX/Util/Primitives.hpp" #include "../GFX/Util/MeshBuilder.hpp" #include <GL/glew.h> #include <array> 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( +Clouds::Clouds(Real ascept, Real fov, Real near, Real far, Vector<3, F32> sky_color, Vector<3, F32> sun_direction) + : m_program( {GFX::Shading::Shader::Type::Vertex, vertex}, {GFX::Shading::Shader::Type::Fragment, fragment} ), @@ -21,24 +22,41 @@ Clouds::Clouds(Real ascept, Real fov, Real near, Real far, Vector<3, F32> sky_co 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"); + auto sun_direction_uniform = m_program.uniform("sun_direction"); m_model_uniform.set(Math::MVP::model<F32>({}, {}, {})); m_view_uniform.set(Math::MVP::view<F32>({}, {})); m_projection_uniform.set(Math::MVP::perspective_projection<F32>(ascept, fov, near, far)); sky_color_uniform.set(sky_color); + sun_direction_uniform.set(sun_direction); m_program.unbind(); } void Clouds::update(U64 time) { - m_position.x() += time / 5000.0; + m_x_offset += time / 5000.0; } void Clouds::render(const GFX::Camera& camera) const { + auto position = camera.position(); + + I32 center_x = std::round((position.x() - m_x_offset) / TileSize); + I32 center_y = std::round(position.z() / TileSize); + + for (Int x = -1; x <= 1; x++) { + for (Int y = -1; y <= 1; y++) { + render_single_instance(camera, center_x + x, center_y + y); + } + } +} + +void Clouds::render_single_instance(const GFX::Camera& camera, Int x, Int y) const { + Vector<3> position{TileSize * x + m_x_offset, Height, TileSize * y}; + m_program.bind(); m_view_uniform.set(Math::MVP::view<F32>(camera.position(), camera.angles())); - m_model_uniform.set(Math::MVP::model<F32>(m_position, Vector<3>{10.0}, {})); + m_model_uniform.set(Math::MVP::model<F32>(position, Vector<3>{Scale}, {})); m_mesh.bind(); glDrawElements(GL_TRIANGLES, m_mesh.size(), GL_UNSIGNED_INT, nullptr); @@ -51,8 +69,8 @@ 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++) { + for (Int x = 1; x < CloudMatrixSize; x++) { + for (Int y = 1; y < CloudMatrixSize; y++) { if (noise.at({x, y * 2}) > 0.55) { clouds(x, y) = true; } @@ -62,20 +80,31 @@ Clouds::CloudMatrix Clouds::create_cloud_matrix() { } GFX::Mesh Clouds::create_mesh(const CloudMatrix& cloud_matrix) { - GFX::Util::MeshBuilder builder{}; + GFX::Util::MeshBuilder<Vector<3, F32>> 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<Vector<3, F32>, 4> positions = {{{0, 0, 0}, {1, 0, 0}, {0, 0, 1}, {1, 0, 1}}}; - std::array<U32, 6> 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); + auto is_occupied = [&](Int xn, Int yn) { + if (xn < 0 || xn >= CloudMatrixSize || yn < 0 || yn >= CloudMatrixSize) return false; + return cloud_matrix(xn, yn); + }; + std::array<bool, 4> neighbors = { + is_occupied(x - 1, y), is_occupied(x + 1, y), + is_occupied(x, y - 1), is_occupied(x, y + 1), + }; + + using FaceSet = GFX::Util::Primitives::FaceSet; + U8 faces = FaceSet::Top | FaceSet::Bottom; + if (!neighbors[0]) faces |= FaceSet::Left; + if (!neighbors[1]) faces |= FaceSet::Right; + if (!neighbors[2]) faces |= FaceSet::Front; + if (!neighbors[3]) faces |= FaceSet::Back; + + auto aabb = Math::AABB{{x, 0, y}, {x + 1, 1, y + 1}}; + auto box = GFX::Util::Primitives::box(aabb, (FaceSet::Value)faces); + builder.primitive(box); } } @@ -90,7 +119,9 @@ uniform mat4 view_matrix; uniform mat4 projection_matrix; layout (location = 0) in vec3 position; +layout (location = 1) in vec3 normal; +out vec3 surface_normal; out float depth; void main() { @@ -99,7 +130,8 @@ void main() { vec4 clip_position = projection_matrix * view_position; gl_Position = clip_position; - depth = clamp((length(view_position) - 75) / 125, 0.0, 1.0); + surface_normal = (model_matrix * vec4(normal, 0.0)).xyz; + depth = clamp((length(view_position) - 200) / 400, 0.0, 1.0); } )v"; @@ -107,14 +139,18 @@ const Char* Clouds::fragment = R"f( #version 330 core uniform vec3 sky_color; +uniform vec3 sun_direction; +in vec3 surface_normal; in float depth; out vec4 color; void main() { - vec3 white = vec3(1.0, 1.0, 1.0); + float brightness = dot(normalize(surface_normal), normalize(-sun_direction)); + vec3 diffuse = vec3(1 - clamp(brightness, -0.3, 0.2)); + vec3 base = vec3(1.0, 1.0, 1.0) * diffuse; - color = vec4(mix(sky_color, white, 1 - depth), 0.5); + color = vec4(mix(sky_color, base, 1 - depth), 0.3); } )f"; diff --git a/src/World/Clouds.hpp b/src/World/Clouds.hpp index 6a91901..b2d5a10 100644 --- a/src/World/Clouds.hpp +++ b/src/World/Clouds.hpp @@ -9,21 +9,27 @@ namespace MC::World { class Clouds { public: - Clouds(Real ascept, Real fov, Real near, Real far, Vector<3, F32> sky_color); + Clouds(Real ascept, Real fov, Real near, Real far, Vector<3, F32> sky_color, Vector<3, F32> sun_direction); void update(U64 time); void render(const GFX::Camera& camera) const; private: constexpr static U32 CloudMatrixSize = 128; + constexpr static Int Height = 200; + constexpr static Real Scale = 15; + constexpr static Real TileSize = CloudMatrixSize * Scale; + using CloudMatrix = Matrix<CloudMatrixSize, CloudMatrixSize, Bool>; + void render_single_instance(const GFX::Camera& camera, Int x, Int y) const; + 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; + Real m_x_offset = 0.0; GFX::Shading::Program m_program; GFX::BindableMesh m_mesh; diff --git a/src/main.cpp b/src/main.cpp index 1688dac..6e78dab 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -81,7 +81,7 @@ 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}; + MC::World::Clouds clouds{ASPECT, FOV, 0.1f, 1000.0f, sky_color, sun_direction}; glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); |
