diff --git a/src/engine/gl/texture.cpp b/src/engine/gl/texture.cpp index 47291fa..cc4d3bb 100644 --- a/src/engine/gl/texture.cpp +++ b/src/engine/gl/texture.cpp @@ -331,7 +331,7 @@ void texture::resize(std::uint16_t width, std::uint16_t height, std::uint16_t de /// @TODO: remove this if (format == pixel_format::d) { - glTexParameteri(m_gl_texture_target, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + glTexParameteri(m_gl_texture_target, GL_TEXTURE_COMPARE_FUNC, GL_GREATER); glTexParameteri(m_gl_texture_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); } } diff --git a/src/engine/math/matrix.hpp b/src/engine/math/matrix.hpp index 52c165a..58b3143 100644 --- a/src/engine/math/matrix.hpp +++ b/src/engine/math/matrix.hpp @@ -584,7 +584,7 @@ template * @return Viewing transformation matrix. */ template -[[nodiscard]] constexpr matrix look_at(const vector& position, const vector& target, vector up); +[[nodiscard]] constexpr mat4 look_at(const vec3& position, const vec3& target, vec3 up); /** * Multiplies two matrices @@ -677,15 +677,14 @@ template [[nodiscard]] mat3 rotate_z(T angle); /** - * Scales a matrix. + * Constructs a scale matrix. * - * @param m Matrix to scale. * @param v Scale vector. * - * @return Scaled matrix. + * @return Scale matrix. */ template -[[nodiscard]] constexpr matrix scale(const matrix& m, const vector& v); +[[nodiscard]] constexpr mat4 scale(const vec3& v); /** * Subtracts a matrix from another matrix. @@ -731,15 +730,14 @@ template [[nodiscard]] constexpr T trace(const matrix& m) noexcept; /** - * Translates a matrix. + * Constructs a translation matrix. * - * @param m Matrix to translate. * @param v Translation vector. * - * @return Translated matrix. + * @return Translation matrix. */ template -[[nodiscard]] constexpr matrix translate(const matrix& m, const vector& v); +[[nodiscard]] constexpr mat4 translate(const vec3& v); /** * Calculates the transpose of a matrix. @@ -966,13 +964,12 @@ constexpr matrix inverse(const matrix& m) noexcept } template -constexpr matrix look_at(const vector& position, const vector& target, vector up) +constexpr mat4 look_at(const vec3& position, const vec3& target, vec3 up) { - vector forward = normalize(sub(target, position)); - vector right = normalize(cross(forward, up)); + const auto forward = normalize(sub(target, position)); + const auto right = normalize(cross(forward, up)); up = cross(right, forward); - - matrix m + const auto m = mat4 {{ {right[0], up[0], -forward[0], T{0}}, {right[1], up[1], -forward[1], T{0}}, @@ -980,7 +977,7 @@ constexpr matrix look_at(const vector& position, const vector @@ -1105,19 +1102,15 @@ mat3 rotate_z(T angle) } template -constexpr matrix scale(const matrix& m, const vector& v) +constexpr mat4 scale(const vec3& v) { - return mul - ( - m, - matrix - {{ - {v[0], T{0}, T{0}, T{0}}, - {T{0}, v[1], T{0}, T{0}}, - {T{0}, T{0}, v[2], T{0}}, - {T{0}, T{0}, T{0}, T{1}} - }} - ); + return + {{ + {v[0], T{0}, T{0}, T{0}}, + {T{0}, v[1], T{0}, T{0}}, + {T{0}, T{0}, v[2], T{0}}, + {T{0}, T{0}, T{0}, T{1}} + }}; } /// @private @@ -1173,15 +1166,15 @@ constexpr T trace(const matrix& m) noexcept } template -constexpr matrix translate(const matrix& m, const vector& v) +constexpr mat4 translate(const vec3& v) { - return mul(m, matrix + return {{ {T{1}, T{0}, T{0}, T{0}}, {T{0}, T{1}, T{0}, T{0}}, {T{0}, T{0}, T{1}, T{0}}, {v[0], v[1], v[2], T{1}} - }}); + }}; } /// @private diff --git a/src/engine/physics/kinematics/collider.hpp b/src/engine/physics/kinematics/collider.hpp index 101cf7c..1b54e29 100644 --- a/src/engine/physics/kinematics/collider.hpp +++ b/src/engine/physics/kinematics/collider.hpp @@ -41,7 +41,7 @@ public: /** * Sets the layer mask of the collider. * - * @param mask 32-bit layer mask in which each bit represents a layer with which the collider can interact. + * @param mask 32-bit layer mask in which each set bit represents a layer with which the collider can interact. */ inline constexpr void set_layer_mask(std::uint32_t mask) noexcept { diff --git a/src/engine/render/context.hpp b/src/engine/render/context.hpp index 6eb3c36..510a23f 100644 --- a/src/engine/render/context.hpp +++ b/src/engine/render/context.hpp @@ -42,7 +42,7 @@ struct context const scene::camera* camera; /// Collection of scene objects being rendered. - const scene::collection* collection; + scene::collection* collection; /// Current time, in seconds. float t; diff --git a/src/engine/render/operation.hpp b/src/engine/render/operation.hpp index 842ec78..81253b2 100644 --- a/src/engine/render/operation.hpp +++ b/src/engine/render/operation.hpp @@ -37,15 +37,17 @@ struct operation { const gl::vertex_array* vertex_array{nullptr}; gl::drawing_mode drawing_mode{gl::drawing_mode::triangles}; - std::size_t start_index{0}; - std::size_t index_count{0}; + std::size_t start_index{}; + std::size_t index_count{}; std::shared_ptr material; math::fmat4 transform{math::fmat4::identity()}; - float depth{0.0f}; + float depth{}; - std::size_t instance_count{0}; + std::size_t instance_count{}; std::span matrix_palette{}; + + std::uint32_t layer_mask{}; }; } // namespace render diff --git a/src/engine/render/passes/material-pass.cpp b/src/engine/render/passes/material-pass.cpp index 3960253..d2e1e4a 100644 --- a/src/engine/render/passes/material-pass.cpp +++ b/src/engine/render/passes/material-pass.cpp @@ -95,20 +95,27 @@ bool operation_compare(const render::operation* a, const render::operation* b) } else { - // A and B are both opaque - + // A and B are both opaque, sort by material hash const std::size_t hash_a = a->material->hash(); const std::size_t hash_b = b->material->hash(); - if (hash_a == hash_b) + if (hash_a != hash_b) { - // A and B have same material hash, sort by VAO - return (a->vertex_array < b->vertex_array); + // A and B have different material hashes, sort by hash + return (hash_a < hash_b); } else { - // A and B have different material hashes, sort by hash - return (hash_a < hash_b); + // A and B have the same material hash, sort by layer mask + if (a->layer_mask != b->layer_mask) + { + return (a->layer_mask < b->layer_mask); + } + else + { + // A and B have the same layer mask, sort by VAO + return (a->vertex_array < b->vertex_array); + } } } } @@ -152,10 +159,11 @@ void material_pass::render(render::context& ctx) material_blend_mode active_blend_mode = material_blend_mode::opaque; std::size_t active_cache_key = 0; shader_cache_entry* active_cache_entry = nullptr; + std::uint32_t active_layer_mask = 0; + std::size_t active_lighting_state_hash = 0; // Gather information evaluate_camera(ctx); - evaluate_lighting(ctx); evaluate_misc(ctx); // Sort render operations @@ -177,13 +185,20 @@ void material_pass::render(render::context& ctx) material = fallback_material.get(); } + // Evaluate visible lights + if (active_layer_mask != operation->layer_mask) + { + evaluate_lighting(ctx, operation->layer_mask & ctx.camera->get_layer_mask()); + active_layer_mask = operation->layer_mask; + } + // Switch materials if necessary - if (active_material != material) + if (active_material != material || active_lighting_state_hash != lighting_state_hash) { - if (!material->get_shader_template()) - { - continue; - } + // if (!material->get_shader_template()) + // { + // continue; + // } if (active_material_hash != material->hash()) { @@ -271,6 +286,7 @@ void material_pass::render(render::context& ctx) } active_material = material; + active_lighting_state_hash = lighting_state_hash; } // Update geometry-dependent shader variables @@ -315,7 +331,7 @@ void material_pass::evaluate_camera(const render::context& ctx) log_depth_coef = 2.0f / std::log2(clip_depth[1] + 1.0f); } -void material_pass::evaluate_lighting(const render::context& ctx) +void material_pass::evaluate_lighting(const render::context& ctx, std::uint32_t layer_mask) { // Reset light and shadow counts light_probe_count = 0; @@ -328,6 +344,11 @@ void material_pass::evaluate_lighting(const render::context& ctx) const auto& light_probes = ctx.collection->get_objects(scene::light_probe::object_type_id); for (const scene::object_base* object: light_probes) { + if (!(object->get_layer_mask() & layer_mask)) + { + continue; + } + if (!light_probe_count) { const scene::light_probe& light_probe = static_cast(*object); @@ -340,6 +361,11 @@ void material_pass::evaluate_lighting(const render::context& ctx) const auto& lights = ctx.collection->get_objects(scene::light::object_type_id); for (const scene::object_base* object: lights) { + if (!(object->get_layer_mask() & layer_mask)) + { + continue; + } + const scene::light& light = static_cast(*object); switch (light.get_light_type()) @@ -370,15 +396,13 @@ void material_pass::evaluate_lighting(const render::context& ctx) if (directional_shadow_count > directional_shadow_maps.size()) { directional_shadow_maps.resize(directional_shadow_count); - directional_shadow_biases.resize(directional_shadow_count); directional_shadow_splits.resize(directional_shadow_count); directional_shadow_matrices.resize(directional_shadow_count); } directional_shadow_maps[index] = static_cast(directional_light.get_shadow_framebuffer()->get_depth_attachment()); - directional_shadow_biases[index] = directional_light.get_shadow_bias(); - directional_shadow_splits[index] = &directional_light.get_shadow_cascade_distances(); - directional_shadow_matrices[index] = &directional_light.get_shadow_cascade_matrices(); + directional_shadow_splits[index] = directional_light.get_shadow_cascade_distances(); + directional_shadow_matrices[index] = directional_light.get_shadow_cascade_matrices(); } break; } @@ -659,25 +683,23 @@ void material_pass::build_shader_command_buffer(std::vectorupdate(std::span{directional_shadow_maps.data(), directional_shadow_count}); - directional_shadow_biases_var->update(std::span{directional_shadow_biases.data(), directional_shadow_count}); std::size_t offset = 0; for (std::size_t i = 0; i < directional_shadow_count; ++i) { - directional_shadow_splits_var->update(*directional_shadow_splits[i], offset * 4); - directional_shadow_matrices_var->update(*directional_shadow_matrices[i], offset); - offset += directional_shadow_splits[i]->size(); + directional_shadow_splits_var->update(directional_shadow_splits[i], offset * 4); + directional_shadow_matrices_var->update(directional_shadow_matrices[i], offset); + offset += directional_shadow_splits[i].size(); } } ); diff --git a/src/engine/render/passes/material-pass.hpp b/src/engine/render/passes/material-pass.hpp index 6e459cf..b9abeba 100644 --- a/src/engine/render/passes/material-pass.hpp +++ b/src/engine/render/passes/material-pass.hpp @@ -79,7 +79,7 @@ private: /** * Evaluates scene lights and stores lighting information in local variables to be passed to shaders. */ - void evaluate_lighting(const render::context& ctx); + void evaluate_lighting(const render::context& ctx, std::uint32_t layer_mask); void evaluate_misc(const render::context& ctx); @@ -115,9 +115,8 @@ private: // Directional shadows std::vector directional_shadow_maps; - std::vector directional_shadow_biases; - std::vector*> directional_shadow_splits; - std::vector*> directional_shadow_matrices; + std::vector> directional_shadow_splits; + std::vector> directional_shadow_matrices; std::size_t directional_shadow_count; // Spot lights diff --git a/src/engine/render/passes/shadow-map-pass.cpp b/src/engine/render/passes/shadow-map-pass.cpp index 869f7b8..539984e 100644 --- a/src/engine/render/passes/shadow-map-pass.cpp +++ b/src/engine/render/passes/shadow-map-pass.cpp @@ -25,12 +25,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -47,54 +47,65 @@ static bool operation_compare(const render::operation* a, const render::operatio shadow_map_pass::shadow_map_pass(gl::rasterizer* rasterizer, resource_manager* resource_manager): pass(rasterizer, nullptr) { + std::unordered_map definitions; + definitions["VERTEX_POSITION"] = std::to_string(vertex_attribute::position); + definitions["VERTEX_UV"] = std::to_string(vertex_attribute::uv); + definitions["VERTEX_NORMAL"] = std::to_string(vertex_attribute::normal); + definitions["VERTEX_TANGENT"] = std::to_string(vertex_attribute::tangent); + definitions["VERTEX_COLOR"] = std::to_string(vertex_attribute::color); + definitions["VERTEX_BONE_INDEX"] = std::to_string(vertex_attribute::bone_index); + definitions["VERTEX_BONE_WEIGHT"] = std::to_string(vertex_attribute::bone_weight); + definitions["VERTEX_BONE_WEIGHT"] = std::to_string(vertex_attribute::bone_weight); + definitions["MAX_BONE_COUNT"] = std::to_string(64); + // Load unskinned shader template auto unskinned_shader_template = resource_manager->load("depth-unskinned.glsl"); // Build unskinned shader program - unskinned_shader_program = unskinned_shader_template->build({}); + unskinned_shader_program = unskinned_shader_template->build(definitions); + if (!unskinned_shader_program->linked()) + { + debug::log::error("Failed to build unskinned shadow map shader program: {}", unskinned_shader_program->info()); + debug::log::warning("{}", unskinned_shader_template->configure(gl::shader_stage::vertex)); + } unskinned_model_view_projection_var = unskinned_shader_program->variable("model_view_projection"); // Load skinned shader template auto skinned_shader_template = resource_manager->load("depth-skinned.glsl"); // Build skinned shader program - skinned_shader_program = skinned_shader_template->build({}); - skinned_model_view_projection_var = skinned_shader_program->variable("model_view_projection"); - - // Calculate bias-tile matrices - math::fmat4 bias_matrix = math::translate(math::fmat4::identity(), math::fvec3{0.5f, 0.5f, 0.5f}) * math::scale(math::fmat4::identity(), math::fvec3{0.5f, 0.5f, 0.5f}); - math::fmat4 tile_scale = math::scale(math::fmat4::identity(), math::fvec3{0.5f, 0.5f, 1.0f}); - for (int i = 0; i < 4; ++i) + skinned_shader_program = skinned_shader_template->build(definitions); + if (!skinned_shader_program->linked()) { - float x = static_cast(i % 2) * 0.5f; - float y = static_cast(i / 2) * 0.5f; - math::fmat4 tile_matrix = math::translate(math::fmat4::identity(), math::fvec3{x, y, 0.0f}) * tile_scale; - bias_tile_matrices[i] = tile_matrix * bias_matrix; + debug::log::error("Failed to build skinned shadow map shader program: {}", skinned_shader_program->info()); + debug::log::warning("{}", skinned_shader_template->configure(gl::shader_stage::vertex)); } + skinned_model_view_projection_var = skinned_shader_program->variable("model_view_projection"); + skinned_matrix_palette_var = skinned_shader_program->variable("matrix_palette"); } void shadow_map_pass::render(render::context& ctx) { // For each light const auto& lights = ctx.collection->get_objects(scene::light::object_type_id); - for (const scene::object_base* object: lights) + for (scene::object_base* object: lights) { // Ignore non-directional lights - const scene::light& light = static_cast(*object); + auto& light = static_cast(*object); if (light.get_light_type() != scene::light_type::directional) { continue; } // Ignore non-shadow casters - const scene::directional_light& directional_light = static_cast(light); + auto& directional_light = static_cast(light); if (!directional_light.is_shadow_caster()) { continue; } // Ignore improperly-configured lights - if (!directional_light.get_shadow_cascade_count() || !directional_light.get_shadow_framebuffer()) + if (!directional_light.get_shadow_framebuffer() || !directional_light.get_shadow_cascade_count()) { continue; } @@ -104,8 +115,16 @@ void shadow_map_pass::render(render::context& ctx) } } -void shadow_map_pass::render_csm(const scene::directional_light& light, render::context& ctx) +void shadow_map_pass::render_csm(scene::directional_light& light, render::context& ctx) { + // Get light layer mask + const auto light_layer_mask = light.get_layer_mask(); + + if (!light_layer_mask & ctx.camera->get_layer_mask()) + { + return; + } + rasterizer->use_framebuffer(*light.get_shadow_framebuffer()); // Disable blending @@ -113,7 +132,7 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render:: // Enable depth testing glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); + glDepthFunc(GL_GREATER); glDepthMask(GL_TRUE); // Enable back-face culling @@ -124,17 +143,18 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render:: // For half-z buffer glDepthRange(-1.0f, 1.0f); + + // Get camera const scene::camera& camera = *ctx.camera; // Calculate distance to shadow cascade depth clipping planes const float shadow_clip_far = math::lerp(camera.get_clip_near(), camera.get_clip_far(), light.get_shadow_cascade_coverage()); - const unsigned int cascade_count = light.get_shadow_cascade_count(); - - /// @TODO: don't const_cast - auto& cascade_distances = const_cast&>(light.get_shadow_cascade_distances()); - auto& cascade_matrices = const_cast&>(light.get_shadow_cascade_matrices()); + // Get light shadow cascade distances and matrices + const auto cascade_count = light.get_shadow_cascade_count(); + const auto cascade_distances = light.get_shadow_cascade_distances(); + const auto cascade_matrices = light.get_shadow_cascade_matrices(); // Calculate cascade far clipping plane distances cascade_distances[cascade_count - 1] = shadow_clip_far; @@ -166,101 +186,76 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render:: viewport[3] = cascade_resolution; } - // Reverse half z clip-space coordinates of a cube - constexpr math::fvec4 clip_space_cube[8] = - { - {-1, -1, 1, 1}, // NBL - { 1, -1, 1, 1}, // NBR - {-1, 1, 1, 1}, // NTL - { 1, 1, 1, 1}, // NTR - {-1, -1, 0, 1}, // FBL - { 1, -1, 0, 1}, // FBR - {-1, 1, 0, 1}, // FTL - { 1, 1, 0, 1} // FTR - }; - - // Calculate world-space corners of camera view frustum - math::fvec3 view_frustum_corners[8]; - for (std::size_t i = 0; i < 8; ++i) - { - math::fvec4 corner = camera.get_inverse_view_projection() * clip_space_cube[i]; - view_frustum_corners[i] = math::fvec3(corner) / corner[3]; - } - // Sort render operations std::sort(std::execution::par_unseq, ctx.operations.begin(), ctx.operations.end(), operation_compare); gl::shader_program* active_shader_program = nullptr; + // Precalculate frustum minimal bounding sphere terms + const auto k = std::sqrt(1.0f + camera.get_aspect_ratio() * camera.get_aspect_ratio()) * std::tan(camera.get_vertical_fov() * 0.5f); + const auto k2 = k * k; + const auto k4 = k2 * k2; + for (unsigned int i = 0; i < cascade_count; ++i) { // Set viewport for this shadow map const math::ivec4& viewport = shadow_map_viewports[i]; rasterizer->set_viewport(viewport[0], viewport[1], viewport[2], viewport[3]); - // Calculate world-space corners and center of camera subfrustum - const float t_near = (i) ? cascade_distances[i - 1] / camera.get_clip_far() : 0.0f; - const float t_far = cascade_distances[i] / camera.get_clip_far(); - math::fvec3 subfrustum_center{0, 0, 0}; - math::fvec3 subfrustum_corners[8]; - for (std::size_t i = 0; i < 4; ++i) + // Find minimal bounding sphere of subfrustum in view-space + // @see https://lxjk.github.io/2017/04/15/Calculate-Minimal-Bounding-Sphere-of-Frustum.html + geom::sphere subfrustum_bounds; { - subfrustum_corners[i] = math::lerp(view_frustum_corners[i], view_frustum_corners[i + 4], t_near); - subfrustum_corners[i + 4] = math::lerp(view_frustum_corners[i], view_frustum_corners[i + 4], t_far); + // Get subfrustum near and far distances + const auto n = (i) ? cascade_distances[i - 1] : camera.get_clip_near(); + const auto f = cascade_distances[i]; - subfrustum_center += subfrustum_corners[i]; - subfrustum_center += subfrustum_corners[i + 4]; + if (k2 >= (f - n) / (f + n)) + { + subfrustum_bounds.center = {0, 0, -f}; + subfrustum_bounds.radius = f * k; + } + else + { + subfrustum_bounds.center = {0, 0, -0.5f * (f + n) * (1.0f + k2)}; + subfrustum_bounds.radius = 0.5f * std::sqrt((k4 + 2.0f * k2 + 1.0f) * (f * f + n * n) + 2.0f * f * (k4 - 1.0f) * n); + } } - subfrustum_center *= (1.0f / 8.0f); - // Calculate a view-projection matrix from the light's point-of-view - const math::fvec3 light_up = light.get_rotation() * config::global_up; - math::fmat4 light_view = math::look_at(subfrustum_center, subfrustum_center + light.get_direction(), light_up); - math::fmat4 light_projection = math::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); - math::fmat4 light_view_projection = light_projection * light_view; + // Transform subfrustum bounds into world-space + subfrustum_bounds.center = camera.get_translation() + camera.get_rotation() * subfrustum_bounds.center; - // Calculate AABB of the subfrustum corners in light clip-space - geom::box cropping_bounds = {math::fvec3::infinity(), -math::fvec3::infinity()}; - for (std::size_t i = 0; i < 8; ++i) - { - math::fvec4 corner4 = math::fvec4(subfrustum_corners[i]); - corner4[3] = 1.0f; - corner4 = light_view_projection * corner4; - - const math::fvec3 corner3 = math::fvec3(corner4) / corner4[3]; - - cropping_bounds.min = math::min(cropping_bounds.min, corner3); - cropping_bounds.max = math::max(cropping_bounds.max, corner3); - } + // Discretize view-space subfrustum bounds + const auto texel_scale = static_cast(cascade_resolution) / (subfrustum_bounds.radius * 2.0f); + subfrustum_bounds.center = math::conjugate(light.get_rotation()) * subfrustum_bounds.center; + subfrustum_bounds.center = math::floor(subfrustum_bounds.center * texel_scale) / texel_scale; + subfrustum_bounds.center = light.get_rotation() * subfrustum_bounds.center; - // Quantize clip-space coordinates - const float texel_scale_x = (cropping_bounds.max.x() - cropping_bounds.min.x()) / static_cast(cascade_resolution); - const float texel_scale_y = (cropping_bounds.max.y() - cropping_bounds.min.y()) / static_cast(cascade_resolution); - cropping_bounds.min.x() = std::floor(cropping_bounds.min.x() / texel_scale_x) * texel_scale_x; - cropping_bounds.max.x() = std::floor(cropping_bounds.max.x() / texel_scale_x) * texel_scale_x; - cropping_bounds.min.y() = std::floor(cropping_bounds.min.y() / texel_scale_y) * texel_scale_y; - cropping_bounds.max.y() = std::floor(cropping_bounds.max.y() / texel_scale_y) * texel_scale_y; + // Construct light view matrix + const auto light_view = math::look_at(subfrustum_bounds.center, subfrustum_bounds.center + light.get_direction(), light.get_rotation() * math::fvec3{0, 1, 0}); - /// @NOTE: light z should be modified here to included shadow casters outside the view frustum - // cropping_bounds.min.z() -= 10.0f; - // cropping_bounds.max.z() += 10.0f; - - // Crop light projection matrix - light_projection = math::ortho_half_z + // Construct light projection matrix (reversed half-z) + const auto light_projection = math::ortho_half_z ( - cropping_bounds.min.x(), cropping_bounds.max.x(), - cropping_bounds.min.y(), cropping_bounds.max.y(), - cropping_bounds.min.z(), cropping_bounds.max.z() + -subfrustum_bounds.radius, subfrustum_bounds.radius, + -subfrustum_bounds.radius, subfrustum_bounds.radius, + subfrustum_bounds.radius, -subfrustum_bounds.radius ); - // Recalculate light view projection matrix - light_view_projection = light_projection * light_view; + // Construct light view-projection matrix + const auto light_view_projection = light_projection * light_view; - // Calculate world-space to cascade texture-space transformation matrix - cascade_matrices[i] = bias_tile_matrices[i] * light_view_projection; + // Update world-space to cascade texture-space transformation matrix + cascade_matrices[i] = light.get_shadow_bias_scale_matrices()[i] * light_view_projection; for (const render::operation* operation: ctx.operations) { + // Skip operations which don't share any layers with the shadow-casting light + if (!(operation->layer_mask & light_layer_mask)) + { + continue; + } + const render::material* material = operation->material.get(); if (material) { @@ -304,6 +299,7 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render:: else if (active_shader_program == skinned_shader_program.get()) { skinned_model_view_projection_var->update(model_view_projection); + skinned_matrix_palette_var->update(operation->matrix_palette); } // Draw geometry diff --git a/src/engine/render/passes/shadow-map-pass.hpp b/src/engine/render/passes/shadow-map-pass.hpp index 943b94b..3cbc172 100644 --- a/src/engine/render/passes/shadow-map-pass.hpp +++ b/src/engine/render/passes/shadow-map-pass.hpp @@ -62,15 +62,14 @@ private: * @param ctx Render context. * @param queue Render queue. */ - void render_csm(const scene::directional_light& light, render::context& ctx); + void render_csm(scene::directional_light& light, render::context& ctx); std::unique_ptr unskinned_shader_program; const gl::shader_variable* unskinned_model_view_projection_var; std::unique_ptr skinned_shader_program; const gl::shader_variable* skinned_model_view_projection_var; - - math::fmat4 bias_tile_matrices[4]; + const gl::shader_variable* skinned_matrix_palette_var; }; } // namespace render diff --git a/src/engine/render/passes/sky-pass.cpp b/src/engine/render/passes/sky-pass.cpp index 5b7ec3a..cfee738 100644 --- a/src/engine/render/passes/sky-pass.cpp +++ b/src/engine/render/passes/sky-pass.cpp @@ -188,6 +188,11 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe void sky_pass::render(render::context& ctx) { + if (!(m_layer_mask & ctx.camera->get_layer_mask())) + { + return; + } + glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); @@ -219,7 +224,7 @@ void sky_pass::render(render::context& ctx) // Construct matrices const scene::camera& camera = *ctx.camera; math::fvec3 model_scale = math::fvec3{1.0f, 1.0f, 1.0f} * (camera.get_clip_near() + camera.get_clip_far()) * 0.5f; - math::fmat4 model = math::scale(math::fmat4::identity(), model_scale); + math::fmat4 model = math::scale(model_scale); math::fmat4 view = math::fmat4(math::fmat3(camera.get_view())); math::fmat4 model_view = view * model; const math::fmat4& projection = camera.get_projection(); @@ -387,8 +392,7 @@ void sky_pass::render(render::context& ctx) { float star_distance = (camera.get_clip_near() + camera.get_clip_far()) * 0.5f; - model = math::fmat4(math::fmat3(icrf_to_eus.r)); - model = math::scale(model, {star_distance, star_distance, star_distance}); + model = math::fmat4(math::fmat3(icrf_to_eus.r)) * math::scale(math::fvec3{star_distance, star_distance, star_distance}); model_view_projection = view_projection * model; diff --git a/src/engine/render/passes/sky-pass.hpp b/src/engine/render/passes/sky-pass.hpp index 3d6a51c..efe6376 100644 --- a/src/engine/render/passes/sky-pass.hpp +++ b/src/engine/render/passes/sky-pass.hpp @@ -211,6 +211,16 @@ public: void set_sky_probe(std::shared_ptr probe); + + /** + * Sets the layer mask of the sky. + * + * @param mask 32-bit layer mask in which each set bit represents a layer in which the sky is visible. + */ + inline constexpr void set_layer_mask(std::uint32_t mask) noexcept + { + m_layer_mask = mask; + } private: void rebuild_transmittance_lut_shader_program(); @@ -358,6 +368,8 @@ private: math::fvec3 m_ground_albedo{}; float magnification; + + std::uint32_t m_layer_mask{1}; }; } // namespace render diff --git a/src/engine/render/renderer.cpp b/src/engine/render/renderer.cpp index 46add24..8f69341 100644 --- a/src/engine/render/renderer.cpp +++ b/src/engine/render/renderer.cpp @@ -45,7 +45,7 @@ renderer::renderer(gl::rasterizer& rasterizer, ::resource_manager& resource_mana m_queue_stage = std::make_unique(); } -void renderer::render(float t, float dt, float alpha, const scene::collection& collection) +void renderer::render(float t, float dt, float alpha, scene::collection& collection) { // Init render context m_ctx.collection = &collection; diff --git a/src/engine/render/renderer.hpp b/src/engine/render/renderer.hpp index 901f320..2eafff2 100644 --- a/src/engine/render/renderer.hpp +++ b/src/engine/render/renderer.hpp @@ -53,7 +53,7 @@ public: * @param alpha Subframe interpolation factor. * @param collection Collection of scene objects to render. */ - void render(float t, float dt, float alpha, const scene::collection& collection); + void render(float t, float dt, float alpha, scene::collection& collection); private: render::context m_ctx; diff --git a/src/engine/render/stages/culling-stage.cpp b/src/engine/render/stages/culling-stage.cpp index bab656e..e5be4eb 100644 --- a/src/engine/render/stages/culling-stage.cpp +++ b/src/engine/render/stages/culling-stage.cpp @@ -31,7 +31,8 @@ void culling_stage::execute(render::context& ctx) // Get all objects in the collection const auto& objects = ctx.collection->get_objects(); - // Get camera view frustum + // Get camera layer mask and view frustum + const auto camera_layer_mask = ctx.camera->get_layer_mask(); const auto& view_frustum = ctx.camera->get_view_frustum(); // Construct mutex to guard set of visible objects @@ -52,8 +53,10 @@ void culling_stage::execute(render::context& ctx) } // Cull object if it doesn't share any common layers with the camera - //if (!(object->get_layer_mask() & camera_layer_mask)) - // return; + if (!(object->get_layer_mask() & camera_layer_mask)) + { + return; + } // Cull object if it's outside of the camera view frustum if (!view_frustum.intersects(object->get_bounds())) diff --git a/src/engine/scene/billboard.cpp b/src/engine/scene/billboard.cpp index 482bda8..1887d80 100644 --- a/src/engine/scene/billboard.cpp +++ b/src/engine/scene/billboard.cpp @@ -125,6 +125,7 @@ void billboard::render(render::context& ctx) const } m_render_op.depth = ctx.camera->get_view_frustum().near().distance(get_translation()); + m_render_op.layer_mask = get_layer_mask(); ctx.operations.emplace_back(&m_render_op); } diff --git a/src/engine/scene/directional-light.cpp b/src/engine/scene/directional-light.cpp index caa0c77..5b21563 100644 --- a/src/engine/scene/directional-light.cpp +++ b/src/engine/scene/directional-light.cpp @@ -23,8 +23,11 @@ namespace scene { directional_light::directional_light(): m_shadow_cascade_distances(m_shadow_cascade_count), - m_shadow_cascade_matrices(m_shadow_cascade_count) -{} + m_shadow_cascade_matrices(m_shadow_cascade_count), + m_shadow_bias_scale_matrices(m_shadow_cascade_count) +{ + set_shadow_bias(m_shadow_bias); +} void directional_light::set_direction(const math::fvec3& direction) { @@ -44,6 +47,7 @@ void directional_light::set_shadow_framebuffer(std::shared_ptr void directional_light::set_shadow_bias(float bias) noexcept { m_shadow_bias = bias; + update_shadow_bias_scale_matrices(); } void directional_light::set_shadow_cascade_count(unsigned int count) noexcept @@ -51,6 +55,8 @@ void directional_light::set_shadow_cascade_count(unsigned int count) noexcept m_shadow_cascade_count = count; m_shadow_cascade_distances.resize(m_shadow_cascade_count); m_shadow_cascade_matrices.resize(m_shadow_cascade_count); + m_shadow_bias_scale_matrices.resize(m_shadow_cascade_count); + update_shadow_bias_scale_matrices(); } void directional_light::set_shadow_cascade_coverage(float factor) noexcept @@ -78,4 +84,19 @@ void directional_light::illuminance_updated() m_colored_illuminance = m_color * m_illuminance; } +void directional_light::update_shadow_bias_scale_matrices() +{ + // Construct shadow bias-scale matrix + auto m = math::translate(math::fvec3{0.5f, 0.5f, 0.5f + m_shadow_bias}) * math::scale(math::fvec3{0.5f, 0.5f, 0.5f}); + + // Apply cascade scale + m = math::scale(math::fvec3{0.5f, 0.5f, 1.0f}) * m; + + for (unsigned int i = 0; i < m_shadow_cascade_count; ++i) + { + // Apply cascade translation + m_shadow_bias_scale_matrices[i] = math::translate(math::fvec3{static_cast(i % 2) * 0.5f, static_cast(i / 2) * 0.5f, 0.0f}) * m; + } +} + } // namespace scene diff --git a/src/engine/scene/directional-light.hpp b/src/engine/scene/directional-light.hpp index 56611f0..bf9f59d 100644 --- a/src/engine/scene/directional-light.hpp +++ b/src/engine/scene/directional-light.hpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace scene { @@ -76,25 +77,25 @@ public: } /// Returns a unit vector pointing in the light direction. - [[nodiscard]] inline const math::fvec3& get_direction() const noexcept + [[nodiscard]] inline constexpr const math::fvec3& get_direction() const noexcept { return m_direction; } /// Returns the color of the light. - [[nodiscard]] inline const math::fvec3& get_color() const noexcept + [[nodiscard]] inline constexpr const math::fvec3& get_color() const noexcept { return m_color; } /// Returns the illuminance of the light on a surface perpendicular to the light direction. - [[nodiscard]] inline float get_illuminance() const noexcept + [[nodiscard]] inline constexpr float get_illuminance() const noexcept { return m_illuminance; } /// Returns the color-modulated illuminance of the light on a surface perpendicular to the light direction. - [[nodiscard]] inline const math::fvec3& get_colored_illuminance() const noexcept + [[nodiscard]] inline constexpr const math::fvec3& get_colored_illuminance() const noexcept { return m_colored_illuminance; } @@ -184,23 +185,29 @@ public: /// Returns the array of shadow cascade far clipping plane distances. /// @{ - [[nodiscard]] inline const std::vector& get_shadow_cascade_distances() const noexcept + [[nodiscard]] inline constexpr std::span get_shadow_cascade_distances() const noexcept { return m_shadow_cascade_distances; } - [[nodiscard]] inline std::vector& get_shadow_cascade_distances() noexcept + [[nodiscard]] inline constexpr std::span get_shadow_cascade_distances() noexcept { return m_shadow_cascade_distances; } /// @} + /// Returns the array of shadow cascade bias-scale matrices. + [[nodiscard]] inline constexpr std::span get_shadow_bias_scale_matrices() const noexcept + { + return m_shadow_bias_scale_matrices; + } + /// Returns the array of world-space to cascade texture-space transformation matrices. /// @{ - [[nodiscard]] inline const std::vector& get_shadow_cascade_matrices() const noexcept + [[nodiscard]] inline constexpr std::span get_shadow_cascade_matrices() const noexcept { return m_shadow_cascade_matrices; } - [[nodiscard]] inline std::vector& get_shadow_cascade_matrices() noexcept + [[nodiscard]] inline constexpr std::span get_shadow_cascade_matrices() noexcept { return m_shadow_cascade_matrices; } @@ -212,6 +219,7 @@ private: void transformed() override; void color_updated(); void illuminance_updated(); + void update_shadow_bias_scale_matrices(); math::fvec3 m_direction{0.0f, 0.0f, -1.0f}; math::fvec3 m_color{1.0f, 1.0f, 1.0f}; @@ -220,12 +228,13 @@ private: bool m_shadow_caster{false}; std::shared_ptr m_shadow_framebuffer{nullptr}; - float m_shadow_bias{0.005f}; + float m_shadow_bias{0.001f}; unsigned int m_shadow_cascade_count{4}; float m_shadow_cascade_coverage{1.0f}; float m_shadow_cascade_distribution{0.8f}; - mutable std::vector m_shadow_cascade_distances; - mutable std::vector m_shadow_cascade_matrices; + std::vector m_shadow_cascade_distances; + std::vector m_shadow_cascade_matrices; + std::vector m_shadow_bias_scale_matrices; }; } // namespace scene diff --git a/src/engine/scene/object.hpp b/src/engine/scene/object.hpp index 6a04027..9c1a8a1 100644 --- a/src/engine/scene/object.hpp +++ b/src/engine/scene/object.hpp @@ -42,7 +42,7 @@ public: using aabb_type = geom::box; /// Returns the type ID for this scene object type. - virtual const std::size_t get_object_type_id() const noexcept = 0; + [[nodiscard]] virtual const std::size_t get_object_type_id() const noexcept = 0; /** * Adds render operations to a render context. @@ -55,7 +55,17 @@ public: * */ void look_at(const vector_type& position, const vector_type& target, const vector_type& up); - + + /** + * Sets the layer mask of the object. + * + * @param mask 32-bit layer mask in which each set bit represents a layer in which the object is visible. + */ + inline constexpr void set_layer_mask(std::uint32_t mask) noexcept + { + m_layer_mask = mask; + } + /** * Sets the transform of the object. * @@ -106,27 +116,33 @@ public: transformed(); } /// @} + + /// Returns the layer mask of the object. + [[nodiscard]] inline constexpr std::uint32_t get_layer_mask() const noexcept + { + return m_layer_mask; + } /// Returns the transform of the object. - [[nodiscard]] inline const transform_type& get_transform() const noexcept + [[nodiscard]] inline constexpr const transform_type& get_transform() const noexcept { return m_transform; } /// Returns the translation of the object. - [[nodiscard]] inline const vector_type& get_translation() const noexcept + [[nodiscard]] inline constexpr const vector_type& get_translation() const noexcept { return m_transform.translation; } /// Returns the rotation of the object. - [[nodiscard]] inline const quaternion_type& get_rotation() const noexcept + [[nodiscard]] inline constexpr const quaternion_type& get_rotation() const noexcept { return m_transform.rotation; } /// Returns the scale of the object. - [[nodiscard]] inline const vector_type& get_scale() const noexcept + [[nodiscard]] inline constexpr const vector_type& get_scale() const noexcept { return m_transform.scale; } @@ -136,16 +152,13 @@ public: protected: static std::size_t next_object_type_id(); - -private: - /// Interpolates between two transforms. - static transform_type interpolate_transforms(const transform_type& x, const transform_type& y, float a); /** * Called every time the scene object's tranform is changed. */ inline virtual void transformed() {} + std::uint32_t m_layer_mask{1}; transform_type m_transform{transform_type::identity()}; }; @@ -161,7 +174,7 @@ public: /// Unique type ID for this scene object type. static const std::atomic object_type_id; - inline const std::size_t get_object_type_id() const noexcept final + [[nodiscard]] inline const std::size_t get_object_type_id() const noexcept final { return object_type_id; } diff --git a/src/engine/scene/skeletal-mesh.cpp b/src/engine/scene/skeletal-mesh.cpp index 0afead2..4ea0784 100644 --- a/src/engine/scene/skeletal-mesh.cpp +++ b/src/engine/scene/skeletal-mesh.cpp @@ -115,6 +115,7 @@ void skeletal_mesh::render(render::context& ctx) const for (auto& operation: m_operations) { operation.depth = depth; + operation.layer_mask = get_layer_mask(); ctx.operations.push_back(&operation); } } diff --git a/src/engine/scene/static-mesh.cpp b/src/engine/scene/static-mesh.cpp index a0860a8..58ba1ef 100644 --- a/src/engine/scene/static-mesh.cpp +++ b/src/engine/scene/static-mesh.cpp @@ -113,6 +113,7 @@ void static_mesh::render(render::context& ctx) const for (auto& operation: m_operations) { operation.depth = depth; + operation.layer_mask = get_layer_mask(); ctx.operations.push_back(&operation); } } diff --git a/src/engine/scene/text.cpp b/src/engine/scene/text.cpp index c47da97..59809a8 100644 --- a/src/engine/scene/text.cpp +++ b/src/engine/scene/text.cpp @@ -79,6 +79,7 @@ void text::render(render::context& ctx) const if (m_vertex_count) { m_render_op.depth = ctx.camera->get_view_frustum().near().distance(get_translation()); + m_render_op.layer_mask = get_layer_mask(); ctx.operations.push_back(&m_render_op); } } diff --git a/src/game/controls/ant-controls.cpp b/src/game/controls/ant-controls.cpp index c04acfd..b14991d 100644 --- a/src/game/controls/ant-controls.cpp +++ b/src/game/controls/ant-controls.cpp @@ -24,6 +24,7 @@ #include "game/components/legged-locomotion-component.hpp" #include "game/components/ovary-component.hpp" #include "game/components/spring-arm-component.hpp" +#include "game/components/scene-component.hpp" #include #include #include @@ -228,7 +229,14 @@ void setup_ant_controls(::game& ctx) ( [&](const auto& event) { - world::switch_scene(ctx); + if (ctx.active_camera_eid == entt::null) + { + return; + } + + auto& camera_object = *ctx.entity_registry->get(ctx.active_camera_eid).object; + + camera_object.set_layer_mask(camera_object.get_layer_mask() == 1 ? 2 : 1); } ) ); diff --git a/src/game/game.cpp b/src/game/game.cpp index 7c48329..4cc2228 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -738,13 +738,13 @@ void game::setup_rendering() { surface_shadow_map_clear_pass = std::make_unique(window->get_rasterizer(), shadow_map_framebuffer.get()); surface_shadow_map_clear_pass->set_cleared_buffers(false, true, false); - surface_shadow_map_clear_pass->set_clear_depth(1.0f); + surface_shadow_map_clear_pass->set_clear_depth(0.0f); surface_shadow_map_pass = std::make_unique(window->get_rasterizer(), resource_manager.get()); surface_clear_pass = std::make_unique(window->get_rasterizer(), hdr_framebuffer.get()); surface_clear_pass->set_clear_color({0.0f, 0.0f, 0.0f, 1.0f}); - surface_clear_pass->set_clear_depth(-1.0f); + surface_clear_pass->set_clear_depth(0.0f); surface_clear_pass->set_clear_stencil(0); surface_clear_pass->set_cleared_buffers(true, true, true); @@ -816,7 +816,7 @@ void game::setup_scenes() // Allocate and init surface camera surface_camera = std::make_shared(); - surface_camera->set_perspective(math::radians(45.0f), viewport_aspect_ratio, 0.1f, 5000.0f); + surface_camera->set_perspective(math::radians(45.0f), viewport_aspect_ratio, 0.1f, 1000.0f); surface_camera->set_compositor(surface_compositor.get()); surface_camera->set_composite_index(0); diff --git a/src/game/graphics.cpp b/src/game/graphics.cpp index 6147a6b..fb50ecc 100644 --- a/src/game/graphics.cpp +++ b/src/game/graphics.cpp @@ -78,7 +78,7 @@ void create_framebuffers(::game& ctx) // Create shadow map framebuffer ctx.shadow_map_depth_texture = std::make_shared(ctx.shadow_map_resolution, ctx.shadow_map_resolution, gl::pixel_type::float_32, gl::pixel_format::d); - ctx.shadow_map_depth_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); + ctx.shadow_map_depth_texture->set_wrapping(gl::texture_wrapping::clip, gl::texture_wrapping::clip); ctx.shadow_map_depth_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); ctx.shadow_map_depth_texture->set_max_anisotropy(0.0f); ctx.shadow_map_framebuffer = std::make_shared(ctx.shadow_map_resolution, ctx.shadow_map_resolution); diff --git a/src/game/states/experiments/treadmill-experiment-state.cpp b/src/game/states/experiments/treadmill-experiment-state.cpp index 76faec3..7025192 100644 --- a/src/game/states/experiments/treadmill-experiment-state.cpp +++ b/src/game/states/experiments/treadmill-experiment-state.cpp @@ -176,42 +176,69 @@ treadmill_experiment_state::treadmill_experiment_state(::game& ctx): // ctx.entity_registry->emplace(nest_exterior_eid, std::move(nest_exterior_scene_component)); // } - // Create nest interior - // { - // scene_component nest_interior_scene_component; - // nest_interior_scene_component.object = std::make_shared(ctx.resource_manager->load("round-petri-dish-nest-100mm-interior.mdl")); - // nest_interior_scene_component.layer_mask = 1; + // Create nest exterior + { + scene_component nest_exterior_scene_component; + nest_exterior_scene_component.object = std::make_shared(ctx.resource_manager->load("sphere-nest-100mm-exterior.mdl")); + nest_exterior_scene_component.layer_mask = 1; - // auto nest_interior_mesh = ctx.resource_manager->load("round-petri-dish-nest-100mm-interior.msh"); - // geom::generate_vertex_normals(*nest_interior_mesh); + auto nest_exterior_mesh = ctx.resource_manager->load("sphere-nest-100mm-exterior.msh"); - // auto nest_interior_rigid_body = std::make_unique(); - // nest_interior_rigid_body->set_mass(0.0f); - // nest_interior_rigid_body->set_collider(std::make_shared(std::move(nest_interior_mesh))); + auto nest_exterior_rigid_body = std::make_unique(); + nest_exterior_rigid_body->set_mass(0.0f); + nest_exterior_rigid_body->set_collider(std::make_shared(std::move(nest_exterior_mesh))); - // auto nest_interior_eid = ctx.entity_registry->create(); - // ctx.entity_registry->emplace(nest_interior_eid, std::move(nest_interior_scene_component)); - // ctx.entity_registry->emplace(nest_interior_eid, std::move(nest_interior_rigid_body)); - // } + auto nest_exterior_eid = ctx.entity_registry->create(); + ctx.entity_registry->emplace(nest_exterior_eid, std::move(nest_exterior_scene_component)); + ctx.entity_registry->emplace(nest_exterior_eid, std::move(nest_exterior_rigid_body)); + } + // Create nest interior { scene_component nest_interior_scene_component; - nest_interior_scene_component.object = std::make_shared(ctx.resource_manager->load("soil-nest.mdl")); + nest_interior_scene_component.object = std::make_shared(ctx.resource_manager->load("sphere-nest-100mm-interior.mdl")); + nest_interior_scene_component.object->set_layer_mask(0b10); nest_interior_scene_component.layer_mask = 1; - auto nest_interior_mesh = ctx.resource_manager->load("soil-nest.msh"); + auto nest_interior_mesh = ctx.resource_manager->load("sphere-nest-100mm-interior.msh"); auto nest_interior_rigid_body = std::make_unique(); nest_interior_rigid_body->set_mass(0.0f); nest_interior_rigid_body->set_collider(std::make_shared(std::move(nest_interior_mesh))); + nest_interior_rigid_body->get_collider()->set_layer_mask(0b10); auto nest_interior_eid = ctx.entity_registry->create(); ctx.entity_registry->emplace(nest_interior_eid, std::move(nest_interior_scene_component)); ctx.entity_registry->emplace(nest_interior_eid, std::move(nest_interior_rigid_body)); } + + // Create rectangle light + { + area_light = std::make_unique(); + area_light->set_luminous_flux(5000000.0f); + area_light->set_translation({0.0f, 0.0f, 0.0f}); + area_light->set_rotation(math::fquat::rotate_x(math::radians(90.0f))); + area_light->set_scale(5.0f); + area_light->set_layer_mask(0b10); + ctx.surface_scene->add_object(*area_light); + + // Create light rectangle + auto light_rectangle_model = ctx.resource_manager->load("light-rectangle.mdl"); + auto light_rectangle_material = std::make_shared(*light_rectangle_model->get_groups().front().material); + light_rectangle_emissive = std::static_pointer_cast(light_rectangle_material->get_variable("emissive")); + light_rectangle_emissive->set(area_light->get_colored_luminance()); + auto light_rectangle_static_mesh = std::make_shared(light_rectangle_model); + light_rectangle_static_mesh->set_material(0, light_rectangle_material); + light_rectangle_static_mesh->set_transform(area_light->get_transform()); + light_rectangle_static_mesh->set_layer_mask(area_light->get_layer_mask()); + auto light_rectangle_eid = ctx.entity_registry->create(); + ctx.entity_registry->emplace(light_rectangle_eid, std::move(light_rectangle_static_mesh), std::uint8_t{1}); + } + // Create worker auto worker_skeletal_mesh = std::make_unique(worker_model); + worker_skeletal_mesh->set_layer_mask(0b11); // Create worker IK rig const auto& worker_skeleton = worker_model->get_skeleton(); @@ -310,7 +337,7 @@ treadmill_experiment_state::treadmill_experiment_state(::game& ctx): ::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0); // Init time scale - double time_scale = 60.0; + double time_scale = 0.0; // Set time scale ::world::set_time_scale(ctx, time_scale); @@ -385,6 +412,7 @@ void treadmill_experiment_state::create_third_person_camera_rig() spring_arm.far_focal_plane_height = 80.0 * subject_scale; spring_arm.near_hfov = math::radians(90.0); spring_arm.far_hfov = math::radians(45.0); + // spring_arm.far_hfov = math::radians(90.0); spring_arm.zoom = 0.25; spring_arm.focal_point_offset = {0, static_cast(worker_phenome->legs->standing_height) * subject_scale, 0}; @@ -535,7 +563,9 @@ void treadmill_experiment_state::setup_controls() const auto& mouse_position = (*ctx.input_manager->get_mice().begin())->get_position(); const auto mouse_ray = get_mouse_ray(mouse_position); - if (auto trace = ctx.physics_system->trace(mouse_ray)) + const auto& camera_object = *ctx.entity_registry->get<::scene_component>(ctx.active_camera_eid).object; + + if (auto trace = ctx.physics_system->trace(mouse_ray, entt::null, camera_object.get_layer_mask())) { // debug::log::debug("HIT! EID: {}; distance: {}; face: {}", static_cast(std::get<0>(*trace)), std::get<1>(*trace), std::get<2>(*trace)); diff --git a/src/game/states/experiments/treadmill-experiment-state.hpp b/src/game/states/experiments/treadmill-experiment-state.hpp index 043526c..815895f 100644 --- a/src/game/states/experiments/treadmill-experiment-state.hpp +++ b/src/game/states/experiments/treadmill-experiment-state.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -119,6 +120,7 @@ private: std::shared_ptr worker_ik_rig; std::shared_ptr sky_probe; + std::shared_ptr area_light; }; #endif // ANTKEEPER_TREADMILL_EXPERIMENT_STATE_HPP diff --git a/src/game/systems/render-system.cpp b/src/game/systems/render-system.cpp index 8422e51..ff287c3 100644 --- a/src/game/systems/render-system.cpp +++ b/src/game/systems/render-system.cpp @@ -72,7 +72,7 @@ void render_system::draw(float alpha) { if (renderer) { - for (const scene::collection* collection: layers) + for (scene::collection* collection: layers) { renderer->render(t + dt * alpha, dt, alpha, *collection); } diff --git a/src/game/world.cpp b/src/game/world.cpp index 1a6ba54..21b0265 100644 --- a/src/game/world.cpp +++ b/src/game/world.cpp @@ -363,9 +363,9 @@ void create_sun(::game& ctx) ctx.sun_light = std::make_unique(); ctx.sun_light->set_shadow_caster(true); ctx.sun_light->set_shadow_framebuffer(ctx.shadow_map_framebuffer); - ctx.sun_light->set_shadow_bias(0.005f); + ctx.sun_light->set_shadow_bias(0.001f); ctx.sun_light->set_shadow_cascade_count(4); - ctx.sun_light->set_shadow_cascade_coverage(0.15f); + ctx.sun_light->set_shadow_cascade_coverage(0.05f); ctx.sun_light->set_shadow_cascade_distribution(0.8f); // Add sun light scene objects to surface scene