BLEN-326: Pass MaterialX to Hydra via hdMaterialNetwork #5

Merged
Bogdan Nagirniak merged 4 commits from George-Shakula/blender:mtlx-translation into hydra-render 2023-03-02 12:35:51 +01:00
8 changed files with 157 additions and 4 deletions
Showing only changes of commit 2f5f8e5e83 - Show all commits

View File

@ -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/*.*" )

View File

@ -86,4 +86,17 @@ set(LIB
blender_add_lib(bf_render_hydra "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(TARGET MaterialXCore AND TARGET MaterialXFormat)
George-Shakula marked this conversation as resolved
Review

We expect that MaterialX is enabled for hydra_render project. Can be removed.

We expect that MaterialX is enabled for hydra_render project. Can be removed.
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)

View File

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

View File

@ -5,6 +5,7 @@
#include <pxr/imaging/hd/tokens.h>
#include <pxr/imaging/hd/material.h>
#include <pxr/imaging/hd/renderDelegate.h>
#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();
}

View File

@ -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);
George-Shakula marked this conversation as resolved
Review

scene_delegate is already available in MaterialData from IdData

`scene_delegate` is already available in MaterialData from IdData
void export_mtlx();
private:

View File

@ -0,0 +1,86 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "mtlxHydraAdapter.h"
#include <pxr/base/arch/fileSystem.h>
#include <pxr/usd/ar/resolver.h>
#include <pxr/usd/ar/resolverContextBinder.h>
#include <pxr/usd/ar/resolverScopedCache.h>
#include <pxr/usd/usdMtlx/reader.h>
#include <pxr/usd/usdMtlx/utils.h>
#include <pxr/usd/usdShade/material.h>
#include <pxr/usd/usdShade/shader.h>
#include <pxr/usdImaging/usdImaging/materialParamUtils.h>
#include <pxr/imaging/hd/material.h>
#include <pxr/imaging/hd/tokens.h>
namespace mx = MaterialX;
PXR_NAMESPACE_OPEN_SCOPE
template<typename R> 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); })) {
George-Shakula marked this conversation as resolved
Review

This part with _Read() and lambda function is hard to maintain in future + used in one place, can you move it content of _Read here.

This part with `_Read()` and lambda function is hard to maintain in future + used in one place, can you move it content of `_Read` here.
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)) {
BogdanNagirniak marked this conversation as resolved
Review

Change construction if (...) if (...) .... to if (!...) return; if (!...) return as more understandable and easier to maintain.

Change construction `if (...) if (...) .... ` to `if (!...) return; if (!...) return` as more understandable and easier to maintain.
UsdImagingBuildHdMaterialNetworkFromTerminal(mtlxSurface.GetPrim(),
HdMaterialTerminalTokens->surface,
shaderSourceTypes,
renderContexts,
out,
UsdTimeCode::Default());
}
}
}
}
}
}
PXR_NAMESPACE_CLOSE_SCOPE

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#pragma once
#if defined(_MTLX_TRANSLATION_ENABLED)
# include <pxr/base/tf/token.h>
# include <pxr/pxr.h>
# include <string>
PXR_NAMESPACE_OPEN_SCOPE
struct HdMaterialNetworkMap;
void HdMtlxConvertToMaterialNetworkMap(std::string const &mtlxPath,
BogdanNagirniak marked this conversation as resolved
Review

Can we move this function into MaterialData class as method?

Can we move this function into MaterialData class as method?
Review

Yes, we can. One of the reasons it is in a separate file is that Brian wanted to have this feature separated from anything else for convenient sharing with others. By keeping it in its own files we ensure this is easily relocatable and not obscured by anything else.

Yes, we can. One of the reasons it is in a separate file is that Brian wanted to have this feature separated from anything else for convenient sharing with others. By keeping it in its own files we ensure this is easily relocatable and not obscured by anything else.
Review

I see, ok

I see, ok
TfTokenVector const &shaderSourceTypes,
TfTokenVector const &renderContexts,
HdMaterialNetworkMap *out);
PXR_NAMESPACE_CLOSE_SCOPE
#endif // _MTLX_TRANSLATION_ENABLED

View File

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