diff --git a/source/blender/io/usd/hydra/hydra_scene_delegate.cc b/source/blender/io/usd/hydra/hydra_scene_delegate.cc index aa42a694ea5b..a5d1a780f3de 100644 --- a/source/blender/io/usd/hydra/hydra_scene_delegate.cc +++ b/source/blender/io/usd/hydra/hydra_scene_delegate.cc @@ -5,6 +5,7 @@ #include +#include "DNA_light_types.h" #include "DNA_scene_types.h" #include "BLI_set.hh" @@ -238,6 +239,39 @@ void HydraSceneDelegate::clear() view3d = nullptr; } +bool HydraSceneDelegate::has_shadows() +{ + + bool has_shadows = false; + + DEGObjectIterSettings settings = {0}; + settings.depsgraph = depsgraph; + settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS; + DEGObjectIterData data = {0}; + data.settings = &settings; + data.graph = settings.depsgraph; + data.flag = settings.flags; + + ITER_BEGIN (DEG_iterator_objects_begin, + DEG_iterator_objects_next, + DEG_iterator_objects_end, + &data, + Object *, + object) + { + if (object->type == OB_LAMP) { + Light *light = (Light *)object->data; + has_shadows |= light->mode & LA_SHADOW; + if (has_shadows) { + break; + } + } + } + ITER_END; + + return has_shadows; +} + pxr::SdfPath HydraSceneDelegate::prim_id(ID *id, const char *prefix) const { /* Making id of object in form like _ */ diff --git a/source/blender/io/usd/hydra/hydra_scene_delegate.h b/source/blender/io/usd/hydra/hydra_scene_delegate.h index dc8a3ea704f2..798971dfae7c 100644 --- a/source/blender/io/usd/hydra/hydra_scene_delegate.h +++ b/source/blender/io/usd/hydra/hydra_scene_delegate.h @@ -90,6 +90,7 @@ class HydraSceneDelegate : public pxr::HdSceneDelegate { void populate(Depsgraph *depsgraph, View3D *v3d); void clear(); + bool has_shadows(); private: pxr::SdfPath prim_id(ID *id, const char *prefix) const; diff --git a/source/blender/io/usd/hydra/light.cc b/source/blender/io/usd/hydra/light.cc index 1380125dcce2..00dd5ec0e468 100644 --- a/source/blender/io/usd/hydra/light.cc +++ b/source/blender/io/usd/hydra/light.cc @@ -3,11 +3,15 @@ #include "light.h" +#include #include #include +#include +#include #include #include "DNA_light_types.h" +#include "DNA_scene_types.h" #include "BLI_math_rotation.h" @@ -15,6 +19,48 @@ namespace blender::io::hydra { +class ShadowMatrix : public pxr::HdxShadowMatrixComputation { + public: + ShadowMatrix() + { + _frustum = pxr::GfFrustum(); + } + + std::vector Compute(const pxr::GfVec4f &viewport, + pxr::CameraUtilConformWindowPolicy policy) override + { + return {_frustum.ComputeViewMatrix() * _frustum.ComputeProjectionMatrix()}; + } + + std::vector Compute(const pxr::CameraUtilFraming &framing, + pxr::CameraUtilConformWindowPolicy policy) override + { + return {_frustum.ComputeViewMatrix() * _frustum.ComputeProjectionMatrix()}; + } + + void set_projection_type(const pxr::GfFrustum::ProjectionType projection_type) + { + _frustum.SetProjectionType(projection_type); + } + + void set_near_far(const float near_dist, const float far_dist) + { + _frustum.SetNearFar(pxr::GfRange1d(near_dist, far_dist)); + } + + void set_transform(const pxr::GfMatrix4d &transform) + { + _frustum.Transform(transform); + } + + void set_window(const float x, const float y) + { + _frustum.SetWindow(pxr::GfRange2d(pxr::GfVec2d(-x, -y), pxr::GfVec2d(x, y))); + } + + pxr::GfFrustum _frustum; +}; + LightData::LightData(HydraSceneDelegate *scene_delegate, Object *object, pxr::SdfPath const &prim_id) @@ -92,9 +138,44 @@ void LightData::init() prim_type_ = prim_type(light); + write_shadow_params(); write_transform(); } +void LightData::write_shadow_params() +{ + /* Shadow section, only Sunlight is supported. + we verified if any of light's shadow is turned on, if yes shadow task will be added*/ + Light *light = (Light *)((Object *)id)->data; + bool use_shadow = (light->mode & LA_SHADOW) && light->type == LA_SUN; + data_[pxr::HdLightTokens->hasShadow] = use_shadow; + if (!use_shadow) { + return; + } + pxr::HdxShadowParams shadow_params = pxr::HdxShadowParams(); + + /* ShadowMatrix class is used to calculates shadow matrix from light frustum.*/ + ShadowMatrix *shadow_matrix = new ShadowMatrix(); + shadow_matrix->set_near_far(0.1, light->cascade_max_dist); + shadow_matrix->set_transform(gf_matrix_from_transform(((Object *)id)->object_to_world)); + + /* SetWindow sets size of projected shadow texture texture in + the approximate value is calculated using sun_angle property + 180 degrees is window size 1000 by 1000 */ + shadow_matrix->set_window(light->sun_angle * 0.5f / M_PI * 1000, + light->sun_angle * 0.5f / M_PI * 1000); + shadow_matrix->set_projection_type(pxr::GfFrustum::Orthographic); + shadow_params.enabled = use_shadow; + shadow_params.resolution = scene_delegate_->scene->eevee.shadow_cascade_size; + shadow_params.shadowMatrix = pxr::HdxShadowMatrixComputationSharedPtr(shadow_matrix); + shadow_params.bias = -1.0 * light->bias; + shadow_params.blur = light->cascade_fade; + + data_[pxr::HdLightTokens->shadowParams] = shadow_params; + data_[pxr::HdLightTokens->shadowCollection] = pxr::HdRprimCollection( + pxr::HdTokens->geometry, pxr::HdReprSelector(pxr::HdReprTokens->refined)); +} + void LightData::insert() { ID_LOGN(1, ""); @@ -123,8 +204,14 @@ void LightData::update() bits = pxr::HdLight::AllDirty; } else if (id->recalc & ID_RECALC_TRANSFORM) { - write_transform(); - bits = pxr::HdLight::DirtyTransform; + if (light->mode & LA_SHADOW) { + init(); + bits = pxr::HdLight::AllDirty; + } + else { + write_transform(); + bits = pxr::HdLight::DirtyTransform; + } } if (bits != pxr::HdChangeTracker::Clean) { scene_delegate_->GetRenderIndex().GetChangeTracker().MarkSprimDirty(prim_id, bits); diff --git a/source/blender/io/usd/hydra/light.h b/source/blender/io/usd/hydra/light.h index a5fe919777a5..d8cae3bfba0a 100644 --- a/source/blender/io/usd/hydra/light.h +++ b/source/blender/io/usd/hydra/light.h @@ -30,6 +30,7 @@ class LightData : public ObjectData { void remove() override; void update() override; + void write_shadow_params(); pxr::VtValue get_data(pxr::TfToken const &key) const override; protected: diff --git a/source/blender/render/hydra/engine.cc b/source/blender/render/hydra/engine.cc index d8ced6fb2bfd..e5849e5ea072 100644 --- a/source/blender/render/hydra/engine.cc +++ b/source/blender/render/hydra/engine.cc @@ -146,6 +146,9 @@ pxr::HdTaskSharedPtrVector Engine::tasks() #endif } res.push_back(light_tasks_delegate_->simple_task()); + if (hydra_scene_delegate_->has_shadows()) { + res.push_back(light_tasks_delegate_->shadow_task()); + } } res.push_back(render_task_delegate_->task()); return res; diff --git a/source/blender/render/hydra/final_engine.cc b/source/blender/render/hydra/final_engine.cc index e12b24608c1e..a084ae966e29 100644 --- a/source/blender/render/hydra/final_engine.cc +++ b/source/blender/render/hydra/final_engine.cc @@ -48,6 +48,7 @@ void FinalEngine::render() render_task_delegate_->set_viewport(pxr::GfVec4d(0, 0, width, height)); if (light_tasks_delegate_) { light_tasks_delegate_->set_viewport(pxr::GfVec4d(0, 0, width, height)); + light_tasks_delegate_->set_shadows(hydra_scene_delegate_->has_shadows()); } RenderResult *rr = RE_engine_get_result(bl_engine_); diff --git a/source/blender/render/hydra/light_tasks_delegate.cc b/source/blender/render/hydra/light_tasks_delegate.cc index 0f4ef1295724..67eff19c6065 100644 --- a/source/blender/render/hydra/light_tasks_delegate.cc +++ b/source/blender/render/hydra/light_tasks_delegate.cc @@ -14,6 +14,8 @@ LightTasksDelegate::LightTasksDelegate(pxr::HdRenderIndex *parent_index, GetRenderIndex().InsertTask(this, simple_task_id_); skydome_task_id_ = GetDelegateID().AppendElementString("skydomeTask"); GetRenderIndex().InsertTask(this, skydome_task_id_); + shadow_task_id_ = GetDelegateID().AppendElementString("shadowTask"); + GetRenderIndex().InsertTask(this, shadow_task_id_); CLOG_INFO(LOG_HYDRA_RENDER, 1, "%s", simple_task_id_.GetText()); CLOG_INFO(LOG_HYDRA_RENDER, 1, "%s", skydome_task_id_.GetText()); @@ -30,6 +32,9 @@ pxr::VtValue LightTasksDelegate::Get(pxr::SdfPath const &id, pxr::TfToken const else if (id == skydome_task_id_) { return pxr::VtValue(skydome_task_params_); } + else if (id == shadow_task_id_) { + return pxr::VtValue(shadow_task_params_); + } } return pxr::VtValue(); } @@ -39,6 +44,11 @@ pxr::HdTaskSharedPtr LightTasksDelegate::simple_task() return GetRenderIndex().GetTask(simple_task_id_); } +pxr::HdTaskSharedPtr LightTasksDelegate::shadow_task() +{ + return GetRenderIndex().GetTask(shadow_task_id_); +} + pxr::HdTaskSharedPtr LightTasksDelegate::skydome_task() { /* Note that this task is intended to be the first "Render Task", @@ -58,6 +68,23 @@ void LightTasksDelegate::set_camera(pxr::SdfPath const &camera_id) skydome_task_params_.camera = camera_id; GetRenderIndex().GetChangeTracker().MarkTaskDirty(skydome_task_id_, pxr::HdChangeTracker::DirtyParams); + + GetRenderIndex().GetChangeTracker().MarkTaskDirty(shadow_task_id_, + pxr::HdChangeTracker::DirtyParams); +} + +void LightTasksDelegate::set_shadows(bool const &enable_shadows) +{ + if (simple_task_params_.enableShadows == enable_shadows) { + return; + } + shadow_task_params_.depthBiasEnable = true; + simple_task_params_.enableShadows = enable_shadows; + GetRenderIndex().GetChangeTracker().MarkTaskDirty(simple_task_id_, + pxr::HdChangeTracker::DirtyParams); + + GetRenderIndex().GetChangeTracker().MarkTaskDirty(shadow_task_id_, + pxr::HdChangeTracker::DirtyParams); } void LightTasksDelegate::set_viewport(pxr::GfVec4d const &viewport) diff --git a/source/blender/render/hydra/light_tasks_delegate.h b/source/blender/render/hydra/light_tasks_delegate.h index d1131392d1c3..4b66df064eb0 100644 --- a/source/blender/render/hydra/light_tasks_delegate.h +++ b/source/blender/render/hydra/light_tasks_delegate.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include @@ -19,14 +20,18 @@ class LightTasksDelegate : public pxr::HdSceneDelegate { pxr::HdTaskSharedPtr simple_task(); pxr::HdTaskSharedPtr skydome_task(); + pxr::HdTaskSharedPtr shadow_task(); void set_camera(pxr::SdfPath const &camera_id); void set_viewport(pxr::GfVec4d const &viewport); + void set_shadows(bool const &enable_shadows); private: pxr::SdfPath simple_task_id_; pxr::SdfPath skydome_task_id_; + pxr::SdfPath shadow_task_id_; pxr::HdxSimpleLightTaskParams simple_task_params_; pxr::HdxRenderTaskParams skydome_task_params_; + pxr::HdxShadowTaskParams shadow_task_params_; }; } // namespace blender::render::hydra diff --git a/source/blender/render/hydra/viewport_engine.cc b/source/blender/render/hydra/viewport_engine.cc index be78e6ab437d..b4383e08d5a2 100644 --- a/source/blender/render/hydra/viewport_engine.cc +++ b/source/blender/render/hydra/viewport_engine.cc @@ -227,6 +227,7 @@ void ViewportEngine::render() render_task_delegate_->set_viewport(viewport); if (light_tasks_delegate_) { light_tasks_delegate_->set_viewport(viewport); + light_tasks_delegate_->set_shadows(hydra_scene_delegate_->has_shadows()); } render_task_delegate_->add_aov(pxr::HdAovTokens->color);