Skip to content

Commit

Permalink
Merge pull request #3990 from Autodesk/gamaj/MAYA-133932/import_expor…
Browse files Browse the repository at this point in the history
…t_open_pbr

MAYA-133932 - Implement OpenPBR import/export
  • Loading branch information
samuelliu-adsk authored Nov 12, 2024
2 parents 9164ed2 + 16fbe8a commit 9711854
Show file tree
Hide file tree
Showing 35 changed files with 3,244 additions and 361 deletions.
7 changes: 7 additions & 0 deletions cmake/modules/FindMaya.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# Cache variables:
# MAYA_HAS_DEFAULT_MATERIAL_API Presence of a default material API on MRenderItem.
# MAYA_HAS_COLOR_MANAGEMENT_SUPPORT_API Maya API provides color management support
# MAYA_HAS_OPENPBR_SURFACE_SHADER Maya has an OpenPBR shader
# MAYA_NEW_POINT_SNAPPING_SUPPORT Presence of point new snapping support.
# MAYA_CURRENT_UFE_CAMERA_SUPPORT Presence of MFrameContext::getCurrentUfeCameraPath.
# MAYA_HAS_CRASH_DETECTION Presence of isInCrashHandler API
Expand Down Expand Up @@ -350,6 +351,12 @@ if(MAYA_INCLUDE_DIRS AND EXISTS "${MAYA_INCLUDE_DIR}/maya/MFragmentManager.h")
endif()
endif()

set(MAYA_HAS_OPENPBR_SURFACE_SHADER FALSE CACHE INTERNAL "OpenPBRSurfaceShader")
if(MAYA_INCLUDE_DIRS AND EXISTS "${MAYA_INCLUDE_DIR}/maya/MFnOpenPBRSurfaceShader.h")
set(MAYA_HAS_OPENPBR_SURFACE_SHADER TRUE CACHE INTERNAL "OpenPBRSurfaceShader")
message(STATUS "Maya has OpenPBR Surface Shader")
endif()

set(MAYA_NEW_POINT_SNAPPING_SUPPORT FALSE CACHE INTERNAL "snapToActive")
if (MAYA_INCLUDE_DIRS AND EXISTS "${MAYA_INCLUDE_DIR}/maya/MSelectionContext.h")
file(STRINGS ${MAYA_INCLUDE_DIR}/maya/MSelectionContext.h MAYA_HAS_API REGEX "snapToActive")
Expand Down
16 changes: 16 additions & 0 deletions cmake/modules/FindUSD.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,22 @@ if (USD_LIBRARY_DIR AND EXISTS "${USD_LIBRARY_DIR}/${USD_LIB_PREFIX}usdMtlx${CMA
endif()
endif()

# See if we are getting OpenPBR Surface shader from USD:
set(USD_HAS_MX_OPENPBR_SURFACE FALSE CACHE INTERNAL "USD.MaterialX.OpenPBRSurface")
if (PXR_USD_LOCATION AND
(EXISTS "${PXR_USD_LOCATION}/libraries/bxdf/mx39_open_pbr_surface.mtlx" OR
EXISTS "${PXR_USD_LOCATION}/libraries/bxdf/open_pbr_surface.mtlx"))
set(USD_HAS_MX_OPENPBR_SURFACE TRUE CACHE INTERNAL "USD.MaterialX.OpenPBRSurface")
message(STATUS "USD has OpenPBR Surface")
endif()

# See if we are using the backported OpenPBR Surface shader, which needs special handling of Mx39FresnelData:
set(USD_HAS_BACKPORTED_MX39_OPENPBR FALSE CACHE INTERNAL "USD.MaterialX.Mx39OpenPBRSurface")
if (PXR_USD_LOCATION AND EXISTS "${PXR_USD_LOCATION}/libraries/pbrlib/genglsl/lib/mx39_microfacet_specular.glsl")
set(USD_HAS_BACKPORTED_MX39_OPENPBR TRUE CACHE INTERNAL "USD.MaterialX.Mx39OpenPBRSurface")
message(STATUS "USD has backported MaterialX 1.39 OpenPBR Surface code")
endif()

include(FindPackageHandleStandardArgs)

find_package_handle_standard_args(USD
Expand Down
7 changes: 7 additions & 0 deletions lib/mayaUsd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ if (MAYA_HAS_COLOR_MANAGEMENT_SUPPORT_API)
)
endif()

if (MAYA_HAS_OPENPBR_SURFACE_SHADER)
target_compile_definitions(${PROJECT_NAME}
PRIVATE
MAYA_HAS_OPENPBR_SURFACE_SHADER=1
)
endif()

message(STATUS "MAYA_NEW_POINT_SNAPPING_SUPPORT is ${MAYA_NEW_POINT_SNAPPING_SUPPORT}")
if (MAYA_NEW_POINT_SNAPPING_SUPPORT)
target_compile_definitions(${PROJECT_NAME}
Expand Down
13 changes: 13 additions & 0 deletions lib/mayaUsd/fileio/shading/shadingModeRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,28 @@ TF_DECLARE_PUBLIC_TOKENS(
MAYAUSD_CORE_PUBLIC,
PXRUSDMAYA_SHADINGMODE_TOKENS);

#ifdef MAYA_HAS_OPENPBR_SURFACE_SHADER
// clang-format off
#define PXRUSDMAYA_SHADINGCONVERSION_TOKENS \
(none) \
(lambert) \
(openPBRSurface) \
(standardSurface) \
(usdPreviewSurface) \
(blinn) \
(phong)
// clang-format on
#else
// clang-format off
#define PXRUSDMAYA_SHADINGCONVERSION_TOKENS \
(none) \
(lambert) \
(standardSurface) \
(usdPreviewSurface) \
(blinn) \
(phong)
// clang-format on
#endif

TF_DECLARE_PUBLIC_TOKENS(
UsdMayaPreferredMaterialTokens,
Expand Down
20 changes: 20 additions & 0 deletions lib/mayaUsd/fileio/shading/shadingModeUseRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,26 @@ class UseRegistryShadingModeImporter
}

if (!mayaAttr.isNull()) {
// Connecting the R component of a color to a color should be possible. Check
// if there is a compatible parent in case of type mismatch.
MFnAttribute srcFnAttr(srcAttr.attribute());
MFnAttribute mayaFnAttr(mayaAttr.attribute());
if (!srcFnAttr.acceptsAttribute(mayaFnAttr)) {
if (srcAttr.isChild()) {
const auto srcParentPlug = srcAttr.parent();
MFnAttribute srcParentAttr(srcParentPlug.attribute());
if (srcParentAttr.acceptsAttribute(mayaFnAttr)) {
srcAttr = srcParentPlug;
}
} else if (mayaAttr.isChild()) {
const auto mayaParentPlug = mayaAttr.parent();
MFnAttribute mayaParentAttr(mayaParentPlug.attribute());
if (srcFnAttr.acceptsAttribute(mayaParentAttr)) {
mayaAttr = mayaParentPlug;
}
}
}

UsdMayaUtil::Connect(srcAttr, mayaAttr, false);
}
}
Expand Down
17 changes: 17 additions & 0 deletions lib/mayaUsd/render/MaterialXGenOgsXml/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ target_sources(${PROJECT_NAME}
)
endif()

if(USD_HAS_BACKPORTED_MX39_OPENPBR)
target_compile_definitions(${PROJECT_NAME}
PRIVATE
USD_HAS_BACKPORTED_MX39_OPENPBR
)
target_sources(${PROJECT_NAME}
PRIVATE
Nodes/MayaClosureSourceCodeNode.cpp
)
endif()

set(HEADERS
CombinedMaterialXVersion.h
GlslFragmentGenerator.h
Expand All @@ -56,6 +67,12 @@ list(APPEND LIGHT_IMPLEMENTATIONS
libraries/mx_lighting_maya_v3.glsl
)

if(USD_HAS_BACKPORTED_MX39_OPENPBR)
list(APPEND LIGHT_IMPLEMENTATIONS
libraries/mx39_lighting_maya_all.glsl
)
endif()

list(APPEND NODE_DECLARATIONS
libraries/maya_surfaces.mtlx
libraries/maya_utilities.mtlx
Expand Down
28 changes: 28 additions & 0 deletions lib/mayaUsd/render/MaterialXGenOgsXml/GlslFragmentGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#include "Nodes/MayaHwImageNode.h"
#include "Nodes/MayaSourceCodeNode.h"
#endif
#ifdef USD_HAS_BACKPORTED_MX39_OPENPBR
#include "Nodes/MayaClosureSourceCodeNode.h"
#endif

#include <mayaUsd/render/MaterialXGenOgsXml/CombinedMaterialXVersion.h>
#include <mayaUsd/render/MaterialXGenOgsXml/GlslOcioNodeImpl.h>
Expand Down Expand Up @@ -559,21 +562,33 @@ ShaderPtr GlslFragmentGenerator::generate(
emitLineBreak(pixelStage);
MX_EMIT_INCLUDE(
libRoot + "pbrlib/genglsl/ogsxml/mx_lighting_maya_v3.glsl", context, pixelStage);
#ifdef USD_HAS_BACKPORTED_MX39_OPENPBR
emitLine("#define MAYA_MX39_USING_ENVIRONMENT_FIS", pixelStage, false);
#endif
} else if (specularMethod == SPECULAR_ENVIRONMENT_PREFILTER) {
if (OgsXmlGenerator::useLightAPI() < 2) {
MX_EMIT_INCLUDE(
libRoot + "pbrlib/genglsl/ogsxml/mx_lighting_maya_v1.glsl",
context,
pixelStage);
#ifdef USD_HAS_BACKPORTED_MX39_OPENPBR
emitLine("#define MAYA_MX39_USING_ENVIRONMENT_PREFILTER_V1", pixelStage, false);
#endif
} else {
MX_EMIT_INCLUDE(
libRoot + "pbrlib/genglsl/ogsxml/mx_lighting_maya_v2.glsl",
context,
pixelStage);
#ifdef USD_HAS_BACKPORTED_MX39_OPENPBR
emitLine("#define MAYA_MX39_USING_ENVIRONMENT_PREFILTER_V2", pixelStage, false);
#endif
}
} else if (specularMethod == SPECULAR_ENVIRONMENT_NONE) {
MX_EMIT_INCLUDE(
libRoot + "pbrlib/genglsl/ogsxml/mx_lighting_maya_none.glsl", context, pixelStage);
#ifdef USD_HAS_BACKPORTED_MX39_OPENPBR
emitLine("#define MAYA_MX39_USING_ENVIRONMENT_NONE", pixelStage, false);
#endif
} else {
throw ExceptionShaderGenError(
"Invalid hardware specular environment method specified: '"
Expand Down Expand Up @@ -954,6 +969,19 @@ GlslFragmentGenerator::getImplementation(const NodeDef& nodedef, GenContext& con
context.addNodeImplementation(name, impl);

return impl;
#ifdef USD_HAS_BACKPORTED_MX39_OPENPBR
} else if (
implElement->getName() == "IM_dielectric_tf_bsdf_genglsl"
|| implElement->getName() == "IM_generalized_schlick_tf_82_bsdf_genglsl") {
// We need to inject lighting code into the backported OpenPBR:
impl = MayaClosureSourceCodeNode::create();
impl->initialize(*implElement, context);

// Cache it.
context.addNodeImplementation(name, impl);

return impl;
#endif
}
return GlslShaderGenerator::getImplementation(nodedef, context);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//

#include "MayaClosureSourceCodeNode.h"

#include <MaterialXGenShader/HwShaderGenerator.h>

MATERIALX_NAMESPACE_BEGIN

ShaderNodeImplPtr MayaClosureSourceCodeNode::create()
{
return std::make_shared<MayaClosureSourceCodeNode>();
}

void MayaClosureSourceCodeNode::emitFunctionDefinition(
const ShaderNode& node,
GenContext& context,
ShaderStage& stage) const
{
// Pre-inject backported OpenPBR lighting code:
if (_name == "IM_dielectric_tf_bsdf_genglsl"
|| _name == "IM_generalized_schlick_tf_82_bsdf_genglsl") {
static const auto allIncludes
= std::array<FilePath, 2> { "pbrlib/genglsl/lib/mx39_microfacet_specular.glsl",
"pbrlib/genglsl/ogsxml/mx39_lighting_maya_all.glsl" };
for (auto const& toInclude : allIncludes) {
// Update source code to inject our mx39 lighting functions:
FilePath libraryPrefix = context.getOptions().libraryPrefix;
FilePath fullFilename = libraryPrefix.isEmpty() ? toInclude : libraryPrefix / toInclude;
FilePath resolvedFilename = context.resolveSourceFile(fullFilename, FilePath());
stage.addInclude(fullFilename, resolvedFilename, context);
}
}
return ClosureSourceCodeNode::emitFunctionDefinition(node, context, stage);
}

MATERIALX_NAMESPACE_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//

#ifndef MAYA_MATERIALX_CLOSURESOURCECODENODE_H
#define MAYA_MATERIALX_CLOSURESOURCECODENODE_H

#include <MaterialXGenShader/Nodes/ClosureSourceCodeNode.h>

MATERIALX_NAMESPACE_BEGIN

/// Source code node that supports the backported OpenPBR Surface node from MaterialX 1.39
class MayaClosureSourceCodeNode : public ClosureSourceCodeNode
{
public:
static ShaderNodeImplPtr create();

void emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage)
const override;
};

MATERIALX_NAMESPACE_END

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#ifdef MAYA_MX39_USING_ENVIRONMENT_FIS

vec3 mx39_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, Mx39FresnelData fd)
{
if (mayaGetSpecularEnvironmentNumLOD() == 0) {
return vec3(0);
}

// Generate tangent frame.
X = normalize(X - dot(X, N) * N);
vec3 Y = cross(N, X);
mat3 tangentToWorld = mat3(X, Y, N);

// Transform the view vector to tangent space.
V = vec3(dot(V, X), dot(V, Y), dot(V, N));

// Compute derived properties.
float NdotV = clamp(V.z, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(alpha);
float G1V = mx_ggx_smith_G1(NdotV, avgAlpha);

// Integrate outgoing radiance using filtered importance sampling.
// http://cgg.mff.cuni.cz/~jaroslav/papers/2008-egsr-fis/2008-egsr-fis-final-embedded.pdf
vec3 radiance = vec3(0.0);
for (int i = 0; i < MX_NUM_FIS_SAMPLES; i++)
{
vec2 Xi = mx_spherical_fibonacci(i, MX_NUM_FIS_SAMPLES);

// Compute the half vector and incoming light direction.
vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, alpha);
vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, H, fd.ior.x) : -reflect(V, H);

// Compute dot products for this sample.
float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0);
float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0);

// Sample the environment light from the given direction.
vec3 Lw = tangentToWorld * L;
float pdf = mx_ggx_NDF(H, alpha) * G1V / (4.0 * NdotV);
float lod = mx_latlong_compute_lod_adsk(Lw, pdf, float(mayaGetSpecularEnvironmentNumLOD() - 1), MX_NUM_FIS_SAMPLES);
vec3 sampleColor = mayaSampleSpecularEnvironmentAtLOD(Lw, lod);

// Compute the Fresnel term.
vec3 F = mx39_compute_fresnel(VdotH, fd);

// Compute the geometric term.
float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha);

// Compute the combined FG term, which is inverted for refraction.
vec3 FG = fd.refraction ? vec3(1.0) - (F * G) : F * G;

// Add the radiance contribution of this sample.
// From https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
// incidentLight = sampleColor * NdotL
// microfacetSpecular = D * F * G / (4 * NdotL * NdotV)
// pdf = D * G1V / (4 * NdotV);
// radiance = incidentLight * microfacetSpecular / pdf
radiance += sampleColor * FG;
}

// Apply the global component of the geometric term and normalize.
radiance /= G1V * float(MX_NUM_FIS_SAMPLES);

// Return the final radiance.
return radiance;
}

#endif

#ifdef MAYA_MX39_USING_ENVIRONMENT_PREFILTER_V1

vec3 mx39_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, Mx39FresnelData fd)
{
N = mx_forward_facing_normal(N, V);
vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, N, fd.ior.x) : -reflect(V, N);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(alpha);
vec3 F = mx39_compute_fresnel(NdotV, fd);
float G = mx_ggx_smith_G2(NdotV, NdotV, avgAlpha);
vec3 FG = fd.refraction ? vec3(1.0) - (F * G) : F * G;
vec3 Li = mix(g_specularI, g_diffuseI, avgAlpha);
return Li * FG;
}

#endif

#ifdef MAYA_MX39_USING_ENVIRONMENT_PREFILTER_V2

vec3 mx39_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, Mx39FresnelData fd)
{
N = mx_forward_facing_normal(N, V);
vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, N, fd.ior.x) : -reflect(V, N);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(alpha);
vec3 F = mx39_compute_fresnel(NdotV, fd);
float G = mx_ggx_smith_G2(NdotV, NdotV, avgAlpha);
vec3 FG = fd.refraction ? vec3(1.0) - (F * G) : F * G;
float phongExp = mayaRoughnessToPhongExp(sqrt(avgAlpha));
vec3 Li = mayaGetSpecularEnvironment(N, V, phongExp);
return Li * FG;
}

#endif

#ifdef MAYA_MX39_USING_ENVIRONMENT_NONE

vec3 mx39_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, Mx39FresnelData fd)
{
return vec3(0.0);
}

#endif
Loading

0 comments on commit 9711854

Please sign in to comment.