diff --git a/scripts/startup/bl_ui/properties_render.py b/scripts/startup/bl_ui/properties_render.py index 912e0be9ac14..a83880182bcf 100644 --- a/scripts/startup/bl_ui/properties_render.py +++ b/scripts/startup/bl_ui/properties_render.py @@ -950,6 +950,25 @@ class RENDER_PT_simplify_greasepencil(RenderButtonsPanel, Panel, GreasePencilSim bl_options = {'DEFAULT_CLOSED'} +class RENDER_PT_hydra_debug(RenderButtonsPanel, Panel): + bl_label = "Hydra Debug" + bl_options = {'DEFAULT_CLOSED'} + bl_order = 200 + COMPAT_ENGINES = {'HYDRA_STORM'} + + @classmethod + def poll(cls, context): + prefs = context.preferences + return (context.engine in cls.COMPAT_ENGINES) and prefs.view.show_developer_ui + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + hydra = context.scene.hydra + layout.prop(hydra, "export_method") + + classes = ( RENDER_PT_context, RENDER_PT_eevee_sampling, @@ -985,6 +1004,7 @@ classes = ( RENDER_PT_opengl_color, RENDER_PT_opengl_options, RENDER_PT_opengl_film, + RENDER_PT_hydra_debug, RENDER_PT_color_management, RENDER_PT_color_management_curves, RENDER_PT_simplify, diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index e1f12fbe2389..ea9b61a2200e 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -93,6 +93,7 @@ set(SRC intern/usd_reader_volume.cc intern/usd_reader_xform.cc + usd.hh usd.h intern/usd_asset_utils.h diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc index 1b3db7e3460d..5bda033d01d0 100644 --- a/source/blender/io/usd/intern/usd_capi_export.cc +++ b/source/blender/io/usd/intern/usd_capi_export.cc @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "usd.h" +#include "usd.hh" #include "usd_hierarchy_iterator.h" #include @@ -198,67 +199,41 @@ static bool perform_usdz_conversion(const ExportJobData *data) return true; } -static void export_startjob(void *customdata, - /* Cannot be const, this function implements wm_jobs_start_callback. - * NOLINTNEXTLINE: readability-non-const-parameter. */ - bool *stop, - bool *do_update, - float *progress) +static pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms, + Depsgraph *depsgraph, + const char *filepath, + bool *stop, + bool *do_update, + float *progress) { - ExportJobData *data = static_cast(customdata); - data->export_ok = false; - data->start_time = timeit::Clock::now(); - - G.is_rendering = true; - if (data->wm) { - WM_set_locked_interface(data->wm, true); - } - G.is_break = false; - - /* Construct the depsgraph for exporting. */ - Scene *scene = DEG_get_input_scene(data->depsgraph); - if (data->params.visible_objects_only) { - DEG_graph_build_from_view_layer(data->depsgraph); - } - else { - DEG_graph_build_for_all_objects(data->depsgraph); - } - BKE_scene_graph_update_tagged(data->depsgraph, data->bmain); - - *progress = 0.0f; - *do_update = true; - - /* For restoring the current frame after exporting animation is done. */ - const int orig_frame = scene->r.cfra; - - pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(data->unarchived_filepath); + pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(filepath); if (!usd_stage) { - /* This happens when the USD JSON files cannot be found. When that happens, - * the USD library doesn't know it has the functionality to write USDA and - * USDC files, and creating a new UsdStage fails. */ - WM_reportf(RPT_ERROR, - "USD Export: unable to find suitable USD plugin to write %s", - data->unarchived_filepath); - return; + return usd_stage; } - usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z)); + Scene *scene = DEG_get_input_scene(depsgraph); + Main *bmain = DEG_get_bmain(depsgraph); + usd_stage->SetMetadata(pxr::UsdGeomTokens->metersPerUnit, double(scene->unit.scale_length)); usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender v") + BKE_blender_version_string()); /* Set up the stage for animated data. */ - if (data->params.export_animation) { + if (params.export_animation) { usd_stage->SetTimeCodesPerSecond(FPS); usd_stage->SetStartTimeCode(scene->r.sfra); usd_stage->SetEndTimeCode(scene->r.efra); } - ensure_root_prim(usd_stage, data->params); + /* For restoring the current frame after exporting animation is done. */ + const int orig_frame = scene->r.cfra; - USDHierarchyIterator iter(data->bmain, data->depsgraph, usd_stage, data->params); + usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z)); + ensure_root_prim(usd_stage, params); - if (data->params.export_animation) { + USDHierarchyIterator iter(bmain, depsgraph, usd_stage, params); + + if (params.export_animation) { /* Writing the animated frames is not 100% of the work, but it's our best guess. */ float progress_per_frame = 1.0f / std::max(1, (scene->r.efra - scene->r.sfra + 1)); @@ -270,13 +245,17 @@ static void export_startjob(void *customdata, /* Update the scene for the next frame to render. */ scene->r.cfra = int(frame); scene->r.subframe = frame - scene->r.cfra; - BKE_scene_graph_update_for_newframe(data->depsgraph); + BKE_scene_graph_update_for_newframe(depsgraph); iter.set_export_frame(frame); iter.iterate_and_write(); - *progress += progress_per_frame; - *do_update = true; + if (progress) { + *progress += progress_per_frame; + } + if (do_update) { + *do_update = true; + } } } else { @@ -296,14 +275,65 @@ static void export_startjob(void *customdata, } } - usd_stage->GetRootLayer()->Save(); - /* Finish up by going back to the keyframe that was current before we started. */ if (scene->r.cfra != orig_frame) { scene->r.cfra = orig_frame; - BKE_scene_graph_update_for_newframe(data->depsgraph); + BKE_scene_graph_update_for_newframe(depsgraph); } + return usd_stage; +} + +pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms, + Depsgraph *depsgraph, + const char *filepath) +{ + return export_to_stage(params, depsgraph, filepath, nullptr, nullptr, nullptr); +} + +static void export_startjob(void *customdata, + /* Cannot be const, this function implements wm_jobs_start_callback. + * NOLINTNEXTLINE: readability-non-const-parameter. */ + bool *stop, + bool *do_update, + float *progress) +{ + ExportJobData *data = static_cast(customdata); + data->export_ok = false; + data->start_time = timeit::Clock::now(); + + G.is_rendering = true; + if (data->wm) { + WM_set_locked_interface(data->wm, true); + } + G.is_break = false; + + /* Construct the depsgraph for exporting. */ + if (data->params.visible_objects_only) { + DEG_graph_build_from_view_layer(data->depsgraph); + } + else { + DEG_graph_build_for_all_objects(data->depsgraph); + } + BKE_scene_graph_update_tagged(data->depsgraph, data->bmain); + + *progress = 0.0f; + *do_update = true; + + pxr::UsdStageRefPtr usd_stage = export_to_stage( + data->params, data->depsgraph, data->unarchived_filepath, stop, do_update, progress); + if (!usd_stage) { + /* This happens when the USD JSON files cannot be found. When that happens, + * the USD library doesn't know it has the functionality to write USDA and + * USDC files, and creating a new UsdStage fails. */ + WM_reportf(RPT_ERROR, + "USD Export: unable to find suitable USD plugin to write %s", + data->unarchived_filepath); + return; + } + + usd_stage->GetRootLayer()->Save(); + if (data->targets_usdz()) { bool usd_conversion_success = perform_usdz_conversion(data); if (!usd_conversion_success) { diff --git a/source/blender/io/usd/usd.hh b/source/blender/io/usd/usd.hh new file mode 100644 index 000000000000..44c9dd3d1add --- /dev/null +++ b/source/blender/io/usd/usd.hh @@ -0,0 +1,18 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include + +struct Depsgraph; +struct USDExportParams; + +namespace blender::io::usd { + +pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms, + Depsgraph *depsgraph, + const char *filepath); + +}; diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index 63eecd2829e3..aef051547960 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -227,6 +227,11 @@ SCE_EEVEE_SSR_HALF_RESOLUTION | SCE_EEVEE_SHADOW_SOFT, \ } +#define _DNA_DEFAULT_SceneHydra \ + { \ + .export_method = SCE_HYDRA_EXPORT_HYDRA, \ + } + #define _DNA_DEFAULT_Scene \ { \ .cursor = _DNA_DEFAULT_View3DCursor, \ @@ -240,6 +245,8 @@ .safe_areas = _DNA_DEFAULT_DisplaySafeAreas, \ \ .eevee = _DNA_DEFAULT_SceneEEVEE, \ + \ + .hydra = _DNA_DEFAULT_SceneHydra, \ } /** \} */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index bf64b1737d7c..3c72864e613c 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1883,6 +1883,11 @@ typedef struct SceneGpencil { char _pad[4]; } SceneGpencil; +typedef struct SceneHydra { + int export_method; + int _pad0; +} SceneHydra; + /** \} */ /* -------------------------------------------------------------------- */ @@ -2029,6 +2034,7 @@ typedef struct Scene { struct SceneDisplay display; struct SceneEEVEE eevee; struct SceneGpencil grease_pencil_settings; + struct SceneHydra hydra; } Scene; /** \} */ @@ -2830,6 +2836,13 @@ enum { SCE_DISPLAY_AA_SAMPLES_32 = 32, }; +/** #SceneHydra->export_method */ + +enum { + SCE_HYDRA_EXPORT_HYDRA = 0, + SCE_HYDRA_EXPORT_USD = 1, +}; + /** \} */ #ifdef __cplusplus diff --git a/source/blender/makesrna/intern/rna_scene.cc b/source/blender/makesrna/intern/rna_scene.cc index 36a9c43f79eb..9d8ee188d93e 100644 --- a/source/blender/makesrna/intern/rna_scene.cc +++ b/source/blender/makesrna/intern/rna_scene.cc @@ -1197,6 +1197,11 @@ static char *rna_SceneGpencil_path(const PointerRNA * /*ptr*/) return BLI_strdup("grease_pencil_settings"); } +static char *rna_SceneHydra_path(const PointerRNA * /*ptr*/) +{ + return BLI_strdup("hydra"); +} + static int rna_RenderSettings_stereoViews_skip(CollectionPropertyIterator *iter, void * /*data*/) { ListBaseIterator *internal = &iter->internal.listbase; @@ -7974,6 +7979,36 @@ static void rna_def_scene_gpencil(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr); } +static void rna_def_scene_hydra(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static const EnumPropertyItem hydra_export_method_items[] = { + {SCE_HYDRA_EXPORT_HYDRA, + "HYDRA", + 0, + "Hydra", + "Fast interactive editing through native Hydra integration"}, + {SCE_HYDRA_EXPORT_USD, + "USD", + 0, + "USD", + "Export scene through USD file, for accurate comparison with USD file export"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + srna = RNA_def_struct(brna, "SceneHydra", nullptr); + RNA_def_struct_path_func(srna, "rna_SceneHydra_path"); + RNA_def_struct_ui_text(srna, "Scene Hydra", "Scene Hydra render engine settings"); + + prop = RNA_def_property(srna, "export_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, hydra_export_method_items); + RNA_def_property_ui_text( + prop, "Export Method", "How to export the Blender scene to the Hydra render engine"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr); +} + void RNA_def_scene(BlenderRNA *brna) { StructRNA *srna; @@ -8467,6 +8502,11 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_struct_type(prop, "SceneGpencil"); RNA_def_property_ui_text(prop, "Grease Pencil", "Grease Pencil settings for the scene"); + /* Hydra */ + prop = RNA_def_property(srna, "hydra", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "SceneHydra"); + RNA_def_property_ui_text(prop, "Hydra", "Hydra settings for the scene"); + /* Nestled Data. */ /* *** Non-Animated *** */ RNA_define_animate_sdna(false); @@ -8485,6 +8525,7 @@ void RNA_def_scene(BlenderRNA *brna) rna_def_display_safe_areas(brna); rna_def_scene_display(brna); rna_def_scene_eevee(brna); + rna_def_scene_hydra(brna); rna_def_view_layer_aov(brna); rna_def_view_layer_lightgroup(brna); rna_def_view_layer_eevee(brna); diff --git a/source/blender/render/hydra/CMakeLists.txt b/source/blender/render/hydra/CMakeLists.txt index 6dc9daadc19c..3da25f21f4b0 100644 --- a/source/blender/render/hydra/CMakeLists.txt +++ b/source/blender/render/hydra/CMakeLists.txt @@ -42,6 +42,7 @@ set(INC ../../depsgraph ../../blenkernel ../../imbuf + ../../io/usd ../../gpu ../../gpu/intern ../../python/intern @@ -90,30 +91,33 @@ set(SRC simple_light_task_delegate.cc simple_light_task_delegate.h - scene_delegate/blender_scene_delegate.h scene_delegate/blender_scene_delegate.cc - scene_delegate/id.h - scene_delegate/id.cc - scene_delegate/object.h - scene_delegate/object.cc - scene_delegate/material.h - scene_delegate/material.cc - scene_delegate/mesh.h - scene_delegate/mesh.cc - scene_delegate/curves.h + scene_delegate/blender_scene_delegate.h scene_delegate/curves.cc - scene_delegate/mtlx_hydra_adapter.h - scene_delegate/mtlx_hydra_adapter.cc - scene_delegate/light.h - scene_delegate/light.cc - scene_delegate/world.h - scene_delegate/world.cc - scene_delegate/instancer.h - scene_delegate/instancer.cc - scene_delegate/image.h + scene_delegate/curves.h + scene_delegate/id.cc + scene_delegate/id.h scene_delegate/image.cc - scene_delegate/volume.h + scene_delegate/image.h + scene_delegate/instancer.cc + scene_delegate/instancer.h + scene_delegate/light.cc + scene_delegate/light.h + scene_delegate/material.cc + scene_delegate/material.h + scene_delegate/mesh.cc + scene_delegate/mesh.h + scene_delegate/mtlx_hydra_adapter.cc + scene_delegate/mtlx_hydra_adapter.h + scene_delegate/object.cc + scene_delegate/object.h + scene_delegate/settings.h + scene_delegate/usd_scene_delegate.cc + scene_delegate/usd_scene_delegate.hh scene_delegate/volume.cc + scene_delegate/volume.h + scene_delegate/world.cc + scene_delegate/world.h ) blender_add_lib(bf_render_hydra "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/render/hydra/engine.cc b/source/blender/render/hydra/engine.cc index 6db6920a31a2..618a7b96072d 100644 --- a/source/blender/render/hydra/engine.cc +++ b/source/blender/render/hydra/engine.cc @@ -9,8 +9,11 @@ #include #include "BLI_path_util.h" + #include "GPU_context.h" +#include "DEG_depsgraph_query.h" + #include "engine.h" namespace blender::render::hydra { @@ -47,8 +50,6 @@ Engine::Engine(RenderEngine *bl_engine, const std::string &render_delegate_name) render_index_.reset(pxr::HdRenderIndex::New(render_delegate_.Get(), hd_drivers)); free_camera_delegate_ = std::make_unique( render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("freeCamera")); - scene_delegate_ = std::make_unique( - render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene"), this); render_task_delegate_ = std::make_unique( render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("renderTask")); if (render_delegate_name == "HdStormRendererPlugin") { @@ -62,21 +63,44 @@ Engine::Engine(RenderEngine *bl_engine, const std::string &render_delegate_name) void Engine::sync(Depsgraph *depsgraph, bContext *context) { - scene_delegate_->populate(depsgraph, context); -} + const Scene *scene = DEG_get_evaluated_scene(depsgraph); -void Engine::sync_usd(pxr::UsdStageRefPtr stage) -{ - if (!usd_delegate_) { - usd_delegate_ = std::make_unique( - render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("usd")); + if (scene->hydra.export_method == SCE_HYDRA_EXPORT_HYDRA) { + /* Fast path. */ + usd_scene_delegate_.reset(); + + if (!hydra_scene_delegate_) { + pxr::SdfPath scene_path = pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene"); + hydra_scene_delegate_ = std::make_unique( + render_index_.get(), scene_path, scene_delegate_settings_); + } + hydra_scene_delegate_->populate(depsgraph, context); + } + else { + /* Slow USD export for reference. */ + if (hydra_scene_delegate_) { + /* Freeing the Hydra scene delegate crashes as something internal to USD + * still holds a pointer to it, only clear it instead. */ + hydra_scene_delegate_->clear(); + } + + if (!usd_scene_delegate_) { + pxr::SdfPath scene_path = pxr::SdfPath::AbsoluteRootPath().AppendElementString("usd_scene"); + usd_scene_delegate_ = std::make_unique( + render_index_.get(), scene_path, scene_delegate_settings_); + } + usd_scene_delegate_->populate(depsgraph, context); } - usd_delegate_->Populate(stage->GetPseudoRoot()); } void Engine::set_sync_setting(const std::string &key, const pxr::VtValue &val) { - scene_delegate_->set_setting(key, val); + if (key == "MaterialXFilenameKey") { + scene_delegate_settings_.mx_filename_key = pxr::TfToken(val.Get()); + } + else { + scene_delegate_settings_.render_tokens.add_overwrite(pxr::TfToken(key), val); + } } void Engine::set_render_setting(const std::string &key, const pxr::VtValue &val) diff --git a/source/blender/render/hydra/engine.h b/source/blender/render/hydra/engine.h index dd3af2dfea29..d2b4776d5ef2 100644 --- a/source/blender/render/hydra/engine.h +++ b/source/blender/render/hydra/engine.h @@ -18,9 +18,11 @@ #include "CLG_log.h" #include "render_task_delegate.h" -#include "scene_delegate/blender_scene_delegate.h" #include "simple_light_task_delegate.h" +#include "scene_delegate/blender_scene_delegate.h" +#include "scene_delegate/usd_scene_delegate.hh" + namespace blender::render::hydra { extern struct CLG_LogRef *LOG_RENDER_HYDRA; @@ -31,7 +33,6 @@ class Engine { virtual ~Engine() = default; void sync(Depsgraph *depsgraph, bContext *context); - void sync_usd(pxr::UsdStageRefPtr stage); virtual void render(Depsgraph *depsgraph) = 0; void set_sync_setting(const std::string &key, const pxr::VtValue &val); @@ -42,18 +43,21 @@ class Engine { protected: float renderer_percent_done(); - RenderEngine *bl_engine_; + RenderEngine *bl_engine_ = nullptr; /* The order is important due to deletion order */ pxr::HgiUniquePtr hgi_; pxr::HdDriver hgi_driver_; pxr::HdPluginRenderDelegateUniqueHandle render_delegate_; std::unique_ptr render_index_; - std::unique_ptr scene_delegate_; + + SceneDelegateSettings scene_delegate_settings_; + std::unique_ptr hydra_scene_delegate_; + std::unique_ptr usd_scene_delegate_; + std::unique_ptr render_task_delegate_; std::unique_ptr free_camera_delegate_; std::unique_ptr simple_light_task_delegate_; - std::unique_ptr usd_delegate_; std::unique_ptr engine_; }; diff --git a/source/blender/render/hydra/final_engine.cc b/source/blender/render/hydra/final_engine.cc index d5d26df4336b..e6b48744a9e5 100644 --- a/source/blender/render/hydra/final_engine.cc +++ b/source/blender/render/hydra/final_engine.cc @@ -148,14 +148,21 @@ void FinalEngineGPU::render(Depsgraph *depsgraph) GPU_framebuffer_bind(framebuffer); float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - pxr::VtValue world_color = scene_delegate_->GetLightParamValue( - scene_delegate_->GetDelegateID().AppendElementString("World"), pxr::HdLightTokens->color); - if (!world_color.IsEmpty()) { - auto &c = world_color.Get(); - clear_color[0] = c[0]; - clear_color[1] = c[1]; - clear_color[2] = c[2]; + + /* Workaround Storm rendering with transparent background. Does not currently work for + * USD, and should probably be optional depending on the Blender film transparency setting. */ + if (hydra_scene_delegate_ && render_delegate_name == "HdStormRendererPlugin") { + pxr::VtValue world_color = hydra_scene_delegate_->GetLightParamValue( + hydra_scene_delegate_->GetDelegateID().AppendElementString("World"), + pxr::HdLightTokens->color); + if (!world_color.IsEmpty()) { + auto &c = world_color.Get(); + clear_color[0] = c[0]; + clear_color[1] = c[1]; + clear_color[2] = c[2]; + } } + GPU_framebuffer_clear_color_depth(framebuffer, clear_color, 1.0f); /* Important: we have to create and bind at least one Vertex Array Object (VAO) before render diff --git a/source/blender/render/hydra/python.cc b/source/blender/render/hydra/python.cc index 7b8e0152555f..7f4799399c08 100644 --- a/source/blender/render/hydra/python.cc +++ b/source/blender/render/hydra/python.cc @@ -123,24 +123,6 @@ static PyObject *engine_sync_func(PyObject * /*self*/, PyObject *args) Py_RETURN_NONE; } -static PyObject *engine_sync_usd_func(PyObject * /*self*/, PyObject *args) -{ - PyObject *pyengine, *pystage; - if (!PyArg_ParseTuple(args, "OO", &pyengine, &pystage)) { - Py_RETURN_NONE; - } - - Engine *engine = (Engine *)PyLong_AsVoidPtr(pyengine); - - boost::python::extract extract(pystage); - pxr::UsdStagePtr stage = extract(); - - CLOG_INFO(LOG_RENDER_HYDRA, 2, "Engine %p", engine); - engine->sync_usd(stage); - - Py_RETURN_NONE; -} - static PyObject *engine_render_func(PyObject * /*self*/, PyObject *args) { PyObject *pyengine, *pydepsgraph; @@ -253,7 +235,6 @@ static PyMethodDef methods[] = { {"engine_create", engine_create_func, METH_VARARGS, ""}, {"engine_free", engine_free_func, METH_VARARGS, ""}, {"engine_sync", engine_sync_func, METH_VARARGS, ""}, - {"engine_sync_usd", engine_sync_usd_func, METH_VARARGS, ""}, {"engine_render", engine_render_func, METH_VARARGS, ""}, {"engine_view_draw", engine_view_draw_func, METH_VARARGS, ""}, {"engine_set_sync_setting", engine_set_sync_setting_func, METH_VARARGS, ""}, diff --git a/source/blender/render/hydra/scene_delegate/blender_scene_delegate.cc b/source/blender/render/hydra/scene_delegate/blender_scene_delegate.cc index 10742f657ac3..3ed4b88e5692 100644 --- a/source/blender/render/hydra/scene_delegate/blender_scene_delegate.cc +++ b/source/blender/render/hydra/scene_delegate/blender_scene_delegate.cc @@ -28,8 +28,8 @@ bool BlenderSceneDelegate::ShadingSettings::operator==(const ShadingSettings &ot BlenderSceneDelegate::BlenderSceneDelegate(pxr::HdRenderIndex *parent_index, pxr::SdfPath const &delegate_id, - Engine *engine) - : HdSceneDelegate(parent_index, delegate_id), engine(engine) + const SceneDelegateSettings &settings) + : HdSceneDelegate(parent_index, delegate_id), settings(settings) { instancer_data_ = std::make_unique(this, instancer_prim_id()); } @@ -259,16 +259,6 @@ void BlenderSceneDelegate::clear() view3d = nullptr; } -void BlenderSceneDelegate::set_setting(const std::string &key, const pxr::VtValue &val) -{ - if (key == "MaterialXFilenameKey") { - settings.mx_filename_key = pxr::TfToken(val.Get()); - } - else { - settings.render_tokens.add_overwrite(pxr::TfToken(key), val); - } -} - pxr::SdfPath BlenderSceneDelegate::prim_id(ID *id, const char *prefix) const { /* Making id of object in form like _ */ diff --git a/source/blender/render/hydra/scene_delegate/blender_scene_delegate.h b/source/blender/render/hydra/scene_delegate/blender_scene_delegate.h index 156b220b23ab..a745c87fc3df 100644 --- a/source/blender/render/hydra/scene_delegate/blender_scene_delegate.h +++ b/source/blender/render/hydra/scene_delegate/blender_scene_delegate.h @@ -17,6 +17,7 @@ #include "light.h" #include "mesh.h" #include "object.h" +#include "settings.h" #include "volume.h" #include "world.h" @@ -34,11 +35,6 @@ class BlenderSceneDelegate : public pxr::HdSceneDelegate { friend MaterialData; /* has access to objects and instancers */ public: - struct Settings { - pxr::TfToken mx_filename_key; - Map render_tokens; - }; - struct ShadingSettings { bool use_scene_lights = true; bool use_scene_world = true; @@ -51,7 +47,7 @@ class BlenderSceneDelegate : public pxr::HdSceneDelegate { BlenderSceneDelegate(pxr::HdRenderIndex *parent_index, pxr::SdfPath const &delegate_id, - Engine *engine); + const SceneDelegateSettings &settings); ~BlenderSceneDelegate() override = default; /* Delegate methods */ @@ -77,14 +73,12 @@ class BlenderSceneDelegate : public pxr::HdSceneDelegate { void populate(Depsgraph *depsgraph, bContext *context); void clear(); - void set_setting(const std::string &key, const pxr::VtValue &val); Depsgraph *depsgraph = nullptr; bContext *context = nullptr; View3D *view3d = nullptr; Scene *scene = nullptr; - Engine *engine; - Settings settings; + const SceneDelegateSettings &settings; ShadingSettings shading_settings; private: diff --git a/source/blender/render/hydra/scene_delegate/image.cc b/source/blender/render/hydra/scene_delegate/image.cc index b04c82678f55..d54dfb3fb682 100644 --- a/source/blender/render/hydra/scene_delegate/image.cc +++ b/source/blender/render/hydra/scene_delegate/image.cc @@ -19,7 +19,7 @@ namespace blender::render::hydra { static std::string get_cache_file(const std::string &file_name, bool mkdir = true) { char dir_path[FILE_MAX]; - BLI_path_join(dir_path, sizeof(dir_path), BKE_tempdir_session(), "hydra_image_cache"); + BLI_path_join(dir_path, sizeof(dir_path), BKE_tempdir_session(), "hydra", "image_cache"); if (mkdir) { BLI_dir_create_recursive(dir_path); } diff --git a/source/blender/render/hydra/scene_delegate/light.cc b/source/blender/render/hydra/scene_delegate/light.cc index 8be058e90696..a7e754ce2ab0 100644 --- a/source/blender/render/hydra/scene_delegate/light.cc +++ b/source/blender/render/hydra/scene_delegate/light.cc @@ -140,7 +140,7 @@ pxr::VtValue LightData::get_data(pxr::TfToken const &key) const return pxr::VtValue(it->second); } - pxr::VtValue *ret_ptr = scene_delegate_->settings.render_tokens.lookup_ptr(key); + const pxr::VtValue *ret_ptr = scene_delegate_->settings.render_tokens.lookup_ptr(key); if (ret_ptr) { return *ret_ptr; } diff --git a/source/blender/render/hydra/scene_delegate/settings.h b/source/blender/render/hydra/scene_delegate/settings.h new file mode 100644 index 000000000000..9680345ad173 --- /dev/null +++ b/source/blender/render/hydra/scene_delegate/settings.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2023 Blender Foundation */ + +#pragma once + +#include + +#include "BLI_map.hh" + +namespace blender::render::hydra { + +struct SceneDelegateSettings { + pxr::TfToken mx_filename_key; + Map render_tokens; +}; + +}; // namespace blender::render::hydra diff --git a/source/blender/render/hydra/scene_delegate/usd_scene_delegate.cc b/source/blender/render/hydra/scene_delegate/usd_scene_delegate.cc new file mode 100644 index 000000000000..12122e1125c1 --- /dev/null +++ b/source/blender/render/hydra/scene_delegate/usd_scene_delegate.cc @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "usd_scene_delegate.hh" + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "BKE_appdir.h" + +#include "DEG_depsgraph_query.h" + +#include "usd.h" +#include "usd.hh" + +namespace blender::render::hydra { + +USDSceneDelegate::USDSceneDelegate(pxr::HdRenderIndex *render_index, + pxr::SdfPath const &delegate_id, + const SceneDelegateSettings &settings) + : render_index_(render_index), delegate_id_(delegate_id), settings_(settings) +{ + /* Temporary directory to write any additional files to, like image or VDB files. */ + char unique_name[FILE_MAXFILE]; + BLI_snprintf(unique_name, sizeof(unique_name), "%p", this); + + char dir_path[FILE_MAX]; + BLI_path_join( + dir_path, sizeof(dir_path), BKE_tempdir_session(), "usd_scene_delegate", unique_name); + BLI_dir_create_recursive(dir_path); + + char file_path[FILE_MAX]; + BLI_path_join(file_path, sizeof(file_path), dir_path, "scene.usdc"); + + temp_dir_ = dir_path; + temp_file_ = file_path; +} + +USDSceneDelegate::~USDSceneDelegate() +{ + BLI_delete(temp_dir_.c_str(), true, true); +} + +void USDSceneDelegate::populate(Depsgraph *depsgraph, bContext * /*context*/) +{ + /* TODO: implement MaterialX support in USD exporter. */ + const bool use_materialx = !settings_.mx_filename_key.IsEmpty(); + (void)use_materialx; + + USDExportParams params = {}; + params.export_hair = true; + params.export_uvmaps = true; + params.export_normals = true; + params.export_materials = true; + params.selected_objects_only = false; + params.visible_objects_only = true; + params.use_instancing = true; + params.evaluation_mode = DEG_get_mode(depsgraph); + params.generate_preview_surface = true; + params.export_textures = true; + params.overwrite_textures = true; + params.relative_paths = true; + + /* Create clean directory for export. */ + BLI_delete(temp_dir_.c_str(), true, true); + BLI_dir_create_recursive(temp_dir_.c_str()); + + /* Free previous delegate and stage first to save memory. */ + delegate_.reset(); + stage_.Reset(); + + /* Convert depsgraph to stage + aditional file in temp directory. */ + stage_ = io::usd::export_to_stage(params, depsgraph, temp_file_.c_str()); + delegate_ = std::make_unique(render_index_, delegate_id_); + delegate_->Populate(stage_->GetPseudoRoot()); +} + +} // namespace blender::render::hydra diff --git a/source/blender/render/hydra/scene_delegate/usd_scene_delegate.hh b/source/blender/render/hydra/scene_delegate/usd_scene_delegate.hh new file mode 100644 index 000000000000..df22089bc9ea --- /dev/null +++ b/source/blender/render/hydra/scene_delegate/usd_scene_delegate.hh @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2023 Blender Foundation */ + +#pragma once + +#include +#include + +#include + +#include "settings.h" + +struct Depsgraph; +struct bContext; + +namespace blender::render::hydra { + +/* Populate Hydra render index using USD file export, for testing. */ +class USDSceneDelegate { + pxr::HdRenderIndex *render_index_; + pxr::SdfPath const delegate_id_; + pxr::UsdStageRefPtr stage_; + std::unique_ptr delegate_; + const SceneDelegateSettings &settings_; + + std::string temp_dir_; + std::string temp_file_; + + public: + USDSceneDelegate(pxr::HdRenderIndex *render_index, + pxr::SdfPath const &delegate_id, + const SceneDelegateSettings &settings_); + ~USDSceneDelegate(); + + void populate(Depsgraph *depsgraph, bContext *context); +}; + +} // namespace blender::render::hydra