2026-08-04 18:32:37 +01:00
|
|
|
#include "HydraDirectionalShadowSourceSystem.h"
|
2026-07-28 00:26:04 +01:00
|
|
|
#include "../../engine/HydraEngine.h"
|
|
|
|
|
#include "../../camera/HydraCamera.h"
|
|
|
|
|
#include "../HydraECS.h"
|
2026-08-04 18:32:37 +01:00
|
|
|
#include "../components/HydraDirectionalShadowSourceComponent.h"
|
2026-07-28 00:26:04 +01:00
|
|
|
#include "../components/HydraPositionComponent.h"
|
|
|
|
|
#include "../components/HydraLightComponent.h"
|
|
|
|
|
|
|
|
|
|
#include "../../buffer/HydraShadowBuffer.h"
|
|
|
|
|
#include "../../buffer/HydraTextureBufferManager.h"
|
|
|
|
|
|
|
|
|
|
#include "../../scheduler/HydraTaskScheduler.h"
|
|
|
|
|
#include "../../task/buffer/HydraCreateGPUBufferTask.hpp"
|
|
|
|
|
#include "../../task/buffer/HydraUpdateWholeGPUBufferTask.hpp"
|
|
|
|
|
#include "../../task/buffer/HydraUpdatePartialGPUBufferTask.hpp"
|
|
|
|
|
#include "../../task/buffer/HydraCreateUnBoundTextureTask.hpp"
|
2026-08-04 17:39:07 +01:00
|
|
|
#include "../../task/renderer/HydraCreateCascadeShadowFrameBuffer.hpp"
|
2026-07-28 19:02:45 +01:00
|
|
|
#include "../../task/renderer/HydraCreateShadowFrameBuffer.hpp"
|
2026-07-28 00:26:04 +01:00
|
|
|
#include "../../actor/HydraActorManager.h"
|
|
|
|
|
|
2026-08-04 18:32:37 +01:00
|
|
|
void HydraDirectionalShadowSourceSystem::Initialise()
|
2026-07-25 16:40:34 +01:00
|
|
|
{
|
2026-07-28 00:26:04 +01:00
|
|
|
HydraTaskScheduler *task_scheduler = GetEngine()->TaskScheduler();
|
|
|
|
|
|
2026-08-03 22:34:52 +01:00
|
|
|
for(uint32_t i = 0; i < MAX_SHADOWS; i++)
|
|
|
|
|
{
|
|
|
|
|
m_available_shadows.push(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_shadows.resize(MAX_SHADOWS);
|
|
|
|
|
|
2026-07-28 00:26:04 +01:00
|
|
|
HydraID create_gpu_buffer_task_id = task_scheduler->CreateTask<HydraCreateGPUBufferTask>(HydraThreadAffinity::Render);
|
|
|
|
|
HydraCreateGPUBufferTask *task = static_cast<HydraCreateGPUBufferTask *>(task_scheduler->GetTask(create_gpu_buffer_task_id));
|
2026-08-04 18:32:37 +01:00
|
|
|
task->Intialise("ShadowBuffer", 1, MAX_SHADOWS * sizeof(HydraDirectionalShadowSourceComponent), &m_shadow_buffer_id, HYDRA_BUFFER_TYPE::HYDRA_SSBO_BUFFER);
|
2026-07-28 00:26:04 +01:00
|
|
|
task_scheduler->WaitForTask(create_gpu_buffer_task_id);
|
2026-07-25 16:40:34 +01:00
|
|
|
}
|
|
|
|
|
|
2026-08-04 18:32:37 +01:00
|
|
|
void HydraDirectionalShadowSourceSystem::InitialiseComponent(HydraID entity_id)
|
2026-07-28 19:02:45 +01:00
|
|
|
{
|
|
|
|
|
HydraEngine *engine = GetEngine();
|
|
|
|
|
HydraECS *ecs = engine->ECS();
|
|
|
|
|
HydraLightComponent &light_comp = ecs->GetComponent<HydraLightComponent>(entity_id);
|
2026-08-03 22:34:52 +01:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
assert(m_available_shadows.size() > 0 && "Run out of shadows");
|
|
|
|
|
uint32_t shad_id = m_available_shadows.front();
|
|
|
|
|
m_available_shadows.pop();
|
|
|
|
|
light_comp.shadow_map_id = shad_id;
|
|
|
|
|
light_comp.shadow_caster = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-04 22:40:48 +01:00
|
|
|
|
|
|
|
|
_InitialiseShadowMap(entity_id);
|
2026-08-04 17:39:07 +01:00
|
|
|
|
2026-07-25 16:40:34 +01:00
|
|
|
}
|
2026-07-28 00:26:04 +01:00
|
|
|
|
2026-08-04 18:32:37 +01:00
|
|
|
void HydraDirectionalShadowSourceSystem::UpdateSystem(float delta_t_seconds)
|
2026-07-28 00:26:04 +01:00
|
|
|
{
|
2026-07-28 19:02:45 +01:00
|
|
|
HydraEngine *engine = GetEngine();
|
|
|
|
|
HydraECS *ecs = engine->ECS();
|
2026-08-04 18:32:37 +01:00
|
|
|
std::vector<HydraDirectionalShadowSourceComponent> shadows;
|
2026-07-28 19:02:45 +01:00
|
|
|
for (HydraID entity_id : Entities)
|
2026-07-28 00:26:04 +01:00
|
|
|
{
|
|
|
|
|
|
2026-07-28 19:02:45 +01:00
|
|
|
HydraLightComponent &light_comp = ecs->GetComponent<HydraLightComponent>(entity_id);
|
2026-08-04 22:40:48 +01:00
|
|
|
|
|
|
|
|
_UpdateShadowMap(entity_id);
|
2026-07-28 00:26:04 +01:00
|
|
|
|
2026-08-04 18:32:37 +01:00
|
|
|
HydraDirectionalShadowSourceComponent shad_comp = ecs->GetComponent<HydraDirectionalShadowSourceComponent>(entity_id);
|
2026-08-03 22:34:52 +01:00
|
|
|
m_shadows[light_comp.shadow_map_id] = shad_comp;
|
2026-07-28 00:26:04 +01:00
|
|
|
}
|
2026-08-03 22:34:52 +01:00
|
|
|
_WriteToGPU();
|
2026-07-28 00:26:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-08-04 22:40:48 +01:00
|
|
|
void HydraDirectionalShadowSourceSystem::_UpdateShadowMap(HydraID entity_id)
|
2026-07-28 00:26:04 +01:00
|
|
|
{
|
2026-07-28 19:02:45 +01:00
|
|
|
HydraEngine *engine = GetEngine();
|
|
|
|
|
HydraECS *ecs = engine->ECS();
|
2026-07-28 00:26:04 +01:00
|
|
|
HydraPositionComponent pos_comp = ecs->GetComponent<HydraPositionComponent>(entity_id);
|
2026-08-04 18:32:37 +01:00
|
|
|
HydraDirectionalShadowSourceComponent &shad_comp = ecs->GetComponent<HydraDirectionalShadowSourceComponent>(entity_id);
|
2026-07-28 00:26:04 +01:00
|
|
|
|
2026-08-04 22:40:48 +01:00
|
|
|
float view_size = 4.0f;
|
2026-08-04 20:06:37 +01:00
|
|
|
float view_near = 0.1f;
|
2026-08-04 22:40:48 +01:00
|
|
|
float view_far = 4.0f;
|
2026-08-04 20:06:37 +01:00
|
|
|
|
|
|
|
|
glm::mat4 light_rot = glm::eulerAngleXYZ(pos_comp.orientation.x, pos_comp.orientation.y, pos_comp.orientation.z);
|
|
|
|
|
glm::vec3 light_dir = glm::normalize(glm::vec3(light_rot * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f)));
|
2026-07-28 00:26:04 +01:00
|
|
|
|
2026-07-28 19:02:45 +01:00
|
|
|
glm::vec3 camera_pos = GetEngine()->Camera()->GetPosition();
|
2026-08-04 18:32:37 +01:00
|
|
|
|
2026-07-28 19:02:45 +01:00
|
|
|
for (uint32_t i = 0; i < 6; i++)
|
|
|
|
|
{
|
2026-08-04 22:40:48 +01:00
|
|
|
glm::vec3 light_pos = camera_pos;//- (light_dir * 2.0f);
|
2026-08-04 20:06:37 +01:00
|
|
|
glm::vec3 target_pos = light_pos + light_dir;
|
|
|
|
|
glm::vec3 up_vector = glm::vec3(0.0f, 1.0f, 0.0f);
|
2026-07-28 00:26:04 +01:00
|
|
|
|
2026-08-04 20:06:37 +01:00
|
|
|
if (glm::abs(glm::dot(light_dir, up_vector)) > 0.99f)
|
|
|
|
|
{
|
|
|
|
|
up_vector = glm::vec3(1.0f, 0.0f, 0.0f); // Prevent gimbal lock
|
|
|
|
|
}
|
2026-07-28 00:26:04 +01:00
|
|
|
|
2026-08-04 20:06:37 +01:00
|
|
|
glm::mat4 view = glm::lookAt(light_pos, target_pos, up_vector);
|
|
|
|
|
glm::mat4 proj = glm::ortho(-view_size, view_size, -view_size, view_size, view_near, view_far);
|
2026-07-28 00:26:04 +01:00
|
|
|
|
2026-08-04 20:06:37 +01:00
|
|
|
// Save data to component
|
|
|
|
|
shad_comp.far_plane[i] = view_far;
|
|
|
|
|
shad_comp.near_plane[i] = view_near;
|
|
|
|
|
shad_comp.light_space_proj[i] = proj;
|
|
|
|
|
shad_comp.light_space_view[i] = view;
|
|
|
|
|
|
|
|
|
|
// Scale bounds exponentially for the next cascade tier
|
2026-08-04 22:40:48 +01:00
|
|
|
view_size *= 3.0f;
|
|
|
|
|
view_far *= 3.0f;
|
2026-07-28 19:02:45 +01:00
|
|
|
}
|
2026-07-28 00:26:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-08-04 20:06:37 +01:00
|
|
|
|
2026-08-04 22:40:48 +01:00
|
|
|
void HydraDirectionalShadowSourceSystem::_InitialiseShadowMap(HydraID entity_id)
|
2026-07-28 00:26:04 +01:00
|
|
|
{
|
2026-07-28 19:02:45 +01:00
|
|
|
HydraEngine *engine = GetEngine();
|
|
|
|
|
HydraECS *ecs = engine->ECS();
|
|
|
|
|
HydraTextureBufferManager *tex_man = engine->TextureBufferManager();
|
2026-08-04 18:32:37 +01:00
|
|
|
HydraDirectionalShadowSourceComponent &shad_comp = ecs->GetComponent<HydraDirectionalShadowSourceComponent>(entity_id);
|
|
|
|
|
HydraLightComponent &light_comp = ecs->GetComponent<HydraLightComponent>(entity_id);
|
2026-08-04 20:06:37 +01:00
|
|
|
|
2026-07-28 00:26:04 +01:00
|
|
|
shad_comp.entity_id = entity_id;
|
|
|
|
|
shad_comp.cascade_count = 6;
|
2026-08-04 18:32:37 +01:00
|
|
|
|
2026-07-28 00:26:04 +01:00
|
|
|
HydraTaskScheduler *task_scheduler = GetEngine()->TaskScheduler();
|
|
|
|
|
|
2026-08-03 22:34:52 +01:00
|
|
|
uint32_t depth_texture_id = 0;
|
2026-08-04 17:39:07 +01:00
|
|
|
HydraID create_framebuffer_task_id = task_scheduler->CreateTask<HydraCreateCascadeShadowFrameBuffer>(HydraThreadAffinity::Render);
|
|
|
|
|
HydraCreateCascadeShadowFrameBuffer *fb_task = static_cast<HydraCreateCascadeShadowFrameBuffer *>(task_scheduler->GetTask(create_framebuffer_task_id));
|
2026-08-03 22:34:52 +01:00
|
|
|
fb_task->Initialise(&shad_comp.shadow_texture_id, &depth_texture_id, &shad_comp.frame_buffer_id);
|
|
|
|
|
|
2026-07-28 19:02:45 +01:00
|
|
|
task_scheduler->WaitForTask(create_framebuffer_task_id);
|
2026-08-03 22:34:52 +01:00
|
|
|
shad_comp.shadow_texture_id = depth_texture_id;
|
2026-07-28 00:26:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-08-04 18:32:37 +01:00
|
|
|
void HydraDirectionalShadowSourceSystem::_WriteToGPU()
|
2026-07-28 00:26:04 +01:00
|
|
|
{
|
2026-07-28 19:02:45 +01:00
|
|
|
HydraEngine *engine = GetEngine();
|
|
|
|
|
HydraECS *ecs = engine->ECS();
|
|
|
|
|
|
2026-08-03 22:34:52 +01:00
|
|
|
void *buffer = static_cast<void *>(m_shadows.data());
|
2026-07-28 00:26:04 +01:00
|
|
|
HydraTaskScheduler *task_scheduler = GetEngine()->TaskScheduler();
|
|
|
|
|
|
2026-08-03 22:34:52 +01:00
|
|
|
HydraID update_buffer_task_id = task_scheduler->CreateTask<HydraUpdateWholeGPUBufferTask>(HydraThreadAffinity::Render);
|
|
|
|
|
HydraUpdateWholeGPUBufferTask *task = static_cast<HydraUpdateWholeGPUBufferTask *>(task_scheduler->GetTask(update_buffer_task_id));
|
|
|
|
|
task->Intialise(m_shadow_buffer_id, buffer);
|
2026-07-28 00:26:04 +01:00
|
|
|
task_scheduler->WaitForTask(update_buffer_task_id);
|
|
|
|
|
}
|