BLEN-368: Fixes in hydra.py #15

Merged
Bogdan Nagirniak merged 2 commits from BLEN-368 into hydra-render 2023-03-16 14:43:06 +01:00
6 changed files with 141 additions and 94 deletions

View 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 ""

View File

@ -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 ""

View File

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

View File

@ -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

View File

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

View File

@ -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);
Py_DECREF(result); result = PyObject_CallFunction(func, "O", material);
Py_DECREF(material);
std::string path;
if (result) {
path = PyUnicode_AsUTF8(result);
Py_DECREF(result);
}
else {
PyErr_Print();
}
Py_DECREF(module); Py_DECREF(module);
PyGILState_Release(gstate); PyGILState_Release(gstate);