Add scene setting to export through either Hydra or USD, for debugging #65

Merged
Brecht Van Lommel merged 7 commits from brecht/blender:hydra-usd-export into hydra-render 2023-07-14 19:41:17 +02:00
18 changed files with 389 additions and 129 deletions
Showing only changes of commit 0ed2525b04 - Show all commits

View File

@ -883,6 +883,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,
@ -915,6 +934,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,

View File

@ -97,6 +97,7 @@ set(SRC
intern/usd_reader_volume.cc
intern/usd_reader_xform.cc
usd.hh
usd.h
intern/usd_asset_utils.h

View File

@ -3,6 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "usd.h"
#include "usd.hh"
#include "usd_hierarchy_iterator.h"
#include <pxr/base/plug/registry.h>
@ -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. */
static pxr::UsdStageRefPtr export_to_stage(const USDExportParams &params,
Depsgraph *depsgraph,
const char *filepath,
bool *stop,
bool *do_update,
float *progress)
{
ExportJobData *data = static_cast<ExportJobData *>(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,15 +245,19 @@ 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();
if (progress) {
*progress += progress_per_frame;
}
if (do_update) {
*do_update = true;
}
}
}
else {
/* If we're not animating, a single iteration over all objects is enough. */
iter.iterate_and_write();
@ -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 &params,
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<ExportJobData *>(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) {

View File

@ -0,0 +1,18 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <pxr/usd/usd/stage.h>
struct Depsgraph;
struct USDExportParams;
namespace blender::io::usd {
pxr::UsdStageRefPtr export_to_stage(const USDExportParams &params,
Depsgraph *depsgraph,
const char *filepath);
};

View File

@ -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, \
}
/** \} */

View File

@ -1858,6 +1858,11 @@ typedef struct SceneGpencil {
char _pad[4];
} SceneGpencil;
typedef struct SceneHydra {
int export_method;
int _pad0;
} SceneHydra;
/** \} */
/* -------------------------------------------------------------------- */
@ -2004,6 +2009,7 @@ typedef struct Scene {
struct SceneDisplay display;
struct SceneEEVEE eevee;
struct SceneGpencil grease_pencil_settings;
struct SceneHydra hydra;
} Scene;
/** \} */
@ -2741,6 +2747,13 @@ enum {
SCE_DISPLAY_AA_SAMPLES_32 = 32,
};
/** #SceneHydra->export_method */
enum {
SCE_HYDRA_EXPORT_HYDRA = 0,
SCE_HYDRA_EXPORT_USD = 1,
};
/** \} */
#ifdef __cplusplus

View File

@ -1188,6 +1188,11 @@ static char *rna_SceneGpencil_path(const PointerRNA *UNUSED(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 *UNUSED(data))
{
@ -7975,6 +7980,36 @@ static void rna_def_scene_gpencil(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
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;
@ -8468,6 +8503,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);
@ -8486,6 +8526,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);

View File

@ -30,6 +30,7 @@ set(INC
../../depsgraph
../../blenkernel
../../imbuf
../../io/usd
../../gpu
../../gpu/intern
../../python/intern
@ -65,30 +66,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
)
set(LIB

View File

@ -9,8 +9,11 @@
#include <pxr/usd/usdGeom/tokens.h>
#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<pxr::HdxFreeCameraSceneDelegate>(
render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("freeCamera"));
scene_delegate_ = std::make_unique<BlenderSceneDelegate>(
render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene"), this);
render_task_delegate_ = std::make_unique<RenderTaskDelegate>(
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);
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<BlenderSceneDelegate>(
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();
}
void Engine::sync_usd(pxr::UsdStageRefPtr stage)
{
if (!usd_delegate_) {
usd_delegate_ = std::make_unique<pxr::UsdImagingDelegate>(
render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("usd"));
if (!usd_scene_delegate_) {
pxr::SdfPath scene_path = pxr::SdfPath::AbsoluteRootPath().AppendElementString("usd_scene");
usd_scene_delegate_ = std::make_unique<USDSceneDelegate>(
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<std::string>());
}
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)

View File

@ -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<pxr::HdRenderIndex> render_index_;
std::unique_ptr<BlenderSceneDelegate> scene_delegate_;
SceneDelegateSettings scene_delegate_settings_;
std::unique_ptr<BlenderSceneDelegate> hydra_scene_delegate_;
std::unique_ptr<USDSceneDelegate> usd_scene_delegate_;
std::unique_ptr<RenderTaskDelegate> render_task_delegate_;
std::unique_ptr<pxr::HdxFreeCameraSceneDelegate> free_camera_delegate_;
std::unique_ptr<SimpleLightTaskDelegate> simple_light_task_delegate_;
std::unique_ptr<pxr::UsdImagingDelegate> usd_delegate_;
std::unique_ptr<pxr::HdEngine> engine_;
};

View File

@ -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<pxr::UsdStageRefPtr> extract(pystage);
pxr::UsdStagePtr stage = extract();
engine->sync_usd(stage);
CLOG_INFO(LOG_RENDER_HYDRA, 2, "Engine %016llx", engine);
Py_RETURN_NONE;
}
static PyObject *engine_render_func(PyObject * /*self*/, PyObject *args)
{
PyObject *pyengine, *pydepsgraph;
@ -249,7 +231,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, ""},

View File

@ -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<InstancerData>(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<std::string>());
}
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 <prefix>_<pointer in 16 hex digits format> */

View File

@ -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<pxr::TfToken, pxr::VtValue> 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:

View File

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

View File

@ -142,7 +142,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;
}

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2023 Blender Foundation */
#pragma once
#include <pxr/base/tf/token.h>
#include "BLI_map.hh"
namespace blender::render::hydra {
struct SceneDelegateSettings {
pxr::TfToken mx_filename_key;
Map<pxr::TfToken, pxr::VtValue> render_tokens;
};
}; // namespace blender::render::hydra

View File

@ -0,0 +1,78 @@
/* 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);
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<pxr::UsdImagingDelegate>(render_index_, delegate_id_);
delegate_->Populate(stage_->GetPseudoRoot());
}
} // namespace blender::render::hydra

View File

@ -0,0 +1,38 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2023 Blender Foundation */
#pragma once
#include <pxr/imaging/hd/renderIndex.h>
#include <pxr/usdImaging/usdImaging/delegate.h>
#include <string>
#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<pxr::UsdImagingDelegate> 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