From 2f5f8e5e8380e7d7f4d34ad140ec1728332ec4a7 Mon Sep 17 00:00:00 2001 From: George Shakula Date: Wed, 22 Feb 2023 17:59:50 +0200 Subject: [PATCH 1/4] BLEN-326: Pass MaterialX to Hydra via hdMaterialNetwork --- .../cmake/platform/platform_win32.cmake | 7 ++ source/blender/render/hydra/CMakeLists.txt | 13 +++ .../sceneDelegate/blenderSceneDelegate.cc | 2 +- .../render/hydra/sceneDelegate/material.cc | 21 ++++- .../render/hydra/sceneDelegate/material.h | 2 +- .../hydra/sceneDelegate/mtlxHydraAdapter.cc | 86 +++++++++++++++++++ .../hydra/sceneDelegate/mtlxHydraAdapter.h | 24 ++++++ source/creator/CMakeLists.txt | 6 ++ 8 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.cc create mode 100644 source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.h diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 675429deb770..a47d0cf47d5d 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -899,6 +899,13 @@ if(WITH_USD) endif() endif() +if(WITH_MATERIALX) + windows_find_package(MaterialX) + if(NOT MaterialX_FOUND) + include("${LIBDIR}/MaterialX/lib/cmake/MaterialX/MaterialXTargets.cmake") + endif() +endif() + if(WINDOWS_PYTHON_DEBUG) # Include the system scripts in the blender_python_system_scripts project. file(GLOB_RECURSE inFiles "${CMAKE_SOURCE_DIR}/release/scripts/*.*" ) diff --git a/source/blender/render/hydra/CMakeLists.txt b/source/blender/render/hydra/CMakeLists.txt index 883177b61977..89a2592b0c81 100644 --- a/source/blender/render/hydra/CMakeLists.txt +++ b/source/blender/render/hydra/CMakeLists.txt @@ -86,4 +86,17 @@ set(LIB blender_add_lib(bf_render_hydra "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") +if(TARGET MaterialXCore AND TARGET MaterialXFormat) + target_sources(bf_render_hydra PRIVATE + sceneDelegate/mtlxHydraAdapter.h + sceneDelegate/mtlxHydraAdapter.cc) + target_compile_definitions(bf_render_hydra PRIVATE + _MTLX_TRANSLATION_ENABLED) + target_link_libraries(bf_render_hydra PRIVATE + MaterialXCore + MaterialXFormat) +else() + message(WARN "Compiling Hydra Scene Delegate without MaterialX-to-Hydra translation") +endif() + add_dependencies(bf_render_hydra bf_rna) diff --git a/source/blender/render/hydra/sceneDelegate/blenderSceneDelegate.cc b/source/blender/render/hydra/sceneDelegate/blenderSceneDelegate.cc index 22a244d512dd..e9d84b8f046e 100644 --- a/source/blender/render/hydra/sceneDelegate/blenderSceneDelegate.cc +++ b/source/blender/render/hydra/sceneDelegate/blenderSceneDelegate.cc @@ -343,7 +343,7 @@ VtValue BlenderSceneDelegate::GetMaterialResource(SdfPath const& id) { MaterialData *mat_data = material_data(id); if (mat_data) { - return mat_data->material_resource(); + return mat_data->material_resource(this); } return VtValue(); } diff --git a/source/blender/render/hydra/sceneDelegate/material.cc b/source/blender/render/hydra/sceneDelegate/material.cc index 492157bfa5cd..7c25b6963014 100644 --- a/source/blender/render/hydra/sceneDelegate/material.cc +++ b/source/blender/render/hydra/sceneDelegate/material.cc @@ -5,6 +5,7 @@ #include #include +#include #include "glog/logging.h" @@ -12,6 +13,7 @@ #include "BKE_lib_id.h" #include "material.h" +#include "mtlxHydraAdapter.h" using namespace pxr; @@ -47,9 +49,24 @@ VtValue MaterialData::get_data(TfToken const &key) return ret; } -pxr::VtValue MaterialData::material_resource() +pxr::VtValue MaterialData::material_resource(pxr::HdSceneDelegate *scene_delegate) { - /* TODO: Implement return of HdMaterialNetwork */ +#if defined(_MTLX_TRANSLATION_ENABLED) + std::string const &path = mtlx_path.GetResolvedPath(); + if (!path.empty()) { + HdRenderDelegate *render_delegate = scene_delegate->GetRenderIndex().GetRenderDelegate(); + TfTokenVector shader_source_types = render_delegate->GetShaderSourceTypes(); + TfTokenVector render_contexts = render_delegate->GetMaterialRenderContexts(); + + HdMaterialNetworkMap material_network_map; + HdMtlxConvertToMaterialNetworkMap( + path, shader_source_types, render_contexts, &material_network_map); + return VtValue(material_network_map); + } +#else +# pragma message("Compiling without MaterialX translation") +#endif + return pxr::VtValue(); } diff --git a/source/blender/render/hydra/sceneDelegate/material.h b/source/blender/render/hydra/sceneDelegate/material.h index 17a21382a270..2a1cf18cc08e 100644 --- a/source/blender/render/hydra/sceneDelegate/material.h +++ b/source/blender/render/hydra/sceneDelegate/material.h @@ -25,7 +25,7 @@ class MaterialData: IdData { void remove_prim() override; void mark_prim_dirty(DirtyBits dirty_bits) override; - pxr::VtValue material_resource(); + pxr::VtValue material_resource(pxr::HdSceneDelegate *scene_delegate); void export_mtlx(); private: diff --git a/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.cc b/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.cc new file mode 100644 index 000000000000..946f9b7f69e6 --- /dev/null +++ b/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.cc @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "mtlxHydraAdapter.h" + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace mx = MaterialX; + +PXR_NAMESPACE_OPEN_SCOPE + +template static bool _Read(UsdStagePtr stage, R &&reader) +{ + try { + auto doc = reader(); + if (doc) { + UsdMtlxRead(doc, stage); + return true; + } + } + catch (mx::ExceptionFoundCycle &x) { + TF_RUNTIME_ERROR("MaterialX cycle found: %s\n", x.what()); + return false; + } + catch (mx::Exception &x) { + TF_RUNTIME_ERROR("MaterialX error: %s\n", x.what()); + return false; + } + return false; +} + +void HdMtlxConvertToMaterialNetworkMap(std::string const &mtlxPath, + TfTokenVector const &shaderSourceTypes, + TfTokenVector const &renderContexts, + HdMaterialNetworkMap *out) +{ + if (mtlxPath.empty()) { + return; + } + + std::string basePath = TfGetPathName(mtlxPath); + + ArResolver &resolver = ArGetResolver(); + const ArResolverContext context = resolver.CreateDefaultContextForAsset(mtlxPath); + ArResolverContextBinder binder(context); + ArResolverScopedCache resolverCache; + + std::string mtlxName = TfGetBaseName(mtlxPath); + std::string stageId = TfStringPrintf( + "%s%s%s.usda", basePath.c_str(), ARCH_PATH_SEP, mtlxName.c_str()); + auto stage = UsdStage::CreateInMemory(stageId, context); + if (_Read(stage, [&mtlxPath]() { return UsdMtlxReadDocument(mtlxPath); })) { + if (UsdPrim materials = stage->GetPrimAtPath(SdfPath("/MaterialX/Materials"))) { + if (UsdPrimSiblingRange children = materials.GetChildren()) { + if (auto material = UsdShadeMaterial( + *children.begin())) { // TODO: specify which material to use from the mtlx + if (UsdShadeShader mtlxSurface = material.ComputeSurfaceSource(renderContexts)) { + UsdImagingBuildHdMaterialNetworkFromTerminal(mtlxSurface.GetPrim(), + HdMaterialTerminalTokens->surface, + shaderSourceTypes, + renderContexts, + out, + UsdTimeCode::Default()); + } + } + } + } + } +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.h b/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.h new file mode 100644 index 000000000000..42fdadd499b2 --- /dev/null +++ b/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#pragma once + +#if defined(_MTLX_TRANSLATION_ENABLED) + +# include +# include + +# include + +PXR_NAMESPACE_OPEN_SCOPE + +struct HdMaterialNetworkMap; + +void HdMtlxConvertToMaterialNetworkMap(std::string const &mtlxPath, + TfTokenVector const &shaderSourceTypes, + TfTokenVector const &renderContexts, + HdMaterialNetworkMap *out); + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // _MTLX_TRANSLATION_ENABLED diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 4c8dc9a49718..f89f243d6f56 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -980,6 +980,9 @@ elseif(WIN32) ${LIBDIR}/materialx/bin/MaterialXGenMdl.dll ${LIBDIR}/materialx/bin/MaterialXGenOsl.dll ${LIBDIR}/materialx/bin/MaterialXGenShader.dll + ${LIBDIR}/materialx/bin/MaterialXRender.dll + ${LIBDIR}/materialx/bin/MaterialXRenderHw.dll + ${LIBDIR}/materialx/bin/MaterialXRenderGlsl.dll RELEASE ) windows_install_shared_manifest( @@ -990,6 +993,9 @@ elseif(WIN32) ${LIBDIR}/materialx/bin/MaterialXGenMdl_d.dll ${LIBDIR}/materialx/bin/MaterialXGenOsl_d.dll ${LIBDIR}/materialx/bin/MaterialXGenShader_d.dll + ${LIBDIR}/materialx/bin/MaterialXRender_d.dll + ${LIBDIR}/materialx/bin/MaterialXRenderHw_d.dll + ${LIBDIR}/materialx/bin/MaterialXRenderGlsl_d.dll DEBUG ) -- 2.30.2 From b19266c88f68b02e1a81eecd047552c891cac7d8 Mon Sep 17 00:00:00 2001 From: hshakula Date: Wed, 1 Mar 2023 21:32:47 +0200 Subject: [PATCH 2/4] Remove unneeded scene delegate parameter --- .../blender/render/hydra/sceneDelegate/blenderSceneDelegate.cc | 2 +- source/blender/render/hydra/sceneDelegate/material.cc | 2 +- source/blender/render/hydra/sceneDelegate/material.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/render/hydra/sceneDelegate/blenderSceneDelegate.cc b/source/blender/render/hydra/sceneDelegate/blenderSceneDelegate.cc index e9d84b8f046e..22a244d512dd 100644 --- a/source/blender/render/hydra/sceneDelegate/blenderSceneDelegate.cc +++ b/source/blender/render/hydra/sceneDelegate/blenderSceneDelegate.cc @@ -343,7 +343,7 @@ VtValue BlenderSceneDelegate::GetMaterialResource(SdfPath const& id) { MaterialData *mat_data = material_data(id); if (mat_data) { - return mat_data->material_resource(this); + return mat_data->material_resource(); } return VtValue(); } diff --git a/source/blender/render/hydra/sceneDelegate/material.cc b/source/blender/render/hydra/sceneDelegate/material.cc index 7c25b6963014..60717684343a 100644 --- a/source/blender/render/hydra/sceneDelegate/material.cc +++ b/source/blender/render/hydra/sceneDelegate/material.cc @@ -49,7 +49,7 @@ VtValue MaterialData::get_data(TfToken const &key) return ret; } -pxr::VtValue MaterialData::material_resource(pxr::HdSceneDelegate *scene_delegate) +pxr::VtValue MaterialData::material_resource() { #if defined(_MTLX_TRANSLATION_ENABLED) std::string const &path = mtlx_path.GetResolvedPath(); diff --git a/source/blender/render/hydra/sceneDelegate/material.h b/source/blender/render/hydra/sceneDelegate/material.h index 2a1cf18cc08e..17a21382a270 100644 --- a/source/blender/render/hydra/sceneDelegate/material.h +++ b/source/blender/render/hydra/sceneDelegate/material.h @@ -25,7 +25,7 @@ class MaterialData: IdData { void remove_prim() override; void mark_prim_dirty(DirtyBits dirty_bits) override; - pxr::VtValue material_resource(pxr::HdSceneDelegate *scene_delegate); + pxr::VtValue material_resource(); void export_mtlx(); private: -- 2.30.2 From 54f1e1d9305112026a3efd3f313e2f2478ba2313 Mon Sep 17 00:00:00 2001 From: hshakula Date: Wed, 1 Mar 2023 21:41:52 +0200 Subject: [PATCH 3/4] Activate Hydra only with MaterialX --- CMakeLists.txt | 2 +- source/blender/render/hydra/CMakeLists.txt | 17 +++++++---------- .../render/hydra/sceneDelegate/material.cc | 4 ---- .../hydra/sceneDelegate/mtlxHydraAdapter.h | 10 +++------- 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 678d4bb9ae21..269e88da548e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -794,7 +794,7 @@ set(POSTCONFIGURE_SCRIPT "" CACHE FILEPATH "Run given CMake script as the last s mark_as_advanced(POSTCONFIGURE_SCRIPT) # USD Hydra plugin. -if(WIN32 AND WITH_USD) +if(WIN32 AND WITH_USD AND WITH_MATERIALX) option(WITH_HYDRA "Enable USD Hydra plugin" ON) endif() diff --git a/source/blender/render/hydra/CMakeLists.txt b/source/blender/render/hydra/CMakeLists.txt index 89a2592b0c81..4982fab72b7e 100644 --- a/source/blender/render/hydra/CMakeLists.txt +++ b/source/blender/render/hydra/CMakeLists.txt @@ -1,6 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2011-2022 Blender Foundation +if(NOT TARGET MaterialXCore OR NOT TARGET MaterialXFormat) + message(FATAL_ERROR "Hydra Scene Delegate requires MaterialX") +endif() + if(WIN32) add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -DBOOST_DEBUG_PYTHON) endif() @@ -70,6 +74,8 @@ set(SRC sceneDelegate/material.cc sceneDelegate/mesh.h sceneDelegate/mesh.cc + sceneDelegate/mtlxHydraAdapter.h + sceneDelegate/mtlxHydraAdapter.cc sceneDelegate/light.h sceneDelegate/light.cc sceneDelegate/world.h @@ -86,17 +92,8 @@ set(LIB blender_add_lib(bf_render_hydra "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -if(TARGET MaterialXCore AND TARGET MaterialXFormat) - target_sources(bf_render_hydra PRIVATE - sceneDelegate/mtlxHydraAdapter.h - sceneDelegate/mtlxHydraAdapter.cc) - target_compile_definitions(bf_render_hydra PRIVATE - _MTLX_TRANSLATION_ENABLED) - target_link_libraries(bf_render_hydra PRIVATE +target_link_libraries(bf_render_hydra PRIVATE MaterialXCore MaterialXFormat) -else() - message(WARN "Compiling Hydra Scene Delegate without MaterialX-to-Hydra translation") -endif() add_dependencies(bf_render_hydra bf_rna) diff --git a/source/blender/render/hydra/sceneDelegate/material.cc b/source/blender/render/hydra/sceneDelegate/material.cc index 60717684343a..a7ab14190995 100644 --- a/source/blender/render/hydra/sceneDelegate/material.cc +++ b/source/blender/render/hydra/sceneDelegate/material.cc @@ -51,7 +51,6 @@ VtValue MaterialData::get_data(TfToken const &key) pxr::VtValue MaterialData::material_resource() { -#if defined(_MTLX_TRANSLATION_ENABLED) std::string const &path = mtlx_path.GetResolvedPath(); if (!path.empty()) { HdRenderDelegate *render_delegate = scene_delegate->GetRenderIndex().GetRenderDelegate(); @@ -63,9 +62,6 @@ pxr::VtValue MaterialData::material_resource() path, shader_source_types, render_contexts, &material_network_map); return VtValue(material_network_map); } -#else -# pragma message("Compiling without MaterialX translation") -#endif return pxr::VtValue(); } diff --git a/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.h b/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.h index 42fdadd499b2..7bfcafd40cc1 100644 --- a/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.h +++ b/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.h @@ -3,12 +3,10 @@ #pragma once -#if defined(_MTLX_TRANSLATION_ENABLED) +#include +#include -# include -# include - -# include +#include PXR_NAMESPACE_OPEN_SCOPE @@ -20,5 +18,3 @@ void HdMtlxConvertToMaterialNetworkMap(std::string const &mtlxPath, HdMaterialNetworkMap *out); PXR_NAMESPACE_CLOSE_SCOPE - -#endif // _MTLX_TRANSLATION_ENABLED -- 2.30.2 From e51b97d4cc9e3b64922dfa0752e37cb00f1e8b18 Mon Sep 17 00:00:00 2001 From: hshakula Date: Wed, 1 Mar 2023 22:38:45 +0200 Subject: [PATCH 4/4] Remove _Read wrap function --- .../hydra/sceneDelegate/mtlxHydraAdapter.cc | 59 ++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.cc b/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.cc index 946f9b7f69e6..4888af16945e 100644 --- a/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.cc +++ b/source/blender/render/hydra/sceneDelegate/mtlxHydraAdapter.cc @@ -24,26 +24,6 @@ namespace mx = MaterialX; PXR_NAMESPACE_OPEN_SCOPE -template static bool _Read(UsdStagePtr stage, R &&reader) -{ - try { - auto doc = reader(); - if (doc) { - UsdMtlxRead(doc, stage); - return true; - } - } - catch (mx::ExceptionFoundCycle &x) { - TF_RUNTIME_ERROR("MaterialX cycle found: %s\n", x.what()); - return false; - } - catch (mx::Exception &x) { - TF_RUNTIME_ERROR("MaterialX error: %s\n", x.what()); - return false; - } - return false; -} - void HdMtlxConvertToMaterialNetworkMap(std::string const &mtlxPath, TfTokenVector const &shaderSourceTypes, TfTokenVector const &renderContexts, @@ -63,20 +43,31 @@ void HdMtlxConvertToMaterialNetworkMap(std::string const &mtlxPath, std::string mtlxName = TfGetBaseName(mtlxPath); std::string stageId = TfStringPrintf( "%s%s%s.usda", basePath.c_str(), ARCH_PATH_SEP, mtlxName.c_str()); - auto stage = UsdStage::CreateInMemory(stageId, context); - if (_Read(stage, [&mtlxPath]() { return UsdMtlxReadDocument(mtlxPath); })) { - if (UsdPrim materials = stage->GetPrimAtPath(SdfPath("/MaterialX/Materials"))) { - if (UsdPrimSiblingRange children = materials.GetChildren()) { - if (auto material = UsdShadeMaterial( - *children.begin())) { // TODO: specify which material to use from the mtlx - if (UsdShadeShader mtlxSurface = material.ComputeSurfaceSource(renderContexts)) { - UsdImagingBuildHdMaterialNetworkFromTerminal(mtlxSurface.GetPrim(), - HdMaterialTerminalTokens->surface, - shaderSourceTypes, - renderContexts, - out, - UsdTimeCode::Default()); - } + UsdStageRefPtr stage = UsdStage::CreateInMemory(stageId, context); + + try { + mx::DocumentPtr doc = UsdMtlxReadDocument(mtlxPath); + UsdMtlxRead(doc, stage); + } + catch (mx::ExceptionFoundCycle &x) { + TF_RUNTIME_ERROR("MaterialX cycle found: %s\n", x.what()); + return; + } + catch (mx::Exception &x) { + TF_RUNTIME_ERROR("MaterialX error: %s\n", x.what()); + return; + } + + if (UsdPrim materials = stage->GetPrimAtPath(SdfPath("/MaterialX/Materials"))) { + if (UsdPrimSiblingRange children = materials.GetChildren()) { + if (auto material = UsdShadeMaterial(*children.begin())) { + if (UsdShadeShader mtlxSurface = material.ComputeSurfaceSource(renderContexts)) { + UsdImagingBuildHdMaterialNetworkFromTerminal(mtlxSurface.GetPrim(), + HdMaterialTerminalTokens->surface, + shaderSourceTypes, + renderContexts, + out, + UsdTimeCode::Default()); } } } -- 2.30.2