Browse Source

Improve cascaded shadow maps

master
C. J. Howard 8 months ago
parent
commit
17ab179ad9
28 changed files with 338 additions and 221 deletions
  1. +1
    -1
      src/engine/gl/texture.cpp
  2. +23
    -30
      src/engine/math/matrix.hpp
  3. +1
    -1
      src/engine/physics/kinematics/collider.hpp
  4. +1
    -1
      src/engine/render/context.hpp
  5. +6
    -4
      src/engine/render/operation.hpp
  6. +47
    -25
      src/engine/render/passes/material-pass.cpp
  7. +3
    -4
      src/engine/render/passes/material-pass.hpp
  8. +90
    -94
      src/engine/render/passes/shadow-map-pass.cpp
  9. +2
    -3
      src/engine/render/passes/shadow-map-pass.hpp
  10. +7
    -3
      src/engine/render/passes/sky-pass.cpp
  11. +12
    -0
      src/engine/render/passes/sky-pass.hpp
  12. +1
    -1
      src/engine/render/renderer.cpp
  13. +1
    -1
      src/engine/render/renderer.hpp
  14. +6
    -3
      src/engine/render/stages/culling-stage.cpp
  15. +1
    -0
      src/engine/scene/billboard.cpp
  16. +23
    -2
      src/engine/scene/directional-light.cpp
  17. +20
    -11
      src/engine/scene/directional-light.hpp
  18. +24
    -11
      src/engine/scene/object.hpp
  19. +1
    -0
      src/engine/scene/skeletal-mesh.cpp
  20. +1
    -0
      src/engine/scene/static-mesh.cpp
  21. +1
    -0
      src/engine/scene/text.cpp
  22. +9
    -1
      src/game/controls/ant-controls.cpp
  23. +3
    -3
      src/game/game.cpp
  24. +1
    -1
      src/game/graphics.cpp
  25. +48
    -18
      src/game/states/experiments/treadmill-experiment-state.cpp
  26. +2
    -0
      src/game/states/experiments/treadmill-experiment-state.hpp
  27. +1
    -1
      src/game/systems/render-system.cpp
  28. +2
    -2
      src/game/world.cpp

+ 1
- 1
src/engine/gl/texture.cpp View File

@ -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);
}
}

+ 23
- 30
src/engine/math/matrix.hpp View File

@ -584,7 +584,7 @@ template
* @return Viewing transformation matrix.
*/
template <class T>
[[nodiscard]] constexpr matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up);
[[nodiscard]] constexpr mat4<T> look_at(const vec3<T>& position, const vec3<T>& target, vec3<T> up);
/**
* Multiplies two matrices
@ -677,15 +677,14 @@ template
[[nodiscard]] mat3<T> 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 <class T>
[[nodiscard]] constexpr matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
[[nodiscard]] constexpr mat4<T> scale(const vec3<T>& v);
/**
* Subtracts a matrix from another matrix.
@ -731,15 +730,14 @@ template
[[nodiscard]] constexpr T trace(const matrix<T, N, N>& 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 <class T>
[[nodiscard]] constexpr matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
[[nodiscard]] constexpr mat4<T> translate(const vec3<T>& v);
/**
* Calculates the transpose of a matrix.
@ -966,13 +964,12 @@ constexpr matrix inverse(const matrix& m) noexcept
}
template <class T>
constexpr matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up)
constexpr mat4<T> look_at(const vec3<T>& position, const vec3<T>& target, vec3<T> up)
{
vector<T, 3> forward = normalize(sub(target, position));
vector<T, 3> right = normalize(cross(forward, up));
const auto forward = normalize(sub(target, position));
const auto right = normalize(cross(forward, up));
up = cross(right, forward);
matrix<T, 4, 4> m
const auto m = mat4<T>
{{
{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
{T{0}, T{0}, T{0}, T{1}}
}};
return translate(m, negate(position));
return mul(m, translate(-position));
}
template <class T, std::size_t N, std::size_t M, std::size_t P>
@ -1105,19 +1102,15 @@ mat3 rotate_z(T angle)
}
template <class T>
constexpr matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
constexpr mat4<T> scale(const vec3<T>& v)
{
return mul
(
m,
matrix<T, 4, 4>
{{
{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 <class T>
constexpr matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
constexpr mat4<T> translate(const vec3<T>& v)
{
return mul(m, matrix<T, 4, 4>
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

+ 1
- 1
src/engine/physics/kinematics/collider.hpp View File

@ -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
{

+ 1
- 1
src/engine/render/context.hpp View File

@ -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;

+ 6
- 4
src/engine/render/operation.hpp View File

@ -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<render::material> 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<const math::fmat4> matrix_palette{};
std::uint32_t layer_mask{};
};
} // namespace render

+ 47
- 25
src/engine/render/passes/material-pass.cpp View File

@ -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<const scene::light_probe&>(*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<const scene::light&>(*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<const gl::texture_2d*>(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::vector
{
if (auto directional_shadow_maps_var = shader_program.variable("directional_shadow_maps"))
{
auto directional_shadow_biases_var = shader_program.variable("directional_shadow_biases");
auto directional_shadow_splits_var = shader_program.variable("directional_shadow_splits");
auto directional_shadow_matrices_var = shader_program.variable("directional_shadow_matrices");
if (directional_shadow_maps_var && directional_shadow_biases_var && directional_shadow_splits_var && directional_shadow_matrices_var)
if (directional_shadow_maps_var && directional_shadow_splits_var && directional_shadow_matrices_var)
{
command_buffer.emplace_back
(
[&, directional_shadow_maps_var, directional_shadow_biases_var, directional_shadow_splits_var, directional_shadow_matrices_var]()
[&, directional_shadow_maps_var, directional_shadow_splits_var, directional_shadow_matrices_var]()
{
directional_shadow_maps_var->update(std::span<const gl::texture_2d* const>{directional_shadow_maps.data(), directional_shadow_count});
directional_shadow_biases_var->update(std::span<const float>{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();
}
}
);

+ 3
- 4
src/engine/render/passes/material-pass.hpp View File

@ -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<const gl::texture_2d*> directional_shadow_maps;
std::vector<float> directional_shadow_biases;
std::vector<const std::vector<float>*> directional_shadow_splits;
std::vector<const std::vector<math::fmat4>*> directional_shadow_matrices;
std::vector<std::span<const float>> directional_shadow_splits;
std::vector<std::span<const math::fmat4>> directional_shadow_matrices;
std::size_t directional_shadow_count;
// Spot lights

+ 90
- 94
src/engine/render/passes/shadow-map-pass.cpp View File

@ -25,12 +25,12 @@
#include <engine/gl/drawing-mode.hpp>
#include <engine/render/context.hpp>
#include <engine/render/material.hpp>
#include <engine/render/vertex-attribute.hpp>
#include <engine/gl/shader-template.hpp>
#include <engine/scene/camera.hpp>
#include <engine/scene/collection.hpp>
#include <engine/scene/light.hpp>
#include <engine/geom/primitives/view-frustum.hpp>
#include <engine/config.hpp>
#include <engine/math/interpolation.hpp>
#include <engine/math/vector.hpp>
#include <engine/math/matrix.hpp>
@ -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<std::string, std::string> 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<gl::shader_template>("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<gl::shader_template>("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<float>(i % 2) * 0.5f;
float y = static_cast<float>(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<const scene::light&>(*object);
auto& light = static_cast<scene::light&>(*object);
if (light.get_light_type() != scene::light_type::directional)
{
continue;
}
// Ignore non-shadow casters
const scene::directional_light& directional_light = static_cast<const scene::directional_light&>(light);
auto& directional_light = static_cast<scene::directional_light&>(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<std::vector<float>&>(light.get_shadow_cascade_distances());
auto& cascade_matrices = const_cast<std::vector<math::fmat4>&>(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<float> 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<float> 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<float>(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<float>(cascade_resolution);
const float texel_scale_y = (cropping_bounds.max.y() - cropping_bounds.min.y()) / static_cast<float>(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

+ 2
- 3
src/engine/render/passes/shadow-map-pass.hpp View File

@ -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<gl::shader_program> unskinned_shader_program;
const gl::shader_variable* unskinned_model_view_projection_var;
std::unique_ptr<gl::shader_program> 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

+ 7
- 3
src/engine/render/passes/sky-pass.cpp View File

@ -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;

+ 12
- 0
src/engine/render/passes/sky-pass.hpp View File

@ -211,6 +211,16 @@ public:
void set_sky_probe(std::shared_ptr<scene::light_probe> 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

+ 1
- 1
src/engine/render/renderer.cpp View File

@ -45,7 +45,7 @@ renderer::renderer(gl::rasterizer& rasterizer, ::resource_manager& resource_mana
m_queue_stage = std::make_unique<render::queue_stage>();
}
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;

+ 1
- 1
src/engine/render/renderer.hpp View File

@ -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;

+ 6
- 3
src/engine/render/stages/culling-stage.cpp View File

@ -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()))

+ 1
- 0
src/engine/scene/billboard.cpp View File

@ -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);
}

+ 23
- 2
src/engine/scene/directional-light.cpp View File

@ -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<float>(i % 2) * 0.5f, static_cast<float>(i / 2) * 0.5f, 0.0f}) * m;
}
}
} // namespace scene

+ 20
- 11
src/engine/scene/directional-light.hpp View File

@ -25,6 +25,7 @@
#include <engine/math/vector.hpp>
#include <memory>
#include <vector>
#include <span>
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<float>& get_shadow_cascade_distances() const noexcept
[[nodiscard]] inline constexpr std::span<const float> get_shadow_cascade_distances() const noexcept
{
return m_shadow_cascade_distances;
}
[[nodiscard]] inline std::vector<float>& get_shadow_cascade_distances() noexcept
[[nodiscard]] inline constexpr std::span<float> get_shadow_cascade_distances() noexcept
{
return m_shadow_cascade_distances;
}
/// @}
/// Returns the array of shadow cascade bias-scale matrices.
[[nodiscard]] inline constexpr std::span<const math::fmat4> 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<math::fmat4>& get_shadow_cascade_matrices() const noexcept
[[nodiscard]] inline constexpr std::span<const math::fmat4> get_shadow_cascade_matrices() const noexcept
{
return m_shadow_cascade_matrices;
}
[[nodiscard]] inline std::vector<math::fmat4>& get_shadow_cascade_matrices() noexcept
[[nodiscard]] inline constexpr std::span<math::fmat4> 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<gl::framebuffer> 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<float> m_shadow_cascade_distances;
mutable std::vector<math::fmat4> m_shadow_cascade_matrices;
std::vector<float> m_shadow_cascade_distances;
std::vector<math::fmat4> m_shadow_cascade_matrices;
std::vector<math::fmat4> m_shadow_bias_scale_matrices;
};
} // namespace scene

+ 24
- 11
src/engine/scene/object.hpp View File

@ -42,7 +42,7 @@ public:
using aabb_type = geom::box<float>;
/// 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<std::size_t> 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;
}

+ 1
- 0
src/engine/scene/skeletal-mesh.cpp View File

@ -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);
}
}

+ 1
- 0
src/engine/scene/static-mesh.cpp View File

@ -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);
}
}

+ 1
- 0
src/engine/scene/text.cpp View File

@ -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);
}
}

+ 9
- 1
src/game/controls/ant-controls.cpp View File

@ -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 <engine/math/interpolation.hpp>
#include <engine/math/euler-angles.hpp>
#include <engine/debug/log.hpp>
@ -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<scene_component>(ctx.active_camera_eid).object;
camera_object.set_layer_mask(camera_object.get_layer_mask() == 1 ? 2 : 1);
}
)
);

+ 3
- 3
src/game/game.cpp View File

@ -738,13 +738,13 @@ void game::setup_rendering()
{
surface_shadow_map_clear_pass = std::make_unique<render::clear_pass>(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<render::shadow_map_pass>(window->get_rasterizer(), resource_manager.get());
surface_clear_pass = std::make_unique<render::clear_pass>(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<scene::camera>();
surface_camera->set_perspective(math::radians<float>(45.0f), viewport_aspect_ratio, 0.1f, 5000.0f);
surface_camera->set_perspective(math::radians<float>(45.0f), viewport_aspect_ratio, 0.1f, 1000.0f);
surface_camera->set_compositor(surface_compositor.get());
surface_camera->set_composite_index(0);

+ 1
- 1
src/game/graphics.cpp View File

@ -78,7 +78,7 @@ void create_framebuffers(::game& ctx)
// Create shadow map framebuffer
ctx.shadow_map_depth_texture = std::make_shared<gl::texture_2d>(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<gl::framebuffer>(ctx.shadow_map_resolution, ctx.shadow_map_resolution);

+ 48
- 18
src/game/states/experiments/treadmill-experiment-state.cpp View File

@ -176,42 +176,69 @@ treadmill_experiment_state::treadmill_experiment_state(::game& ctx):
// ctx.entity_registry->emplace<scene_component>(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<scene::static_mesh>(ctx.resource_manager->load<render::model>("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<scene::static_mesh>(ctx.resource_manager->load<render::model>("sphere-nest-100mm-exterior.mdl"));
nest_exterior_scene_component.layer_mask = 1;
// auto nest_interior_mesh = ctx.resource_manager->load<geom::brep_mesh>("round-petri-dish-nest-100mm-interior.msh");
// geom::generate_vertex_normals(*nest_interior_mesh);
auto nest_exterior_mesh = ctx.resource_manager->load<geom::brep_mesh>("sphere-nest-100mm-exterior.msh");
// auto nest_interior_rigid_body = std::make_unique<physics::rigid_body>();
// nest_interior_rigid_body->set_mass(0.0f);
// nest_interior_rigid_body->set_collider(std::make_shared<physics::mesh_collider>(std::move(nest_interior_mesh)));
auto nest_exterior_rigid_body = std::make_unique<physics::rigid_body>();
nest_exterior_rigid_body->set_mass(0.0f);
nest_exterior_rigid_body->set_collider(std::make_shared<physics::mesh_collider>(std::move(nest_exterior_mesh)));
// auto nest_interior_eid = ctx.entity_registry->create();
// ctx.entity_registry->emplace<scene_component>(nest_interior_eid, std::move(nest_interior_scene_component));
// ctx.entity_registry->emplace<rigid_body_component>(nest_interior_eid, std::move(nest_interior_rigid_body));
// }
auto nest_exterior_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<scene_component>(nest_exterior_eid, std::move(nest_exterior_scene_component));
ctx.entity_registry->emplace<rigid_body_component>(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<scene::static_mesh>(ctx.resource_manager->load<render::model>("soil-nest.mdl"));
nest_interior_scene_component.object = std::make_shared<scene::static_mesh>(ctx.resource_manager->load<render::model>("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<geom::brep_mesh>("soil-nest.msh");
auto nest_interior_mesh = ctx.resource_manager->load<geom::brep_mesh>("sphere-nest-100mm-interior.msh");
auto nest_interior_rigid_body = std::make_unique<physics::rigid_body>();
nest_interior_rigid_body->set_mass(0.0f);
nest_interior_rigid_body->set_collider(std::make_shared<physics::mesh_collider>(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<scene_component>(nest_interior_eid, std::move(nest_interior_scene_component));
ctx.entity_registry->emplace<rigid_body_component>(nest_interior_eid, std::move(nest_interior_rigid_body));
}
// Create rectangle light
{
area_light = std::make_unique<scene::rectangle_light>();
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<render::model>("light-rectangle.mdl");
auto light_rectangle_material = std::make_shared<render::material>(*light_rectangle_model->get_groups().front().material);
light_rectangle_emissive = std::static_pointer_cast<render::matvar_fvec3>(light_rectangle_material->get_variable("emissive"));
light_rectangle_emissive->set(area_light->get_colored_luminance());
auto light_rectangle_static_mesh = std::make_shared<scene::static_mesh>(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<scene_component>(light_rectangle_eid, std::move(light_rectangle_static_mesh), std::uint8_t{1});
}
// Create worker
auto worker_skeletal_mesh = std::make_unique<scene::skeletal_mesh>(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<double>(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<int>(std::get<0>(*trace)), std::get<1>(*trace), std::get<2>(*trace));

+ 2
- 0
src/game/states/experiments/treadmill-experiment-state.hpp View File

@ -30,6 +30,7 @@
#include <engine/geom/primitives/plane.hpp>
#include <engine/math/angles.hpp>
#include <engine/scene/light-probe.hpp>
#include <engine/scene/rectangle-light.hpp>
#include <engine/geom/bvh/bvh.hpp>
#include <engine/geom/brep/brep-mesh.hpp>
#include <engine/animation/ik/ik-rig.hpp>
@ -119,6 +120,7 @@ private:
std::shared_ptr<ik_rig> worker_ik_rig;
std::shared_ptr<scene::light_probe> sky_probe;
std::shared_ptr<scene::rectangle_light> area_light;
};
#endif // ANTKEEPER_TREADMILL_EXPERIMENT_STATE_HPP

+ 1
- 1
src/game/systems/render-system.cpp View File

@ -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);
}

+ 2
- 2
src/game/world.cpp View File

@ -363,9 +363,9 @@ void create_sun(::game& ctx)
ctx.sun_light = std::make_unique<scene::directional_light>();
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

Loading…
Cancel
Save