Hydra render engine #104712

Closed
Bogdan Nagirniak wants to merge 142 commits from BogdanNagirniak/blender:hydra-render into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
10 changed files with 622 additions and 965 deletions
Showing only changes of commit 6107598d23 - Show all commits

View File

@ -8,14 +8,17 @@ endif()
# USD headers use deprecated TBB headers, silence warning.
add_definitions(-DTBB_SUPPRESS_DEPRECATED_MESSAGES=1)
add_definitions(${GFLAGS_DEFINES})
add_definitions(${GLOG_DEFINES})
add_definitions(-DGLOG_NO_ABBREVIATED_SEVERITIES)
add_definitions(-DBLENDER_GFLAGS_NAMESPACE=${GFLAGS_NAMESPACE})
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DBOOST_DEBUG_PYTHON")
set(INC
../gflags/src
# ../../intern
../../intern/glew-mx
../../intern/guardedalloc
# ../../mikktspace
../../source/blender/makesdna
../../source/blender/makesrna
../../source/blender/blenlib
@ -39,8 +42,8 @@ set(INC_SYS
set(SRC
python.cpp
session.h
session.cpp
engine.h
engine.cpp
utils.h
utils.cpp
@ -85,17 +88,10 @@ set(ADDON_STORM_FILES
addon/storm/ui.py
)
set(USDHYDRA_INSTALL_PATH "scripts/addons/usdhydra")
add_definitions(${GFLAGS_DEFINES})
add_definitions(${GLOG_DEFINES})
add_definitions(-DGLOG_NO_ABBREVIATED_SEVERITIES)
add_definitions(-DBLENDER_GFLAGS_NAMESPACE=${GFLAGS_NAMESPACE})
blender_add_lib(extern_usdhydra "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_dependencies(extern_usdhydra bf_rna)
set(USDHYDRA_INSTALL_PATH "scripts/addons/usdhydra")
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${ADDON_FILES}" ${USDHYDRA_INSTALL_PATH})
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${ADDON_STORM_FILES}" ${USDHYDRA_INSTALL_PATH}/storm)

View File

@ -20,14 +20,14 @@ class HydraRenderEngine(bpy.types.RenderEngine):
bl_use_preview = True
delegate_name = ''
session = None
delegate_id = ''
engine_ptr = None
def __del__(self):
if not self.session:
if not self.engine_ptr:
return
session_free(self.session)
_usdhydra.engine.free(self.engine_ptr)
def get_delegate_settings(self, engine_type):
return {}
@ -37,30 +37,30 @@ class HydraRenderEngine(bpy.types.RenderEngine):
engine_type = 'PREVIEW' if self.is_preview else 'FINAL'
log("update", self, engine_type)
self.session = session_create(self, engine_type, self.delegate_name)
self.engine_ptr = _usdhydra.engine.create(self.as_pointer(), engine_type, self.delegate_id)
delegate_settings = self.get_delegate_settings(engine_type)
session_sync(self.session, depsgraph, delegate_settings)
_usdhydra.engine.sync(self.engine_ptr, depsgraph.as_pointer(), bpy.context.as_pointer(), delegate_settings)
def render(self, depsgraph):
log("render", self)
session_render(self.session)
_usdhydra.engine.render(self.engine_ptr, depsgraph.as_pointer())
# viewport render
def view_update(self, context, depsgraph):
log("view_update", self)
if not self.session:
self.session = session_create(self, 'VIEWPORT', self.delegate_name)
if not self.engine_ptr:
self.engine_ptr = _usdhydra.engine.create(self.as_pointer(), 'VIEWPORT', self.delegate_id)
delegate_settings = self.get_delegate_settings('VIEWPORT')
session_sync(self.session, depsgraph, delegate_settings)
_usdhydra.engine.sync(self.engine_ptr, depsgraph.as_pointer(), context.as_pointer(), delegate_settings)
def view_draw(self, context, depsgraph):
if not self.session:
if not self.engine_ptr:
return
log("view_draw", self)
session_view_draw(self.session, depsgraph, context, context.space_data, context.region_data)
_usdhydra.engine.view_draw(self.engine_ptr, depsgraph.as_pointer(), context.as_pointer())
@classmethod
def register(cls):
@ -73,31 +73,6 @@ class HydraRenderEngine(bpy.types.RenderEngine):
ui.unregister_engine(cls.bl_idname)
def session_create(engine: HydraRenderEngine, engine_type, delegate_name):
return _usdhydra.session.create(engine.as_pointer(), engine_type, delegate_name)
def session_free(session):
_usdhydra.session.free(session)
def session_render(session):
_usdhydra.session.render(session)
def session_sync(session, depsgraph, delegate_settings):
_usdhydra.session.sync(session, depsgraph.as_pointer(), delegate_settings)
def session_view_draw(session, depsgraph, context, space_data, region_data):
_usdhydra.session.view_draw(session, depsgraph.as_pointer(), context.as_pointer(),
space_data.as_pointer(), region_data.as_pointer())
def session_get_render_plugins():
return _usdhydra.session.get_render_plugins()
def register():
if addon_preferences().storm_render_engine:
from . import storm

View File

@ -16,7 +16,7 @@ class HdStormHydraRenderEngine(HydraRenderEngine):
bl_use_preview = False
bl_use_gpu_context = True
delegate_name = "HdStormRendererPlugin"
delegate_id = 'HdStormRendererPlugin'
def get_delegate_settings(self, engine_type):
settings = bpy.context.scene.usdhydra_storm

507
extern/usdhydra/engine.cpp vendored Normal file
View File

@ -0,0 +1,507 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <pxr/pxr.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/base/gf/camera.h>
#include <pxr/imaging/glf/drawTarget.h>
#include <pxr/usd/usdGeom/camera.h>
#include <pxr/usd/usdLux/domeLight.h>
#include <pxr/usd/usdLux/shapingAPI.h>
#include <pxr/usdImaging/usdImagingGL/engine.h>
#include <pxr/usdImaging/usdImagingGL/renderParams.h>
#include <pxr/usdImaging/usdAppUtils/camera.h>
#include <pxr/base/plug/plugin.h>
#include <pxr/base/plug/registry.h>
#include "intern/usd_hierarchy_iterator.h"
#include "usdImagingLite/engine.h"
#include "usdImagingLite/renderParams.h"
#include "engine.h"
#include "glog/logging.h"
using namespace pxr;
namespace usdhydra {
Engine::Engine(BL::RenderEngine &b_engine, const char* delegateId)
: b_engine(b_engine)
, delegateId(delegateId)
{
}
Engine::~Engine()
{
}
void Engine::exportScene(BL::Depsgraph& b_depsgraph, BL::Context& b_context)
{
Depsgraph *depsgraph = (Depsgraph *)b_depsgraph.ptr.data;
Scene *scene = DEG_get_input_scene(depsgraph);
World *world = scene->world;
DEG_graph_build_for_all_objects(depsgraph);
bContext *C = (bContext *)b_context.ptr.data;
Main *bmain = CTX_data_main(C);
USDExportParams usd_export_params;
usd_export_params.selected_objects_only = false;
usd_export_params.visible_objects_only = false;
//stage->Reload();
stage->SetMetadata(UsdGeomTokens->upAxis, VtValue(UsdGeomTokens->z));
stage->SetMetadata(UsdGeomTokens->metersPerUnit, static_cast<double>(scene->unit.scale_length));
stage->GetRootLayer()->SetDocumentation(std::string("Blender v") + BKE_blender_version_string());
/* Set up the stage for animated data. */
//if (data->params.export_animation) {
// stage->SetTimeCodesPerSecond(FPS);
// stage->SetStartTimeCode(scene->r.sfra);
// stage->SetEndTimeCode(scene->r.efra);
//}
blender::io::usd::USDHierarchyIterator iter(bmain, depsgraph, stage, usd_export_params);
iter.iterate_and_write();
iter.release_writers();
}
void FinalEngine::sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context, pxr::HdRenderSettingsMap &renderSettings)
{
this->renderSettings = renderSettings;
stage = UsdStage::CreateInMemory();
exportScene(b_depsgraph, b_context);
}
void FinalEngine::render(BL::Depsgraph &b_depsgraph)
{
if (b_engine.bl_use_gpu_context()) {
renderGL(b_depsgraph);
}
else {
renderLite(b_depsgraph);
}
}
void FinalEngine::renderGL(BL::Depsgraph &b_depsgraph)
{
std::unique_ptr<UsdImagingGLEngine> imagingGLEngine = std::make_unique<UsdImagingGLEngine>();
if (!imagingGLEngine->SetRendererPlugin(TfToken(delegateId))) {
DLOG(ERROR) << "Error in SetRendererPlugin(" << delegateId << ")";
return;
}
for (auto const& setting : renderSettings) {
imagingGLEngine->SetRendererSetting(setting.first, setting.second);
}
BL::Scene b_scene = b_depsgraph.scene_eval();
int width, height;
getResolution(b_scene.render(), width, height);
UsdGeomCamera usdCamera = UsdAppUtilsGetCameraAtPath(stage, SdfPath(TfMakeValidIdentifier(b_scene.camera().data().name())));
GfCamera gfCamera = usdCamera.GetCamera(UsdTimeCode(b_scene.frame_current()));
GlfDrawTargetRefPtr drawTarget = GlfDrawTarget::New(GfVec2i(width, height));
drawTarget->Bind();
drawTarget->AddAttachment("color", GL_RGBA, GL_FLOAT, GL_RGBA);
imagingGLEngine->SetRenderViewport(GfVec4d(0, 0, width, height));
imagingGLEngine->SetRendererAov(HdAovTokens->color);
imagingGLEngine->SetCameraState(gfCamera.GetFrustum().ComputeViewMatrix(),
gfCamera.GetFrustum().ComputeProjectionMatrix());
UsdImagingGLRenderParams renderParams;
renderParams.frame = UsdTimeCode(b_scene.frame_current());
renderParams.clearColor = GfVec4f(1.0, 1.0, 1.0, 0.0);
imagingGLEngine->Render(stage->GetPseudoRoot(), renderParams);
map<string, vector<float>> renderImages{{"Combined", vector<float>(width * height * 4)}}; // 4 - number of channels
vector<float> &pixels = renderImages["Combined"];
glReadPixels(0, 0, width, height, GL_RGBA, GL_FLOAT, pixels.data());
drawTarget->Unbind();
updateRenderResult(renderImages, b_depsgraph.view_layer().name(), width, height);
}
template <typename T>
float getRendererPercentDone(T &renderer)
{
float percent = 0.0;
VtDictionary render_stats = renderer.GetRenderStats();
auto it = render_stats.find("percentDone");
if (it != render_stats.end()) {
percent = (float)it->second.UncheckedGet<double>();
}
return round(percent * 10.0f) / 10.0f;
}
void FinalEngine::renderLite(BL::Depsgraph &b_depsgraph)
{
std::unique_ptr<UsdImagingLiteEngine> imagingLiteEngine = std::make_unique<UsdImagingLiteEngine>();
if (!imagingLiteEngine->SetRendererPlugin(TfToken(delegateId))) {
DLOG(ERROR) << "Error in SetRendererPlugin(" << delegateId << ")";
return;
}
for (auto const& setting : renderSettings) {
imagingLiteEngine->SetRendererSetting(setting.first, setting.second);
}
BL::Scene b_scene = b_depsgraph.scene_eval();
int width, height;
getResolution(b_scene.render(), width, height);
UsdGeomCamera usdCamera = UsdAppUtilsGetCameraAtPath(stage, SdfPath(TfMakeValidIdentifier(b_scene.camera().data().name())));
GfCamera gfCamera = usdCamera.GetCamera(UsdTimeCode(b_scene.frame_current()));
imagingLiteEngine->SetCameraState(gfCamera);
imagingLiteEngine->SetRenderViewport(GfVec4d(0, 0, width, height));
imagingLiteEngine->SetRendererAov(HdAovTokens->color);
UsdImagingLiteRenderParams renderParams;
renderParams.frame = UsdTimeCode(b_scene.frame_current());
renderParams.clearColor = GfVec4f(1.0, 1.0, 1.0, 0.0);
chrono::time_point<chrono::steady_clock> timeBegin = chrono::steady_clock::now(), timeCurrent;
chrono::milliseconds elapsedTime;
float percentDone = 0.0;
string layerName = b_depsgraph.view_layer().name();
map<string, vector<float>> renderImages{{"Combined", vector<float>(width * height * 4)}}; // 4 - number of channels
vector<float> &pixels = renderImages["Combined"];
while (true) {
if (b_engine.test_break()) {
break;
}
imagingLiteEngine->Render(stage->GetPseudoRoot(), renderParams);
percentDone = getRendererPercentDone(*imagingLiteEngine);
timeCurrent = chrono::steady_clock::now();
elapsedTime = chrono::duration_cast<chrono::milliseconds>(timeCurrent - timeBegin);
notifyStatus(percentDone / 100.0,
b_scene.name() + ": " + layerName,
"Render Time: " + format_milliseconds(elapsedTime) + " | Done: " + to_string(int(percentDone)) + "%");
if (imagingLiteEngine->IsConverged()) {
break;
}
imagingLiteEngine->GetRendererAov(HdAovTokens->color, pixels.data());
updateRenderResult(renderImages, layerName, width, height);
}
imagingLiteEngine->GetRendererAov(HdAovTokens->color, pixels.data());
updateRenderResult(renderImages, layerName, width, height);
}
void FinalEngine::getResolution(BL::RenderSettings b_render, int &width, int &height)
{
float border_w = 1.0, border_h = 1.0;
if (b_render.use_border()) {
border_w = b_render.border_max_x() - b_render.border_min_x();
border_h = b_render.border_max_y() - b_render.border_min_y();
}
width = int(b_render.resolution_x() * border_w * b_render.resolution_percentage() / 100);
height = int(b_render.resolution_y() * border_h * b_render.resolution_percentage() / 100);
}
void FinalEngine::updateRenderResult(map<string, vector<float>>& renderImages, const string &layerName, int width, int height)
{
BL::RenderResult b_result = b_engine.begin_result(0, 0, width, height, layerName.c_str(), NULL);
BL::CollectionRef b_passes = b_result.layers[0].passes;
for (BL::RenderPass b_pass : b_passes) {
auto it_image = renderImages.find(b_pass.name());
if (it_image == renderImages.end()) {
continue;
}
b_pass.rect(it_image->second.data());
}
b_engine.end_result(b_result, false, false, false);
}
void FinalEngine::notifyStatus(float progress, const string &title, const string &info)
{
b_engine.update_progress(progress);
b_engine.update_stats(title.c_str(), info.c_str());
}
void ViewportEngine::sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context, pxr::HdRenderSettingsMap &renderSettings_)
{
renderSettings = renderSettings_;
if (!imagingGLEngine) {
stage = UsdStage::CreateInMemory();
exportScene(b_depsgraph, b_context);
imagingGLEngine = std::make_unique<UsdImagingGLEngine>();
imagingGLEngine->SetRendererPlugin(TfToken(delegateId));
}
for (auto const& pair : renderSettings) {
imagingGLEngine->SetRendererSetting(pair.first, pair.second);
}
}
void ViewportEngine::viewDraw(BL::Depsgraph &b_depsgraph, BL::Context &b_context)
{
ViewSettings viewSettings(b_context);
if (viewSettings.get_width() * viewSettings.get_height() == 0) {
return;
};
BL::Scene b_scene = b_depsgraph.scene_eval();
GfCamera gfCamera = viewSettings.export_camera();
vector<GfVec4f> clipPlanes = gfCamera.GetClippingPlanes();
for (int i = 0; i < clipPlanes.size(); i++) {
renderParams.clipPlanes.push_back((GfVec4d)clipPlanes[i]);
}
imagingGLEngine->SetCameraState(gfCamera.GetFrustum().ComputeViewMatrix(),
gfCamera.GetFrustum().ComputeProjectionMatrix());
imagingGLEngine->SetRenderViewport(GfVec4d((double)viewSettings.border[0][0], (double)viewSettings.border[0][1],
(double)viewSettings.border[1][0], (double)viewSettings.border[1][1]));
b_engine.bind_display_space_shader(b_scene);
if (getRendererPercentDone(*imagingGLEngine) == 0.0f) {
timeBegin = chrono::steady_clock::now();
}
imagingGLEngine->Render(stage->GetPseudoRoot(), renderParams);
b_engine.unbind_display_space_shader();
glClear(GL_DEPTH_BUFFER_BIT);
chrono::time_point<chrono::steady_clock> timeCurrent = chrono::steady_clock::now();
chrono::milliseconds elapsedTime = chrono::duration_cast<chrono::milliseconds>(timeCurrent - timeBegin);
string formattedTime = format_milliseconds(elapsedTime);
if (!imagingGLEngine->IsConverged()) {
notifyStatus("Time: " + formattedTime + " | Done: " + to_string(int(getRendererPercentDone(*imagingGLEngine))) + "%",
"Render", true);
}
else {
notifyStatus(("Time: " + formattedTime).c_str(), "Rendering Done", false);
}
}
void ViewportEngine::notifyStatus(const string &info, const string &status, bool redraw)
{
b_engine.update_stats(status.c_str(), info.c_str());
if (redraw) {
b_engine.tag_redraw();
}
}
/* ------------------------------------------------------------------------- */
/* Python API for Engine
*/
static PyObject *create_func(PyObject * /*self*/, PyObject *args)
{
DLOG(INFO) << "create_func";
PyObject *b_pyengine;
char *engineType, *delegateId;
if (!PyArg_ParseTuple(args, "Oss", &b_pyengine, &engineType, &delegateId)) {
Py_RETURN_NONE;
}
PointerRNA b_engineptr;
RNA_pointer_create(NULL, &RNA_RenderEngine, (void *)PyLong_AsVoidPtr(b_pyengine), &b_engineptr);
BL::RenderEngine b_engine(b_engineptr);
/* create engine */
Engine *engine;
if (string(engineType) == "VIEWPORT") {
engine = new ViewportEngine(b_engine, delegateId);
}
else {
engine = new FinalEngine(b_engine, delegateId);
}
return PyLong_FromVoidPtr(engine);
}
static PyObject *free_func(PyObject * /*self*/, PyObject *args)
{
LOG(INFO) << "free_func";
PyObject *pyengine;
if (!PyArg_ParseTuple(args, "O", &pyengine)) {
Py_RETURN_NONE;
}
delete (Engine *)PyLong_AsVoidPtr(pyengine);
Py_RETURN_NONE;
}
static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
{
LOG(INFO) << "sync_func";
PyObject *pyengine, *pydepsgraph, *pycontext, *pysettings;
if (!PyArg_ParseTuple(args, "OOOO", &pyengine, &pydepsgraph, &pycontext, &pysettings)) {
Py_RETURN_NONE;
}
Engine *engine = (Engine *)PyLong_AsVoidPtr(pyengine);
PointerRNA depsgraphptr;
RNA_pointer_create(NULL, &RNA_Context, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph b_depsgraph(depsgraphptr);
PointerRNA contextptr;
RNA_pointer_create(NULL, &RNA_Context, (ID *)PyLong_AsVoidPtr(pycontext), &contextptr);
BL::Context b_context(contextptr);
HdRenderSettingsMap settings;
PyObject *pyiter = PyObject_GetIter(pysettings);
if (pyiter) {
PyObject *pykey, *pyval;
while (pykey = PyIter_Next(pyiter)) {
TfToken key(PyUnicode_AsUTF8(pykey));
pyval = PyDict_GetItem(pysettings, pykey);
if (PyLong_Check(pyval)) {
settings[key] = PyLong_AsLong(pyval);
}
else if (PyFloat_Check(pyval)) {
settings[key] = PyFloat_AsDouble(pyval);
}
else if (PyUnicode_Check(pyval)) {
settings[key] = PyUnicode_AsUTF8(pyval);
}
}
}
engine->sync(b_depsgraph, b_context, settings);
Py_RETURN_NONE;
}
static PyObject *render_func(PyObject * /*self*/, PyObject *args)
{
LOG(INFO) << "render_func";
PyObject *pyengine, *pydepsgraph;
if (!PyArg_ParseTuple(args, "OO", &pyengine, &pydepsgraph)) {
Py_RETURN_NONE;
}
FinalEngine *engine = (FinalEngine *)PyLong_AsVoidPtr(pyengine);
PointerRNA depsgraphptr;
RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph depsgraph(depsgraphptr);
/* Allow Blender to execute other Python scripts. */
Py_BEGIN_ALLOW_THREADS
engine->render(depsgraph);
Py_END_ALLOW_THREADS
Py_RETURN_NONE;
}
static PyObject *view_draw_func(PyObject * /*self*/, PyObject *args)
{
LOG(INFO) << "view_draw_func";
PyObject *pyengine, *pydepsgraph, *pycontext;
if (!PyArg_ParseTuple(args, "OOO", &pyengine, &pydepsgraph, &pycontext)) {
Py_RETURN_NONE;
}
ViewportEngine *engine = (ViewportEngine *)PyLong_AsVoidPtr(pyengine);
PointerRNA depsgraphptr;
RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph b_depsgraph(depsgraphptr);
PointerRNA contextptr;
RNA_pointer_create(NULL, &RNA_Context, (ID *)PyLong_AsVoidPtr(pycontext), &contextptr);
BL::Context b_context(contextptr);
/* Allow Blender to execute other Python scripts. */
Py_BEGIN_ALLOW_THREADS
engine->viewDraw(b_depsgraph, b_context);
Py_END_ALLOW_THREADS
Py_RETURN_NONE;
}
static PyObject* get_render_plugins_func(PyObject* /*self*/, PyObject* args)
{
PlugRegistry &registry = PlugRegistry::GetInstance();
TfTokenVector pluginsIds = UsdImagingGLEngine::GetRendererPlugins();
PyObject *ret = PyTuple_New(pluginsIds.size());
for (int i = 0; i < pluginsIds.size(); ++i) {
PyObject *descr = PyDict_New();
PyDict_SetItemString(descr, "id", PyUnicode_FromString(pluginsIds[i].GetText()));
PyDict_SetItemString(descr, "name", PyUnicode_FromString(UsdImagingGLEngine::GetRendererDisplayName(pluginsIds[i]).c_str()));
std::string plugin_name = pluginsIds[i];
plugin_name = plugin_name.substr(0, plugin_name.size()-6);
plugin_name[0] = tolower(plugin_name[0]);
std::string path = "";
PlugPluginPtr plugin = registry.GetPluginWithName(plugin_name);
if (plugin) {
path = plugin->GetPath();
}
PyDict_SetItemString(descr, "path", PyUnicode_FromString(path.c_str()));
PyTuple_SetItem(ret, i, descr);
}
return ret;
}
static PyMethodDef methods[] = {
{"create", create_func, METH_VARARGS, ""},
{"free", free_func, METH_VARARGS, ""},
{"render", render_func, METH_VARARGS, ""},
{"sync", sync_func, METH_VARARGS, ""},
{"view_draw", view_draw_func, METH_VARARGS, ""},
{"get_render_plugins", get_render_plugins_func, METH_VARARGS, ""},
{NULL, NULL, 0, NULL},
};
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT,
"engine",
"",
-1,
methods,
NULL,
NULL,
NULL,
NULL,
};
PyObject *addPythonSubmodule_engine(PyObject *mod)
{
PyObject *submodule = PyModule_Create(&module);
PyModule_AddObject(mod, "engine", submodule);
return submodule;
}
} // namespace usdhydra

83
extern/usdhydra/engine.h vendored Normal file
View File

@ -0,0 +1,83 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#pragma once
#include <chrono>
#include <Python.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/usdImaging/usdImagingGL/engine.h>
#include <pxr/usdImaging/usdAppUtils/camera.h>
#include "MEM_guardedalloc.h"
#include "RNA_blender_cpp.h"
#include "usd.h"
#include "intern/usd_exporter_context.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_context.h"
#include "BKE_blender_version.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "utils.h"
#include "engine.h"
#include "stage.h"
#include "view_settings.h"
namespace usdhydra {
class Engine {
public:
Engine(BL::RenderEngine &b_engine, const char* delegateId);
virtual ~Engine();
virtual void sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context, pxr::HdRenderSettingsMap &renderSettings) = 0;
protected:
void exportScene(BL::Depsgraph &b_depsgraph, BL::Context &b_context);
protected:
BL::RenderEngine b_engine;
std::string delegateId;
pxr::HdRenderSettingsMap renderSettings;
pxr::UsdStageRefPtr stage;
};
class FinalEngine : public Engine {
public:
using Engine::Engine;
void sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context, pxr::HdRenderSettingsMap &renderSettings) override;
void render(BL::Depsgraph &b_depsgraph);
private:
void renderGL(BL::Depsgraph &b_depsgraph);
void renderLite(BL::Depsgraph &b_depsgraph);
void getResolution(BL::RenderSettings b_render, int &width, int &height);
void updateRenderResult(map<string, vector<float>> &render_images, const string &layerName, int width, int height);
void notifyStatus(float progress, const std::string &title, const std::string &info);
};
class ViewportEngine : public Engine {
public:
using Engine::Engine;
void sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context, pxr::HdRenderSettingsMap &renderSettings) override;
void viewDraw(BL::Depsgraph &b_depsgraph, BL::Context &b_context);
private:
void notifyStatus(const string &title, const string &info, bool redraw);
private:
std::unique_ptr<pxr::UsdImagingGLEngine> imagingGLEngine;
pxr::UsdImagingGLRenderParams renderParams;
chrono::time_point<chrono::steady_clock> timeBegin;
};
PyObject *addPythonSubmodule_engine(PyObject *mod);
} // namespace usdhydra

View File

@ -15,7 +15,7 @@
#include "BKE_appdir.h"
#include "stage.h"
#include "session.h"
#include "engine.h"
#include "utils.h"
using namespace std;
@ -105,7 +105,7 @@ PyObject *USDHydra_initPython(void)
{
PyObject *mod = PyModule_Create(&usdhydra::module);
usdhydra::addPythonSubmodule_stage(mod);
usdhydra::addPythonSubmodule_session(mod);
usdhydra::addPythonSubmodule_engine(mod);
usdhydra::addPythonSubmodule_utils(mod);
return mod;

View File

@ -1,806 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <pxr/pxr.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/base/gf/camera.h>
#include <pxr/imaging/glf/drawTarget.h>
#include <pxr/usd/usdGeom/camera.h>
#include <pxr/usd/usdLux/domeLight.h>
#include <pxr/usd/usdLux/shapingAPI.h>
#include <pxr/usdImaging/usdImagingGL/engine.h>
#include <pxr/usdImaging/usdImagingGL/renderParams.h>
#include <pxr/usdImaging/usdAppUtils/camera.h>
#include <pxr/base/plug/plugin.h>
#include <pxr/base/plug/registry.h>
#include "intern/usd_hierarchy_iterator.h"
#include "usdImagingLite/engine.h"
#include "usdImagingLite/renderParams.h"
#include "session.h"
#include "glog/logging.h"
using namespace pxr;
namespace usdhydra {
BlenderSession::BlenderSession(BL::RenderEngine &b_engine)
: b_engine(b_engine)
{
}
BlenderSession::~BlenderSession()
{
}
void BlenderSession::create()
{
stage = UsdStage::CreateInMemory();
}
void add_reference_to_prim(int is_preview, UsdStageRefPtr stage, UsdStageRefPtr new_stage, UsdPrim prim) {
if (is_preview) {
for (auto allowed_prim_name : preview_allowed_prims) {
if (prim.GetName().GetString().rfind(allowed_prim_name) != std::string::npos) {
UsdPrim override_prim = stage->OverridePrim(stage->GetPseudoRoot().GetPath().AppendChild(prim.GetName()));
override_prim.SetActive(true);
override_prim.GetReferences().ClearReferences();
override_prim.GetReferences().AddReference(new_stage->GetRootLayer()->GetRealPath(), prim.GetPath());
break;
}
}
}
else {
UsdPrim override_prim = stage->OverridePrim(stage->GetPseudoRoot().GetPath().AppendChild(prim.GetName()));
override_prim.SetActive(true);
override_prim.GetReferences().ClearReferences();
override_prim.GetReferences().AddReference(new_stage->GetRootLayer()->GetRealPath(), prim.GetPath());
}
}
void BlenderSession::reset(BL::Context &b_context, BL::Depsgraph &b_depsgraph, bool is_blender_scene, int stageId,
const char *render_delegate, int is_preview)
{
Depsgraph *depsgraph = (Depsgraph *)b_depsgraph.ptr.data;
set<SdfPath> existing_paths, new_paths, paths_to_remove, paths_to_add;
set<string> objects_to_update;
for (BL::DepsgraphUpdate &b_update : b_depsgraph.updates) {
BL::ID b_id(b_update.id());
objects_to_update.insert(b_id.name_full());
if (b_id.is_a(&RNA_Scene) || b_id.is_a(&RNA_Collection)) {
;
}
else if (b_id.is_a(&RNA_Material)) {
BL::Material b_mat(b_id);
}
else if (b_id.is_a(&RNA_Light)) {
BL::Light b_light(b_id);
}
else if (b_id.is_a(&RNA_Object)) {
// update_collection = true;
BL::Object b_ob(b_id);
}
else if (b_id.is_a(&RNA_Mesh)) {
BL::Mesh b_mesh(b_id);
}
else if (b_id.is_a(&RNA_World)) {
BL::World b_world(b_id);
}
else if (b_id.is_a(&RNA_Volume)) {
BL::Volume b_volume(b_id);
}
}
set_difference(existing_paths.begin(), existing_paths.end(),
new_paths.begin(), new_paths.end(),
inserter(paths_to_remove, paths_to_remove.end()));
set_difference(new_paths.begin(), new_paths.end(),
existing_paths.begin(), existing_paths.end(),
inserter(paths_to_add, paths_to_add.end()));
if (is_blender_scene) {
export_scene_to_usd(b_context, b_depsgraph, render_delegate, existing_paths, objects_to_update);
}
else {
stage = stageCache->Find(UsdStageCache::Id::FromLongInt(stageId));
}
}
void BlenderSession::render_gl(BL::Depsgraph &b_depsgraph, const char *render_delegate, HdRenderSettingsMap delegate_settings)
{
std::unique_ptr<UsdImagingGLEngine> imagingGLEngine = std::make_unique<UsdImagingGLEngine>();
if (!imagingGLEngine->SetRendererPlugin(TfToken(render_delegate))) {
return;
}
if (!delegate_settings.empty()){
for (auto const& pair : delegate_settings) {
imagingGLEngine->SetRendererSetting(pair.first, pair.second);
}
}
BL::Scene b_scene = b_depsgraph.scene_eval();
GlfDrawTargetRefPtr draw_target_ptr = GlfDrawTarget::New(GfVec2i(width, height));
draw_target_ptr->Bind();
draw_target_ptr->AddAttachment("color", GL_RGBA, GL_FLOAT, GL_RGBA);
UsdGeomCamera usd_camera = UsdAppUtilsGetCameraAtPath(stage, SdfPath(TfMakeValidIdentifier(b_scene.camera().data().name())));
UsdTimeCode usd_timecode = UsdTimeCode(b_scene.frame_current());
GfCamera gf_camera = usd_camera.GetCamera(usd_timecode);
imagingGLEngine->SetCameraState(gf_camera.GetFrustum().ComputeViewMatrix(),
gf_camera.GetFrustum().ComputeProjectionMatrix());
imagingGLEngine->SetRenderViewport(GfVec4d(0, 0, width, height));
imagingGLEngine->SetRendererAov(HdAovTokens->color);
render_params.frame = UsdTimeCode(b_scene.frame_current());
render_params.clearColor = GfVec4f(1.0, 1.0, 1.0, 0.0);
imagingGLEngine->Render(stage->GetPseudoRoot(), render_params);
BL::RenderResult b_result = b_engine.begin_result(0, 0, width, height, b_render_layer_name.c_str(), NULL);
BL::CollectionRef b_render_passes = b_result.layers[0].passes;
int channels = 4;
vector<float> pixels(width * height * channels);
glReadPixels(0, 0, width, height, GL_RGBA, GL_FLOAT, pixels.data());
draw_target_ptr->Unbind();
map<string, vector<float>> render_images{{"Combined", pixels}};
vector<float> images;
for (BL::RenderPass b_pass : b_render_passes) {
map<string, vector<float>>::iterator it_image = render_images.find(b_pass.name());
vector<float> image = it_image->second;
if (it_image == render_images.end()) {
image = vector<float>(width * height * channels);
}
if (b_pass.channels() != channels) {
for (int i = image.size(); i >= b_pass.channels(); i -= b_pass.channels()) {
image.erase(image.end() - i);
}
}
images.insert(images.end(), image.begin(), image.end());
}
for (BL::RenderPass b_pass : b_render_passes) {
b_pass.rect(images.data());
}
b_engine.end_result(b_result, false, false, false);
}
void BlenderSession::render(BL::Depsgraph& b_depsgraph, const char* render_delegate, HdRenderSettingsMap delegate_settings)
{
std::unique_ptr<UsdImagingLiteEngine> imagingLiteEngine = std::make_unique<UsdImagingLiteEngine>();
if (!imagingLiteEngine->SetRendererPlugin(TfToken(render_delegate))) {
return;
}
if (!delegate_settings.empty()){
for (auto const& pair : delegate_settings) {
imagingLiteEngine->SetRendererSetting(pair.first, pair.second);
}
}
BL::Scene b_scene = b_depsgraph.scene_eval();
UsdGeomCamera usd_camera = UsdAppUtilsGetCameraAtPath(stage, SdfPath(TfMakeValidIdentifier(b_scene.camera().data().name())));
UsdTimeCode usd_timecode = UsdTimeCode(b_scene.frame_current());
GfCamera gf_camera = usd_camera.GetCamera(usd_timecode);
imagingLiteEngine->SetCameraState(gf_camera);
imagingLiteEngine->SetRenderViewport(GfVec4d(0, 0, width, height));
imagingLiteEngine->SetRendererAov(HdAovTokens->color);
UsdImagingLiteRenderParams render_params;
render_params.frame = UsdTimeCode(b_scene.frame_current());
render_params.clearColor = GfVec4f(1.0, 1.0, 1.0, 0.0);
time_begin = chrono::steady_clock::now();
chrono::time_point<chrono::steady_clock> time_current;
chrono::milliseconds elapsed_time;
string formatted_time;
float percent_done = 0.0;
int channels = 4;
map<string, vector<float>> render_images{{"Combined", vector<float>(width * height * channels)}};
vector<float> &pixels = render_images["Combined"];
while (true) {
if (b_engine.test_break()) {
break;
}
imagingLiteEngine->Render(stage->GetPseudoRoot(), render_params);
percent_done = get_renderer_percent_done(&imagingLiteEngine);
time_current = chrono::steady_clock::now();
elapsed_time = chrono::duration_cast<chrono::milliseconds>(time_current - time_begin);
formatted_time = format_milliseconds(elapsed_time);
notify_final_render_status(percent_done / 100.0,
(b_scene.name() + ": " + b_render_layer_name).c_str(),
("Render Time: " + formatted_time + " | Done: " + to_string(int(percent_done)) + '%').c_str());
if (imagingLiteEngine->IsConverged()) {
break;
}
imagingLiteEngine->GetRendererAov(HdAovTokens->color, pixels.data());
update_render_result(render_images, b_render_layer_name, width, height, channels);
}
imagingLiteEngine->GetRendererAov(HdAovTokens->color, pixels.data());
update_render_result(render_images, b_render_layer_name, width, height, channels);
}
void BlenderSession::view_draw(BL::Depsgraph &b_depsgraph, BL::Context &b_context)
{
BL::Scene b_scene = b_depsgraph.scene_eval();
ViewSettings view_settings(b_context);
if (view_settings.get_width() * view_settings.get_height() == 0) {
return;
};
GfCamera gf_camera = view_settings.export_camera();
vector<GfVec4f> clip_planes = gf_camera.GetClippingPlanes();
for (int i = 0; i < clip_planes.size(); i++) {
render_params.clipPlanes.push_back((GfVec4d)clip_planes[i]);
}
imagingGLEngine->SetCameraState(gf_camera.GetFrustum().ComputeViewMatrix(),
gf_camera.GetFrustum().ComputeProjectionMatrix());
imagingGLEngine->SetRenderViewport(GfVec4d((double)view_settings.border[0][0], (double)view_settings.border[0][1],
(double)view_settings.border[1][0], (double)view_settings.border[1][1]));
b_engine.bind_display_space_shader(b_scene);
if (get_renderer_percent_done(&imagingGLEngine) == 0.0) {
time_begin = chrono::steady_clock::now();
}
imagingGLEngine->Render(stage->GetPseudoRoot(), render_params);
b_engine.unbind_display_space_shader();
glClear(GL_DEPTH_BUFFER_BIT);
chrono::time_point<chrono::steady_clock> time_current = chrono::steady_clock::now();
chrono::milliseconds elapsed_time = chrono::duration_cast<chrono::milliseconds>(time_current - time_begin);
string formatted_time = format_milliseconds(elapsed_time);
if (!imagingGLEngine->IsConverged()) {
notify_status(("Time: " + formatted_time + " | Done: " +
to_string(int(get_renderer_percent_done(&imagingGLEngine))) + '%').c_str(),
"Render");
}
else {
notify_status(("Time: " + formatted_time).c_str(), "Rendering Done", false);
}
}
void BlenderSession::view_update(BL::Depsgraph &b_depsgraph, BL::Context &b_context, const char *render_delegate, HdRenderSettingsMap delegate_settings)
{
if (!imagingGLEngine) {
imagingGLEngine = std::make_unique<UsdImagingGLEngine>();
}
imagingGLEngine->SetRendererPlugin(TfToken(render_delegate));
if (!delegate_settings.empty()){
for (auto const& pair : delegate_settings) {
imagingGLEngine->SetRendererSetting(pair.first, pair.second);
}
}
if (imagingGLEngine->IsPauseRendererSupported()) {
imagingGLEngine->PauseRenderer();
}
sync(b_depsgraph, b_context);
if (imagingGLEngine->IsPauseRendererSupported()) {
imagingGLEngine->ResumeRenderer();
}
}
void BlenderSession::sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context)
{
BL::Scene b_scene = b_depsgraph.scene_eval();
ViewSettings view_settings(b_context);
render_params.frame = UsdTimeCode(b_scene.frame_current());
}
void BlenderSession::sync_final_render(BL::Depsgraph& b_depsgraph) {
BL::Scene b_scene = b_depsgraph.scene_eval();
b_render_layer_name = b_depsgraph.view_layer().name();
vector<vector<float>> border ={{0.0, 0.0}, {1.0, 1.0}};
if (b_scene.render().use_border()) {
border = {
{b_scene.render().border_min_x(),
b_scene.render().border_min_y()},
{b_scene.render().border_max_x() - b_scene.render().border_min_x(),
b_scene.render().border_max_y() - b_scene.render().border_min_y()}
};
}
int screen_width = int(b_scene.render().resolution_x() * b_scene.render().resolution_percentage() / 100);
int screen_height = int(b_scene.render().resolution_y() * b_scene.render().resolution_percentage() / 100);
width = int(screen_width * border[1][0]);
height = int(screen_height * border[1][1]);
}
void BlenderSession::export_scene_to_usd(BL::Context &b_context, BL::Depsgraph &b_depsgraph,
const char *render_delegate, set<pxr::SdfPath> existing_paths, set<string> objects_to_update)
{
LOG(INFO) << "export_scene_to_usd";
Depsgraph *depsgraph = (Depsgraph *)b_depsgraph.ptr.data;
Scene *scene = DEG_get_input_scene(depsgraph);
World *world = scene->world;
DEG_graph_build_for_all_objects(depsgraph);
bContext *C = (bContext *)b_context.ptr.data;
Main *bmain = CTX_data_main(C);
USDExportParams usd_export_params;
usd_export_params.selected_objects_only = false;
usd_export_params.visible_objects_only = false;
stage->Reload();
stage->SetMetadata(UsdGeomTokens->upAxis, VtValue(UsdGeomTokens->z));
stage->SetMetadata(UsdGeomTokens->metersPerUnit, static_cast<double>(scene->unit.scale_length));
stage->GetRootLayer()->SetDocumentation(std::string("Blender v") + BKE_blender_version_string());
/* Set up the stage for animated data. */
//if (data->params.export_animation) {
// stage->SetTimeCodesPerSecond(FPS);
// stage->SetStartTimeCode(scene->r.sfra);
// stage->SetEndTimeCode(scene->r.efra);
//}
blender::io::usd::USDHierarchyIterator iter(bmain, depsgraph, stage, usd_export_params);
iter.iterate_and_write();
iter.release_writers();
UsdLuxDomeLight world_light = UsdLuxDomeLight::Get(stage, SdfPath("/World/World"));
if (world_light){
pxr::UsdGeomXformOp xOp = world_light.AddRotateXOp();
pxr::UsdGeomXformOp yOp = world_light.AddRotateYOp();
if (strcmp(render_delegate, "HdStormRendererPlugin") == 0){
yOp.Set(90.0f);
}
else if (strcmp(render_delegate, "HdRprPlugin") == 0){
xOp.Set(180.0f);
yOp.Set(-90.0f);
}
}
//if (data->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));
// for (float frame = scene->r.sfra; frame <= scene->r.efra; frame++) {
// if (G.is_break || (stop != nullptr && *stop)) {
// break;
// }
// /* Update the scene for the next frame to render. */
// scene->r.cfra = static_cast<int>(frame);
// scene->r.subframe = frame - scene->r.cfra;
// BKE_scene_graph_update_for_newframe(data->depsgraph);
// iter.set_export_frame(frame);
// iter.iterate_and_write();
// *progress += progress_per_frame;
// *do_update = true;
// }
//}
//else {
// /* If we're not animating, a single iteration over all objects is enough. */
// iter.iterate_and_write();
//}
}
void BlenderSession::update_render_result(map<string, vector<float>> &render_images, string b_render_layer_name, int width, int height, int channels)
{
BL::RenderResult b_result = b_engine.begin_result(0, 0, width, height, b_render_layer_name.c_str(), NULL);
BL::CollectionRef b_render_passes = b_result.layers[0].passes;
vector<float> images;
for (BL::RenderPass b_pass : b_render_passes) {
map<string, vector<float>>::iterator it_image = render_images.find(b_pass.name());
vector<float> image = it_image->second;
if (it_image == render_images.end()) {
image = vector<float>(width * height * channels);
}
if (b_pass.channels() != channels) {
for (int i = image.size(); i >= b_pass.channels(); i -= b_pass.channels()) {
image.erase(image.end() - i);
}
}
images.insert(images.end(), image.begin(), image.end());
}
for (BL::RenderPass b_pass : b_render_passes) {
b_pass.rect(images.data());
}
b_engine.end_result(b_result, false, false, false);
}
void BlenderSession::notify_status(const char *info, const char *status, bool redraw)
{
b_engine.update_stats(status, info);
if (redraw) {
b_engine.tag_redraw();
}
};
void BlenderSession::notify_final_render_status(float progress, const char *title, const char* info)
{
b_engine.update_progress(progress);
b_engine.update_stats(title, info);
}
/* ------------------------------------------------------------------------- */
/* Python API for BlenderSession
*/
static PyObject *create_func(PyObject * /*self*/, PyObject *args)
{
DLOG(INFO) << "create_func";
PyObject *pyengine;
char *engine_type, *delegate_name;
if (!PyArg_ParseTuple(args, "Oss", &pyengine, &engine_type, &delegate_name)) {
Py_RETURN_NONE;
}
PointerRNA engineptr;
RNA_pointer_create(NULL, &RNA_RenderEngine, (void *)PyLong_AsVoidPtr(pyengine), &engineptr);
BL::RenderEngine engine(engineptr);
/* create session */
BlenderSession *session = new BlenderSession(engine);
session->create();
return PyLong_FromVoidPtr(session);
}
static PyObject *free_func(PyObject * /*self*/, PyObject *args)
{
LOG(INFO) << "free_func";
PyObject *pysession;
if (!PyArg_ParseTuple(args, "O", &pysession)) {
Py_RETURN_NONE;
}
delete (BlenderSession *)PyLong_AsVoidPtr(pysession);
Py_RETURN_NONE;
}
static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
{
LOG(INFO) << "reset_func";
PyObject *pysession, *pydata, *pycontext, *pydepsgraph;
int stageId = 0;
int is_blender_scene = 1, is_preview = 0;
const char *render_delegate;
if (!PyArg_ParseTuple(args, "OOOOiisi", &pysession, &pydata, &pycontext, &pydepsgraph,
&is_blender_scene, &stageId, &render_delegate, &is_preview)) {
Py_RETURN_NONE;
}
PointerRNA depsgraphptr;
RNA_pointer_create(NULL, &RNA_Context, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph b_depsgraph(depsgraphptr);
PointerRNA contextptr;
RNA_pointer_create(NULL, &RNA_Context, (ID *)PyLong_AsVoidPtr(pycontext), &contextptr);
BL::Context b_context(contextptr);
BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
//PointerRNA dataptr;
//RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
//BL::BlendData data(dataptr);
//PointerRNA depsgraphptr;
//RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
//BL::Depsgraph depsgraph(depsgraphptr);
session->reset(b_context, b_depsgraph, is_blender_scene, stageId, render_delegate, is_preview);
Py_RETURN_NONE;
}
static PyObject* final_update_func(PyObject* /*self*/, PyObject* args)
{
LOG(INFO) << "final_update_func";
PyObject *pysession, *pydepsgraph;
if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph)) {
Py_RETURN_NONE;
}
PointerRNA depsgraphptr;
RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph depsgraph(depsgraphptr);
BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
session->sync_final_render(depsgraph);
Py_RETURN_NONE;
}
static PyObject *render_func(PyObject * /*self*/, PyObject *args)
{
LOG(INFO) << "render_func";
PyObject *pysession, *pydepsgraph, *delegate_settings;
const char *render_delegate;
if (!PyArg_ParseTuple(args, "OOsO", &pysession, &pydepsgraph, &render_delegate, &delegate_settings)) {
Py_RETURN_NONE;
}
PointerRNA depsgraphptr;
RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph depsgraph(depsgraphptr);
BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
HdRenderSettingsMap settings;
if (delegate_settings != Py_None) {
PyObject *iter = PyObject_GetIter(delegate_settings);
if (iter) {
while (true) {
PyObject *next = PyIter_Next(iter);
char *key_dirty = nullptr;
char *value_dirty_s = nullptr;
float value_dirty_f = 0.0f;
int value_dirty_i = 0;
VtValue value;
TfToken key;
if (!next) {
break;
}
PyErr_Clear();
if (PyArg_ParseTuple(next, "si", &key_dirty, &value_dirty_i)) {
TfToken key(key_dirty);
VtValue value(value_dirty_i);
settings.insert(pair (key, value));
continue;
}
if (PyArg_ParseTuple(next, "ss", &key_dirty, &value_dirty_s)) {
TfToken key(key_dirty);
VtValue value(value_dirty_s);
settings.insert(pair (key, value));
continue;
}
if (PyArg_ParseTuple(next, "sf", &key_dirty, &value_dirty_f)) {
TfToken key(key_dirty);
VtValue value(value_dirty_f);
settings.insert(pair (key, value));
continue;
}
}
PyErr_Clear();
}
}
if (strcmp(render_delegate, "HdRprPlugin") == 0) {
session->render(depsgraph, render_delegate, settings);
}
else {
session->render_gl(depsgraph, render_delegate, settings);
}
Py_RETURN_NONE;
}
static PyObject *render_frame_finish_func(PyObject * /*self*/, PyObject *args)
{
Py_RETURN_NONE;
}
static PyObject *view_update_func(PyObject * /*self*/, PyObject *args)
{
LOG(INFO) << "view_update_func";
PyObject *pysession, *pydepsgraph, *pycontext, *pyspaceData, *pyregionData, *delegate_settings;
const char *render_delegate;
if (!PyArg_ParseTuple(args, "OOOOOsO", &pysession, &pydepsgraph, &pycontext, &pyspaceData, &pyregionData, &render_delegate, &delegate_settings)) {
Py_RETURN_NONE;
}
PointerRNA depsgraphptr;
RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph b_depsgraph(depsgraphptr);
PointerRNA contextptr;
RNA_pointer_create(NULL, &RNA_Context, (ID *)PyLong_AsVoidPtr(pycontext), &contextptr);
BL::Context b_context(contextptr);
BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
HdRenderSettingsMap settings;
if (delegate_settings != Py_None) {
PyObject *iter = PyObject_GetIter(delegate_settings);
if (iter) {
while (true) {
PyObject *next = PyIter_Next(iter);
char *key_dirty = nullptr;
char *value_dirty_s = nullptr;
float value_dirty_f = 0.0f;
int value_dirty_i = 0;
VtValue value;
TfToken key;
if (!next) {
break;
}
if (PyArg_ParseTuple(next, "si", &key_dirty, &value_dirty_i)) {
TfToken key(key_dirty);
VtValue value(value_dirty_i);
settings.insert(pair (key, value));
continue;
}
if (PyArg_ParseTuple(next, "ss", &key_dirty, &value_dirty_s)) {
TfToken key(key_dirty);
VtValue value(value_dirty_s);
settings.insert(pair (key, value));
continue;
}
if (PyArg_ParseTuple(next, "sf", &key_dirty, &value_dirty_f)) {
TfToken key(key_dirty);
VtValue value(value_dirty_f);
settings.insert(pair (key, value));
continue;
}
}
PyErr_Clear();
}
}
session->view_update(b_depsgraph, b_context, render_delegate, settings);
Py_RETURN_NONE;
}
static PyObject *view_draw_func(PyObject * /*self*/, PyObject *args)
{
LOG(INFO) << "view_draw_func";
PyObject *pysession, *pydepsgraph, *pycontext, *pyspaceData, *pyregionData;
if (!PyArg_ParseTuple(args, "OOOOO", &pysession, &pydepsgraph, &pycontext, &pyspaceData, &pyregionData)) {
Py_RETURN_NONE;
}
PointerRNA depsgraphptr;
RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph b_depsgraph(depsgraphptr);
PointerRNA contextptr;
RNA_pointer_create(NULL, &RNA_Context, (ID *)PyLong_AsVoidPtr(pycontext), &contextptr);
BL::Context b_context(contextptr);
BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
session->view_draw(b_depsgraph, b_context);
///* Allow Blender to execute other Python scripts. */
//python_thread_state_save(&session->python_thread_state);
//session->render(b_depsgraph);
//python_thread_state_restore(&session->python_thread_state);
Py_RETURN_NONE;
}
static PyObject* get_render_plugins_func(PyObject* /*self*/, PyObject* args)
{
PlugRegistry &registry = PlugRegistry::GetInstance();
TfTokenVector pluginsIds = UsdImagingGLEngine::GetRendererPlugins();
PyObject *ret = PyTuple_New(pluginsIds.size());
for (int i = 0; i < pluginsIds.size(); ++i) {
PyObject *descr = PyDict_New();
PyDict_SetItemString(descr, "id", PyUnicode_FromString(pluginsIds[i].GetText()));
PyDict_SetItemString(descr, "name", PyUnicode_FromString(UsdImagingGLEngine::GetRendererDisplayName(pluginsIds[i]).c_str()));
std::string plugin_name = pluginsIds[i];
plugin_name = plugin_name.substr(0, plugin_name.size()-6);
plugin_name[0] = tolower(plugin_name[0]);
std::string path = "";
PlugPluginPtr plugin = registry.GetPluginWithName(plugin_name);
if (plugin) {
path = plugin->GetPath();
}
PyDict_SetItemString(descr, "path", PyUnicode_FromString(path.c_str()));
PyTuple_SetItem(ret, i, descr);
}
return ret;
}
static PyMethodDef methods[] = {
{"create", create_func, METH_VARARGS, ""},
{"free", free_func, METH_VARARGS, ""},
{"render", render_func, METH_VARARGS, ""},
{"sync", sync_func, METH_VARARGS, ""},
{"view_draw", view_draw_func, METH_VARARGS, ""},
{"get_render_plugins", get_render_plugins_func, METH_VARARGS, ""},
{NULL, NULL, 0, NULL},
};
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT,
"session",
"",
-1,
methods,
NULL,
NULL,
NULL,
NULL,
};
PyObject *addPythonSubmodule_session(PyObject *mod)
{
PyObject *submodule = PyModule_Create(&module);
PyModule_AddObject(mod, "session", submodule);
return submodule;
}
} // namespace usdhydra

View File

@ -1,91 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#pragma once
#include <chrono>
#include <Python.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/usdImaging/usdImagingGL/engine.h>
#include <pxr/usdImaging/usdAppUtils/camera.h>
#include "MEM_guardedalloc.h"
#include "RNA_blender_cpp.h"
#include "usd.h"
#include "intern/usd_exporter_context.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_context.h"
#include "BKE_blender_version.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "utils.h"
#include "session.h"
#include "stage.h"
#include "view_settings.h"
namespace usdhydra {
const vector<string> preview_allowed_prims = {"World", "Camera", "Floor", "_materials", "preview_", "CircularLight"};
class BlenderSession {
public:
BlenderSession(BL::RenderEngine &b_engine);
~BlenderSession();
void create();
void reset(BL::Context &b_context, BL::Depsgraph &b_depsgraph, bool is_blender_scene, int stageId,
const char *render_delegate, int is_preview);
void render(BL::Depsgraph &b_depsgraph, const char *render_delegate, HdRenderSettingsMap delegate_settings);
void render_gl(BL::Depsgraph &b_depsgraph, const char *render_delegate, HdRenderSettingsMap delegate_settings);
void view_draw(BL::Depsgraph &b_depsgraph, BL::Context &b_context);
void view_update(BL::Depsgraph &b_depsgraph, BL::Context &b_context, const char *render_delegate, HdRenderSettingsMap delegate_settings);
void sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context);
void sync_final_render(BL::Depsgraph &b_depsgraph);
void export_scene_to_usd(BL::Context &b_context, BL::Depsgraph &b_depsgraph,
const char *render_delegate, set<SdfPath> existing_paths = {}, set<string> objects_to_update = {});
template <typename T>
float get_renderer_percent_done(T *renderer)
{
float percent_done = 0.0;
VtDictionary render_stats = renderer->get()->GetRenderStats();
auto it = render_stats.find("percentDone");
if (it != render_stats.end()) {
percent_done = (float)it->second.UncheckedGet<double>();
}
return round(percent_done * 10.0f) / 10.0f;
}
protected:
void update_render_result(map<string, vector<float>> &render_images, string b_render_layer_name, int width, int height, int channels = 4);
void notify_status(const char *info, const char *status, bool redraw = true);
void notify_final_render_status(float progress, const char *title, const char *info);
public:
BL::RenderEngine b_engine;
//BL::BlendData b_data;
std::unique_ptr<pxr::UsdImagingGLEngine> imagingGLEngine;
pxr::UsdImagingGLRenderParams render_params;
pxr::UsdStageRefPtr stage;
protected:
chrono::time_point<chrono::steady_clock> time_begin;
int width;
int height;
string b_render_layer_name;
};
PyObject *addPythonSubmodule_session(PyObject *mod);
} // namespace usdhydra

View File

@ -92,10 +92,6 @@ ViewSettings::ViewSettings(BL::Context b_context)
border[1][1] = y2 - y1;
}
ViewSettings::~ViewSettings()
{
}
int ViewSettings::get_width()
{
return border[1][0];

View File

@ -10,22 +10,19 @@
namespace usdhydra {
class ViewSettings {
public:
ViewSettings(BL::Context b_context);
struct ViewSettings {
ViewSettings(BL::Context b_context);
~ViewSettings();
int get_width();
int get_height();
int get_width();
int get_height();
pxr::GfCamera export_camera();
pxr::GfCamera export_camera();
CameraData camera_data;
CameraData camera_data;
int screen_width;
int screen_height;
int border[2][2];
int screen_width;
int screen_height;
int border[2][2];
};
} // namespace usdhydra