forked from blender/blender
BLEN-368: Fixes in hydra.py #15
114
release/scripts/modules/bpy_hydra.py
Normal file
114
release/scripts/modules/bpy_hydra.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
"""
|
||||||
|
Implementation of class `HydraRenderEngine`.
|
||||||
|
|
||||||
|
Render Blender addon with Hydra render delegate should inherit `HydraRenderEngine`.
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
import bpy_hydra
|
||||||
|
|
||||||
|
class CustomHydraRenderEngine(HydraRenderEngine):
|
||||||
|
bl_idname = 'CustomHydraRenderEngine'
|
||||||
|
bl_label = "Hydra: Custom"
|
||||||
|
bl_info = "Hydra Custom render delegate"
|
||||||
|
|
||||||
|
delegate_id = 'HdCustomRendererPlugin'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def register(cls):
|
||||||
|
super().register()
|
||||||
|
|
||||||
|
bpy_hydra.register_plugins(["/path/to/plugin")], ["/additional/system/path")])
|
||||||
|
|
||||||
|
def get_delegate_settings(self, engine_type):
|
||||||
|
return {
|
||||||
|
'setting1': 1,
|
||||||
|
'setting2': "2",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"HydraRenderEngine",
|
||||||
|
"export_mtlx",
|
||||||
|
"register_plugins",
|
||||||
|
"get_render_plugins",
|
||||||
|
)
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import _bpy_hydra
|
||||||
|
|
||||||
|
from _bpy_hydra import register_plugins, get_render_plugins
|
||||||
|
|
||||||
|
|
||||||
|
class HydraRenderEngine(bpy.types.RenderEngine):
|
||||||
|
""" Render addon with Hydra render delegate should inherit this class """
|
||||||
|
|
||||||
|
bl_use_shading_nodes_custom = False
|
||||||
|
|
||||||
|
delegate_id = ''
|
||||||
|
engine_ptr = None
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
if not self.engine_ptr:
|
||||||
|
return
|
||||||
|
|
||||||
|
_bpy_hydra.engine_free(self.engine_ptr)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def register(cls):
|
||||||
|
_bpy_hydra.init()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unregister(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_delegate_settings(self, engine_type):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
# final render
|
||||||
|
def update(self, data, depsgraph):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def render(self, depsgraph):
|
||||||
|
engine_type = 'PREVIEW' if self.is_preview else 'FINAL'
|
||||||
|
|
||||||
|
self.engine_ptr = _bpy_hydra.engine_create(self.as_pointer(), engine_type, self.delegate_id)
|
||||||
|
delegate_settings = self.get_delegate_settings(engine_type)
|
||||||
|
|
||||||
|
_bpy_hydra.engine_sync(self.engine_ptr, depsgraph.as_pointer(), bpy.context.as_pointer(), delegate_settings)
|
||||||
|
_bpy_hydra.engine_render(self.engine_ptr, depsgraph.as_pointer())
|
||||||
|
|
||||||
|
# viewport render
|
||||||
|
def view_update(self, context, depsgraph):
|
||||||
|
if not self.engine_ptr:
|
||||||
|
self.engine_ptr = _bpy_hydra.engine_create(self.as_pointer(), 'VIEWPORT', self.delegate_id)
|
||||||
|
|
||||||
|
delegate_settings = self.get_delegate_settings('VIEWPORT')
|
||||||
|
_bpy_hydra.engine_sync(self.engine_ptr, depsgraph.as_pointer(), context.as_pointer(), delegate_settings)
|
||||||
|
|
||||||
|
def view_draw(self, context, depsgraph):
|
||||||
|
if not self.engine_ptr:
|
||||||
|
return
|
||||||
|
|
||||||
|
_bpy_hydra.engine_view_draw(self.engine_ptr, depsgraph.as_pointer(), context.as_pointer())
|
||||||
|
|
||||||
|
|
||||||
|
def export_mtlx(material):
|
||||||
|
""" Exports material to .mtlx file. It is called from Blender source code. """
|
||||||
|
try:
|
||||||
|
import materialx.utils as mx_utils
|
||||||
|
|
||||||
|
doc = mx_utils.export(material, None)
|
||||||
|
if not doc:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
mtlx_file = mx_utils.get_temp_file(".mtlx", material.name)
|
||||||
|
mx_utils.export_to_file(doc, mtlx_file, export_deps=True, copy_deps=False)
|
||||||
|
return str(mtlx_file)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
print("ERROR: no MaterialX addon available")
|
||||||
|
|
||||||
|
return ""
|
@ -1,85 +0,0 @@
|
|||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
# Copyright 2011-2022 Blender Foundation
|
|
||||||
|
|
||||||
# <pep8 compliant>
|
|
||||||
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
import bpy
|
|
||||||
import _hydra
|
|
||||||
|
|
||||||
from _hydra import register_plugins, get_render_plugins
|
|
||||||
|
|
||||||
|
|
||||||
class HydraRenderEngine(bpy.types.RenderEngine):
|
|
||||||
bl_use_preview = True
|
|
||||||
bl_use_shading_nodes_custom = False
|
|
||||||
|
|
||||||
delegate_id = ''
|
|
||||||
engine_ptr = None
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
if not self.engine_ptr:
|
|
||||||
return
|
|
||||||
|
|
||||||
_hydra.engine_free(self.engine_ptr)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def register(cls):
|
|
||||||
_hydra.init()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def unregister(cls):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_delegate_settings(self, engine_type):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
# final render
|
|
||||||
def update(self, data, depsgraph):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def render(self, depsgraph):
|
|
||||||
engine_type = 'PREVIEW' if self.is_preview else 'FINAL'
|
|
||||||
|
|
||||||
self.engine_ptr = _hydra.engine_create(self.as_pointer(), engine_type, self.delegate_id)
|
|
||||||
delegate_settings = self.get_delegate_settings(engine_type)
|
|
||||||
|
|
||||||
_hydra.engine_sync(self.engine_ptr, depsgraph.as_pointer(), bpy.context.as_pointer(), delegate_settings)
|
|
||||||
_hydra.engine_render(self.engine_ptr, depsgraph.as_pointer())
|
|
||||||
|
|
||||||
# viewport render
|
|
||||||
def view_update(self, context, depsgraph):
|
|
||||||
if not self.engine_ptr:
|
|
||||||
self.engine_ptr = _hydra.engine_create(self.as_pointer(), 'VIEWPORT', self.delegate_id)
|
|
||||||
|
|
||||||
delegate_settings = self.get_delegate_settings('VIEWPORT')
|
|
||||||
_hydra.engine_sync(self.engine_ptr, depsgraph.as_pointer(), context.as_pointer(), delegate_settings)
|
|
||||||
|
|
||||||
def view_draw(self, context, depsgraph):
|
|
||||||
if not self.engine_ptr:
|
|
||||||
return
|
|
||||||
|
|
||||||
_hydra.engine_view_draw(self.engine_ptr, depsgraph.as_pointer(), context.as_pointer())
|
|
||||||
|
|
||||||
|
|
||||||
def export_mtlx(material_name):
|
|
||||||
try:
|
|
||||||
import materialx.utils as mx_utils
|
|
||||||
|
|
||||||
material = bpy.data.materials[material_name]
|
|
||||||
doc = mx_utils.export(material, None)
|
|
||||||
if not doc:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
mtlx_file = mx_utils.get_temp_file(".mtlx", material.name)
|
|
||||||
mx_utils.export_to_file(doc, mtlx_file, export_deps=True, copy_deps=False)
|
|
||||||
return str(mtlx_file)
|
|
||||||
|
|
||||||
except ImportError:
|
|
||||||
print("ERROR: no MaterialX addon available")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print("ERROR:", e, traceback.format_exc())
|
|
||||||
|
|
||||||
return ""
|
|
@ -256,8 +256,8 @@ static PyObject *CCL_initPython(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_HYDRA
|
#ifdef WITH_HYDRA
|
||||||
/* defined in USD Hydra module */
|
/* defined in render_hydra module */
|
||||||
extern PyObject *Hydra_initPython(void);
|
extern PyObject *BPyInit_hydra(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct _inittab bpy_internal_modules[] = {
|
static struct _inittab bpy_internal_modules[] = {
|
||||||
@ -290,7 +290,7 @@ static struct _inittab bpy_internal_modules[] = {
|
|||||||
{"gpu", BPyInit_gpu},
|
{"gpu", BPyInit_gpu},
|
||||||
{"idprop", BPyInit_idprop},
|
{"idprop", BPyInit_idprop},
|
||||||
#ifdef WITH_HYDRA
|
#ifdef WITH_HYDRA
|
||||||
{"_hydra", Hydra_initPython},
|
{"_bpy_hydra", BPyInit_hydra},
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
@ -34,7 +34,9 @@ set(INC
|
|||||||
../../gpu
|
../../gpu
|
||||||
../../gpu/opengl
|
../../gpu/opengl
|
||||||
../../gpu/intern
|
../../gpu/intern
|
||||||
|
../../python/intern
|
||||||
..
|
..
|
||||||
|
${CMAKE_BINARY_DIR}/source/blender/makesrna/intern
|
||||||
)
|
)
|
||||||
|
|
||||||
set(INC_SYS
|
set(INC_SYS
|
||||||
|
@ -266,7 +266,7 @@ static PyMethodDef methods[] = {
|
|||||||
|
|
||||||
static struct PyModuleDef module = {
|
static struct PyModuleDef module = {
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"_hydra",
|
"_bpy_hydra",
|
||||||
"Hydra render API",
|
"Hydra render API",
|
||||||
-1,
|
-1,
|
||||||
methods,
|
methods,
|
||||||
@ -282,7 +282,7 @@ static struct PyModuleDef module = {
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PyObject *Hydra_initPython(void)
|
PyObject *BPyInit_hydra(void)
|
||||||
{
|
{
|
||||||
PyObject *mod = PyModule_Create(&blender::render::hydra::module);
|
PyObject *mod = PyModule_Create(&blender::render::hydra::module);
|
||||||
return mod;
|
return mod;
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
#include "BKE_lib_id.h"
|
#include "BKE_lib_id.h"
|
||||||
#include "BKE_material.h"
|
#include "BKE_material.h"
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
#include "RNA_blender_cpp.h"
|
||||||
|
#include "bpy_rna.h"
|
||||||
|
|
||||||
#include "blender_scene_delegate.h"
|
#include "blender_scene_delegate.h"
|
||||||
#include "material.h"
|
#include "material.h"
|
||||||
#include "mtlx_hydra_adapter.h"
|
#include "mtlx_hydra_adapter.h"
|
||||||
@ -74,14 +78,26 @@ void MaterialData::export_mtlx()
|
|||||||
gstate = PyGILState_Ensure();
|
gstate = PyGILState_Ensure();
|
||||||
|
|
||||||
PyObject *module, *dict, *func, *result;
|
PyObject *module, *dict, *func, *result;
|
||||||
module = PyImport_ImportModule("hydra");
|
module = PyImport_ImportModule("bpy_hydra");
|
||||||
dict = PyModule_GetDict(module);
|
dict = PyModule_GetDict(module);
|
||||||
func = PyDict_GetItemString(dict, "export_mtlx");
|
func = PyDict_GetItemString(dict, "export_mtlx");
|
||||||
result = PyObject_CallFunction(func, "s", name().c_str());
|
|
||||||
|
|
||||||
std::string path = PyUnicode_AsUTF8(result);
|
PointerRNA materialptr;
|
||||||
|
RNA_pointer_create(NULL, &RNA_Material, id, &materialptr);
|
||||||
|
PyObject *material = pyrna_struct_CreatePyObject(&materialptr);
|
||||||
|
|
||||||
|
result = PyObject_CallFunction(func, "O", material);
|
||||||
|
|
||||||
|
Py_DECREF(material);
|
||||||
|
|
||||||
|
std::string path;
|
||||||
|
if (result) {
|
||||||
|
path = PyUnicode_AsUTF8(result);
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_Print();
|
||||||
|
}
|
||||||
Py_DECREF(module);
|
Py_DECREF(module);
|
||||||
|
|
||||||
PyGILState_Release(gstate);
|
PyGILState_Release(gstate);
|
||||||
|
Loading…
Reference in New Issue
Block a user