mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-18 00:27:02 +08:00
feat(renderer): smooth shadow sun direction transitions using quantized directions and slerp
This commit is contained in:
@@ -45,6 +45,7 @@ private:
|
|||||||
static constexpr float SUN_SIZE = 50.0f;
|
static constexpr float SUN_SIZE = 50.0f;
|
||||||
static constexpr float MOON_SIZE = 50.0f;
|
static constexpr float MOON_SIZE = 50.0f;
|
||||||
static constexpr float DEPTH_MAP_SIZE = 4096.0f;
|
static constexpr float DEPTH_MAP_SIZE = 4096.0f;
|
||||||
|
static constexpr float ANGLE_STEP_DEG = 0.5f;
|
||||||
float m_ambient_strength = 0.1f;
|
float m_ambient_strength = 0.1f;
|
||||||
|
|
||||||
const Camera& m_camera;
|
const Camera& m_camera;
|
||||||
@@ -93,6 +94,12 @@ private:
|
|||||||
glm::mat4 m_ui_m_matrix;
|
glm::mat4 m_ui_m_matrix;
|
||||||
std::unordered_map<std::size_t, Shader> m_shaders;
|
std::unordered_map<std::size_t, Shader> m_shaders;
|
||||||
|
|
||||||
|
glm::vec3 m_blend_from_sundir;
|
||||||
|
glm::vec3 m_blend_to_sundir;
|
||||||
|
float m_blend_t = 1.0f;
|
||||||
|
bool m_blend_initialized = false;
|
||||||
|
static constexpr float BLEND_DURATION = 0.15f;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
0 - quad vao
|
0 - quad vao
|
||||||
1 - sky vao
|
1 - sky vao
|
||||||
@@ -114,6 +121,11 @@ private:
|
|||||||
void render_world();
|
void render_world();
|
||||||
void render_underwater();
|
void render_underwater();
|
||||||
void render_dev_panel();
|
void render_dev_panel();
|
||||||
|
|
||||||
|
glm::vec3 quantize_sun_direction(const glm::vec3& sundir,
|
||||||
|
float angle_step_deg) const;
|
||||||
|
glm::vec3 get_smoothed_shadow_sundir(const glm::vec3& raw_shadow_sundir,
|
||||||
|
float dt);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -12,6 +12,8 @@ float smootherstep(float edge0, float edge1, float x);
|
|||||||
bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents,
|
bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents,
|
||||||
const std::vector<glm::vec4>& planes);
|
const std::vector<glm::vec4>& planes);
|
||||||
float deterministic_random(int x, int z, uint64_t seed);
|
float deterministic_random(int x, int z, uint64_t seed);
|
||||||
|
glm::vec3 slerp(const glm::vec3& from, const glm::vec3& to, float t);
|
||||||
|
|
||||||
} // namespace Math
|
} // namespace Math
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Cubed/tools/cubed_hash.hpp"
|
#include "Cubed/tools/cubed_hash.hpp"
|
||||||
|
|
||||||
#include <execution>
|
#include <execution>
|
||||||
|
#include <glm/gtc/constants.hpp>
|
||||||
#include <numbers>
|
#include <numbers>
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
@@ -1047,7 +1048,7 @@ glm::vec3 World::sunlight_dir() const {
|
|||||||
glm::vec3 dir{cos(altitude) * cos(azimuth), sin(altitude),
|
glm::vec3 dir{cos(altitude) * cos(azimuth), sin(altitude),
|
||||||
cos(altitude) * sin(azimuth)};
|
cos(altitude) * sin(azimuth)};
|
||||||
|
|
||||||
return glm::normalize(dir);
|
return glm::normalize(-dir);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
Renderer::Renderer(const Camera& camera, World& world,
|
Renderer::Renderer(const Camera& camera, World& world,
|
||||||
@@ -515,10 +516,14 @@ void Renderer::render_world() {
|
|||||||
glm::vec3 center = cam_pos + cam_fwd * (half_extent * 0.5f);
|
glm::vec3 center = cam_pos + cam_fwd * (half_extent * 0.5f);
|
||||||
|
|
||||||
glm::vec3 sundir = glm::normalize(m_world.sunlight_dir());
|
glm::vec3 sundir = glm::normalize(m_world.sunlight_dir());
|
||||||
glm::vec3 up =
|
glm::vec3 raw_shadow_sundir =
|
||||||
fabs(sundir.y) > 0.99f ? glm::vec3(0, 0, 1) : glm::vec3(0, 1, 0);
|
quantize_sun_direction(sundir, ANGLE_STEP_DEG);
|
||||||
|
glm::vec3 shadow_sundir =
|
||||||
|
get_smoothed_shadow_sundir(raw_shadow_sundir, m_delta_time);
|
||||||
|
glm::vec3 up = fabs(shadow_sundir.y) > 0.99f ? glm::vec3(0, 0, 1)
|
||||||
|
: glm::vec3(0, 1, 0);
|
||||||
|
|
||||||
glm::mat4 light_basis = glm::lookAt(glm::vec3(0.0f), sundir, up);
|
glm::mat4 light_basis = glm::lookAt(glm::vec3(0.0f), shadow_sundir, up);
|
||||||
float texels_per_unit = DEPTH_MAP_SIZE / (half_extent * 2.0f);
|
float texels_per_unit = DEPTH_MAP_SIZE / (half_extent * 2.0f);
|
||||||
glm::vec3 ls_center = glm::vec3(light_basis * glm::vec4(center, 1.0f));
|
glm::vec3 ls_center = glm::vec3(light_basis * glm::vec4(center, 1.0f));
|
||||||
ls_center.x =
|
ls_center.x =
|
||||||
@@ -531,7 +536,7 @@ void Renderer::render_world() {
|
|||||||
float distance = half_extent * 1.5f;
|
float distance = half_extent * 1.5f;
|
||||||
float near_plane = 1.0f;
|
float near_plane = 1.0f;
|
||||||
float far_plane = distance + half_extent * 2.0f;
|
float far_plane = distance + half_extent * 2.0f;
|
||||||
glm::vec3 light_pos = snapped_center - sundir * distance;
|
glm::vec3 light_pos = snapped_center - shadow_sundir * distance;
|
||||||
glm::mat4 light_view = glm::lookAt(light_pos, snapped_center, up);
|
glm::mat4 light_view = glm::lookAt(light_pos, snapped_center, up);
|
||||||
glm::mat4 light_projection =
|
glm::mat4 light_projection =
|
||||||
glm::ortho(-half_extent, half_extent, -half_extent, half_extent,
|
glm::ortho(-half_extent, half_extent, -half_extent, half_extent,
|
||||||
@@ -757,6 +762,53 @@ void Renderer::render_dev_panel() {
|
|||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 Renderer::quantize_sun_direction(const glm::vec3& sundir,
|
||||||
|
float angle_step_deg) const {
|
||||||
|
float elevation = std::asin(glm::clamp(sundir.y, -1.0f, 1.0f));
|
||||||
|
float azimuth = std::atan2(sundir.z, sundir.x);
|
||||||
|
|
||||||
|
float step = glm::radians(angle_step_deg);
|
||||||
|
|
||||||
|
float quantized_elevation = std::round(elevation / step) * step;
|
||||||
|
float quantized_azimuth = std::round(azimuth / step) * step;
|
||||||
|
|
||||||
|
glm::vec3 quantized_dir;
|
||||||
|
quantized_dir.x =
|
||||||
|
std::cos(quantized_elevation) * std::cos(quantized_azimuth);
|
||||||
|
quantized_dir.z =
|
||||||
|
std::cos(quantized_elevation) * std::sin(quantized_azimuth);
|
||||||
|
quantized_dir.y = std::sin(quantized_elevation);
|
||||||
|
|
||||||
|
return glm::normalize(quantized_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3
|
||||||
|
Renderer::get_smoothed_shadow_sundir(const glm::vec3& raw_shadow_sundir,
|
||||||
|
float dt) {
|
||||||
|
if (!m_blend_initialized) {
|
||||||
|
|
||||||
|
m_blend_from_sundir = raw_shadow_sundir;
|
||||||
|
m_blend_to_sundir = raw_shadow_sundir;
|
||||||
|
m_blend_t = 1.0f;
|
||||||
|
m_blend_initialized = true;
|
||||||
|
return raw_shadow_sundir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw_shadow_sundir != m_blend_to_sundir) {
|
||||||
|
glm::vec3 current_displayed = glm::normalize(
|
||||||
|
Math::slerp(m_blend_from_sundir, m_blend_to_sundir, m_blend_t));
|
||||||
|
|
||||||
|
m_blend_from_sundir = current_displayed;
|
||||||
|
m_blend_to_sundir = raw_shadow_sundir;
|
||||||
|
m_blend_t = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blend_t = glm::min(m_blend_t + dt / BLEND_DURATION, 1.0f);
|
||||||
|
|
||||||
|
return glm::normalize(
|
||||||
|
Math::slerp(m_blend_from_sundir, m_blend_to_sundir, m_blend_t));
|
||||||
|
}
|
||||||
|
|
||||||
float& Renderer::ambient_strength() { return m_ambient_strength; }
|
float& Renderer::ambient_strength() { return m_ambient_strength; }
|
||||||
bool& Renderer::discard_transparent() { return m_discard_tranparent; }
|
bool& Renderer::discard_transparent() { return m_discard_tranparent; }
|
||||||
bool& Renderer::shader_on() { return m_shader_on; }
|
bool& Renderer::shader_on() { return m_shader_on; }
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include "Cubed/tools/math_tools.hpp"
|
#include "Cubed/tools/math_tools.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
namespace Math {
|
namespace Math {
|
||||||
@@ -65,6 +67,39 @@ float deterministic_random(int x, int z, uint64_t seed) {
|
|||||||
h = h * 6364136223846793005ULL + (uint64_t)z;
|
h = h * 6364136223846793005ULL + (uint64_t)z;
|
||||||
return (float)(h >> 40) / (float)(1 << 24);
|
return (float)(h >> 40) / (float)(1 << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 slerp(const glm::vec3& from, const glm::vec3& to, float t) {
|
||||||
|
|
||||||
|
float cos_theta = glm::clamp(glm::dot(from, to), -1.0f, 1.0f);
|
||||||
|
|
||||||
|
if (cos_theta > 0.9995f) {
|
||||||
|
return glm::normalize(glm::mix(from, to, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cos_theta < -0.9995f) {
|
||||||
|
|
||||||
|
glm::vec3 axis = (std::fabs(from.x) < 0.9f)
|
||||||
|
? glm::vec3(1.0f, 0.0f, 0.0f)
|
||||||
|
: glm::vec3(0.0f, 1.0f, 0.0f);
|
||||||
|
glm::vec3 ortho = glm::normalize(glm::cross(from, axis));
|
||||||
|
|
||||||
|
float angle = glm::pi<float>() * t;
|
||||||
|
|
||||||
|
glm::vec3 rotated =
|
||||||
|
from * std::cos(angle) + glm::cross(ortho, from) * std::sin(angle);
|
||||||
|
|
||||||
|
return glm::normalize(rotated);
|
||||||
|
}
|
||||||
|
|
||||||
|
float theta = std::acos(cos_theta);
|
||||||
|
float sin_theta = std::sin(theta);
|
||||||
|
|
||||||
|
float a = std::sin((1.0f - t) * theta) / sin_theta;
|
||||||
|
float b = std::sin(t * theta) / sin_theta;
|
||||||
|
|
||||||
|
return glm::normalize(a * from + b * to);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Math
|
} // namespace Math
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
Reference in New Issue
Block a user