From 2a61e63f445fc547b56d479141b10191e4eb31e1 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 18 Oct 2024 17:27:04 -0700 Subject: [PATCH 01/76] CMake updates for Apple builds (#2077) - Mark the CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY flag as Apple-specific, removing it from CMake interfaces on other platforms. - Simplify comment blocks to highlight key points. - Reorder the order of option declarations for clarity. --- CMakeLists.txt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59afaca01e..31db83e8fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,25 +60,21 @@ option(MATERIALX_DYNAMIC_ANALYSIS "Build MaterialX libraries with dynamic analys option(MATERIALX_OSL_LEGACY_CLOSURES "Build OSL shader generation supporting the legacy OSL closures." OFF) option(MATERIALX_BUILD_IOS "Build MaterialX for iOS. (Deprecated. Set CMAKE_SYSTEM_NAME instead)" OFF) -set(MATERIALX_BUILD_APPLE_EMBEDDED OFF) +option(MATERIALX_BUILD_APPLE_FRAMEWORK "Build MaterialX as an Apple Framework" ${__build_apple_framework}) if (MATERIALX_BUILD_IOS) MESSAGE(WARNING "The MATERIALX_BUILD_IOS is deprecated. Set the CMAKE_SYSTEM_NAME to the platform instead") set(CMAKE_SYSTEM_NAME iOS) endif() -# Cross Compilation detection as defined in CMake docs +# Apple ecosystem cross-compilation # https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos -# Note: All these SDKs may not be supported by MaterialX +set(MATERIALX_BUILD_APPLE_EMBEDDED OFF) set(__build_apple_framework OFF) -if (CMAKE_SYSTEM_NAME MATCHES "iOS" - OR CMAKE_SYSTEM_NAME MATCHES "tvOS" - OR CMAKE_SYSTEM_NAME MATCHES "visionOS" - OR CMAKE_SYSTEM_NAME MATCHES "watchOS") +if (CMAKE_SYSTEM_NAME MATCHES "iOS" OR CMAKE_SYSTEM_NAME MATCHES "tvOS" OR CMAKE_SYSTEM_NAME MATCHES "visionOS" OR CMAKE_SYSTEM_NAME MATCHES "watchOS") set(MATERIALX_BUILD_APPLE_EMBEDDED ON) set(__build_apple_framework ${MATERIALX_BUILD_SHARED_LIBS}) # TARGET_OS_IPHONE refers to all IPHONE derived platforms # https://chaosinmotion.com/2021/08/02/things-to-remember-compiler-conditionals-for-macos-ios-etc/ - # This should be auto-defined, but leaving it in here because it was historically defined add_definitions(-DTARGET_OS_IPHONE=1) set(MATERIALX_BUILD_MONOLITHIC ON) set(MATERIALX_BUILD_PYTHON OFF) @@ -90,8 +86,10 @@ if (CMAKE_SYSTEM_NAME MATCHES "iOS" set(MATERIALX_BUILD_TESTS OFF) endif() -set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" CACHE STRING "The Codesigning identity needed to sign compiled objects") -option(MATERIALX_BUILD_APPLE_FRAMEWORK "Build MaterialX as an Apple Framework" ${__build_apple_framework}) +# Apple framework handling +if(APPLE) + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" CACHE STRING "The Codesigning identity needed to sign compiled objects") +endif() if (MATERIALX_BUILD_APPLE_FRAMEWORK) add_definitions(-DBUILD_APPLE_FRAMEWORK) set(MATERIALX_BUILD_MONOLITHIC ON) From 4cb8ef9ed38975dfc01656493b66b62ef63a715d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 18 Oct 2024 21:05:18 -0700 Subject: [PATCH 02/76] Simplify material test suite (#2078) - Split adjustment.mtlx into separate documents for each node. - Remove test materials for nodes with graph definitions. --- .../stdlib/adjustment/adjustment.mtlx | 383 ------------------ .../stdlib/adjustment/luminance.mtlx | 15 + .../TestSuite/stdlib/adjustment/remap.mtlx | 113 ++++++ .../TestSuite/stdlib/channel/channel.mtlx | 56 --- .../conditional/conditional_switch.mtlx | 199 --------- .../TestSuite/stdlib/convert/convert.mtlx | 30 -- 6 files changed, 128 insertions(+), 668 deletions(-) delete mode 100644 resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx create mode 100644 resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx create mode 100644 resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx delete mode 100644 resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx delete mode 100644 resources/Materials/TestSuite/stdlib/convert/convert.mtlx diff --git a/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx deleted file mode 100644 index 83c4b95e9b..0000000000 --- a/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx new file mode 100644 index 0000000000..6260df8c57 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx new file mode 100644 index 0000000000..9175411a5d --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx b/resources/Materials/TestSuite/stdlib/channel/channel.mtlx index 59dbd160eb..57e90acf45 100644 --- a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx +++ b/resources/Materials/TestSuite/stdlib/channel/channel.mtlx @@ -97,60 +97,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx b/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx deleted file mode 100644 index 38f36a7290..0000000000 --- a/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/convert/convert.mtlx b/resources/Materials/TestSuite/stdlib/convert/convert.mtlx deleted file mode 100644 index f29b1eaab4..0000000000 --- a/resources/Materials/TestSuite/stdlib/convert/convert.mtlx +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From bec073ba952dcd1ca79279ebc7e2698cbd0a94c3 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 19 Oct 2024 11:54:31 -0700 Subject: [PATCH 03/76] Additional refinements to GLSL and MSL (#2079) - Provide mx_mod and mx_inverse in both GLSL and MSL. - Remove a legacy preprocessor definition in MSL. --- libraries/stdlib/genglsl/lib/mx_math.glsl | 2 ++ .../stdlib/genglsl/stdlib_genglsl_impl.mtlx | 26 +++++++++---------- .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 17 ------------ source/MaterialXGenMsl/MslShaderGenerator.cpp | 1 - 4 files changed, 15 insertions(+), 31 deletions(-) diff --git a/libraries/stdlib/genglsl/lib/mx_math.glsl b/libraries/stdlib/genglsl/lib/mx_math.glsl index f87e5653da..d196615e70 100644 --- a/libraries/stdlib/genglsl/lib/mx_math.glsl +++ b/libraries/stdlib/genglsl/lib/mx_math.glsl @@ -1,5 +1,7 @@ #define M_FLOAT_EPS 1e-8 +#define mx_mod mod +#define mx_inverse inverse #define mx_inversesqrt inversesqrt #define mx_sin sin #define mx_cos cos diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index 765c48c77b..69f8f9a7f8 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -252,17 +252,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -458,8 +458,8 @@ - - + + diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index 1920d04b70..afdfb2cfbb 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -100,19 +100,6 @@ - - - - - - - - - - - - - @@ -122,10 +109,6 @@ - - - - diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index 5476b33c90..9511fac7ba 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -944,7 +944,6 @@ void MslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& co emitLine("{}", stage, false); // Add common math functions - emitLine("#define __DECL_GL_MATH_FUNCTIONS__", stage, false); emitLibraryInclude("stdlib/genmsl/lib/mx_math.metal", context, stage); emitLineBreak(stage); From f6355a66b635d11d20e75d0f2705fba728fb38ad Mon Sep 17 00:00:00 2001 From: Jonathan Feldstein Date: Sat, 19 Oct 2024 14:57:43 -0400 Subject: [PATCH 04/76] Add defaultgeomprop support for nodegraph inputs (#2076) This PR makes it so that defaultgeomprop values can be used with nodegraph inputs as opposed to solely used on nodedef inputs. Includes a test file that is a nodegraph version of a checkerboard nodegraph implementation. The nodegraph exposes a defaultgeomprop value on the nodegraph's texcoord input of "UV0". --- .../defaultgeomprop/defaultgeomprop.mtlx | 41 +++++++++++++++++++ source/MaterialXCore/Interface.cpp | 2 +- source/MaterialXGenShader/ShaderGraph.cpp | 18 +++++++- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx diff --git a/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx b/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx new file mode 100644 index 0000000000..86bddc9650 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index 24d3ccfe0d..1c12e38ded 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -295,7 +295,7 @@ bool Input::validate(string* message) const if (hasDefaultGeomPropString()) { - validateRequire(parent->isA(), res, message, "Invalid defaultgeomprop on non-definition input"); + validateRequire(parent->isA() || parent->isA(), res, message, "Invalid defaultgeomprop on non-definition and non-nodegraph input"); validateRequire(getDefaultGeomProp() != nullptr, res, message, "Invalid defaultgeomprop string"); } if (parent->isA()) diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index 0f39b46c32..e9a3b50b79 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -81,7 +81,7 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, ElementPtr connectingElement, GenContext& context) { - // Create the node if it doesn't exists + // Create the node if it doesn't exist. NodePtr upstreamNode = upstreamElement->asA(); if (!upstreamNode) { @@ -95,6 +95,22 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, newNode = createNode(upstreamNode, context); } + // Handle interface inputs with default geometric properties. + for (InputPtr activeInput : upstreamNode->getActiveInputs()) + { + if (!activeInput->hasInterfaceName() || activeInput->getConnectedNode()) + { + continue; + } + + InputPtr graphInput = activeInput->getInterfaceInput(); + if (graphInput && graphInput->hasDefaultGeomPropString()) + { + ShaderInput* shaderInput = getNode(upstreamNode->getName())->getInput(activeInput->getName()); + addDefaultGeomNode(shaderInput, *graphInput->getDefaultGeomProp(), context); + } + } + // // Make connections // From a578d8a9758f0a6eefc5a1a5c7ab10727ee11b2d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 20 Oct 2024 12:31:54 -0700 Subject: [PATCH 05/76] Simplify material test suite (#2080) - Split channel.mtlx into separate documents for each node. - Remove test materials for nodes with graph definitions. - Reduce coupling of unit tests with material examples. --- libraries/stdlib/stdlib_ng.mtlx | 1 - .../channel/{channel.mtlx => combine.mtlx} | 35 ----------------- .../TestSuite/stdlib/channel/extract.mtlx | 38 +++++++++++++++++++ .../stdlib/compositing/compositing.mtlx | 25 ------------ .../{tokenGraph.mtlx => token_graph.mtlx} | 0 source/MaterialXTest/MaterialXCore/Node.cpp | 37 ------------------ 6 files changed, 38 insertions(+), 98 deletions(-) rename resources/Materials/TestSuite/stdlib/channel/{channel.mtlx => combine.mtlx} (65%) create mode 100644 resources/Materials/TestSuite/stdlib/channel/extract.mtlx rename resources/Materials/TestSuite/stdlib/texture/{tokenGraph.mtlx => token_graph.mtlx} (100%) diff --git a/libraries/stdlib/stdlib_ng.mtlx b/libraries/stdlib/stdlib_ng.mtlx index 893e084b68..ef7f5ebc90 100644 --- a/libraries/stdlib/stdlib_ng.mtlx +++ b/libraries/stdlib/stdlib_ng.mtlx @@ -4386,7 +4386,6 @@ - diff --git a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx b/resources/Materials/TestSuite/stdlib/channel/combine.mtlx similarity index 65% rename from resources/Materials/TestSuite/stdlib/channel/channel.mtlx rename to resources/Materials/TestSuite/stdlib/channel/combine.mtlx index 57e90acf45..403b344226 100644 --- a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx +++ b/resources/Materials/TestSuite/stdlib/channel/combine.mtlx @@ -62,39 +62,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/channel/extract.mtlx b/resources/Materials/TestSuite/stdlib/channel/extract.mtlx new file mode 100644 index 0000000000..467707a47f --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/channel/extract.mtlx @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx b/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx index 4a2d032be6..b60b9803a9 100644 --- a/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx +++ b/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx @@ -8,7 +8,6 @@ - burn - dodge - screen - - overlay - disjointover - mask - matte @@ -181,30 +180,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx b/resources/Materials/TestSuite/stdlib/texture/token_graph.mtlx similarity index 100% rename from resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx rename to resources/Materials/TestSuite/stdlib/texture/token_graph.mtlx diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp index 58ee125bad..ef746bfe05 100644 --- a/source/MaterialXTest/MaterialXCore/Node.cpp +++ b/source/MaterialXTest/MaterialXCore/Node.cpp @@ -627,43 +627,6 @@ TEST_CASE("Organization", "[nodegraph]") CHECK(nodeGraph->getBackdrops().empty()); } -TEST_CASE("Tokens", "[nodegraph]") -{ - mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); - mx::DocumentPtr stdlib = mx::createDocument(); - mx::loadLibraries({ "libraries" }, searchPath, stdlib); - - mx::DocumentPtr doc = mx::createDocument(); - mx::readFromXmlFile(doc, "resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx", searchPath); - - mx::StringVec graphNames = { "Tokenized_Image_2k_png", "Tokenized_Image_4k_jpg" }; - mx::StringVec resolutionStrings = { "2k", "4k" }; - mx::StringVec extensionStrings = { "png", "jpg" }; - for (size_t i=0; igetNodeGraph(graphNames[i]); - REQUIRE(graph); - std::vector tokens = graph->getActiveTokens(); - - mx::NodePtr imagePtr = graph->getNode("tiledimage"); - REQUIRE(imagePtr); - - mx::InputPtr input = imagePtr->getInput("file"); - REQUIRE(input); - - // Test file name substitution creation. - mx::StringResolverPtr resolver = input->createStringResolver(); - const mx::StringMap& substitutions = resolver->getFilenameSubstitutions(); - const std::string DELIMITER_PREFIX("["); - const std::string DELIMITER_POSTFIX("]"); - for (auto token : tokens) - { - const std::string tokenString = DELIMITER_PREFIX + token->getName() + DELIMITER_POSTFIX; - REQUIRE(substitutions.count(tokenString)); - } - } -} - TEST_CASE("Node Definition Creation", "[nodedef]") { mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); From 5d6aa6ec30a7966fae51dc75c6b37d0656300a71 Mon Sep 17 00:00:00 2001 From: Karen Lucknavalai <34335343+klucknav@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:12:08 -0700 Subject: [PATCH 06/76] Update UsdPreviewSurface Nodegraph This PR fixes the cutout issue described in gitIssue #2044. It also updates the nodegraph to reflect the recently updated PreviewSurface v2.6 which removes specular highlights for fully transparent materials. --- libraries/bxdf/usd_preview_surface.mtlx | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index 7106da779b..d99fab3a8c 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -6,7 +6,7 @@ - + @@ -152,10 +152,16 @@ + + + + + + - + @@ -170,8 +176,12 @@ + + + + - + @@ -213,8 +223,12 @@ + + + + - + From 5cdb375e81d172048bf881d35d8b22a6c1af5049 Mon Sep 17 00:00:00 2001 From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com> Date: Wed, 23 Oct 2024 18:58:43 -0700 Subject: [PATCH 07/76] Fix hair nodes in MDL backend (#2085) Fix the issue where the generated MDL code with hair nodes does not compile. Also address warnings for unused parameters. --- libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx | 2 +- .../SimpleHair/simple_hair_default.mtlx | 1 + .../mdl/materialx/pbrlib_1_6.mdl | 17 +++++++++-------- .../mdl/materialx/pbrlib_1_7.mdl | 5 +++++ .../mdl/materialx/stdlib_1_6.mdl | 1 + 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index 0737ca82ab..c8f23958ae 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -26,7 +26,7 @@ - + diff --git a/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx index 056c79b554..b3dbd80f9a 100644 --- a/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx +++ b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx @@ -45,6 +45,7 @@ + diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl index b69d59e8b0..e70f849920 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl @@ -430,9 +430,9 @@ export material mx_thin_film_bsdf( export material mx_chiang_hair_bsdf( // TODO: MDL's chiang_hair BSDF has no support tinting each lobes - color mxp_tint_R = color(1.0), - color mxp_tint_TT = color(1.0), - color mxp_tint_TRT = color(1.0), + color mxp_tint_R = color(1.0) [[ anno::unused() ]], + color mxp_tint_TT = color(1.0) [[ anno::unused() ]], + color mxp_tint_TRT = color(1.0) [[ anno::unused() ]], float mxp_ior = 1.55, float2 mxp_roughness_R = float2(0.1, 0.1), float2 mxp_roughness_TT = float2(0.05, 0.05), @@ -452,7 +452,7 @@ export material mx_chiang_hair_bsdf( roughness_TT: mxp_roughness_TT, roughness_TRT: mxp_roughness_TRT, cuticle_angle: mxp_cuticle_angle, - absorption_coefficient: mxp_absorption_coefficient, + absorption_coefficient: color(mxp_absorption_coefficient), ior: mxp_ior ) ); @@ -590,6 +590,7 @@ export material mx_surface( scattering: bsdf_node, emission: edf_node ), + hair: mxp_bsdf.hair, ior: mxp_transmission_ior > 0.0 ? color(mxp_transmission_ior) : mxp_bsdf.ior, volume: bsdf_volume, geometry: material_geometry( @@ -1010,17 +1011,17 @@ export mx_artistic_ior__result mx_artistic_ior( return mx_artistic_ior__result(n,k); } -export float3 mx_dion_hair_absorption_from_melanin( +export float3 mx_deon_hair_absorption_from_melanin( float mxp_melanin_concentration = 0.25, float mxp_melanin_redness = 0.5, color mxp_eumelanin_color = color(0.657704, 0.498077, 0.254107), color mxp_pheomelanin_color = color(0.829444, 0.67032, 0.349938) ) { float melanin = -math::log(math::max(1.0 - mxp_melanin_concentration, 0.0001)); - float eumelanin = melanin * (1.0 = mxp_melanin_redness); + float eumelanin = melanin * (1.0 - mxp_melanin_redness); float pheomelanin = melanin * mxp_melanin_redness; return math::max( - eumelanin * -math::log(mxp_eumelanin_color) + pheomelanin * -math::log(mxp_pheomelanin_color), + eumelanin * -math::log(float3(mxp_eumelanin_color)) + pheomelanin * -math::log(float3(mxp_pheomelanin_color)), float3(0.0) ); } @@ -1038,7 +1039,7 @@ export float3 mx_chiang_hair_absorption_from_color( (10.73 * r2 * mxp_azimuthal_roughness) + (5.574 * r4) + (0.245 * r4 * mxp_azimuthal_roughness); - float3 sigma = math::log(math::min(math::max(mxp_color, 0.001), float3(1.0))) / r_fac; + float3 sigma = math::log(math::min(math::max(float3(mxp_color), 0.001), float3(1.0))) / r_fac; return (sigma * sigma); } diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl index 2d288ee8f2..bea4e59bf6 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl @@ -48,6 +48,7 @@ export using .::pbrlib_1_6 import mx_conductor_bsdf; export using .::pbrlib_1_6 import mx_generalized_schlick_bsdf; export using .::pbrlib_1_6 import mx_subsurface_bsdf; export using .::pbrlib_1_6 import mx_thin_film_bsdf; +export using .::pbrlib_1_6 import mx_chiang_hair_bsdf; export using .::pbrlib_1_6 import mx_uniform_edf; export using .::pbrlib_1_6 import mx_conical_edf; export using .::pbrlib_1_6 import mx_measured_edf; @@ -72,6 +73,10 @@ export using .::pbrlib_1_6 import mx_roughness_dual; export using .::pbrlib_1_6 import mx_blackbody; export using .::pbrlib_1_6 import mx_artistic_ior__result ; export using .::pbrlib_1_6 import mx_artistic_ior; +export using .::pbrlib_1_6 import mx_deon_hair_absorption_from_melanin; +export using .::pbrlib_1_6 import mx_chiang_hair_absorption_from_color; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness__result; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness; diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl index f5d661b17e..3815d892a0 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl @@ -42,6 +42,7 @@ export material mx_surfacematerial( = material( thin_walled: mxp_surfaceshader.thin_walled || mxp_backsurfaceshader.thin_walled, surface: mxp_surfaceshader.surface, + hair: mxp_surfaceshader.hair, backface: mxp_backsurfaceshader.surface, geometry: material_geometry( cutout_opacity: mxp_surfaceshader.geometry.cutout_opacity, From 1734e6dd9d132ddc9abcdd3a095ccf9f37e8fcc5 Mon Sep 17 00:00:00 2001 From: Rui Yang Date: Wed, 23 Oct 2024 19:25:39 -0700 Subject: [PATCH 08/76] Add a combined version define in MaterialX C++ (#2031) PR for https://github.com/AcademySoftwareFoundation/MaterialX/issues/1609 Also added a simple test in source/MaterialXTest/MaterialXCore --- source/MaterialXCore/Library.h | 5 +++++ source/MaterialXTest/MaterialXCore/CoreUtil.cpp | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/source/MaterialXCore/Library.h b/source/MaterialXCore/Library.h index 1a92c634a7..571644c098 100644 --- a/source/MaterialXCore/Library.h +++ b/source/MaterialXCore/Library.h @@ -21,6 +21,11 @@ #include +#define MATERIALX_GENERATE_INDEX(major, minor, build) \ + ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(build))) +#define MATERIALX_VERSION_INDEX \ + MATERIALX_GENERATE_INDEX(MATERIALX_MAJOR_VERSION, MATERIALX_MINOR_VERSION, MATERIALX_BUILD_VERSION) + /// Platform-specific macros for declaring imported and exported symbols. #if defined(MATERIALX_BUILD_SHARED_LIBS) #if defined(_WIN32) diff --git a/source/MaterialXTest/MaterialXCore/CoreUtil.cpp b/source/MaterialXTest/MaterialXCore/CoreUtil.cpp index 11aa826d4f..4bc174a690 100644 --- a/source/MaterialXTest/MaterialXCore/CoreUtil.cpp +++ b/source/MaterialXTest/MaterialXCore/CoreUtil.cpp @@ -10,6 +10,12 @@ namespace mx = MaterialX; +TEST_CASE("Version comparison", "[coreutil]") +{ + // Test for version comparison + REQUIRE(MATERIALX_VERSION_INDEX > MATERIALX_GENERATE_INDEX(1, 38, 8)); +} + TEST_CASE("String utilities", "[coreutil]") { std::string invalidName("test.name"); From 593e175f3f17ccd00337cad29682d321643babaa Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 28 Oct 2024 17:14:33 -0700 Subject: [PATCH 09/76] Restore specular terms of UsdPreviewSurface (#2088) This changelist restores the interpretation of the reflective and transmissive specular terms of UsdPreviewSurface, reverting some unintended changes in PR #2081. --- libraries/bxdf/usd_preview_surface.mtlx | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index d99fab3a8c..a521c756bc 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -152,16 +152,10 @@ - - - - - - - + @@ -176,12 +170,8 @@ - - - - - + @@ -223,12 +213,8 @@ - - - - - + From 7af264b4039f06b78133b68e56c03e20b20449e6 Mon Sep 17 00:00:00 2001 From: JGamache-autodesk <56274617+JGamache-autodesk@users.noreply.github.com> Date: Mon, 28 Oct 2024 20:56:17 -0400 Subject: [PATCH 10/76] Coat layer should affect emission in USD translation (#2087) The standard_surface coat parameters are currently affecting the baseColor of UsdPreviewSurface. It should also affect emission color. --- libraries/bxdf/translation/standard_surface_to_usd.mtlx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/bxdf/translation/standard_surface_to_usd.mtlx b/libraries/bxdf/translation/standard_surface_to_usd.mtlx index 099465e369..51c7d5fc6e 100644 --- a/libraries/bxdf/translation/standard_surface_to_usd.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_usd.mtlx @@ -80,10 +80,14 @@ - + + + + + From 967d4c2f5c5d563f10c0b7fcd8fb7e19e6369768 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 29 Oct 2024 14:44:23 -0700 Subject: [PATCH 11/76] Reduce verbosity of unit tests (#2091) This changelist reduces the verbosity of our unit tests for element equivalence, focusing on REQUIRE statements to provide coverage. --- .../MaterialXTest/MaterialXCore/Document.cpp | 64 ------------------- 1 file changed, 64 deletions(-) diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index 94f8b98708..ae7623084e 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -10,8 +10,6 @@ #include #include -#include - namespace mx = MaterialX; TEST_CASE("Document", "[document]") @@ -123,16 +121,6 @@ TEST_CASE("Document", "[document]") REQUIRE(doc->validate()); } -void printDifferences(const mx::ElementEquivalenceResultVec& results, const std::string& label) -{ - for (const mx::ElementEquivalenceResult& result : results) - { - std::cout << label << ": " << "Element: " << result.path1 << - ", Element: " << result.path2 << ", Difference Type: " << result.differenceType - << ", Value: " << result.attributeName << std::endl; - } -} - TEST_CASE("Document equivalence", "[document]") { mx::DocumentPtr doc = mx::createDocument(); @@ -224,44 +212,18 @@ TEST_CASE("Document equivalence", "[document]") // Check skipping all value compares options.skipValueComparisons = true; bool equivalent = doc->isEquivalent(doc2, options, &results); - if (equivalent) - { - std::cout << "Unexpected skip value equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } - else - { - printDifferences(results, "Expected value differences"); - } REQUIRE(!equivalent); // Check attibute values options.skipValueComparisons = false; results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Unexpected value difference"); - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(equivalent); unsigned int currentPrecision = mx::Value::getFloatPrecision(); // This will compare 0.012345608 versus: 1, 0.012345611 for input10 options.precision = 8; equivalent = doc->isEquivalent(doc2, options); - if (equivalent) - { - std::cout << "Unexpected precision equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } - else - { - printDifferences(results, "Expected precision difference"); - } REQUIRE(!equivalent); options.precision = currentPrecision; @@ -274,12 +236,6 @@ TEST_CASE("Document equivalence", "[document]") floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, "100.0"); } equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Unexpected filtering differences"); - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(equivalent); for (mx::InputPtr floatInput : floatInputs) { @@ -293,16 +249,6 @@ TEST_CASE("Document equivalence", "[document]") mismatchElement->setName("mismatch_color4"); results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Expected name mismatch differences"); - } - else - { - std::cout << "Unexpected name match equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(!equivalent); mismatchElement->setName(previousName); results.clear(); @@ -320,15 +266,5 @@ TEST_CASE("Document equivalence", "[document]") nodeGraph2->setNodeDefString("ND_mygraph"); results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Expected functional graph differences"); - } - else - { - std::cout << "Unexpected functional graph equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(!equivalent); } From 9d875a817f17dac5d8b3ad2b388cdfdee5c6eb6a Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:10:33 -0700 Subject: [PATCH 12/76] Initial implementation of structs in MaterialX (#1831) This PR introduces support for custom structs types. Custom structs are defined using the `typedef` element. ``` ``` `member` elements are used to define the members of the custom struct. The `value` here is the default value used if no initializer is specified. --- .../JsMaterialX/JsMaterialXCore/JsValue.cpp | 2 +- source/MaterialXCore/Definition.cpp | 8 + source/MaterialXCore/Definition.h | 11 +- source/MaterialXCore/Element.cpp | 16 + source/MaterialXCore/Element.h | 14 +- source/MaterialXCore/Exception.h | 8 + source/MaterialXCore/Value.cpp | 73 ++++- source/MaterialXCore/Value.h | 81 ++++- source/MaterialXGenGlsl/GlslSyntax.cpp | 37 +++ source/MaterialXGenGlsl/GlslSyntax.h | 14 + .../mdl/materialx/stdlib_1_8.mdl | 20 ++ source/MaterialXGenOsl/OslShaderGenerator.cpp | 9 +- source/MaterialXGenShader/ShaderGenerator.cpp | 41 +++ source/MaterialXGenShader/ShaderGenerator.h | 6 + source/MaterialXGenShader/ShaderNode.cpp | 4 +- source/MaterialXGenShader/Syntax.cpp | 65 ++++ source/MaterialXGenShader/Syntax.h | 32 ++ source/MaterialXGenShader/TypeDesc.cpp | 129 +++++++- source/MaterialXGenShader/TypeDesc.h | 79 ++++- source/MaterialXGraphEditor/RenderView.cpp | 3 + source/MaterialXRender/Util.cpp | 2 +- source/MaterialXRenderGlsl/GlslMaterial.cpp | 2 +- source/MaterialXRenderGlsl/GlslProgram.cpp | 120 ++++--- source/MaterialXRenderGlsl/GlslProgram.h | 4 +- source/MaterialXRenderMsl/MslMaterial.mm | 2 +- .../MslPipelineStateObject.h | 4 +- .../MslPipelineStateObject.mm | 296 +++++++++++------- source/MaterialXTest/MaterialXCore/Node.cpp | 6 +- .../MaterialXGenShader/GenShaderUtil.cpp | 5 + source/MaterialXView/Viewer.cpp | 3 + .../PyMaterialX/PyMaterialXCore/PyValue.cpp | 6 +- .../PyShaderGenerator.cpp | 2 + 32 files changed, 903 insertions(+), 201 deletions(-) diff --git a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp index d0ddba7e17..5e45ef16cd 100644 --- a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp +++ b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp @@ -47,7 +47,7 @@ EMSCRIPTEN_BINDINGS(value) .function("copy", &mx::Value::copy, ems::pure_virtual()) .function("getTypeString", &mx::Value::getTypeString) .function("getValueString", &mx::Value::getValueString) - .class_function("createValueFromStrings", &mx::Value::createValueFromStrings) + BIND_CLASS_FUNC("createValueFromStrings", mx::Value, createValueFromStrings, 2, 3, stRef, stRef, mx::ConstTypeDefPtr) .class_function("setFloatFormat", &mx::Value::setFloatFormat) .class_function("setFloatPrecision", &mx::Value::setFloatPrecision) .class_function("getFloatFormat", &mx::Value::getFloatFormat) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 22c111f03c..da6c3ca3af 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -196,4 +196,12 @@ vector UnitTypeDef::getUnitDefs() const return unitDefs; } +ValuePtr AttributeDef::getValue() const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType())); +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXCore/Definition.h b/source/MaterialXCore/Definition.h index 6498f21c89..0ce7761b6d 100644 --- a/source/MaterialXCore/Definition.h +++ b/source/MaterialXCore/Definition.h @@ -423,11 +423,11 @@ class MX_CORE_API TargetDef : public TypedElement /// @class Member /// A member element within a TypeDef. -class MX_CORE_API Member : public TypedElement +class MX_CORE_API Member : public ValueElement { public: Member(ElementPtr parent, const string& name) : - TypedElement(parent, CATEGORY, name) + ValueElement(parent, CATEGORY, name) { } virtual ~Member() { } @@ -625,12 +625,7 @@ class MX_CORE_API AttributeDef : public TypedElement /// /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getValue() const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getValueString(), getType()); - } + ValuePtr getValue() const; /// @} /// @name Elements diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index af47a6a2ba..648d7df000 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -638,6 +638,22 @@ string ValueElement::getResolvedValueString(StringResolverPtr resolver) const return resolver->resolve(getValueString(), getType()); } +ValuePtr ValueElement::getValue() const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType())); +} + +ValuePtr ValueElement::getResolvedValue(StringResolverPtr resolver) const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getResolvedValueString(resolver), getType(), getDocument()->getTypeDef(getType())); +} + ValuePtr ValueElement::getDefaultValue() const { ConstElementPtr parent = getParent(); diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index a80bc3a49f..fb4bbe07ce 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -1037,12 +1037,7 @@ class MX_CORE_API ValueElement : public TypedElement /// /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getValue() const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getValueString(), getType()); - } + ValuePtr getValue() const; /// Return the resolved value of an element as a generic value object, which /// may be queried to access its data. @@ -1052,12 +1047,7 @@ class MX_CORE_API ValueElement : public TypedElement /// will be created at this scope and applied to the return value. /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getResolvedValueString(resolver), getType()); - } + ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const; /// Return the default value for this element as a generic value object, which /// may be queried to access its data. diff --git a/source/MaterialXCore/Exception.h b/source/MaterialXCore/Exception.h index 4fc0c728ec..4cf51f1cd5 100644 --- a/source/MaterialXCore/Exception.h +++ b/source/MaterialXCore/Exception.h @@ -50,6 +50,14 @@ class MX_CORE_API Exception : public std::exception string _msg; }; +/// @class ExceptionTypeError +/// An exception that is thrown when a type mismatch is encountered. +class MX_CORE_API ExceptionTypeError : public Exception +{ + public: + using Exception::Exception; +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXCore/Value.cpp b/source/MaterialXCore/Value.cpp index 68da4b5b9d..bb70aa04ae 100644 --- a/source/MaterialXCore/Value.cpp +++ b/source/MaterialXCore/Value.cpp @@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 // +#include +#include #include #include @@ -267,12 +269,18 @@ template ValuePtr TypedValue::createFromString(const string& value) // Value methods // -ValuePtr Value::createValueFromStrings(const string& value, const string& type) +ValuePtr Value::createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef) { CreatorMap::iterator it = _creatorMap.find(type); if (it != _creatorMap.end()) return it->second(value); + if (typeDef && !typeDef->getMembers().empty()) + { + // If we're given a TypeDef pointer that has child members, then we can create a new AggregateValue. + return AggregateValue::createAggregateValueFromString(value, type, typeDef); + } + return TypedValue::createFromString(value); } @@ -291,6 +299,69 @@ template const T& Value::asA() const return typedVal->getData(); } +template <> +MX_CORE_API bool Value::isA() const +{ + return dynamic_cast(this) != nullptr; +} + +template <> +MX_CORE_API const AggregateValue& Value::asA() const +{ + const AggregateValue* typedVal = dynamic_cast(this); + if (!typedVal) + { + throw ExceptionTypeError("Incorrect type specified for value"); + } + return *typedVal; +} + +string AggregateValue::getValueString() const +{ + if (_data.empty()) + return EMPTY_STRING; + + std::string result = "{"; + std::string separator = ""; + for (const auto& val : _data) + { + result += separator + val->getValueString(); + separator = ";"; + } + result += "}"; + + return result; +} + +AggregateValuePtr AggregateValue::createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDef) +{ + StringVec subValues = parseStructValueString(value); + + AggregateValuePtr result = AggregateValue::createAggregateValue(type); + const auto& members = typeDef->getMembers(); + + if (subValues.size() != members.size()) + { + std::stringstream ss; + ss << "Wrong number of initializers - expect " << members.size(); + throw Exception(ss.str()); + } + + auto doc = typeDef->getDocument(); + for (size_t i = 0; i < members.size(); ++i) + { + const auto& member = members[i]; + + // This will return nullptr if the type is not a listed typedef. + ConstTypeDefPtr subTypeDef = doc->getTypeDef(members[i]->getType()); + + // Calling Value::createValueFromStrings() here allows support for recursively nested structs. + result->appendValue(Value::createValueFromStrings(subValues[i], member->getType(), subTypeDef)); + } + + return result; +} + ScopedFloatFormatting::ScopedFloatFormatting(Value::FloatFormat format, int precision) : _format(Value::getFloatFormat()), _precision(Value::getFloatPrecision()) diff --git a/source/MaterialXCore/Value.h b/source/MaterialXCore/Value.h index 764a0ccc01..4dae4ab135 100644 --- a/source/MaterialXCore/Value.h +++ b/source/MaterialXCore/Value.h @@ -24,21 +24,22 @@ using BoolVec = vector; using FloatVec = vector; class Value; +class AggregateValue; /// A shared pointer to a Value using ValuePtr = shared_ptr; /// A shared pointer to a const Value using ConstValuePtr = shared_ptr; -template class TypedValue; +/// A shared pointer to an Aggregate Value +using AggregateValuePtr = shared_ptr; +/// A shared pointer to a const Aggregate Value +using ConstAggregateValuePtr = shared_ptr; -/// @class ExceptionTypeError -/// An exception that is thrown when a type mismatch is encountered. -class MX_CORE_API ExceptionTypeError : public Exception -{ - public: - using Exception::Exception; -}; +class TypeDef; +using ConstTypeDefPtr = shared_ptr; + +template class TypedValue; /// A generic, discriminated value, whose type may be queried dynamically. class MX_CORE_API Value @@ -73,7 +74,7 @@ class MX_CORE_API Value /// Create a new value instance from value and type strings. /// @return A shared pointer to a typed value, or an empty shared pointer /// if the conversion to the given data type cannot be performed. - static ValuePtr createValueFromStrings(const string& value, const string& type); + static ValuePtr createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef = nullptr); /// Create a deep copy of the value. virtual ValuePtr copy() const = 0; @@ -193,6 +194,68 @@ template class MX_CORE_API TypedValue : public Value T _data; }; +/// A subclass for aggregate values with multiple members +class MX_CORE_API AggregateValue : public Value +{ + public: + AggregateValue(const string& typeName) : + _typeName(typeName) + { + } + virtual ~AggregateValue() { } + + /// Create a deep copy of the value. + ValuePtr copy() const override + { + auto result = createAggregateValue(_typeName); + for (const auto& val : _data) + { + result->appendValue(val->copy()); + } + return result; + } + + /// Append a member value to the aggregate. + void appendValue(ConstValuePtr valuePtr) + { + _data.emplace_back(valuePtr); + } + + const vector& getMembers() const + { + return _data; + } + + /// Query an indexed member value from the aggregate. + ConstValuePtr getMemberValue(size_t index) const + { + return _data[index]; + } + + /// Return type string. + const string& getTypeString() const override { return _typeName; } + + /// Return value string. + string getValueString() const override; + + // + // Static helper methods + // + + /// Create a new value from an object of any valid MaterialX type. + static AggregateValuePtr createAggregateValue(const string& typeName) + { + return std::make_shared(typeName); + } + + static AggregateValuePtr createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDefPtr); + + private: + const string _typeName; + + vector _data; +}; + /// @class ScopedFloatFormatting /// An RAII class for controlling the float formatting of values. class MX_CORE_API ScopedFloatFormatting diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp index f91305f1a6..651a4ab5ff 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.cpp +++ b/source/MaterialXGenGlsl/GlslSyntax.cpp @@ -375,4 +375,41 @@ bool GlslSyntax::remapEnumeration(const string& value, TypeDesc type, const stri return true; } +StructTypeSyntaxPtr GlslSyntax::createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const +{ + return std::make_shared( + this, + structTypeName, + defaultValue, + uniformDefaultValue, + typeAlias, + typeDefinition); +} + +string GlslStructTypeSyntax::getValue(const Value& value, bool /* uniform */) const +{ + const AggregateValue& aggValue = static_cast(value); + + string result = aggValue.getTypeString() + "("; + + string separator = ""; + for (const auto& memberValue : aggValue.getMembers()) + { + result += separator; + separator = ","; + + auto memberTypeName = memberValue->getTypeString(); + auto memberTypeDesc = TypeDesc::get(memberTypeName); + + // Recursively use the syntax to generate the output, so we can supported nested structs. + result += _parentSyntax->getValue(memberTypeDesc, *memberValue, true); + } + + result += ")"; + + return result; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/GlslSyntax.h b/source/MaterialXGenGlsl/GlslSyntax.h index 8408534e7e..1e82e354bd 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.h +++ b/source/MaterialXGenGlsl/GlslSyntax.h @@ -45,6 +45,20 @@ class MX_GENGLSL_API GlslSyntax : public Syntax static const StringVec VEC2_MEMBERS; static const StringVec VEC3_MEMBERS; static const StringVec VEC4_MEMBERS; + + protected: + StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const override; +}; + +/// Specialization of TypeSyntax for aggregate types. +class MX_GENGLSL_API GlslStructTypeSyntax : public StructTypeSyntax +{ + public: + using StructTypeSyntax::StructTypeSyntax; + + string getValue(const Value& value, bool uniform) const override; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl index bef1e430d4..bb6eaf157a 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl @@ -441,3 +441,23 @@ export float3 mx_viewdirection_vector3( ::state::coordinate_object, internal_space_direction)); } + + +export float3 mx_extractGroup( + uniform texcoordGroup_struct in = {{0.1,0.1},{0.2,0.2},{0.3,0.3}}, + uniform int index = 0 +) + [[ + anno::description("Node Group: experimental") + ]] +{ + result = in.st_0.ss; + + if (index == 1) + result = in.st_1.ss; + else if (index == 2) + result = in.st_2.ss; + + return result; +} + diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index f29719a39b..d0d9d96cba 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -510,10 +511,10 @@ void OslShaderGenerator::emitMetadata(const ShaderPort* port, ShaderStage& stage { static const std::unordered_map UI_WIDGET_METADATA = { - { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("filename", Type::STRING.getName())) }, - { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("checkBox", Type::STRING.getName())) } + { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("filename")) }, + { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("checkBox")) } }; static const std::set METADATA_TYPE_BLACKLIST = diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index 6c23382f81..398232bf39 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -344,6 +344,47 @@ ShaderNodeImplPtr ShaderGenerator::getImplementation(const NodeDef& nodedef, Gen return impl; } +/// Load any struct type definitions from the document in to the type cache. +void ShaderGenerator::loadStructTypeDefs(const DocumentPtr& doc) +{ + for (const auto& mxTypeDef : doc->getTypeDefs()) + { + const auto& typeDefName = mxTypeDef->getName(); + const auto& members = mxTypeDef->getMembers(); + + // If we don't have any member children then we're not going to consider ourselves a struct. + if (members.empty()) + continue; + + StructTypeDesc newStructTypeDesc; + for (const auto& member : members) + { + auto memberName = member->getName(); + auto memberTypeName = member->getType(); + auto memberType = TypeDesc::get(memberTypeName); + auto memberDefaultValue = member->getValueString(); + + newStructTypeDesc.addMember(memberName, memberType, memberDefaultValue); + } + + auto structIndex = StructTypeDesc::emplace_back(newStructTypeDesc); + + TypeDesc structTypeDesc(typeDefName, TypeDesc::BASETYPE_STRUCT, TypeDesc::SEMANTIC_NONE, 1, structIndex); + + TypeDescRegistry(structTypeDesc, typeDefName); + + StructTypeDesc::get(structIndex).setTypeDesc(TypeDesc::get(typeDefName)); + } + + _syntax->registerStructTypeDescSyntax(); +} + +/// Clear any struct type definitions loaded +void ShaderGenerator::clearStructTypeDefs() +{ + StructTypeDesc::clear(); +} + namespace { diff --git a/source/MaterialXGenShader/ShaderGenerator.h b/source/MaterialXGenShader/ShaderGenerator.h index fa60a4d63e..a2f54fec2e 100644 --- a/source/MaterialXGenShader/ShaderGenerator.h +++ b/source/MaterialXGenShader/ShaderGenerator.h @@ -191,6 +191,12 @@ class MX_GENSHADER_API ShaderGenerator return _tokenSubstitutions; } + /// Load any struct type definitions from the document in to the type cache. + void loadStructTypeDefs(const DocumentPtr& doc); + + /// Clear any struct type definitions loaded + void clearStructTypeDefs(); + /// Register metadata that should be exported to the generated shaders. /// Supported metadata includes standard UI attributes like "uiname", "uifolder", /// "uimin", "uimax", etc. diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index 4e90fcbb2d..d52810ffc4 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -437,7 +437,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) const string& attrValue = nodeDef.getAttribute(nodedefAttr); if (!attrValue.empty()) { - ValuePtr value = Value::createValueFromStrings(attrValue, metadataEntry->type.getName()); + ValuePtr value = metadataEntry->type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; @@ -472,7 +472,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) if (!attrValue.empty()) { const TypeDesc type = metadataEntry->type != Type::NONE ? metadataEntry->type : input->getType(); - ValuePtr value = Value::createValueFromStrings(attrValue, type.getName()); + ValuePtr value = type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index 661aa41660..b8eed3e9b8 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -190,6 +190,36 @@ bool Syntax::remapEnumeration(const string&, TypeDesc, const string&, std::pair< return false; } +void Syntax::registerStructTypeDescSyntax() +{ + for (const auto& typeName : StructTypeDesc::getStructTypeNames()) + { + const auto& typeDesc = TypeDesc::get(typeName); + const auto& structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); + + string structTypeName = typeName; + string defaultValue = typeName + "( "; + string uniformDefaultValue = EMPTY_STRING; + string typeAlias = EMPTY_STRING; + string typeDefinition = "struct " + structTypeName + " { "; + + for (const auto& x : structTypeDesc.getMembers()) + { + string memberName = x._name; + string memberType = x._typeDesc.getName(); + string memberDefaultValue = x._defaultValueStr; + + defaultValue += memberDefaultValue + ", "; + typeDefinition += memberType + " " + memberName + "; "; + } + + typeDefinition += " };"; + defaultValue += " )"; + + registerTypeSyntax(typeDesc, createStructSyntax(structTypeName, defaultValue, uniformDefaultValue, typeAlias, typeDefinition)); + } +} + const StringVec TypeSyntax::EMPTY_MEMBERS; TypeSyntax::TypeSyntax(const string& name, const string& defaultValue, const string& uniformDefaultValue, @@ -246,4 +276,39 @@ string AggregateTypeSyntax::getValue(const Value& value, bool /*uniform*/) const return valueString.empty() ? valueString : getName() + "(" + valueString + ")"; } +StructTypeSyntax::StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias, const string& typeDefinition, const StringVec& members) : + TypeSyntax(name, defaultValue, uniformDefaultValue, typeAlias, typeDefinition, members), _parentSyntax(parentSyntax) +{ +} + +string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const +{ + const AggregateValue& aggValue = static_cast(value); + + auto typeDesc = TypeDesc::get(aggValue.getTypeString()); + auto structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); + + string result = "{"; + + string separator = ""; + for (const auto& memberValue : aggValue.getMembers()) + { + result += separator; + separator = ";"; + + auto memberTypeName = memberValue->getTypeString(); + auto memberTypeDesc = TypeDesc::get(memberTypeName); + + // Recursively use the syntax to generate the output, so we can support nested structs. + const string valueStr = _parentSyntax->getValue(memberTypeDesc, *memberValue, true); + + result += valueStr; + } + + result += "}"; + + return result; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/Syntax.h b/source/MaterialXGenShader/Syntax.h index a4bb7e49b5..6f16633b59 100644 --- a/source/MaterialXGenShader/Syntax.h +++ b/source/MaterialXGenShader/Syntax.h @@ -20,6 +20,7 @@ MATERIALX_NAMESPACE_BEGIN class Syntax; class TypeSyntax; +class StructTypeSyntax; class TypeDesc; class ShaderPort; @@ -29,6 +30,8 @@ using SyntaxPtr = shared_ptr; using ConstSyntaxPtr = shared_ptr; /// Shared pointer to a TypeSyntax using TypeSyntaxPtr = shared_ptr; +/// Shared pointer to a StructTypeSyntax +using StructTypeSyntaxPtr = shared_ptr; /// Map holding identifier names and a counter for /// creating unique names from them. @@ -67,6 +70,8 @@ class MX_GENSHADER_API Syntax /// Multiple calls will add to the internal set of tokens. void registerInvalidTokens(const StringMap& tokens); + virtual void registerStructTypeDescSyntax(); + /// Returns a set of names that are reserved words for this language syntax. const StringSet& getReservedWords() const { return _reservedWords; } @@ -199,6 +204,19 @@ class MX_GENSHADER_API Syntax /// Protected constructor Syntax(); + virtual StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const + { + return std::make_shared( + this, + structTypeName, + defaultValue, + uniformDefaultValue, + typeAlias, + typeDefinition); + } + vector _typeSyntaxes; std::unordered_map _typeSyntaxIndexByType; @@ -292,6 +310,20 @@ class MX_GENSHADER_API AggregateTypeSyntax : public TypeSyntax string getValue(const Value& value, bool uniform) const override; }; +/// Specialization of TypeSyntax for aggregate types. +class MX_GENSHADER_API StructTypeSyntax : public TypeSyntax +{ + public: + StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias = EMPTY_STRING, const string& typeDefinition = EMPTY_STRING, + const StringVec& members = EMPTY_MEMBERS); + + string getValue(const Value& value, bool uniform) const override; + + protected: + const Syntax* _parentSyntax; +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp index 1267caf14d..5d51680211 100644 --- a/source/MaterialXGenShader/TypeDesc.cpp +++ b/source/MaterialXGenShader/TypeDesc.cpp @@ -5,7 +5,7 @@ #include -#include +#include MATERIALX_NAMESPACE_BEGIN @@ -28,6 +28,16 @@ TypeDescNameMap& typeNameMap() return map; } +using StructTypeDescStorage = vector; +StructTypeDescStorage& structTypeStorage() +{ + // TODO: Our use of the singleton pattern for TypeDescMap and StructTypeDestStorage + // is not thread-safe, and we should consider replacing this with thread-local + // data in the GenContext object. + static StructTypeDescStorage storage; + return storage; +} + } // anonymous namespace const string TypeDesc::NONE_TYPE_NAME = "none"; @@ -46,7 +56,52 @@ TypeDesc TypeDesc::get(const string& name) return it != types.end() ? it->second : Type::NONE; } -TypeDescRegistry::TypeDescRegistry(TypeDesc type, const std::string& name) +void TypeDesc::remove(const string& name) +{ + TypeDescNameMap& typenames = typeNameMap(); + + TypeDescMap& types = typeMap(); + + auto it = types.find(name); + if (it == types.end()) + return; + + typenames.erase(it->second.typeId()); + types.erase(it); +} + +ValuePtr TypeDesc::createValueFromStrings(const string& value) const +{ + ValuePtr newValue = Value::createValueFromStrings(value, getName()); + if (!isStruct()) + return newValue; + + // Value::createValueFromStrings() can only create a valid Value for a struct if it is passed + // the optional TypeDef argument, otherwise it just returns a "string" typed Value. + // So if this is a struct type we need to create a new AggregateValue. + + StringVec subValues = parseStructValueString(value); + + AggregateValuePtr result = AggregateValue::createAggregateValue(getName()); + auto structTypeDesc = StructTypeDesc::get(getStructIndex()); + const auto& members = structTypeDesc.getMembers(); + + if (subValues.size() != members.size()) + { + std::stringstream ss; + ss << "Wrong number of initializers - expect " << members.size(); + throw ExceptionShaderGenError(ss.str()); + } + + for (size_t i = 0; i < members.size(); ++i) + { + result->appendValue( members[i]._typeDesc.createValueFromStrings(subValues[i])); + } + + return result; +} + +TypeDescRegistry::TypeDescRegistry(TypeDesc type, const string& name) { TypeDescMap& types = typeMap(); TypeDescNameMap& typenames = typeNameMap(); @@ -86,4 +141,74 @@ TYPEDESC_REGISTER_TYPE(MATERIAL, "material") } // namespace Type +// +// StructTypeDesc methods +// + +void StructTypeDesc::addMember(const string& name, TypeDesc type, string defaultValueStr) +{ + _members.emplace_back(StructTypeDesc::StructMemberTypeDesc(name, type, defaultValueStr)); +} + +vector StructTypeDesc::getStructTypeNames() +{ + StructTypeDescStorage& structs = structTypeStorage(); + vector structNames; + for (const auto& x : structs) + { + structNames.emplace_back(x.typeDesc().getName()); + } + return structNames; +} + +StructTypeDesc& StructTypeDesc::get(unsigned int index) +{ + StructTypeDescStorage& structs = structTypeStorage(); + return structs[index]; +} + +uint16_t StructTypeDesc::emplace_back(StructTypeDesc structTypeDesc) +{ + StructTypeDescStorage& structs = structTypeStorage(); + if (structs.size() >= std::numeric_limits::max()) + { + throw ExceptionShaderGenError("Maximum number of custom struct types has been exceeded."); + } + uint16_t index = static_cast(structs.size()); + structs.emplace_back(structTypeDesc); + return index; +} + +void StructTypeDesc::clear() +{ + StructTypeDescStorage& structs = structTypeStorage(); + for (const auto& structType: structs) + { + // Need to add typeID to structTypeDesc - and use it here to reference back to typeDesc obj and remove it. + TypeDesc::remove(structType.typeDesc().getName()); + } + structs.clear(); +} + +const string& StructTypeDesc::getName() const +{ + return _typedesc.getName(); +} + +const vector& StructTypeDesc::getMembers() const +{ + return _members; +} + +TypeDesc createStructTypeDesc(std::string_view name) +{ + return {name, TypeDesc::BASETYPE_STRUCT}; +} + +void registerStructTypeDesc(std::string_view name) +{ + auto structTypeDesc = createStructTypeDesc(name); + TypeDescRegistry register_struct(structTypeDesc, string(name)); +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index 1a537b7e58..95d2851915 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -10,6 +10,7 @@ /// Type descriptor for a MaterialX data type. #include +#include #include @@ -61,14 +62,21 @@ class MX_GENSHADER_API TypeDesc /// Empty constructor. constexpr TypeDesc() noexcept : - _id(0), _basetype(BASETYPE_NONE), _semantic(SEMANTIC_NONE), _size(0) { } + _id(0), + _basetype(BASETYPE_NONE), + _semantic(SEMANTIC_NONE), + _size(0), + _structIndex(0) + { + } /// Constructor. - constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1) noexcept : + constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1, uint16_t structIndex = 0) noexcept : _id(constexpr_hash(name)), // Note: We only store the hash to keep the class size minimal. _basetype(basetype), _semantic(semantic), - _size(size) + _size(size), + _structIndex(structIndex) { } @@ -112,6 +120,12 @@ class MX_GENSHADER_API TypeDesc /// Return true if the type represents a closure. bool isClosure() const { return (_semantic == SEMANTIC_CLOSURE || _semantic == SEMANTIC_SHADER || _semantic == SEMANTIC_MATERIAL); } + /// Return true if the type represents a struct. + bool isStruct() const { return _basetype == BASETYPE_STRUCT; } + + /// Return the index for the struct member information in StructTypeDesc, the result is invalid if `isStruct()` returns false. + uint16_t getStructIndex() const { return _structIndex; } + /// Equality operator bool operator==(TypeDesc rhs) const { @@ -143,8 +157,14 @@ class MX_GENSHADER_API TypeDesc /// If no type is found Type::NONE is returned. static TypeDesc get(const string& name); + /// Remove a type description by name, if it exists. + static void remove(const string& name); + static const string NONE_TYPE_NAME; + /// Create a Value from a string for a given typeDesc + ValuePtr createValueFromStrings(const string& value) const; + private: /// Simple constexpr hash function, good enough for the small set of short strings that /// are used for our data type names. @@ -157,6 +177,7 @@ class MX_GENSHADER_API TypeDesc uint8_t _basetype; uint8_t _semantic; uint16_t _size; + uint16_t _structIndex; }; /// @class TypeDescRegistry @@ -208,6 +229,58 @@ TYPEDESC_DEFINE_TYPE(MATERIAL, "material", TypeDesc::BASETYPE_NONE, TypeDesc::SE } // namespace Type + +/// @class StructTypeDesc +/// A type descriptor for MaterialX struct types. +/// +/// All types need to have a type descriptor registered in order for shader generators +/// to know about the type. If the type represented is of basetype=BASETYPE_STRUCT then +/// the type also needs to have an associated StructTypeDesc that describes the members +/// of the struct. +/// +class MX_GENSHADER_API StructTypeDesc +{ + public: + struct StructMemberTypeDesc + { + StructMemberTypeDesc(string name, TypeDesc typeDesc, string defaultValueStr) : + _name(name), _typeDesc(typeDesc), _defaultValueStr(defaultValueStr) + { + } + string _name; + TypeDesc _typeDesc; + string _defaultValueStr; + }; + + /// Empty constructor. + StructTypeDesc() noexcept{} + + void addMember(const string& name, TypeDesc type, string defaultValueStr); + void setTypeDesc(TypeDesc typedesc) { _typedesc = typedesc; } + + /// Return a type description by index. + static StructTypeDesc& get(unsigned int index); + static vector getStructTypeNames(); + static uint16_t emplace_back(StructTypeDesc structTypeDesc); + static void clear(); + + TypeDesc typeDesc() const { return _typedesc; } + + const string& getName() const; + + const vector& getMembers() const; + + private: + TypeDesc _typedesc; + vector _members; +}; + +class MX_GENSHADER_API StructTypeDescRegistry +{ + public: + StructTypeDescRegistry(); +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index dbc9b4f980..92cd8f07c7 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -630,6 +630,9 @@ void RenderView::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Register struct type definitions + context.getShaderGenerator().loadStructTypeDefs(_document); } void RenderView::drawContents() diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index 881f1b7eea..00fdc65381 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -170,7 +170,7 @@ unsigned int getUIProperties(InputPtr input, const string& target, UIProperties& else { valueString += val; - uiProperties.enumerationValues.push_back(Value::createValueFromStrings(valueString, input->getType())); + uiProperties.enumerationValues.push_back(typeDesc.createValueFromStrings(valueString)); valueString.clear(); index = 0; } diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index 788af713b2..064ab898ff 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -360,7 +360,7 @@ void GlslMaterial::modifyUniform(const std::string& path, ConstValuePtr value, s { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index b2ca0aa66e..b63e1faecc 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -508,7 +508,7 @@ ImagePtr GlslProgram::bindTexture(unsigned int uniformType, int uniformLocation, return nullptr; } -MaterialX::ValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -946,47 +946,87 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - int glType = mapTypeToOpenGLType(v->getType()); - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - - // Ignore types which are unsupported in GLSL. - if (glType == Input::INVALID_OPENGL_TYPE) - { - continue; - } + const auto& variablePath = v->getPath(); + const auto& variableUnit = v->getUnit(); + const auto& variableColorspace = v->getColorSpace(); + const auto& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt != _uniformList.end()) + const auto populateUniformInput = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue) -> void { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->unit = v->getUnit(); - input->colorspace = v->getColorSpace(); - input->value = v->getValue(); - if (input->gltype == glType) - { - input->typeString = v->getType().getName(); - } - else + auto populateUniformInput_impl = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". Unit: \"" + (!v->getUnit().empty() ? v->getUnit() : "") - + "\". Colorspace: \"" + (!v->getColorSpace().empty() ? v->getColorSpace() : "") - + "\". GLType: " + std::to_string(mapTypeToOpenGLType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + if (!typedesc.isStruct()) + { + // Handle non-struct types + int glType = mapTypeToOpenGLType(typedesc); + + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } + + // Ignore types which are unsupported in GLSL. + if (glType == Input::INVALID_OPENGL_TYPE) + { + return; + } + + auto inputIt = _uniformList.find(variableName); + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->unit = variableUnit; + input->colorspace = variableColorspace; + input->value = variableValue; + if (input->gltype == glType) + { + input->typeString = typedesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + typedesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". Unit: \"" + (!variableUnit.empty() ? variableUnit : "") + + "\". Colorspace: \"" + (!variableColorspace.empty() ? variableColorspace : "") + + "\". GLType: " + std::to_string(glType)); + uniformTypeMismatchFound = true; + } + } + } + else + { + // If we're a struct - we need to loop over each member + auto structTypeDesc = StructTypeDesc::get(typedesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& member = members[i]; + auto memberTypeDesc = member._typeDesc; + auto memberVariableName = variableName + "." + member._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(memberTypeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(typedesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1100,12 +1140,12 @@ const GlslProgram::InputMap& GlslProgram::updateAttributesList() if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; diff --git a/source/MaterialXRenderGlsl/GlslProgram.h b/source/MaterialXRenderGlsl/GlslProgram.h index 7d58dbaca7..4addd7d54b 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.h +++ b/source/MaterialXRenderGlsl/GlslProgram.h @@ -102,7 +102,7 @@ class MX_RENDERGLSL_API GlslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) @@ -223,7 +223,7 @@ class MX_RENDERGLSL_API GlslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(unsigned int uniformType, int uniformLocation, const FilePath& filePath, diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm index 311d84acee..eb13ea7900 100644 --- a/source/MaterialXRenderMsl/MslMaterial.mm +++ b/source/MaterialXRenderMsl/MslMaterial.mm @@ -318,7 +318,7 @@ { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.h b/source/MaterialXRenderMsl/MslPipelineStateObject.h index b335e29af5..a823662f5f 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.h +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.h @@ -99,7 +99,7 @@ class MX_RENDERMSL_API MslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) @@ -256,7 +256,7 @@ class MX_RENDERMSL_API MslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(id renderCmdEncoder, diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm index 2d5685646f..470fa549b2 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm @@ -235,12 +235,12 @@ int GetStrideOfMetalType(MTLDataType type) if (_shader->hasAttribute(HW::ATTR_TRANSPARENT)) { - psoDesc.colorAttachments[0].blendingEnabled = YES; - psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + psoDesc.colorAttachments[0].blendingEnabled = YES; + psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; psoDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; _alphaBlendingEnabled = true; @@ -265,12 +265,12 @@ int GetStrideOfMetalType(MTLDataType type) if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; @@ -566,8 +566,8 @@ int GetStrideOfMetalType(MTLDataType type) return nullptr; } -MaterialX::ValuePtr MslProgram::findUniformValue(const string& uniformName, - const MslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr MslProgram::findUniformValue(const string& uniformName, + const MslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -925,31 +925,54 @@ int GetStrideOfMetalType(MTLDataType type) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { - for (MTLStructMember* member in arg.bufferStructType.members) - { - std::string uboObjectName = std::string(arg.name.UTF8String); - std::string memberName = member.name.UTF8String; - std::string uboDotMemberName = uboObjectName + "." + memberName; + const auto uboObjectName = string(arg.name.UTF8String); - InputPtr inputPtr = std::make_shared(arg.index, member.dataType, arg.bufferDataSize, EMPTY_STRING); - _uniformList[uboDotMemberName] = inputPtr; - _globalUniformNameList[memberName] = uboDotMemberName; - - if (MTLArrayType* arrayMember = member.arrayType) + const auto addUniformToList = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix) -> void + { + auto addUniformToList_impl = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix, auto& addUniformToList_ref) -> void { - for (int i = 0; i < arrayMember.arrayLength; ++i) + auto memberName = memberNamePrefix + member.name.UTF8String; + + if (MTLStructType* structMember = member.structType) { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + for (MTLStructMember* subMember in structMember.members) { - std::string memberNameDotSubmember = memberName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - std::string uboDotMemberNameDotSubmemberName = uboObjectName + "." + memberNameDotSubmember; + auto namePrefix = memberName + "."; + addUniformToList_ref(subMember, subMember.argumentIndex, subMember.offset, namePrefix, addUniformToList_ref); + } + } + else + { + auto uboDotMemberName = uboObjectName + "." + memberName; + + InputPtr inputPtr = std::make_shared(index, member.dataType, size, EMPTY_STRING); + this->_uniformList[uboDotMemberName] = inputPtr; + this->_globalUniformNameList[memberName] = uboDotMemberName; - InputPtr inputPtr = std::make_shared(ArrayOfStructMember.argumentIndex, ArrayOfStructMember.dataType, ArrayOfStructMember.offset, EMPTY_STRING); - _uniformList[uboDotMemberNameDotSubmemberName] = inputPtr; - _globalUniformNameList[memberNameDotSubmember] = uboDotMemberNameDotSubmemberName; + if (MTLArrayType* arrayMember = member.arrayType) + { + for (int i = 0; i < arrayMember.arrayLength; ++i) + { + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + auto namePrefix = memberName + "[" + std::to_string(i) + "]."; + addUniformToList_ref(ArrayOfStructMember, ArrayOfStructMember.argumentIndex, ArrayOfStructMember.offset, namePrefix, addUniformToList_ref); + } + } } } - } + }; + + return addUniformToList_impl(member, index, size, memberNamePrefix, addUniformToList_impl); + }; + + for (MTLStructMember* member in arg.bufferStructType.members) + { + addUniformToList(member, arg.index, arg.bufferDataSize, ""); } } @@ -1006,55 +1029,90 @@ int GetStrideOfMetalType(MTLDataType type) for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - MTLDataType resourceType = mapTypeToMetalType(v->getType()); - - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - // Ignore types which are unsupported in MSL. - if (resourceType == MTLDataTypeNone) - { - continue; - } + const string& variablePath = v->getPath(); + const string& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt == _uniformList.end()) + const auto populateUniformInput = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue) -> void { - if (v->getType() == Type::FILENAME) + auto populateUniformInput_impl = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - inputIt = _uniformList.find(TEXTURE_NAME(v->getVariable())); - } - else - { - inputIt = _uniformList.find(uniforms.getInstance() + "." + v->getVariable()); - } - } + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } - if (inputIt != _uniformList.end()) - { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->value = v->getValue(); - if (input->resourceType == resourceType) - { - input->typeString = v->getType().getName(); - } - else - { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". resourceType: " + std::to_string(mapTypeToMetalType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + MTLDataType resourceType = mapTypeToMetalType(variableTypeDesc); + // Ignore types which are unsupported in MSL. + if (resourceType == MTLDataTypeNone) + { + return; + } + + if (!variableTypeDesc.isStruct()) + { + auto inputIt = _uniformList.find(variableName); + + if (inputIt == _uniformList.end()) { + if(variableTypeDesc == Type::FILENAME) + { + inputIt = _uniformList.find(TEXTURE_NAME(variableName)); + } + else + { + inputIt = _uniformList.find(uniforms.getInstance() + "." + variableName); + } + } + + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->value = variableValue; + if (input->resourceType == resourceType) + { + input->typeString = variableTypeDesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + variableTypeDesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". resourceType: " + std::to_string(mapTypeToMetalType(variableTypeDesc)) + ); + uniformTypeMismatchFound = true; + } + } + } + else + { + auto structTypeDesc = StructTypeDesc::get(variableTypeDesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& structMember = members[i]; + auto memberVariableName = variableName+"."+structMember._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(structMember._typeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(variableTypeDesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1231,7 +1289,7 @@ int GetStrideOfMetalType(MTLDataType type) return false; }; - auto setValue = [](MaterialX::ValuePtr value, std::vector& data, size_t offset) + auto setValue = [](MaterialX::ConstValuePtr value, std::vector& data, size_t offset) { if (value->getTypeString() == "float") { @@ -1307,7 +1365,7 @@ throw ExceptionRenderError( { if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - MaterialX::ValuePtr value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; + auto value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; if (value) { setValue(value, uniformBufferData, member.offset); @@ -1332,39 +1390,60 @@ throw ExceptionRenderError( if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - auto uniformInfo = _uniformList.find(uniformName); - if (uniformInfo != _uniformList.end()) - { - MaterialX::ValuePtr value = uniformInfo->second->value; - if (value) - { - setValue(value, uniformBufferData, member.offset); - } - } - else - { - } - } - - if (MTLArrayType* arrayMember = member.arrayType) - { - for (int i = 0; i < arrayMember.arrayLength; ++i) + const auto setUniformValue = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset ) -> void { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + auto setUniformValue_impl = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset, auto &setUniformValue_ref ) -> void { - string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - - auto uniformInfo = _uniformList.find(uniformNameSubArray); - if (uniformInfo != _uniformList.end()) + if(MTLArrayType* arrayMember = member.arrayType) { - MaterialX::ValuePtr value = uniformInfo->second->value; - if (value) + for(int i = 0; i < arrayMember.arrayLength; ++i) { - setValue(value, uniformBufferData, member.offset + i * arrayMember.stride + ArrayOfStructMember.offset); + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; + auto uniformInfo = _uniformList.find(uniformNameSubArray); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset + i * arrayMember.stride + ArrayOfStructMember.offset); + } + } + } } } - } - } + else if (MTLStructType* structMember = member.structType) + { + // this code does not support struct recursion yet.... + for (MTLStructMember* subMember in structMember.members) + { + string subUniformName = uniformName+"."+subMember.name.UTF8String; + setUniformValue_ref(subMember, subUniformName, uniformBufferData, offset+subMember.offset, setUniformValue_ref); + } + } + else + { + auto uniformInfo = _uniformList.find(uniformName); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset); + } + } + } + }; + + return setUniformValue_impl(member, uniformName, uniformBufferData, offset, setUniformValue_impl); + }; + + setUniformValue(member, uniformName, uniformBufferData, member.offset); } } @@ -1415,14 +1494,15 @@ throw ExceptionRenderError( // A "filename" is not indicative of type, so just return a 2d sampler. return MTLDataTypeTexture; } - else if (type == Type::BSDF || - type == Type::MATERIAL || + else if (type == Type::BSDF || + type == Type::MATERIAL || type == Type::DISPLACEMENTSHADER || - type == Type::EDF || - type == Type::VDF || - type == Type::SURFACESHADER || - type == Type::LIGHTSHADER || - type == Type::VOLUMESHADER) + type == Type::EDF || + type == Type::VDF || + type == Type::SURFACESHADER || + type == Type::LIGHTSHADER || + type == Type::VOLUMESHADER || + type.isStruct()) return MTLDataTypeStruct; return MTLDataTypeNone; diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp index ef746bfe05..f3ce7d40de 100644 --- a/source/MaterialXTest/MaterialXCore/Node.cpp +++ b/source/MaterialXTest/MaterialXCore/Node.cpp @@ -159,12 +159,12 @@ TEST_CASE("Node", "[node]") REQUIRE(typeDef->getMembers().size() == scalarCount); // Reference the custom type. - std::string d65("400.0,82.75,500.0,109.35,600.0,90.01,700.0,71.61,800.0,59.45"); + std::string d65("{400;82.75;500;109.35;600;90.01;700;71.61;800;59.45}"); constant->setInputValue("value", d65, "spectrum"); REQUIRE(constant->getInput("value")->getType() == "spectrum"); REQUIRE(constant->getInput("value")->getValueString() == d65); - REQUIRE(constant->getInputValue("value")->isA()); - REQUIRE(constant->getInputValue("value")->asA() == d65); + REQUIRE(constant->getInputValue("value")->isA()); + REQUIRE(constant->getInputValue("value")->asA().getValueString() == d65); // Validate the document. REQUIRE(doc->validate()); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 4a8e61645a..78da7e50f3 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -649,6 +649,9 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons addColorManagement(); addUnitSystem(); + // Register struct typedefs from the library files. + _shaderGenerator->loadStructTypeDefs(_dependLib); + // Test suite setup addSkipFiles(); @@ -705,6 +708,8 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons preprocessDocument(doc); _shaderGenerator->registerShaderMetadata(doc, context); + _shaderGenerator->loadStructTypeDefs(doc); + // For each new file clear the implementation cache. // Since the new file might contain implementations with names // colliding with implementations in previous test cases. diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 24aea1eb42..c4c69bb812 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -1769,6 +1769,9 @@ void Viewer::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Initialize the struct typedefs from the stdlib + context.getShaderGenerator().loadStructTypeDefs(_stdLib); } void Viewer::loadStandardLibraries() diff --git a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp index 501f9d5f04..c36bd6c288 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp @@ -6,6 +6,7 @@ #include #include +#include #define BIND_TYPE_INSTANCE(NAME, T) \ py::class_, std::shared_ptr< mx::TypedValue >, mx::Value>(mod, "TypedValue_" #NAME) \ @@ -22,7 +23,10 @@ void bindPyValue(py::module& mod) py::class_(mod, "Value") .def("getValueString", &mx::Value::getValueString) .def("getTypeString", &mx::Value::getTypeString) - .def_static("createValueFromStrings", &mx::Value::createValueFromStrings); + .def_static("createValueFromStrings", &mx::Value::createValueFromStrings, + py::arg("value"), + py::arg("type"), + py::arg("typeDefPtr") = nullptr); BIND_TYPE_INSTANCE(integer, int) BIND_TYPE_INSTANCE(boolean, bool) diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp index b952bd4651..0c8a086e58 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp @@ -22,5 +22,7 @@ void bindPyShaderGenerator(py::module& mod) .def("setUnitSystem", &mx::ShaderGenerator::setUnitSystem) .def("getUnitSystem", &mx::ShaderGenerator::getUnitSystem) .def("getTokenSubstitutions", &mx::ShaderGenerator::getTokenSubstitutions) + .def("loadStructTypeDefs", &mx::ShaderGenerator::loadStructTypeDefs) + .def("clearStructTypeDefs", &mx::ShaderGenerator::clearStructTypeDefs) .def("registerShaderMetadata", &mx::ShaderGenerator::registerShaderMetadata); } From ed450e82de41a9a5d4273c49babfdb37b18b922e Mon Sep 17 00:00:00 2001 From: Chris Rydalch Date: Tue, 29 Oct 2024 18:12:58 -0500 Subject: [PATCH 13/76] Move unimplemented Worley noise features to proposals doc (#2090) The *period* and *metric* parameters are not yet implemented. --- documents/Specification/MaterialX.Proposals.md | 18 ++++++++++++++++++ .../Specification/MaterialX.Specification.md | 4 ---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/documents/Specification/MaterialX.Proposals.md b/documents/Specification/MaterialX.Proposals.md index b96c688f25..d387d28718 100644 --- a/documents/Specification/MaterialX.Proposals.md +++ b/documents/Specification/MaterialX.Proposals.md @@ -188,7 +188,25 @@ We have a standard 3d fractal noise, but a 2d variant would be useful as well. * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for input coordinate repeated at that step. Default is 0, meaning the noise is not periodic. * `in` (float): the 1D coordinate at which the noise is evaluated. + +Expanded 2D Worley noise to support different distance metrics and periodicity. + +* **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). + * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + + + +Expanded 3D Worley noise to support different distance metrics and periodicity. + +* **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). + * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + +#### Periodic Noises + +In #1201 it was decided that separate periodic versions of all of the noises is preferred to adding it to the existing noises. ### Shape Nodes diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 070587340c..65027694d8 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -887,16 +887,12 @@ Standard Noise nodes: * **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `texcoord` (vector2): the 2D position at which the noise is evaluated. Default is to use the first set of texture coordinates. * **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. From b330fd7ade12811aa4a39096bef3b986841d67bb Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:37:10 -0700 Subject: [PATCH 14/76] Removing MDL struct test function (#2099) Removing MDL struct test function incorrectly included in #1831. --- .../mdl/materialx/stdlib_1_8.mdl | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl index bb6eaf157a..bef1e430d4 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl @@ -441,23 +441,3 @@ export float3 mx_viewdirection_vector3( ::state::coordinate_object, internal_space_direction)); } - - -export float3 mx_extractGroup( - uniform texcoordGroup_struct in = {{0.1,0.1},{0.2,0.2},{0.3,0.3}}, - uniform int index = 0 -) - [[ - anno::description("Node Group: experimental") - ]] -{ - result = in.st_0.ss; - - if (index == 1) - result = in.st_1.ss; - else if (index == 2) - result = in.st_2.ss; - - return result; -} - From 1b2852e1db52fc52ba5f845b784a2c46d909ef2d Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Thu, 31 Oct 2024 09:33:36 -0700 Subject: [PATCH 15/76] Simplify the MetalTexture abstraction (#2095) `mx_texture.metal` is used to provide an abstraction to the texture code when being called from GLSL code. There are a few functions in the interface of this abstraction that do not appear to be used anywhere. This PR proposes removing them, as a precursor to other upcoming texture work. I'm proposing this as a separate PR to make things easier to review. All of the MSL unit tests pass. --- libraries/stdlib/genmsl/lib/mx_texture.metal | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/libraries/stdlib/genmsl/lib/mx_texture.metal b/libraries/stdlib/genmsl/lib/mx_texture.metal index 479a8836bf..7e90b60686 100644 --- a/libraries/stdlib/genmsl/lib/mx_texture.metal +++ b/libraries/stdlib/genmsl/lib/mx_texture.metal @@ -2,13 +2,8 @@ struct MetalTexture { texture2d tex; sampler s; - int get_width() { return tex.get_width(); } - int get_height() { return tex.get_height(); } - int get_num_mip_levels() { return tex.get_num_mip_levels(); } }; -int get_width(MetalTexture mtlTex) { return mtlTex.get_width(); } - float4 texture(MetalTexture mtlTex, float2 uv) { return mtlTex.tex.sample(mtlTex.s, uv); @@ -21,10 +16,5 @@ float4 textureLod(MetalTexture mtlTex, float2 uv, float lod) int2 textureSize(MetalTexture mtlTex, int mipLevel) { - return int2(mtlTex.get_width(), mtlTex.get_height()); -} - -int texture_mips(MetalTexture mtlTex) -{ - return mtlTex.tex.get_num_mip_levels(); + return int2(mtlTex.tex.get_width(), mtlTex.tex.get_height()); } From 65862ed56e9fd82dc2771bf3d371e16a1a1e30d3 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 31 Oct 2024 12:05:37 -0700 Subject: [PATCH 16/76] Clarifications to UsdPreviewSurface (#2100) - Set the shading model version to 2.5, reflecting the alignment of this graph definition with the 2.5 specification for UsdPreviewSurface (https://openusd.org/release/spec_usdpreviewsurface.html). - Add UI names for shading model inputs. - Update doc string letter case. --- libraries/bxdf/usd_preview_surface.mtlx | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index a521c756bc..4abdb91d9f 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -6,21 +6,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + From 4339aaa83480693c1bf4d5b54e1cf614654dd507 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 31 Oct 2024 17:12:44 -0700 Subject: [PATCH 17/76] Improvements to the MaterialX Viewer (#2101) - Replace raw pointers with NanoGUI references to improve application robustness. - Allow UI names to be displayed without a corresponding UI folder. --- source/MaterialXRender/Util.cpp | 2 +- source/MaterialXView/Editor.cpp | 103 ++++++++-------- source/MaterialXView/Editor.h | 20 ++-- source/MaterialXView/Viewer.cpp | 204 +++++++++++++++----------------- source/MaterialXView/Viewer.h | 36 +++--- 5 files changed, 179 insertions(+), 186 deletions(-) diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index 00fdc65381..c206514412 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -318,7 +318,7 @@ void createUIPropertyGroups(DocumentPtr doc, const VariableBlock& block, UIPrope // Prepend a parent label for unlabeled node inputs. ElementPtr parent = pair.first->getParent(); - if (item.ui.uiFolder.empty() && parent && parent->isA()) + if (item.ui.uiName.empty() && parent && parent->isA()) { item.label = parent->getName() + pathSeparator + item.label; } diff --git a/source/MaterialXView/Editor.cpp b/source/MaterialXView/Editor.cpp index abba9ce10e..6d64c55b30 100644 --- a/source/MaterialXView/Editor.cpp +++ b/source/MaterialXView/Editor.cpp @@ -18,11 +18,11 @@ namespace class EditorColorPicker : public ng::ColorPicker { public: - EditorColorPicker(ng::Widget* parent, const ng::Color& color) : + EditorColorPicker(ng::ref parent, const ng::Color& color) : ng::ColorPicker(parent, color) { - ng::Popup* popup = this->popup(); - ng::Widget* floatGroup = new ng::Widget(popup); + ng::ref popup = this->popup(); + ng::ref floatGroup = new ng::Widget(popup); auto layout = new ng::GridLayout(ng::Orientation::Horizontal, 2, ng::Alignment::Middle, 2, 2); layout->set_col_alignment({ ng::Alignment::Fill, ng::Alignment::Fill }); @@ -60,7 +60,7 @@ class EditorColorPicker : public ng::ColorPicker protected: // Additional numeric entry / feedback widgets - ng::FloatBox* _colorWidgets[4]; + ng::ref> _colorWidgets[4]; }; } // anonymous namespace @@ -70,10 +70,6 @@ class EditorColorPicker : public ng::ColorPicker // PropertyEditor::PropertyEditor() : - _window(nullptr), - _container(nullptr), - _gridLayout2(nullptr), - _gridLayout3(nullptr), _visible(false), _fileDialogsForImages(true) { @@ -81,7 +77,7 @@ PropertyEditor::PropertyEditor() : void PropertyEditor::create(Viewer& parent) { - ng::Window* parentWindow = parent.getWindow(); + ng::ref parentWindow = parent.getWindow(); // Remove the window associated with the form. // This is done by explicitly creating and owning the window @@ -110,7 +106,7 @@ void PropertyEditor::create(Viewer& parent) _window->set_position(previousPosition); _window->set_visible(_visible); - ng::VScrollPanel* scroll_panel = new ng::VScrollPanel(_window); + ng::ref scroll_panel = new ng::VScrollPanel(_window); scroll_panel->set_fixed_height(300); _container = new ng::Widget(scroll_panel); _container->set_layout(new ng::GroupLayout(1, 1, 1, 1)); @@ -127,7 +123,7 @@ void PropertyEditor::create(Viewer& parent) } void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable) + ng::ref container, Viewer* viewer, bool editable) { const mx::UIProperties& ui = item.ui; mx::ValuePtr value = item.variable->getValue(); @@ -148,9 +144,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!group.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); - ng::Label* groupLabel = new ng::Label(twoColumns, group); + ng::ref groupLabel = new ng::Label(twoColumns, group); groupLabel->set_font_size(20); groupLabel->set_font("sans-bold"); new ng::Label(twoColumns, ""); @@ -187,11 +183,11 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st const size_t valueIndex = indexInEnumeration(); if (INVALID_INDEX != valueIndex) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(static_cast(valueIndex)); @@ -215,7 +211,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st } else { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -252,9 +248,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Float widget else if (value->isA()) { - ng::Widget* threeColumns = new ng::Widget(container); + ng::ref threeColumns = new ng::Widget(container); threeColumns->set_layout(_gridLayout3); - ng::FloatBox* floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) + ng::ref> floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) { mx::MaterialPtr material = viewer->getSelectedMaterial(); if (material) @@ -269,12 +265,12 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Boolean widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); bool v = value->asA(); new ng::Label(twoColumns, label); - ng::CheckBox* boolVar = new ng::CheckBox(twoColumns, ""); + ng::ref boolVar = new ng::CheckBox(twoColumns, ""); boolVar->set_checked(v); boolVar->set_font_size(15); boolVar->set_callback([path, viewer](bool v) @@ -290,7 +286,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color3 input. Can map to a combo box if an enumeration else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); // Determine if there is an enumeration for this @@ -312,7 +308,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Create a combo box. The items are the enumerations in order. if (index >= 0) { - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(index); @@ -353,7 +349,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -376,7 +372,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 2 widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector2 v = value->asA(); @@ -415,7 +411,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 3 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector3 v = value->asA(); @@ -470,7 +466,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector4 v = value->asA(); @@ -542,16 +538,17 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st std::string v = value->asA(); if (!v.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); if (item.variable->getType() == mx::Type::FILENAME) { new ng::Label(twoColumns, label); - ng::Button* buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); + ng::ref buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); buttonVar->set_enabled(editable); buttonVar->set_font_size(15); - buttonVar->set_callback([buttonVar, path, viewer]() + auto buttonVarPtr = buttonVar.get(); + buttonVar->set_callback([buttonVarPtr, path, viewer]() { mx::MaterialPtr material = viewer->getSelectedMaterial(); mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; @@ -572,7 +569,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!filename.empty()) { uniform->setValue(mx::Value::createValue(filename)); - buttonVar->set_caption(mx::FilePath(filename).getBaseName()); + buttonVarPtr->set_caption(mx::FilePath(filename).getBaseName()); viewer->perform_layout(); } } @@ -583,7 +580,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st else { new ng::Label(twoColumns, label); - ng::TextBox* stringVar = new ng::TextBox(twoColumns, v); + ng::ref stringVar = new ng::TextBox(twoColumns, v); stringVar->set_fixed_size({ 100, 20 }); stringVar->set_font_size(15); stringVar->set_callback([path, viewer](const std::string& v) @@ -629,14 +626,12 @@ void PropertyEditor::updateContents(Viewer* viewer) } if (!shaderName.empty() && shaderName != "surface") { - ng::Widget* twoColumns = new ng::Widget(_container); + ng::ref twoColumns = new ng::Widget(_container); twoColumns->set_layout(_gridLayout2); - ng::Widget* threeColumns = new ng::Widget(_container); - threeColumns->set_layout(_gridLayout3); - ng::Label* modelLabel = new ng::Label(twoColumns, "Shading Model"); + ng::ref modelLabel = new ng::Label(twoColumns, "Shading Model"); modelLabel->set_font_size(20); modelLabel->set_font("sans-bold"); - ng::Label* nameLabel = new ng::Label(twoColumns, shaderName); + ng::ref nameLabel = new ng::Label(twoColumns, shaderName); nameLabel->set_font_size(20); } } @@ -688,15 +683,15 @@ void PropertyEditor::updateContents(Viewer* viewer) viewer->perform_layout(); } -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value(value); - ng::FloatBox* box = new ng::FloatBox(parent, value); + ng::ref> box = new ng::FloatBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -734,29 +729,31 @@ ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& la } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value(value); + boxPtr->set_value(value); callback(value); }); - box->set_callback([slider, callback](float value) + box->set_callback([sliderPtr, callback](float value) { - slider->set_value(value); + sliderPtr->set_value(value); callback(value); }); return box; } -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value((float) value); - ng::IntBox* box = new ng::IntBox(parent, value); + ng::ref> box = new ng::IntBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -794,14 +791,16 @@ ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, i } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value((int) value); + boxPtr->set_value((int) value); callback((int) value); }); - box->set_callback([slider, callback](int value) + box->set_callback([sliderPtr, callback](int value) { - slider->set_value((float) value); + sliderPtr->set_value((float) value); callback(value); }); diff --git a/source/MaterialXView/Editor.h b/source/MaterialXView/Editor.h index b1fb4a3ade..b99f1f160c 100644 --- a/source/MaterialXView/Editor.h +++ b/source/MaterialXView/Editor.h @@ -39,7 +39,7 @@ class PropertyEditor } } - ng::Window* getWindow() + ng::ref getWindow() { return _window; } @@ -47,19 +47,19 @@ class PropertyEditor protected: void create(Viewer& parent); void addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable); + ng::ref container, Viewer* viewer, bool editable); - ng::Window* _window; - ng::Widget* _container; - ng::GridLayout* _gridLayout2; - ng::GridLayout* _gridLayout3; + ng::ref _window; + ng::ref _container; + ng::ref _gridLayout2; + ng::ref _gridLayout3; bool _visible; bool _fileDialogsForImages; }; -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback = nullptr); -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback); +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback = nullptr); +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback); #endif // MATERIALXVIEW_EDITOR_H diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index c4c69bb812..46d03a1665 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -158,7 +158,6 @@ Viewer::Viewer(const std::string& materialFilename, const mx::Color3& screenColor) : ng::Screen(ng::Vector2i(screenWidth, screenHeight), "MaterialXView", true, false, true, true, USE_FLOAT_BUFFER, 4, 0), - _window(nullptr), _materialFilename(materialFilename), _meshFilename(meshFilename), _envRadianceFilename(envRadianceFilename), @@ -184,11 +183,7 @@ Viewer::Viewer(const std::string& materialFilename, _shadowSoftness(1), _ambientOcclusionGain(0.6f), _selectedGeom(0), - _geomLabel(nullptr), - _geometrySelectionBox(nullptr), _selectedMaterial(0), - _materialLabel(nullptr), - _materialSelectionBox(nullptr), _identityCamera(mx::Camera::create()), _viewCamera(mx::Camera::create()), _envCamera(mx::Camera::create()), @@ -232,9 +227,6 @@ Viewer::Viewer(const std::string& materialFilename, _bakeHeight(0), _bakeDocumentPerMaterial(false), _frameTiming(false), - _timingLabel(nullptr), - _timingPanel(nullptr), - _timingText(nullptr), _avgFrameTime(0.0) { // Resolve input filenames, taking both the provided search path and @@ -295,11 +287,11 @@ void Viewer::initialize() _imageHandler->setSearchPath(_searchPath); // Initialize user interfaces. - createLoadMeshInterface(_window, "Load Mesh"); - createLoadMaterialsInterface(_window, "Load Material"); - createLoadEnvironmentInterface(_window, "Load Environment"); - createPropertyEditorInterface(_window, "Property Editor"); - createAdvancedSettings(_window); + createLoadMeshInterface((ng::ref) _window, "Load Mesh"); + createLoadMaterialsInterface((ng::ref) _window, "Load Material"); + createLoadEnvironmentInterface((ng::ref) _window, "Load Environment"); + createPropertyEditorInterface((ng::ref) _window, "Property Editor"); + createAdvancedSettings((ng::ref) _window); // Create geometry selection box. _geomLabel = new ng::Label(_window, "Select Geometry"); @@ -562,9 +554,9 @@ mx::ElementPredicate Viewer::getElementPredicate() }; } -void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMeshInterface(ng::ref parent, const std::string& label) { - ng::Button* meshButton = new ng::Button(parent, label); + ng::ref meshButton = new ng::Button(parent, label); meshButton->set_icon(FA_FOLDER); meshButton->set_tooltip("Load a new geometry in the OBJ or glTF format."); meshButton->set_callback([this]() @@ -590,9 +582,9 @@ void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) }); } -void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_FOLDER); materialButton->set_tooltip("Load a material document in the MTLX format."); materialButton->set_callback([this]() @@ -608,9 +600,9 @@ void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& label) +void Viewer::createLoadEnvironmentInterface(ng::ref parent, const std::string& label) { - ng::Button* envButton = new ng::Button(parent, label); + ng::ref envButton = new ng::Button(parent, label); envButton->set_icon(FA_FOLDER); envButton->set_tooltip("Load a lat-long environment light in the HDR format."); envButton->set_callback([this]() @@ -634,9 +626,9 @@ void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& l }); } -void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createSaveMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_SAVE); materialButton->set_tooltip("Save a material document in the MTLX format."); materialButton->set_callback([this]() @@ -664,9 +656,9 @@ void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& label) +void Viewer::createPropertyEditorInterface(ng::ref parent, const std::string& label) { - ng::Button* editorButton = new ng::Button(parent, label); + ng::ref editorButton = new ng::Button(parent, label); editorButton->set_flags(ng::Button::ToggleButton); editorButton->set_tooltip("View or edit properties of the current material."); editorButton->set_change_callback([this](bool state) @@ -676,40 +668,38 @@ void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& la }); } -void Viewer::createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel) +void Viewer::createDocumentationInterface(ng::ref parent) { - ng::GridLayout* documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, - ng::Alignment::Minimum, 13, 5); + ng::ref documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, + ng::Alignment::Minimum, 13, 5); documentationLayout->set_row_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); - ng::Widget* documentationGroup = new ng::Widget(parent); + ng::ref documentationGroup = new ng::Widget(parent); documentationGroup->set_layout(documentationLayout); - ng::Label* documentationLabel = new ng::Label(documentationGroup, "Documentation"); + ng::ref documentationLabel = new ng::Label(documentationGroup, "Documentation"); documentationLabel->set_font_size(20); documentationLabel->set_font("sans-bold"); - ng::Button* shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); - shortcutsButton->set_flags(ng::Button::ToggleButton); - shortcutsButton->set_icon(FA_CARET_RIGHT); - shortcutsButton->set_fixed_width(230); + _shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); + _shortcutsButton->set_flags(ng::Button::ToggleButton); + _shortcutsButton->set_icon(FA_CARET_RIGHT); + _shortcutsButton->set_fixed_width(230); - ng::Widget* shortcutsTable = new ng::Widget(documentationGroup); - shortcutsTable->set_layout(new ng::GroupLayout(13)); - shortcutsTable->set_visible(false); + _shortcutsTable = new ng::Widget(documentationGroup); + _shortcutsTable->set_layout(new ng::GroupLayout(13)); + _shortcutsTable->set_visible(false); - // recompute layout when showing/hiding shortcuts. - shortcutsButton->set_change_callback([this, scrollPanel, shortcutsButton, - shortcutsTable](bool state) + // Recompute layout when showing/hiding shortcuts. + _shortcutsButton->set_change_callback([this](bool state) { - shortcutsTable->set_visible(state); - shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); - scrollPanel->set_scroll(state ? 0.73f : 1.0f); + _shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); + _shortcutsTable->set_visible(state); perform_layout(); }); // 2 cell layout for (key, description) pair. - ng::GridLayout* gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, - ng::Alignment::Minimum, 2, 2); + ng::ref gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, + ng::Alignment::Minimum, 2, 2); gridLayout2->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); const std::vector> KEYBOARD_SHORTCUTS = @@ -741,73 +731,73 @@ void Viewer::createDocumentationInterface(Widget* parent, ng::VScrollPanel* scro for (const auto& shortcut : KEYBOARD_SHORTCUTS) { - ng::Widget* twoColumns = new ng::Widget(shortcutsTable); + ng::ref twoColumns = new ng::Widget(_shortcutsTable); twoColumns->set_layout(gridLayout2); - ng::Label* keyLabel = new ng::Label(twoColumns, shortcut.first); + ng::ref keyLabel = new ng::Label(twoColumns, shortcut.first); keyLabel->set_font("sans-bold"); keyLabel->set_font_size(16); keyLabel->set_fixed_width(40); - ng::Label* descriptionLabel = new ng::Label(twoColumns, shortcut.second); + ng::ref descriptionLabel = new ng::Label(twoColumns, shortcut.second); descriptionLabel->set_font_size(16); descriptionLabel->set_fixed_width(160); } } -void Viewer::createAdvancedSettings(Widget* parent) +void Viewer::createAdvancedSettings(ng::ref parent) { - ng::PopupButton* advancedButton = new ng::PopupButton(parent, "Advanced Settings"); + ng::ref advancedButton = new ng::PopupButton(parent, "Advanced Settings"); advancedButton->set_icon(FA_TOOLS); advancedButton->set_chevron_icon(-1); advancedButton->set_tooltip("Asset and rendering options."); - ng::Popup* advancedPopupParent = advancedButton->popup(); + ng::ref advancedPopupParent = advancedButton->popup(); advancedPopupParent->set_layout(new ng::GroupLayout()); - ng::VScrollPanel* scrollPanel = new ng::VScrollPanel(advancedPopupParent); + ng::ref scrollPanel = new ng::VScrollPanel(advancedPopupParent); scrollPanel->set_fixed_height(500); - ng::Widget* advancedPopup = new ng::Widget(scrollPanel); + ng::ref advancedPopup = new ng::Widget(scrollPanel); advancedPopup->set_layout(new ng::BoxLayout(ng::Orientation::Vertical)); - ng::Widget* settingsGroup = new ng::Widget(advancedPopup); + ng::ref settingsGroup = new ng::Widget(advancedPopup); settingsGroup->set_layout(new ng::GroupLayout(13)); - ng::Label* viewLabel = new ng::Label(settingsGroup, "Viewing Options"); + ng::ref viewLabel = new ng::Label(settingsGroup, "Viewing Options"); viewLabel->set_font_size(20); viewLabel->set_font("sans-bold"); - ng::CheckBox* drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); + ng::ref drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); drawEnvironmentBox->set_checked(_drawEnvironment); drawEnvironmentBox->set_callback([this](bool enable) { _drawEnvironment = enable; }); - ng::CheckBox* outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); + ng::ref outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); outlineSelectedGeometryBox->set_checked(_outlineSelection); outlineSelectedGeometryBox->set_callback([this](bool enable) { _outlineSelection = enable; }); - ng::Label* renderLabel = new ng::Label(settingsGroup, "Render Options"); + ng::ref renderLabel = new ng::Label(settingsGroup, "Render Options"); renderLabel->set_font_size(20); renderLabel->set_font("sans-bold"); - ng::CheckBox* transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); + ng::ref transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); transparencyBox->set_checked(_renderTransparency); transparencyBox->set_callback([this](bool enable) { _renderTransparency = enable; }); - ng::CheckBox* doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); + ng::ref doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); doubleSidedBox->set_checked(_renderDoubleSided); doubleSidedBox->set_callback([this](bool enable) { _renderDoubleSided = enable; }); - ng::CheckBox* importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); + ng::ref importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); importanceSampleBox->set_checked(_genContext.getOptions().hwSpecularEnvironmentMethod == mx::SPECULAR_ENVIRONMENT_FIS); _lightHandler->setUsePrefilteredMap(_genContext.getOptions().hwSpecularEnvironmentMethod != mx::SPECULAR_ENVIRONMENT_FIS); importanceSampleBox->set_callback([this](bool enable) @@ -820,7 +810,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); + ng::ref refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); refractionBox->set_checked(_genContext.getOptions().hwTransmissionRenderMethod == mx::TRANSMISSION_REFRACTION); refractionBox->set_callback([this](bool enable) { @@ -831,14 +821,14 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); + ng::ref refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); refractionSidedBox->set_checked(_lightHandler->getRefractionTwoSided()); refractionSidedBox->set_callback([this](bool enable) { _lightHandler->setRefractionTwoSided(enable); }); - ng::CheckBox* shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); + ng::ref shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); shaderInterfaceBox->set_checked(_genContext.getOptions().shaderInterfaceType == mx::SHADER_INTERFACE_REDUCED); shaderInterfaceBox->set_callback([this](bool enable) { @@ -846,11 +836,11 @@ void Viewer::createAdvancedSettings(Widget* parent) setShaderInterfaceType(interfaceType); }); - Widget* albedoGroup = new Widget(settingsGroup); + ng::ref albedoGroup = new Widget(settingsGroup); albedoGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(albedoGroup, "Albedo Method:"); mx::StringVec albedoOptions = { "Analytic", "Table", "MC" }; - ng::ComboBox* albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); + ng::ref albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); albedoBox->set_chevron_icon(-1); albedoBox->set_selected_index((int) _genContext.getOptions().hwDirectionalAlbedoMethod ); albedoBox->set_callback([this](int index) @@ -877,7 +867,7 @@ void Viewer::createAdvancedSettings(Widget* parent) } }); - Widget* sampleGroup = new Widget(settingsGroup); + ng::ref sampleGroup = new Widget(settingsGroup); sampleGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(sampleGroup, "Environment Samples:"); mx::StringVec sampleOptions; @@ -887,7 +877,7 @@ void Viewer::createAdvancedSettings(Widget* parent) sampleOptions.push_back(std::to_string(i)); m_process_events = true; } - ng::ComboBox* sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); + ng::ref sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); sampleBox->set_chevron_icon(-1); sampleBox->set_selected_index((int)std::log2(_lightHandler->getEnvSampleCount() / MIN_ENV_SAMPLE_COUNT) / 2); sampleBox->set_callback([this](int index) @@ -895,30 +885,30 @@ void Viewer::createAdvancedSettings(Widget* parent) _lightHandler->setEnvSampleCount(MIN_ENV_SAMPLE_COUNT * (int) std::pow(4, index)); }); - ng::Label* lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); + ng::ref lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); lightingLabel->set_font_size(20); lightingLabel->set_font("sans-bold"); - ng::CheckBox* directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); + ng::ref directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); directLightingBox->set_checked(_lightHandler->getDirectLighting()); directLightingBox->set_callback([this](bool enable) { _lightHandler->setDirectLighting(enable); }); - ng::CheckBox* indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); + ng::ref indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); indirectLightingBox->set_checked(_lightHandler->getIndirectLighting()); indirectLightingBox->set_callback([this](bool enable) { _lightHandler->setIndirectLighting(enable); }); - ng::Widget* lightRotationRow = new ng::Widget(settingsGroup); + ng::ref lightRotationRow = new ng::Widget(settingsGroup); lightRotationRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties ui; ui.uiMin = mx::Value::createValue(0.0f); ui.uiMax = mx::Value::createValue(360.0f); - ng::FloatBox* lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", + ng::ref> lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", _lightRotation, &ui, [this](float value) { _lightRotation = value; @@ -926,11 +916,11 @@ void Viewer::createAdvancedSettings(Widget* parent) }); lightRotationBox->set_editable(true); - ng::Label* shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); + ng::ref shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); shadowingLabel->set_font_size(20); shadowingLabel->set_font("sans-bold"); - ng::CheckBox* shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); + ng::ref shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); shadowMapBox->set_checked(_genContext.getOptions().hwShadowMap); shadowMapBox->set_callback([this](bool enable) { @@ -938,7 +928,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); + ng::ref ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); ambientOcclusionBox->set_checked(_genContext.getOptions().hwAmbientOcclusion); ambientOcclusionBox->set_callback([this](bool enable) { @@ -946,23 +936,23 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::Widget* ambientOcclusionGainRow = new ng::Widget(settingsGroup); + ng::ref ambientOcclusionGainRow = new ng::Widget(settingsGroup); ambientOcclusionGainRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", + ng::ref> ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", _ambientOcclusionGain, nullptr, [this](float value) { _ambientOcclusionGain = value; }); ambientOcclusionGainBox->set_editable(true); - ng::Label* sceneLabel = new ng::Label(settingsGroup, "Scene Options"); + ng::ref sceneLabel = new ng::Label(settingsGroup, "Scene Options"); sceneLabel->set_font_size(20); sceneLabel->set_font("sans-bold"); - Widget* unitGroup = new Widget(settingsGroup); + ng::ref unitGroup = new Widget(settingsGroup); unitGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(unitGroup, "Distance Unit:"); - ng::ComboBox* distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); + ng::ref distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); distanceUnitBox->set_fixed_size(ng::Vector2i(100, 20)); distanceUnitBox->set_chevron_icon(-1); if (_distanceUnitConverter) @@ -986,68 +976,68 @@ void Viewer::createAdvancedSettings(Widget* parent) m_process_events = true; }); - ng::Label* meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); + ng::ref meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); meshLoading->set_font_size(20); meshLoading->set_font("sans-bold"); - ng::CheckBox* splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); + ng::ref splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); splitUdimsBox->set_checked(_splitByUdims); splitUdimsBox->set_callback([this](bool enable) { _splitByUdims = enable; }); - ng::Label* materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); + ng::ref materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); materialLoading->set_font_size(20); materialLoading->set_font("sans-bold"); - ng::CheckBox* mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); + ng::ref mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); mergeMaterialsBox->set_checked(_mergeMaterials); mergeMaterialsBox->set_callback([this](bool enable) { _mergeMaterials = enable; }); - ng::CheckBox* showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); + ng::ref showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); showInputsBox->set_checked(_showAllInputs); showInputsBox->set_callback([this](bool enable) { _showAllInputs = enable; }); - ng::CheckBox* flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); + ng::ref flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); flattenBox->set_checked(_flattenSubgraphs); flattenBox->set_callback([this](bool enable) { _flattenSubgraphs = enable; }); - ng::Label* envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); + ng::ref envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); envLoading->set_font_size(20); envLoading->set_font("sans-bold"); - ng::CheckBox* normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); + ng::ref normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); normalizeEnvBox->set_checked(_normalizeEnvironment); normalizeEnvBox->set_callback([this](bool enable) { _normalizeEnvironment = enable; }); - ng::CheckBox* splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); + ng::ref splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); splitDirectLightBox->set_checked(_splitDirectLight); splitDirectLightBox->set_callback([this](bool enable) { _splitDirectLight = enable; }); - ng::Label* translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); + ng::ref translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); translationLabel->set_font_size(20); translationLabel->set_font("sans-bold"); - ng::Widget* targetShaderGroup = new ng::Widget(settingsGroup); + ng::ref targetShaderGroup = new ng::Widget(settingsGroup); targetShaderGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(targetShaderGroup, "Target Shader"); - ng::TextBox* targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); + ng::ref targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); targetShaderBox->set_callback([this](const std::string& choice) { _targetShader = choice; @@ -1056,46 +1046,46 @@ void Viewer::createAdvancedSettings(Widget* parent) targetShaderBox->set_font_size(16); targetShaderBox->set_editable(true); - ng::Label* textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); + ng::ref textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); textureLabel->set_font_size(20); textureLabel->set_font("sans-bold"); - ng::CheckBox* bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); + ng::ref bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); bakeHdrBox->set_checked(_bakeHdr); bakeHdrBox->set_callback([this](bool enable) { _bakeHdr = enable; }); - ng::CheckBox* bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); + ng::ref bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); bakeAverageBox->set_checked(_bakeAverage); bakeAverageBox->set_callback([this](bool enable) { _bakeAverage = enable; }); - ng::CheckBox* bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); + ng::ref bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); bakeOptimized->set_checked(_bakeOptimize); bakeOptimized->set_callback([this](bool enable) { _bakeOptimize = enable; }); - ng::CheckBox* bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); + ng::ref bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); bakeDocumentPerMaterial->set_checked(_bakeDocumentPerMaterial); bakeDocumentPerMaterial->set_callback([this](bool enable) { _bakeDocumentPerMaterial = enable; }); - ng::Label* wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); + ng::ref wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); wedgeLabel->set_font_size(20); wedgeLabel->set_font("sans-bold"); - ng::Widget* wedgeNameGroup = new ng::Widget(settingsGroup); + ng::ref wedgeNameGroup = new ng::Widget(settingsGroup); wedgeNameGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(wedgeNameGroup, "Property Name"); - ng::TextBox* wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); + ng::ref wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); wedgeNameBox->set_callback([this](const std::string& choice) { _wedgePropertyName = choice; @@ -1104,12 +1094,12 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeNameBox->set_font_size(16); wedgeNameBox->set_editable(true); - ng::Widget* wedgeMinGroup = new ng::Widget(settingsGroup); + ng::ref wedgeMinGroup = new ng::Widget(settingsGroup); wedgeMinGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeProp; wedgeProp.uiSoftMin = mx::Value::createValue(0.0f); wedgeProp.uiSoftMax = mx::Value::createValue(1.0f); - ng::FloatBox* wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", + ng::ref> wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMin = value; @@ -1117,9 +1107,9 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMinBox->set_value(0.0); wedgeMinBox->set_editable(true); - ng::Widget* wedgeMaxGroup = new ng::Widget(settingsGroup); + ng::ref wedgeMaxGroup = new ng::Widget(settingsGroup); wedgeMaxGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", + ng::ref> wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMax = value; @@ -1127,13 +1117,13 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMaxBox->set_value(1.0); wedgeMaxBox->set_editable(true); - ng::Widget* wedgeCountGroup = new ng::Widget(settingsGroup); + ng::ref wedgeCountGroup = new ng::Widget(settingsGroup); wedgeCountGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeCountProp; wedgeCountProp.uiMin = mx::Value::createValue(1); wedgeCountProp.uiSoftMax = mx::Value::createValue(8); wedgeCountProp.uiStep = mx::Value::createValue(1); - ng::IntBox* wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", + ng::ref> wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", _wedgeImageCount, &wedgeCountProp, [this](int value) { _wedgeImageCount = value; @@ -1141,7 +1131,7 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeCountBox->set_value(8); wedgeCountBox->set_editable(true); - createDocumentationInterface(advancedPopup, scrollPanel); + createDocumentationInterface(advancedPopup); } void Viewer::updateGeometrySelections() @@ -2441,7 +2431,7 @@ void Viewer::updateCameras() void Viewer::updateDisplayedProperties() { _propertyEditor.updateContents(this); - createSaveMaterialsInterface(_propertyEditor.getWindow(), "Save Material"); + createSaveMaterialsInterface((ng::ref) _propertyEditor.getWindow(), "Save Material"); perform_layout(); } diff --git a/source/MaterialXView/Viewer.h b/source/MaterialXView/Viewer.h index 08712f3c78..8f0257e1e1 100644 --- a/source/MaterialXView/Viewer.h +++ b/source/MaterialXView/Viewer.h @@ -179,7 +179,7 @@ class Viewer : public ng::Screen } // Return the underlying NanoGUI window. - ng::Window* getWindow() const + ng::ref getWindow() const { return _window; } @@ -283,13 +283,13 @@ class Viewer : public ng::Screen void updateMaterialSelectionUI(); void updateDisplayedProperties(); - void createLoadMeshInterface(Widget* parent, const std::string& label); - void createLoadMaterialsInterface(Widget* parent, const std::string& label); - void createLoadEnvironmentInterface(Widget* parent, const std::string& label); - void createSaveMaterialsInterface(Widget* parent, const std::string& label); - void createPropertyEditorInterface(Widget* parent, const std::string& label); - void createAdvancedSettings(Widget* parent); - void createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel); + void createLoadMeshInterface(ng::ref parent, const std::string& label); + void createLoadMaterialsInterface(ng::ref parent, const std::string& label); + void createLoadEnvironmentInterface(ng::ref parent, const std::string& label); + void createSaveMaterialsInterface(ng::ref parent, const std::string& label); + void createPropertyEditorInterface(ng::ref parent, const std::string& label); + void createAdvancedSettings(ng::ref parent); + void createDocumentationInterface(ng::ref parent); // Return the ambient occlusion image, if any, associated with the given material. mx::ImagePtr getAmbientOcclusionImage(mx::MaterialPtr material); @@ -318,7 +318,7 @@ class Viewer : public ng::Screen void setShaderInterfaceType(mx::ShaderInterfaceType interfaceType); private: - ng::Window* _window; + ng::ref _window; RenderPipelinePtr _renderPipeline; mx::FilePath _materialFilename; @@ -380,15 +380,15 @@ class Viewer : public ng::Screen // Geometry selections std::vector _geometryList; size_t _selectedGeom; - ng::Label* _geomLabel; - ng::ComboBox* _geometrySelectionBox; + ng::ref _geomLabel; + ng::ref _geometrySelectionBox; // Material selections std::vector _materials; mx::MaterialPtr _wireMaterial; size_t _selectedMaterial; - ng::Label* _materialLabel; - ng::ComboBox* _materialSelectionBox; + ng::ref _materialLabel; + ng::ref _materialSelectionBox; PropertyEditor _propertyEditor; // Material assignments @@ -475,11 +475,15 @@ class Viewer : public ng::Screen // Frame timing bool _frameTiming; - ng::Label* _timingLabel; - ng::Widget* _timingPanel; - ng::TextBox* _timingText; + ng::ref _timingLabel; + ng::ref _timingPanel; + ng::ref _timingText; mx::ScopedTimer _frameTimer; double _avgFrameTime; + + // Documentation UI + ng::ref _shortcutsButton; + ng::ref _shortcutsTable; }; extern const mx::Vector3 DEFAULT_CAMERA_POSITION; From bef88b9f528cff361ecfcd2c52afb3359836aeb7 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 2 Nov 2024 14:59:16 -0700 Subject: [PATCH 18/76] Extend Chiang tests across languages (#2104) This changelist extends testing of Chiang Hair BSDF nodes across shading languages, allowing render comparisons to include the complete Examples and TestSuite folders. In order to avoid shader compilation errors, placeholder OSL implementations of these nodes have been added, and these should be replaced with accurate implementations once they are supported. --- libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl | 7 +++++++ libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx | 12 ++++++++++++ .../bsdf/{hair_bsdf.mtlx => chiang_hair_bsdf.mtlx} | 0 ...aceshader.mtlx => chiang_hair_surfaceshader.mtlx} | 0 source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp | 7 +------ source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 2 -- source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 6 +----- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 2 -- 8 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl rename resources/Materials/TestSuite/pbrlib/bsdf/{hair_bsdf.mtlx => chiang_hair_bsdf.mtlx} (100%) rename resources/Materials/TestSuite/pbrlib/surfaceshader/{hair_surfaceshader.mtlx => chiang_hair_surfaceshader.mtlx} (100%) diff --git a/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl new file mode 100644 index 0000000000..002bdc3044 --- /dev/null +++ b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl @@ -0,0 +1,7 @@ +void mx_chiang_hair_roughness(float longitudinal, float azimuthal, float scale_TT, float scale_TRT, output vector2 roughness_R, output vector2 roughness_TT, output vector2 roughness_TRT) +{ + // TODO: Write OSL implementation of this node. + roughness_R = vector2(0.0, 0.0); + roughness_TT = vector2(0.0, 0.0); + roughness_TRT = vector2(0.0, 0.0); +} diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx index d3849a5ddb..beac984518 100644 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx +++ b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx @@ -22,6 +22,9 @@ + + + @@ -71,4 +74,13 @@ + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx similarity index 100% rename from resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx rename to resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx similarity index 100% rename from resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx rename to resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp index 414bc3dd5d..b0309ea44d 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp @@ -84,12 +84,7 @@ TEST_CASE("GenShader: MSL Implementation Check", "[genmsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); - generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); - generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); - generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 34); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 30); } TEST_CASE("GenShader: MSL Unique Names", "[genmsl]") diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h index 692c283fda..7c96279d8b 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h @@ -43,8 +43,6 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester void addSkipFiles() override { - _skipFiles.insert("hair_bsdf.mtlx"); - _skipFiles.insert("hair_surfaceshader.mtlx"); } void setupDependentLibraries() override diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp index c89f9ab19d..612d134753 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp @@ -89,12 +89,8 @@ TEST_CASE("GenShader: OSL Implementation Check", "[genosl]") generatorSkipNodeTypes.insert("light"); mx::StringSet generatorSkipNodeDefs; - generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); - generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); - generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); - generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 35); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31); } TEST_CASE("GenShader: OSL Unique Names", "[genosl]") diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h index f02f750d26..959c12d48b 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h @@ -45,8 +45,6 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester void addSkipFiles() override { - _skipFiles.insert("hair_bsdf.mtlx"); - _skipFiles.insert("hair_surfaceshader.mtlx"); } // Ignore light shaders in the document for OSL From 20383ae3e721d93b6dce981b09475c4e2e524989 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 13 Nov 2024 17:05:33 -0800 Subject: [PATCH 19/76] Update deprecated Xcode in CI (#2114) This changelist updates a deprecated version of Xcode in our GitHub CI. --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c11603dd70..b2d5f182bf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,10 +68,10 @@ jobs: cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON python: 3.9 - - name: MacOS_Xcode_14_Python311 + - name: MacOS_Xcode_15_Python311 os: macos-14 compiler: xcode - compiler_version: "14.3" + compiler_version: "15.1" python: 3.11 static_analysis: ON cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON From 65dbd3937db8093011b825e9e5bf0b9ae9757abf Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Thu, 14 Nov 2024 10:31:09 -0500 Subject: [PATCH 20/76] Skip comments in functional equivalence tests (#2110) Skip `comment` blocks when checking for functional equivalency as they should not affect the comparison. --- source/MaterialXCore/Element.cpp | 22 ++++++++++++++++--- .../MaterialXTest/MaterialXCore/Document.cpp | 8 +++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 648d7df000..043d6f4092 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -426,9 +426,25 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& } } - // Compare children. - const vector& children = getChildren(); - const vector& rhsChildren = rhs->getChildren(); + // Compare all child elements that affect functional equivalence. + vector children; + for (ElementPtr child : getChildren()) + { + if (child->getCategory() == CommentElement::CATEGORY) + { + continue; + } + children.push_back(child); + } + vector rhsChildren; + for (ElementPtr child : rhs->getChildren()) + { + if (child->getCategory() == CommentElement::CATEGORY) + { + continue; + } + rhsChildren.push_back(child); + } if (children.size() != rhsChildren.size()) { if (results) diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index ae7623084e..f3a207fc84 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -150,6 +150,9 @@ TEST_CASE("Document equivalence", "[document]") unsigned int index = 0; mx::ElementPtr child = doc->addNodeGraph("mygraph"); mx::NodeGraphPtr graph = child->asA(); + // Add comment block at the start of the first doc to check skipping + mx::ElementPtr comment = doc->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 1"); for (auto it = inputMap.begin(); it != inputMap.end(); ++it) { const std::string inputType = (*it).first; @@ -205,6 +208,11 @@ TEST_CASE("Document equivalence", "[document]") input->setName("input_" + inputType); } } + // Add comment blocks at end of second doc to check value and count checks + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 2"); + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 3"); mx::ElementEquivalenceOptions options; mx::ElementEquivalenceResultVec results; From a368aac8ccc4f8cf7a9d1d5189826b040eced893 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Sat, 16 Nov 2024 18:27:38 -0500 Subject: [PATCH 21/76] Cleanup options for equivalence testing (#2115) User facing naming changes for the functional equivalence API. There are no logic changes. --- source/MaterialXCore/Element.cpp | 12 +++--- source/MaterialXCore/Element.h | 37 +++++++++---------- .../MaterialXTest/MaterialXCore/Document.cpp | 12 +++--- .../PyMaterialX/PyMaterialXCore/PyElement.cpp | 8 ++-- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 043d6f4092..3bede2fe74 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -396,14 +396,14 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& StringVec rhsAttributeNames = rhs->getAttributeNames(); // Filter out any attributes specified in the options. - const StringSet& skipAttributes = options.skipAttributes; - if (!skipAttributes.empty()) + const StringSet& attributeExclusionList = options.attributeExclusionList; + if (!attributeExclusionList.empty()) { attributeNames.erase(std::remove_if(attributeNames.begin(), attributeNames.end(), - [&skipAttributes](const string& attr) { return skipAttributes.find(attr) != skipAttributes.end(); }), + [&attributeExclusionList](const string& attr) { return attributeExclusionList.find(attr) != attributeExclusionList.end(); }), attributeNames.end()); rhsAttributeNames.erase(std::remove_if(rhsAttributeNames.begin(), rhsAttributeNames.end(), - [&skipAttributes](const string& attr) { return skipAttributes.find(attr) != skipAttributes.end(); }), + [&attributeExclusionList](const string& attr) { return attributeExclusionList.find(attr) != attributeExclusionList.end(); }), rhsAttributeNames.end()); } @@ -714,7 +714,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr { // Perform value comparisons bool performedValueComparison = false; - if (!options.skipValueComparisons) + if (options.performValueComparisons) { const StringSet uiAttributes = { @@ -724,7 +724,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr }; // Get precision and format options - ScopedFloatFormatting fmt(options.format, options.precision); + ScopedFloatFormatting fmt(options.floatFormat, options.floatPrecision); ConstValueElementPtr rhsValueElement = rhs->asA(); diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index fb4bbe07ce..05eb2235f3 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -1389,34 +1389,33 @@ class MX_CORE_API ElementEquivalenceOptions public: ElementEquivalenceOptions() { - format = Value::getFloatFormat(); - precision = Value::getFloatPrecision(); - skipAttributes = {}; - skipValueComparisons = false; + performValueComparisons = true; + floatFormat = Value::getFloatFormat(); + floatPrecision = Value::getFloatPrecision(); + attributeExclusionList = {}; }; ~ElementEquivalenceOptions() { } - /// Floating point format option for floating point value comparisons - Value::FloatFormat format; + /// Perform value comparisons as opposed to literal string comparisons. + /// Default is true. + bool performValueComparisons; - /// Floating point precision option for floating point value comparisons - int precision; + /// Floating point format to use for floating point value comparisons + Value::FloatFormat floatFormat; - /// Attribute filtering options. By default all attributes are considered. - /// Name, category attributes cannot be skipped. + /// Floating point precision to use for floating point value comparisons + int floatPrecision; + + /// Specifies the set of attributes that should be excluded when performing a comparison. + /// By default all attributes are considered. Name and category attributes cannot be excluded. /// - /// For example UI attribute comparision be skipped by setting: - /// skipAttributes = { + /// For example, to exclude UI and documentation attributes from consideration the follow may be set: + /// attributeExclusionList = { /// ValueElement::UI_MIN_ATTRIBUTE, ValueElement::UI_MAX_ATTRIBUTE, /// ValueElement::UI_SOFT_MIN_ATTRIBUTE, ValueElement::UI_SOFT_MAX_ATTRIBUTE, /// ValueElement::UI_STEP_ATTRIBUTE, Element::XPOS_ATTRIBUTE, - /// Element::YPOS_ATTRIBUTE }; - StringSet skipAttributes; - - /// Do not perform any value comparisions. Instead perform exact string comparisons for attributes - /// Default is false. The operator==() method can be used instead as it always performs - /// a strict comparison. Default is false. - bool skipValueComparisons; + /// Element::YPOS_ATTRIBUTE, Element::DOC_ATTRIBUTE }; + StringSet attributeExclusionList; }; /// @class ExceptionOrphanedElement diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index f3a207fc84..b593969ccb 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -217,27 +217,27 @@ TEST_CASE("Document equivalence", "[document]") mx::ElementEquivalenceOptions options; mx::ElementEquivalenceResultVec results; - // Check skipping all value compares - options.skipValueComparisons = true; + // Check that this fails when not performing value comparisons + options.performValueComparisons = false; bool equivalent = doc->isEquivalent(doc2, options, &results); REQUIRE(!equivalent); // Check attibute values - options.skipValueComparisons = false; + options.performValueComparisons = true; results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); REQUIRE(equivalent); unsigned int currentPrecision = mx::Value::getFloatPrecision(); // This will compare 0.012345608 versus: 1, 0.012345611 for input10 - options.precision = 8; + options.floatPrecision = 8; equivalent = doc->isEquivalent(doc2, options); REQUIRE(!equivalent); - options.precision = currentPrecision; + options.floatPrecision = currentPrecision; // Check attribute filtering of inputs results.clear(); - options.skipAttributes = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; + options.attributeExclusionList = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; for (mx::InputPtr floatInput : floatInputs) { floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, "0.9"); diff --git a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp index cb70d04704..004fa0a670 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp @@ -224,10 +224,10 @@ void bindPyElement(py::module& mod) .def_readwrite("attributeName", &mx::ElementEquivalenceResult::attributeName); py::class_(mod, "ElementEquivalenceOptions") - .def_readwrite("format", &mx::ElementEquivalenceOptions::format) - .def_readwrite("precision", &mx::ElementEquivalenceOptions::precision) - .def_readwrite("skipAttributes", &mx::ElementEquivalenceOptions::skipAttributes) - .def_readwrite("skipValueComparisons", &mx::ElementEquivalenceOptions::skipValueComparisons) + .def_readwrite("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) + .def_readwrite("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) + .def_readwrite("floatPrecision", &mx::ElementEquivalenceOptions::floatPrecision) + .def_readwrite("attributeExclusionList", &mx::ElementEquivalenceOptions::attributeExclusionList) .def(py::init<>()); py::class_(mod, "StringResolver") From a3a7744f3e7a290b4d029ea60452f4bab8a9496f Mon Sep 17 00:00:00 2001 From: krohmerNV <42233792+krohmerNV@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:48:00 +0100 Subject: [PATCH 22/76] MDL 1.9 updates (#2102) add new version to GenMDL and remove uniform restriction from material IOR Minor updates: - improve MDL printing by adding named parameters - handle 1-element mixes (basically scale) above layers - improve blur and height to normal to return something meaningful (before totally broken) - improve non-material outputs that can be rendered, e.g. float3x3 and float4x4 - preparations for MDL 1.10 - remove shader parameters from the public MDL material interface. backsurfaceshader and displacementshader showed up with default values only after recent upstream changes --- .../pbrlib/genmdl/pbrlib_genmdl_impl.mtlx | 6 +- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 2 +- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 89 +++- source/MaterialXGenMdl/MdlShaderGenerator.h | 9 +- .../Nodes/ClosureLayerNodeMdl.cpp | 45 ++ .../Nodes/ClosureLayerNodeMdl.h | 7 + .../MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp | 13 +- .../MaterialXGenMdl/mdl/materialx/pbrlib.mdl | 10 +- .../mdl/materialx/pbrlib_1_6.mdl | 34 +- .../mdl/materialx/pbrlib_1_9.mdl | 372 +++++++++++++++++ .../mdl/materialx/sampling.mdl | 19 +- .../MaterialXGenMdl/mdl/materialx/stdlib.mdl | 10 +- .../mdl/materialx/stdlib_1_9.mdl | 387 ++++++++++++++++++ .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 22 +- 14 files changed, 961 insertions(+), 64 deletions(-) create mode 100644 source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl create mode 100644 source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index c8f23958ae..45f83f164a 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -2,7 +2,7 @@ - + @@ -11,13 +11,13 @@ - + - + diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index 51566463aa..b190937c41 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -695,7 +695,7 @@ - + diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index 76cd7587fd..71db0d7cf4 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -52,9 +52,11 @@ const string IMPORT_ALL = " import *"; const string MDL_VERSION_1_6 = "1.6"; const string MDL_VERSION_1_7 = "1.7"; const string MDL_VERSION_1_8 = "1.8"; +const string MDL_VERSION_1_9 = "1.9"; const string MDL_VERSION_SUFFIX_1_6 = "1_6"; const string MDL_VERSION_SUFFIX_1_7 = "1_7"; const string MDL_VERSION_SUFFIX_1_8 = "1_8"; +const string MDL_VERSION_SUFFIX_1_9 = "1_9"; } // anonymous namespace @@ -191,6 +193,27 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G emitLineBreak(stage); } + // Emit shader inputs that have been filtered during printing of the public interface + const string uniformPrefix = _syntax->getUniformQualifier() + " "; + for (ShaderGraphInputSocket* inputSocket : graph.getInputSockets()) + { + if (inputSocket->getConnections().size() && + (inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL)) + { + const string& qualifier = inputSocket->isUniform() || inputSocket->getType() == Type::FILENAME + ? uniformPrefix + : EMPTY_STRING; + const string& type = _syntax->getTypeName(inputSocket->getType()); + + emitLineBegin(stage); + emitString(qualifier + type + " " + inputSocket->getVariable() + " = ", stage); + emitString(_syntax->getDefaultValue(inputSocket->getType(), true), stage); + emitLineEnd(stage, true); + } + } + // Emit all texturing nodes. These are inputs to any // closure/shader nodes and need to be emitted first. emitFunctionCalls(graph, context, stage, ShaderNode::Classification::TEXTURE); @@ -215,6 +238,7 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G const string result = getUpstreamResult(outputSocket, context); const TypeDesc outputType = outputSocket->getType(); + // Try to return some meaningful color in case the output is not a material if (graph.hasClassification(ShaderNode::Classification::TEXTURE)) { if (outputType == Type::DISPLACEMENTSHADER) @@ -229,7 +253,25 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G else { emitLine("float3 displacement__ = float3(0.0)", stage); - emitLine("color finalOutput__ = mk_color3(" + result + ")", stage); + std::string finalOutput = "mk_color3(0.0)"; + if (outputType == Type::BOOLEAN) + finalOutput = result + " ? mk_color3(0.0, 1.0, 0.0) : mk_color3(1.0, 0.0, 0.0)"; + else if (outputType == Type::INTEGER) + finalOutput = "mk_color3(" + result + " / 100)"; // arbitrary + else if (outputType == Type::FLOAT) + finalOutput = "mk_color3(" + result + ")"; + else if (outputType == Type::VECTOR2) + finalOutput = "mk_color3(" + result + ".x, " + result + ".y, 0.0)"; + else if (outputType == Type::VECTOR3) + finalOutput = "mk_color3(" + result + ")"; + else if (outputType == Type::COLOR3) + finalOutput = result; + else if (outputType == Type::COLOR4) + finalOutput = result + ".rgb"; + else if (outputType == Type::MATRIX33 || outputType == Type::MATRIX44) + finalOutput = "mk_color3(" + result + "[0][0], " + result + "[1][1], " + result + "[2][2])"; + + emitLine("color finalOutput__ = " + finalOutput, stage); } // End shader body @@ -527,6 +569,13 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen // and are editable by users. if (inputSocket->getConnections().size() && graph->isEditable(*inputSocket)) { + if (inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL) + { + continue; + } + inputs->add(inputSocket->getSelf()); } } @@ -537,7 +586,7 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen outputs->add(outputSocket->getSelf()); } - // MDL does not allow varying data connected to transmission IOR. + // MDL does not allow varying data connected to transmission IOR until MDL 1.9. // We must find all uses of transmission IOR and make sure we don't // have a varying connection to it. If a varying connection is found // we break that connection and revert to using default value on that @@ -552,8 +601,14 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen // this fix will disconnect the transmission IOR on the inside, but // still support the connection to reflection IOR. // - if (graph->hasClassification(ShaderNode::Classification::SHADER) || - graph->hasClassification(ShaderNode::Classification::CLOSURE)) + GenMdlOptions::MdlVersion version = getMdlVersion(context); + bool uniformIorRequired = + version == GenMdlOptions::MdlVersion::MDL_1_6 || + version == GenMdlOptions::MdlVersion::MDL_1_7 || + version == GenMdlOptions::MdlVersion::MDL_1_8; + if (uniformIorRequired && ( + graph->hasClassification(ShaderNode::Classification::SHADER) || + graph->hasClassification(ShaderNode::Classification::CLOSURE))) { // Find dependencies on transmission IOR. std::set graphsWithIorDependency; @@ -641,10 +696,15 @@ void MdlShaderGenerator::emitShaderInputs(const DocumentPtr doc, const VariableB } } -void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const +GenMdlOptions::MdlVersion MdlShaderGenerator::getMdlVersion(GenContext& context) const { GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); - GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; + return options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; +} + +void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const +{ + GenMdlOptions::MdlVersion version = getMdlVersion(context); emitLineBegin(stage); emitString("mdl ", stage); @@ -656,19 +716,22 @@ void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& case GenMdlOptions::MdlVersion::MDL_1_7: emitString(MDL_VERSION_1_7, stage); break; + case GenMdlOptions::MdlVersion::MDL_1_8: + emitString(MDL_VERSION_1_8, stage); + break; default: - // GenMdlOptions::MdlVersion::MDL_1_8 + // GenMdlOptions::MdlVersion::MDL_1_9 // GenMdlOptions::MdlVersion::MDL_LATEST - emitString(MDL_VERSION_1_8, stage); + emitString(MDL_VERSION_1_9, stage); break; } emitLineEnd(stage, true); } + const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& context) const { - GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); - GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; + GenMdlOptions::MdlVersion version = getMdlVersion(context); switch (version) { @@ -676,10 +739,12 @@ const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& contex return MDL_VERSION_SUFFIX_1_6; case GenMdlOptions::MdlVersion::MDL_1_7: return MDL_VERSION_SUFFIX_1_7; + case GenMdlOptions::MdlVersion::MDL_1_8: + return MDL_VERSION_SUFFIX_1_8; default: - // GenMdlOptions::MdlVersion::MDL_1_8 + // GenMdlOptions::MdlVersion::MDL_1_9 // GenMdlOptions::MdlVersion::MDL_LATEST - return MDL_VERSION_SUFFIX_1_8; + return MDL_VERSION_SUFFIX_1_9; } } diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.h b/source/MaterialXGenMdl/MdlShaderGenerator.h index 3a24bcf87d..ef88fbc453 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.h +++ b/source/MaterialXGenMdl/MdlShaderGenerator.h @@ -25,7 +25,8 @@ class MX_GENMDL_API GenMdlOptions : public GenUserData MDL_1_6, MDL_1_7, MDL_1_8, - MDL_LATEST = MDL_1_8 + MDL_1_9, + MDL_LATEST = MDL_1_9 }; /// Create MDL code generator options with default values. @@ -76,7 +77,11 @@ class MX_GENMDL_API MdlShaderGenerator : public ShaderGenerator /// Map of code snippets for geomprops in MDL. static const std::unordered_map GEOMPROP_DEFINITIONS; - /// Add the MDL file header containing the version number of the generated module.. + /// Get the selected MDL target language version number from the context option. + /// If not set, the latest version supported by GenMdl is returned. + GenMdlOptions::MdlVersion getMdlVersion(GenContext& context) const; + + /// Add the MDL file header containing the version number of the generated module. void emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const; /// Add the version number suffix appended to MDL modules that use versions. diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index e3484b0171..8949ae6cc0 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -16,6 +16,10 @@ MATERIALX_NAMESPACE_BEGIN const string StringConstantsMdl::TOP = "top"; const string StringConstantsMdl::BASE = "base"; +const string StringConstantsMdl::FG = "fg"; +const string StringConstantsMdl::BG = "bg"; +const string StringConstantsMdl::MIX = "mix"; +const string StringConstantsMdl::TOP_WEIGHT = "top_weight"; ShaderNodeImplPtr ClosureLayerNodeMdl::create() { @@ -101,6 +105,7 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // Transport the base bsdf further than one layer ShaderNode* baseReceiverNode = top; + ShaderNode* mixTopWeightNode = nullptr; while (true) { // If the top node is again a layer, we don't want to override the base @@ -111,6 +116,26 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& } else { + // TODO is there a more efficient way to check if the node is a mix_bsdf? + std::string name = top->getImplementation().getName(); + if (name == "IM_mix_bsdf_genmdl") + { + // handle one special case: the top node is a mix where either fg or bg is empty + // so basically a scale factor + ShaderOutput* fgOutput = top->getInput(StringConstantsMdl::FG)->getConnection(); + ShaderOutput* bgOutput = top->getInput(StringConstantsMdl::BG)->getConnection(); + ShaderOutput* mixOutput = top->getInput(StringConstantsMdl::MIX)->getConnection(); + ShaderNode* fg = fgOutput ? fgOutput->getNode() : nullptr; + ShaderNode* bg = bgOutput ? bgOutput->getNode() : nullptr; + ShaderNode* mix = mixOutput ? mixOutput->getNode() : nullptr; + if ((fg && !bg) || (!fg && bg)) + { + baseReceiverNode = fg ? fg : bg; // take the node that is valid + top = baseReceiverNode; + mixTopWeightNode = mix; + } + break; + } // we stop at elemental bsdfs // TODO handle mix, add, and multiply break; @@ -150,6 +175,11 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // base BSDF connection and output variable name from the // layer operator itself. topNodeBaseInput->makeConnection(base->getOutput()); + if (mixTopWeightNode) + { + ShaderInput* topNodeTopWeightInput = baseReceiverNode->getInput(StringConstantsMdl::TOP_WEIGHT); + topNodeTopWeightInput->makeConnection(mixTopWeightNode->getOutput()); + } ScopedSetVariableName setVariable(output->getVariable(), top->getOutput()); // Make the call. @@ -171,6 +201,21 @@ void LayerableNodeMdl::addInputs(ShaderNode& node, GenContext& /*context*/) cons { // Add the input to hold base layer BSDF. node.addInput(StringConstantsMdl::BASE, Type::BSDF); + + // Set the top level weight default to 1.0 + ShaderInput* topWeightNode = node.addInput(StringConstantsMdl::TOP_WEIGHT, Type::FLOAT); + ValuePtr value = TypedValue::createValue(1.0f); + topWeightNode->setValue(value); +} + +bool LayerableNodeMdl::isEditable(const ShaderInput& input) const +{ + if (input.getName() == StringConstantsMdl::BASE || + input.getName() == StringConstantsMdl::TOP_WEIGHT) + { + return false; + } + return BASE::isEditable(input); } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h index bced5cfac1..8b6f987287 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h @@ -23,6 +23,10 @@ class MX_GENMDL_API StringConstantsMdl /// String constants static const string TOP; ///< layer parameter name of the top component static const string BASE; ///< layer parameter name of the base component + static const string FG; ///< mix parameter name of the foreground + static const string BG; ///< mix parameter name of the background + static const string MIX; ///< mix parameter name of the amount + static const string TOP_WEIGHT; ///< mix amount forwarded into layer top component }; /// Closure layer node implementation for MDL. @@ -40,11 +44,14 @@ class MX_GENMDL_API ClosureLayerNodeMdl : public ShaderNodeImpl /// Note, not all elemental bsdfs support this kind of transformation. class MX_GENMDL_API LayerableNodeMdl : public SourceCodeNodeMdl { + using BASE = SourceCodeNodeMdl; + public: virtual ~LayerableNodeMdl() = default; static ShaderNodeImplPtr create(); void addInputs(ShaderNode& node, GenContext&) const override; + bool isEditable(const ShaderInput& input) const override; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp index 6477cd9ae8..dd0444d129 100644 --- a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp @@ -59,12 +59,17 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex // Emit calls for the closure dependencies upstream from this node. shadergen.emitDependentFunctionCalls(node, context, stage, ShaderNode::Classification::CLOSURE); - // Check if transmission IOR is used for this shader. + // Check if transmission IOR is used for this shader for MDL versions before 1.9. // MDL only supports a single transmission IOR per material and // it is given as an input on the 'material' constructor. // So if used we must forward this value/connection to the surface // constructor. It's set as an extra input below. - const ShaderInput* ior = findTransmissionIOR(node); + GenMdlOptions::MdlVersion version = shadergen.getMdlVersion(context); + bool uniformIorRequired = + version == GenMdlOptions::MdlVersion::MDL_1_6 || + version == GenMdlOptions::MdlVersion::MDL_1_7 || + version == GenMdlOptions::MdlVersion::MDL_1_8; + const ShaderInput* ior = uniformIorRequired ? findTransmissionIOR(node) : nullptr; shadergen.emitLineBegin(stage); @@ -79,6 +84,9 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex for (ShaderInput* input : node.getInputs()) { shadergen.emitString(delim, stage); + shadergen.emitString("mxp_", stage); + shadergen.emitString(input->getName(), stage); + shadergen.emitString(": ", stage); shadergen.emitInput(input, context, stage); delim = ", "; } @@ -87,6 +95,7 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex { // Emit the extra input for transmission IOR. shadergen.emitString(delim, stage); + shadergen.emitString("mxp_transmission_ior: ", stage); shadergen.emitInput(ior, context, stage); } diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl index 0c11ce3744..789b4cfa77 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl @@ -16,15 +16,15 @@ // MDL implementation of all types and nodes of // MaterialX Physically-Based Shading Nodes -// Document v1.37 REV2, July 16, 2019 (Revised October 17, 2019) +// Document version 1.39, June 29, 2024 // see www.materialx.org // in -// NVIDIA Material Definition Language 1.8 +// NVIDIA Material Definition Language 1.9 // Language Specification -// Document version 1.8.2, May 24, 2023 +// Document version 1.9.2, September 16, 2024 // www.nvidia.com/mdl -mdl 1.8; +mdl 1.9; // forward the latest version -export using .::pbrlib_1_8 import *; +export using .::pbrlib_1_9 import *; diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl index e70f849920..64102d6c27 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl @@ -82,7 +82,8 @@ export material mx_oren_nayar_diffuse_bsdf( float mxp_weight = 1.0, color mxp_color = color(0.18), float mxp_roughness = 0.0, - float3 mxp_normal = state::normal() + float3 mxp_normal = state::normal(), + uniform bool mxp_energy_compensation = false [[ anno::unused() ]] // MDL 1.10 ) [[ anno::usage( "materialx:bsdf") ]] @@ -152,7 +153,8 @@ export material mx_dielectric_bsdf( float3 mxp_tangent = state::texture_tangent_u(0), uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, - material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix float mxp_thinfilm_thickness = 0.0, float mxp_thinfilm_ior = 1.0 ) [[ @@ -174,8 +176,8 @@ export material mx_dielectric_bsdf( layer: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect), base: mxp_base.surface.scattering, @@ -186,8 +188,8 @@ export material mx_dielectric_bsdf( layer: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_transmit), normal: mxp_normal); @@ -200,8 +202,8 @@ export material mx_dielectric_bsdf( base: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect_transmit)), normal: mxp_normal); @@ -258,12 +260,13 @@ export material mx_conductor_bsdf( ) ); -// TODO MDL 1.8 +// MDL 1.8 // * will add support for thin film above a color_custom_curve_layer node until then, thin_film will have no effect // * thin_film(thickness: 0.0, ior: < 1.0) will be handled properly export material mx_generalized_schlick_bsdf( float mxp_weight = 1.0, color mxp_color0 = color(1.0), + color mxp_color82 = color(1.0), // MDL 1.10 color mxp_color90 = color(1.0), float mxp_exponent = 5.0, float2 mxp_roughness = float2(0.05), @@ -271,7 +274,8 @@ export material mx_generalized_schlick_bsdf( float3 mxp_tangent = state::texture_tangent_u(0), uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, - material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix float mxp_thinfilm_thickness = 0.0, float mxp_thinfilm_ior = 1.0 ) [[ @@ -283,8 +287,8 @@ export material mx_generalized_schlick_bsdf( bsdf ggx_model_R = df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: color(1.0), - multiscatter_tint: color(1.0), + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect); @@ -302,7 +306,7 @@ export material mx_generalized_schlick_bsdf( layer: mxp_scatter_mode == mx_scatter_mode_T ? df::color_custom_curve_layer( normal_reflectivity: mxp_color0, - grazing_reflectivity: mxp_color90, + grazing_reflectivity: mxp_color82 * mxp_color90, exponent: mxp_exponent, layer: bsdf(), base: ggx_model_T, @@ -312,7 +316,7 @@ export material mx_generalized_schlick_bsdf( ior: color(coatIor), base: df::color_custom_curve_layer( normal_reflectivity: mxp_color0, - grazing_reflectivity: mxp_color90, + grazing_reflectivity: mxp_color82 * mxp_color90, exponent: mxp_exponent, layer: ggx_model_R, base: mxp_scatter_mode == mx_scatter_mode_R @@ -440,7 +444,7 @@ export material mx_chiang_hair_bsdf( float mxp_cuticle_angle = 0.5, float3 mxp_absorption_coefficient = float3(0.0), // TODO: MDL's chiang_hair BSDF has no support user tangent vector - float3 mxp_curve_direction = state::texture_tangent_u(0) + float3 mxp_curve_direction = state::texture_tangent_u(0) [[ anno::unused() ]] ) [[ anno::usage( "materialx:bsdf") ]] diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl new file mode 100644 index 0000000000..e8654380d3 --- /dev/null +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// MDL implementation of all types and nodes of +// MaterialX Physically-Based Shading Nodes +// Document version 1.39, June 29, 2024 +// see www.materialx.org +// in +// NVIDIA Material Definition Language 1.9 +// Language Specification +// Document version 1.9.2, September 16, 2024 +// www.nvidia.com/mdl + +mdl 1.9; + +import ::anno::*; +import ::df::*; +import ::math::*; +import ::state::*; + +import .::core::*; + +// Changes since MDL 1.8 +// - lift the restriction of uniform IORs + +// forward unchanged definitions from the previous versions +export using .::pbrlib_1_6 import mx_scatter_mode; +export using .::pbrlib_1_6 import mx_map_scatter_mode; +export using .::pbrlib_1_6 import mx_oren_nayar_diffuse_bsdf; +export using .::pbrlib_1_6 import mx_burley_diffuse_bsdf; +export using .::pbrlib_1_6 import mx_translucent_bsdf; +export using .::pbrlib_1_6 import mx_subsurface_bsdf; +export using .::pbrlib_1_6 import mx_thin_film_bsdf; +export using .::pbrlib_1_6 import mx_chiang_hair_bsdf; +export using .::pbrlib_1_6 import mx_uniform_edf; +export using .::pbrlib_1_6 import mx_conical_edf; +export using .::pbrlib_1_6 import mx_measured_edf; +export using .::pbrlib_1_6 import mx_absorption_vdf; +export using .::pbrlib_1_6 import mx_anisotropic_vdf; +export using .::pbrlib_1_6 import mx_light; +export using .::pbrlib_1_6 import mx_displacement_float; +export using .::pbrlib_1_6 import mx_displacement_vector3; +export using .::pbrlib_1_6 import volume_mix_return; +export using .::pbrlib_1_6 import volume_mix; +export using .::pbrlib_1_6 import mx_multiply_bsdf_color3; +export using .::pbrlib_1_6 import mx_multiply_bsdf_float; +export using .::pbrlib_1_6 import mx_multiply_edf_color3; +export using .::pbrlib_1_6 import mx_multiply_edf_float; +export using .::pbrlib_1_6 import mx_multiply_vdf_color3; +export using .::pbrlib_1_6 import mx_multiply_vdf_float; +export using .::pbrlib_1_6 import mx_roughness_anisotropy; +export using .::pbrlib_1_6 import mx_roughness_dual; +export using .::pbrlib_1_6 import mx_blackbody; +export using .::pbrlib_1_6 import mx_artistic_ior__result; +export using .::pbrlib_1_6 import mx_artistic_ior; +export using .::pbrlib_1_6 import mx_deon_hair_absorption_from_melanin; +export using .::pbrlib_1_6 import mx_chiang_hair_absorption_from_color; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness__result; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness; + +export using .::pbrlib_1_7 import mx_sheen_bsdf; +export using .::pbrlib_1_7 import mx_add_bsdf; +export using .::pbrlib_1_7 import mx_add_edf; +export using .::pbrlib_1_7 import mx_mix_edf; +export using .::pbrlib_1_7 import mx_add_vdf; +export using .::pbrlib_1_7 import mx_generalized_schlick_edf; +export using .::pbrlib_1_7 import mx_volume; + +export material mx_mix_bsdf( + material mxp_fg = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_bg = material() [[ anno::usage( "materialx:bsdf") ]], + float mxp_mix = 0.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float mix = math::saturate(mxp_mix); + volume_mix_return v = volume_mix( + mxp_fg.volume.scattering_coefficient, mix, + mxp_bg.volume.scattering_coefficient, (1.0f - mix)); +} in material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mix, + layer: mxp_fg.surface.scattering, + base: mxp_bg.surface.scattering + ) + ), + // we need to carry volume properties along for SSS + ior: mix * mxp_fg.ior + (1.0f - mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component(v.mix_weight1, mxp_fg.volume.scattering), + df::vdf_component(1.0 - v.mix_weight1, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: v.scattering_coefficient + ) +); + +export material mx_mix_vdf( + material mxp_fg = material() [[ anno::usage( "materialx:vdf") ]], + material mxp_bg = material() [[ anno::usage( "materialx:vdf") ]], + float mxp_mix = 0.0 +) [[ + anno::usage( "materialx:vdf") +]] += let { + float mix = math::saturate(mxp_mix); + volume_mix_return v = volume_mix( + mxp_fg.volume.scattering_coefficient, mix, + mxp_bg.volume.scattering_coefficient, (1.0f - mix)); +} in material( + ior: mix * mxp_fg.ior + (1.0f - mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component( v.mix_weight1, mxp_fg.volume.scattering), + df::vdf_component( 1.0 - v.mix_weight1, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: v.scattering_coefficient + ) +); + +// helper to compute ior for generalized_schlick +color mx_f0_to_ior(color F0) +{ + float3 sqrtF0 = math::sqrt(math::clamp(float3(F0), 0.01, 0.99)); + return color((float3(1.0) + sqrtF0) / (float3(1.0) - sqrtF0)); +} + +export material mx_generalized_schlick_bsdf( + float mxp_weight = 1.0, + color mxp_color0 = color(1.0), + color mxp_color82 = color(1.0), // MDL 1.10 + color mxp_color90 = color(1.0), + float mxp_exponent = 5.0, + float2 mxp_roughness = float2(0.05), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + bsdf ggx_model_R = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect); + + bsdf ggx_model_T = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_transmit); + +} in material( + surface: material_surface( + scattering: df::unbounded_mix( + df::bsdf_component[]( + df::bsdf_component( + mxp_weight, + mxp_scatter_mode == mx_scatter_mode_T + ? df::color_custom_curve_layer( + normal_reflectivity: mxp_color0, + grazing_reflectivity: mxp_color82 * mxp_color90, + exponent: mxp_exponent, + layer: bsdf(), + base: ggx_model_T, + normal: mxp_normal) + : df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: df::color_custom_curve_layer( + normal_reflectivity: mxp_color0, + grazing_reflectivity: mxp_color82 * mxp_color90, + exponent: mxp_exponent, + layer: ggx_model_R, + base: mxp_scatter_mode == mx_scatter_mode_R + ? mxp_base.surface.scattering + : ggx_model_T, + normal: mxp_normal)) + ), + df::bsdf_component( + 1.0 - mxp_weight, + mxp_base.surface.scattering) + ) + ) + ), + ior: mx_f0_to_ior(mxp_color0), + // we need to carry volume properties along for SSS + volume: mxp_base.volume +); + + +// TODO MDL 1.8 +// * will add support for thin film above a color_custom_curve_layer node until then, thin_film will have no effect +// * thin_film(thickness: 0.0, ior: < 1.0) will be handled properly +export material mx_dielectric_bsdf( + float mxp_weight = 1.0, + color mxp_tint = color(1.0), + float mxp_ior = 1.5, + float2 mxp_roughness = float2(0.0), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + float grazing_refl = math::max((1.0 - math::average(mxp_roughness)), 0.0); + float root_r = (mxp_ior-1)/(mxp_ior+1); + bsdf bsdf_R = df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + // fresnel layer has issues if base is a diffuse transmission, use custom curve for now + // this will break thin_film but improves standard_surface with diffuse transmission + base: df::custom_curve_layer( + normal_reflectivity: root_r*root_r, + grazing_reflectivity: grazing_refl, + weight: mxp_weight, + layer: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect), + base: mxp_base.surface.scattering, + normal: mxp_normal)); + + bsdf bsdf_T = df::weighted_layer( + weight: mxp_weight, + layer: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_transmit), + normal: mxp_normal); + + bsdf bsdf_RT = df::weighted_layer( + weight: mxp_weight, + layer: df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect_transmit)), + normal: mxp_normal); + + bsdf bsdf_selected = (mxp_scatter_mode == mx_scatter_mode_R) ? bsdf_R : + ((mxp_scatter_mode == mx_scatter_mode_T) ? bsdf_T : bsdf_RT); +} in material( + surface: material_surface( + scattering: bsdf_selected + ), + // we need to carry volume properties along for SSS + ior: color(mxp_ior), + volume: mxp_base.volume +); + +export material mx_conductor_bsdf( + float mxp_weight = 1.0, + color mxp_ior = color(0.18, 0.42, 1.37), + color mxp_extinction = color(3.42, 2.35, 1.77), + float2 mxp_roughness = float2(0.0), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + bsdf ggx_model = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0), + multiscatter_tint: color(1.0), + tangent_u: mxp_tangent); + bsdf conductor = df::fresnel_factor( + ior: mxp_ior, + extinction_coefficient: mxp_extinction, + base: ggx_model); + bsdf thin_film_conductor = df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: conductor); +} in material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mxp_weight, + layer: thin_film_conductor, + normal: mxp_normal + ) + ), + ior: mxp_ior, +); + +// Shader Nodes + +// NOTE: The MDL material with thin_walled == false uses the same material_surface +// properties for the front- and backface, the material will not be black +// from the backside as mandated by the MaterialX spec. +export material mx_surface( + material mxp_bsdf = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_edf = material() [[ anno::usage( "materialx:edf") ]], + float mxp_opacity = 1.0, + uniform bool mxp_thin_walled = false, + float mxp_transmission_ior = 0.0 // extra parameter for setting transmission IOR +) [[ + anno::usage( "materialx:surfaceshader") +]] += let { + bsdf bsdf_node = mxp_bsdf.surface.scattering; + material_emission edf_node = mxp_edf.surface.emission; + // we need to carry volume properties along for SSS + material_volume bsdf_volume = mxp_bsdf.volume; +} in material( + thin_walled: mxp_thin_walled, + surface: material_surface( + scattering: bsdf_node, + emission: edf_node + ), + ior: mxp_transmission_ior > 0.0 ? color(mxp_transmission_ior) : mxp_bsdf.ior, + volume: bsdf_volume, + geometry: material_geometry( + cutout_opacity: mxp_opacity + ) +); diff --git a/source/MaterialXGenMdl/mdl/materialx/sampling.mdl b/source/MaterialXGenMdl/mdl/materialx/sampling.mdl index 1809503653..15228efeca 100644 --- a/source/MaterialXGenMdl/mdl/materialx/sampling.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/sampling.mdl @@ -5,7 +5,9 @@ mdl 1.6; +import ::anno::*; import ::math::*; +import ::state::*; import .::core::*; @@ -15,14 +17,14 @@ export const int MX_MAX_SAMPLE_COUNT = 49; export const int MX_WEIGHT_ARRAY_SIZE = 84; // This is not available in MDL so just use a "small" number -float2 dFdx(float2 uv) +float2 dFdx(float2 uv [[anno::unused()]]) { - return uv+0.0001; + return float2(0.001, 0); } -float2 dFdy(float2 uv) +float2 dFdy(float2 uv [[anno::unused()]]) { - return uv+0.0001; + return float2(0, 0.001); } // @@ -49,11 +51,10 @@ export float2 mx_compute_sample_size_uv(float2 uv, float filterSize, float filte // export float3 mx_normal_from_samples_sobel(float[9] S, float scale) { - float nx = S[0] - S[2] + (2.0*S[3]) - (2.0*S[5]) + S[6] - S[8]; - float ny = S[0] + (2.0*S[1]) + S[2] - S[6] - (2.0*S[7]) - S[8]; - float nz = scale * ::math::sqrt(1.0 - nx*nx - ny*ny); - float3 norm = ::math::normalize(float3(nx, ny, nz)); - return (norm + 1.0) * 0.5; + float nx = S[0] - S[2] + (2.0*S[3]) - (2.0*S[5]) + S[6] - S[8]; + float ny = S[0] + (2.0*S[1]) + S[2] - S[6] - (2.0*S[7]) - S[8]; + float3 norm = math::normalize(float3(nx * scale, ny * scale, 0.125)); + return (norm + 1.0) * 0.5; } // Kernel weights for box filter diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl index 79ed3dff4f..a23c0150ed 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl @@ -4,15 +4,15 @@ // // MDL implementation of all Standard Source Nodes of // MaterialX: An Open Standard for Network-Based CG Object Looks -// Document v1.37 REV2, January 19, 2020 +// Document version 1.39, September 15, 2024 // www.materialx.org // in -// NVIDIA Material Definition Language 1.7 +// NVIDIA Material Definition Language 1.9 // Language Specification -// Document version 1.7.2, January 17, 2022 +// Document version 1.9.2, September 16, 2024 // www.nvidia.com/mdl -mdl 1.8; +mdl 1.9; // forward the latest version -export using .::stdlib_1_8 import *; +export using .::stdlib_1_9 import *; diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl new file mode 100644 index 0000000000..549287c5b7 --- /dev/null +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl @@ -0,0 +1,387 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// +// MDL implementation of all Standard Source Nodes of +// MaterialX: An Open Standard for Network-Based CG Object Looks +// Document version 1.39, September 15, 2024 +// www.materialx.org +// in +// NVIDIA Material Definition Language 1.9 +// Language Specification +// Document version 1.9.2, September 16, 2024 +// www.nvidia.com/mdl + +mdl 1.9; + +import ::anno::*; +import ::df::*; +import ::math::*; +import ::scene::*; +import ::state::*; + +import .::core::*; +import .::noise::*; +import .::hsv::*; + +// Changes since MDL 1.8 +// - lift the restriction of uniform IORs + +// forward unchanged definitions from the previous version +export using .::stdlib_1_7 import mx_surfacematerial; +export using .::stdlib_1_7 import mx_surface_unlit; +export using .::stdlib_1_7 import mx_image_float; +export using .::stdlib_1_7 import mx_image_color3; +export using .::stdlib_1_7 import mx_image_color4; +export using .::stdlib_1_7 import mx_image_vector2; +export using .::stdlib_1_7 import mx_image_vector3; +export using .::stdlib_1_7 import mx_image_vector4; +export using .::stdlib_1_7 import mx_constant_float; +export using .::stdlib_1_7 import mx_constant_color3; +export using .::stdlib_1_7 import mx_constant_color4; +export using .::stdlib_1_7 import mx_constant_vector2; +export using .::stdlib_1_7 import mx_constant_vector3; +export using .::stdlib_1_7 import mx_constant_vector4; +export using .::stdlib_1_7 import mx_constant_boolean; +export using .::stdlib_1_7 import mx_constant_integer; +export using .::stdlib_1_7 import mx_constant_matrix33; +export using .::stdlib_1_7 import mx_constant_matrix44; +export using .::stdlib_1_7 import mx_constant_string; +export using .::stdlib_1_7 import mx_constant_filename; +export using .::stdlib_1_7 import mx_ramplr_float; +export using .::stdlib_1_7 import mx_ramplr_color3; +export using .::stdlib_1_7 import mx_ramplr_color4; +export using .::stdlib_1_7 import mx_ramplr_vector2; +export using .::stdlib_1_7 import mx_ramplr_vector3; +export using .::stdlib_1_7 import mx_ramplr_vector4; +export using .::stdlib_1_7 import mx_ramptb_float; +export using .::stdlib_1_7 import mx_ramptb_color3; +export using .::stdlib_1_7 import mx_ramptb_color4; +export using .::stdlib_1_7 import mx_ramptb_vector2; +export using .::stdlib_1_7 import mx_ramptb_vector3; +export using .::stdlib_1_7 import mx_ramptb_vector4; +export using .::stdlib_1_7 import mx_splitlr_float; +export using .::stdlib_1_7 import mx_splitlr_color3; +export using .::stdlib_1_7 import mx_splitlr_color4; +export using .::stdlib_1_7 import mx_splitlr_vector2; +export using .::stdlib_1_7 import mx_splitlr_vector3; +export using .::stdlib_1_7 import mx_splitlr_vector4; +export using .::stdlib_1_7 import mx_splittb_float; +export using .::stdlib_1_7 import mx_splittb_color3; +export using .::stdlib_1_7 import mx_splittb_color4; +export using .::stdlib_1_7 import mx_splittb_vector2; +export using .::stdlib_1_7 import mx_splittb_vector3; +export using .::stdlib_1_7 import mx_splittb_vector4; +export using .::stdlib_1_7 import mx_position_vector3; +export using .::stdlib_1_7 import mx_normal_vector3; +export using .::stdlib_1_7 import mx_tangent_vector3; +export using .::stdlib_1_7 import mx_bitangent_vector3; +export using .::stdlib_1_7 import mx_texcoord_vector2; +export using .::stdlib_1_7 import mx_texcoord_vector3; +export using .::stdlib_1_7 import mx_geomcolor_float; +export using .::stdlib_1_7 import mx_geomcolor_color3; +export using .::stdlib_1_7 import mx_geomcolor_color4; +export using .::stdlib_1_7 import mx_ambientocclusion_float; +export using .::stdlib_1_7 import mx_frame_float; +export using .::stdlib_1_7 import mx_time_float; +export using .::stdlib_1_7 import mx_modulo_color3; +export using .::stdlib_1_7 import mx_modulo_color4; +export using .::stdlib_1_7 import mx_modulo_color3FA; +export using .::stdlib_1_7 import mx_modulo_color4FA; +export using .::stdlib_1_7 import mx_invert_color4; +export using .::stdlib_1_7 import mx_invert_color4FA; +export using .::stdlib_1_7 import mx_absval_color4; +export using .::stdlib_1_7 import mx_floor_color3; +export using .::stdlib_1_7 import mx_floor_color4; +export using .::stdlib_1_7 import mx_ceil_color3; +export using .::stdlib_1_7 import mx_ceil_color4; +export using .::stdlib_1_7 import mx_round_color3; +export using .::stdlib_1_7 import mx_round_color4; +export using .::stdlib_1_7 import mx_power_color4; +export using .::stdlib_1_7 import mx_power_color4FA; +export using .::stdlib_1_7 import mx_sin_float; +export using .::stdlib_1_7 import mx_cos_float; +export using .::stdlib_1_7 import mx_tan_float; +export using .::stdlib_1_7 import mx_asin_float; +export using .::stdlib_1_7 import mx_acos_float; +export using .::stdlib_1_7 import mx_atan2_float; +export using .::stdlib_1_7 import mx_sin_vector2; +export using .::stdlib_1_7 import mx_cos_vector2; +export using .::stdlib_1_7 import mx_tan_vector2; +export using .::stdlib_1_7 import mx_asin_vector2; +export using .::stdlib_1_7 import mx_acos_vector2; +export using .::stdlib_1_7 import mx_atan2_vector2; +export using .::stdlib_1_7 import mx_sin_vector3; +export using .::stdlib_1_7 import mx_cos_vector3; +export using .::stdlib_1_7 import mx_tan_vector3; +export using .::stdlib_1_7 import mx_asin_vector3; +export using .::stdlib_1_7 import mx_acos_vector3; +export using .::stdlib_1_7 import mx_atan2_vector3; +export using .::stdlib_1_7 import mx_sin_vector4; +export using .::stdlib_1_7 import mx_cos_vector4; +export using .::stdlib_1_7 import mx_tan_vector4; +export using .::stdlib_1_7 import mx_asin_vector4; +export using .::stdlib_1_7 import mx_acos_vector4; +export using .::stdlib_1_7 import mx_atan2_vector4; +export using .::stdlib_1_7 import mx_sqrt_float; +export using .::stdlib_1_7 import mx_ln_float; +export using .::stdlib_1_7 import mx_exp_float; +export using .::stdlib_1_7 import mx_sqrt_vector2; +export using .::stdlib_1_7 import mx_ln_vector2; +export using .::stdlib_1_7 import mx_exp_vector2; +export using .::stdlib_1_7 import mx_sqrt_vector3; +export using .::stdlib_1_7 import mx_ln_vector3; +export using .::stdlib_1_7 import mx_exp_vector3; +export using .::stdlib_1_7 import mx_sqrt_vector4; +export using .::stdlib_1_7 import mx_ln_vector4; +export using .::stdlib_1_7 import mx_exp_vector4; +export using .::stdlib_1_7 import mx_sign_color3; +export using .::stdlib_1_7 import mx_sign_color4; +export using .::stdlib_1_7 import mx_clamp_color4; +export using .::stdlib_1_7 import mx_clamp_color4FA; +export using .::stdlib_1_7 import mx_min_color4; +export using .::stdlib_1_7 import mx_min_color4; +export using .::stdlib_1_7 import mx_max_color4; +export using .::stdlib_1_7 import mx_max_color4; +export using .::stdlib_1_7 import mx_transformpoint_vector3; +export using .::stdlib_1_7 import mx_transformvector_vector3; +export using .::stdlib_1_7 import mx_transformnormal_vector3; +export using .::stdlib_1_7 import mx_transformmatrix_vector2M3; +export using .::stdlib_1_7 import mx_transformmatrix_vector3; +export using .::stdlib_1_7 import mx_transformmatrix_vector3M4; +export using .::stdlib_1_7 import mx_transformmatrix_vector4; +export using .::stdlib_1_7 import mx_normalmap_float; +export using .::stdlib_1_7 import mx_normalmap_vector2; +export using .::stdlib_1_7 import mx_transpose_matrix33; +export using .::stdlib_1_7 import mx_transpose_matrix44; +export using .::stdlib_1_7 import mx_determinant_matrix33; +export using .::stdlib_1_7 import mx_determinant_matrix44; +export using .::stdlib_1_7 import mx_invertmatrix_matrix33; +export using .::stdlib_1_7 import mx_invertmatrix_matrix44; +export using .::stdlib_1_7 import mx_rotate2d_vector2; +export using .::stdlib_1_7 import mx_rotate3d_vector3; +export using .::stdlib_1_7 import mx_remap_float; +export using .::stdlib_1_7 import mx_remap_color3; +export using .::stdlib_1_7 import mx_remap_color4; +export using .::stdlib_1_7 import mx_remap_vector2; +export using .::stdlib_1_7 import mx_remap_vector3; +export using .::stdlib_1_7 import mx_remap_vector4; +export using .::stdlib_1_7 import mx_remap_color3FA; +export using .::stdlib_1_7 import mx_remap_color4FA; +export using .::stdlib_1_7 import mx_remap_vector2FA; +export using .::stdlib_1_7 import mx_remap_vector3FA; +export using .::stdlib_1_7 import mx_remap_vector4FA; +export using .::stdlib_1_7 import mx_smoothstep_float; +export using .::stdlib_1_7 import mx_smoothstep_color3; +export using .::stdlib_1_7 import mx_smoothstep_color4; +export using .::stdlib_1_7 import mx_smoothstep_vector2; +export using .::stdlib_1_7 import mx_smoothstep_vector3; +export using .::stdlib_1_7 import mx_smoothstep_vector4; +export using .::stdlib_1_7 import mx_smoothstep_color3FA; +export using .::stdlib_1_7 import mx_smoothstep_color4FA; +export using .::stdlib_1_7 import mx_smoothstep_vector2FA; +export using .::stdlib_1_7 import mx_smoothstep_vector3FA; +export using .::stdlib_1_7 import mx_smoothstep_vector4FA; +export using .::stdlib_1_7 import mx_curveadjust_float; +export using .::stdlib_1_7 import mx_curveadjust_color3; +export using .::stdlib_1_7 import mx_curveadjust_color4; +export using .::stdlib_1_7 import mx_curveadjust_vector2; +export using .::stdlib_1_7 import mx_curveadjust_vector3; +export using .::stdlib_1_7 import mx_curveadjust_vector4; +export using .::stdlib_1_7 import mx_luminance_color3; +export using .::stdlib_1_7 import mx_luminance_color4; +export using .::stdlib_1_7 import mx_rgbtohsv_color3; +export using .::stdlib_1_7 import mx_rgbtohsv_color4; +export using .::stdlib_1_7 import mx_hsvtorgb_color3; +export using .::stdlib_1_7 import mx_hsvtorgb_color4; +export using .::stdlib_1_7 import mx_premult_color4; +export using .::stdlib_1_7 import mx_unpremult_color4; +export using .::stdlib_1_7 import mx_plus_color4; +export using .::stdlib_1_7 import mx_minus_color4; +export using .::stdlib_1_7 import mx_difference_color4; +export using .::stdlib_1_7 import mx_burn_float; +export using .::stdlib_1_7 import mx_burn_color3; +export using .::stdlib_1_7 import mx_burn_color4; +export using .::stdlib_1_7 import mx_dodge_float; +export using .::stdlib_1_7 import mx_dodge_color3; +export using .::stdlib_1_7 import mx_dodge_color4; +export using .::stdlib_1_7 import mx_screen_color4; +export using .::stdlib_1_7 import mx_disjointover_color4; +export using .::stdlib_1_7 import mx_in_color4; +export using .::stdlib_1_7 import mx_mask_color4; +export using .::stdlib_1_7 import mx_matte_color4; +export using .::stdlib_1_7 import mx_out_color4; +export using .::stdlib_1_7 import mx_over_color4; +export using .::stdlib_1_7 import mx_mix_color4; +export using .::stdlib_1_7 import mx_mix_color4_color4; +export using .::stdlib_1_7 import mx_mix_volumeshader; +export using .::stdlib_1_7 import mx_mix_displacementshader; +export using .::stdlib_1_7 import mx_ifgreater_float; +export using .::stdlib_1_7 import mx_ifgreater_integer; +export using .::stdlib_1_7 import mx_ifgreater_color3; +export using .::stdlib_1_7 import mx_ifgreater_color4; +export using .::stdlib_1_7 import mx_ifgreater_vector2; +export using .::stdlib_1_7 import mx_ifgreater_vector3; +export using .::stdlib_1_7 import mx_ifgreater_vector4; +export using .::stdlib_1_7 import mx_ifgreater_matrix33; +export using .::stdlib_1_7 import mx_ifgreater_matrix44; +export using .::stdlib_1_7 import mx_ifgreater_boolean; +export using .::stdlib_1_7 import mx_ifgreater_floatI; +export using .::stdlib_1_7 import mx_ifgreater_integerI; +export using .::stdlib_1_7 import mx_ifgreater_color3I; +export using .::stdlib_1_7 import mx_ifgreater_color4I; +export using .::stdlib_1_7 import mx_ifgreater_vector2I; +export using .::stdlib_1_7 import mx_ifgreater_vector3I; +export using .::stdlib_1_7 import mx_ifgreater_vector4I; +export using .::stdlib_1_7 import mx_ifgreater_matrix33I; +export using .::stdlib_1_7 import mx_ifgreater_matrix44I; +export using .::stdlib_1_7 import mx_ifgreater_booleanI; +export using .::stdlib_1_7 import mx_ifgreatereq_float; +export using .::stdlib_1_7 import mx_ifgreatereq_integer; +export using .::stdlib_1_7 import mx_ifgreatereq_color3; +export using .::stdlib_1_7 import mx_ifgreatereq_color4; +export using .::stdlib_1_7 import mx_ifgreatereq_vector2; +export using .::stdlib_1_7 import mx_ifgreatereq_vector3; +export using .::stdlib_1_7 import mx_ifgreatereq_vector4; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix33; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix44; +export using .::stdlib_1_7 import mx_ifgreatereq_boolean; +export using .::stdlib_1_7 import mx_ifgreatereq_floatI; +export using .::stdlib_1_7 import mx_ifgreatereq_integerI; +export using .::stdlib_1_7 import mx_ifgreatereq_color3I; +export using .::stdlib_1_7 import mx_ifgreatereq_color4I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector2I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector3I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector4I; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix33I; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix44I; +export using .::stdlib_1_7 import mx_ifgreatereq_booleanI; +export using .::stdlib_1_7 import mx_ifequal_float; +export using .::stdlib_1_7 import mx_ifequal_integer; +export using .::stdlib_1_7 import mx_ifequal_color3; +export using .::stdlib_1_7 import mx_ifequal_color4; +export using .::stdlib_1_7 import mx_ifequal_vector2; +export using .::stdlib_1_7 import mx_ifequal_vector3; +export using .::stdlib_1_7 import mx_ifequal_vector4; +export using .::stdlib_1_7 import mx_ifequal_matrix33; +export using .::stdlib_1_7 import mx_ifequal_matrix44; +export using .::stdlib_1_7 import mx_ifequal_boolean; +export using .::stdlib_1_7 import mx_ifequal_floatI; +export using .::stdlib_1_7 import mx_ifequal_integerI; +export using .::stdlib_1_7 import mx_ifequal_color3I; +export using .::stdlib_1_7 import mx_ifequal_color4I; +export using .::stdlib_1_7 import mx_ifequal_vector2I; +export using .::stdlib_1_7 import mx_ifequal_vector3I; +export using .::stdlib_1_7 import mx_ifequal_vector4I; +export using .::stdlib_1_7 import mx_ifequal_matrix33I; +export using .::stdlib_1_7 import mx_ifequal_matrix44I; +export using .::stdlib_1_7 import mx_ifequal_booleanI; +export using .::stdlib_1_7 import mx_ifequal_floatB; +export using .::stdlib_1_7 import mx_ifequal_integerB; +export using .::stdlib_1_7 import mx_ifequal_color3B; +export using .::stdlib_1_7 import mx_ifequal_color4B; +export using .::stdlib_1_7 import mx_ifequal_vector2B; +export using .::stdlib_1_7 import mx_ifequal_vector3B; +export using .::stdlib_1_7 import mx_ifequal_vector4B; +export using .::stdlib_1_7 import mx_ifequal_matrix33B; +export using .::stdlib_1_7 import mx_ifequal_matrix44B; +export using .::stdlib_1_7 import mx_ifequal_booleanB; +export using .::stdlib_1_7 import mx_creatematrix_vector3_matrix33; +export using .::stdlib_1_7 import mx_creatematrix_vector3_matrix44; +export using .::stdlib_1_7 import mx_creatematrix_vector4_matrix44; +export using .::stdlib_1_7 import mx_extract_color3; +export using .::stdlib_1_7 import mx_extract_color4; +export using .::stdlib_1_7 import mx_extract_vector2; +export using .::stdlib_1_7 import mx_extract_vector3; +export using .::stdlib_1_7 import mx_extract_vector4; +export using .::stdlib_1_7 import mx_blur_float; +export using .::stdlib_1_7 import mx_blur_color3; +export using .::stdlib_1_7 import mx_blur_color4; +export using .::stdlib_1_7 import mx_blur_vector2; +export using .::stdlib_1_7 import mx_blur_vector3; +export using .::stdlib_1_7 import mx_blur_vector4; +export using .::stdlib_1_7 import mx_heighttonormal_vector3; +export using .::stdlib_1_7 import mx_noise2d_float; +export using .::stdlib_1_7 import mx_noise2d_float2; +export using .::stdlib_1_7 import mx_noise2d_float3; +export using .::stdlib_1_7 import mx_noise2d_float4; +export using .::stdlib_1_7 import mx_noise3d_float; +export using .::stdlib_1_7 import mx_noise3d_float2; +export using .::stdlib_1_7 import mx_noise3d_float3; +export using .::stdlib_1_7 import mx_noise3d_float4; +export using .::stdlib_1_7 import mx_fractal3d_float; +export using .::stdlib_1_7 import mx_fractal3d_float2; +export using .::stdlib_1_7 import mx_fractal3d_float3; +export using .::stdlib_1_7 import mx_fractal3d_float4; +export using .::stdlib_1_7 import mx_cellnoise2d_float; +export using .::stdlib_1_7 import mx_cellnoise3d_float; +export using .::stdlib_1_7 import mx_worleynoise2d_float; +export using .::stdlib_1_7 import mx_worleynoise2d_float2; +export using .::stdlib_1_7 import mx_worleynoise2d_float3; +export using .::stdlib_1_7 import mx_worleynoise3d_float; +export using .::stdlib_1_7 import mx_worleynoise3d_float2; +export using .::stdlib_1_7 import mx_worleynoise3d_float3; +export using .::stdlib_1_7 import mx_combine2_color4CF; + +export using .::stdlib_1_7 import mx_geompropvalue_string; +export using .::stdlib_1_8 import mx_geompropvalue_boolean; +export using .::stdlib_1_8 import mx_geompropvalue_integer; +export using .::stdlib_1_8 import mx_geompropvalue_float; +export using .::stdlib_1_8 import mx_geompropvalue_color3; +export using .::stdlib_1_8 import mx_geompropvalue_color4; +export using .::stdlib_1_8 import mx_geompropvalue_vector2; +export using .::stdlib_1_8 import mx_geompropvalue_vector3; +export using .::stdlib_1_8 import mx_geompropvalue_vector4; +export using .::stdlib_1_8 import mx_viewdirection_vector3; + + + +// mix all parts of the material, bsdf, edf, and vdf, geometry +export material mx_mix_surfaceshader( + material mxp_fg = material() [[ anno::usage( "materialx:surfaceshader") ]], + material mxp_bg = material() [[ anno::usage( "materialx:surfaceshader") ]], + float mxp_mix = 0.0 +) [[ + anno::description("Node Group: compositing"), + anno::usage( "materialx:surfaceshader") +]] += material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mxp_mix, + layer: mxp_fg.surface.scattering, + base: mxp_bg.surface.scattering + ), + emission: material_emission( + emission: df::clamped_mix( + df::edf_component[]( + df::edf_component( mxp_mix, mxp_fg.surface.emission.emission), + df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission)) + ), + intensity: mxp_mix * mxp_fg.surface.emission.intensity + + (1.0 - mxp_mix) * mxp_bg.surface.emission.intensity + ) + ), + + // we need to carry volume properties along for SSS + ior: mxp_mix * mxp_fg.ior + (1.0 - mxp_mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component( mxp_mix, mxp_fg.volume.scattering), + df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mxp_mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mxp_mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: mxp_mix * mxp_fg.volume.scattering_coefficient + + (1.0 - mxp_mix) * mxp_bg.volume.scattering_coefficient + ), + geometry: material_geometry( + displacement: mxp_mix * mxp_fg.geometry.displacement + + (1.0 - mxp_mix) * mxp_bg.geometry.displacement, + cutout_opacity: mxp_mix * mxp_fg.geometry.cutout_opacity + + (1.0 - mxp_mix) * mxp_bg.geometry.cutout_opacity, + normal: mxp_mix * mxp_fg.geometry.normal + + (1.0 - mxp_mix) * mxp_bg.geometry.normal + ) +); diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index e1a23cf7d4..638a4fd10c 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -225,15 +225,9 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so moduleToTest = moduleToTest.substr(0, moduleToTest.size() - sourceCodePaths[0].getExtension().length() - 1); std::string renderExec(MATERIALX_MDL_RENDER_EXECUTABLE); - bool testMDLC = renderExec.empty(); - if (testMDLC) + std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); + if (!mdlcExec.empty()) // always run compiler { - std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); - if (mdlcExec.empty()) - { - return; - } - std::string mdlcCommand = mdlcExec; // use the same paths as the resolver @@ -264,12 +258,19 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so _logFile << "\tReturn code: " << std::to_string(returnValue) << std::endl; writeErrorCode = true; } - _logFile << "\tError: " << line << std::endl; + if (line.find(": Warning ") != std::string::npos) + { + _logFile << "\tWarning: " << line << std::endl; + } + else + { + _logFile << "\tError: " << line << std::endl; + } } CHECK(returnValue == 0); } - else + if (!renderExec.empty()) // render if renderer is availabe { std::string renderCommand = renderExec; @@ -358,6 +359,7 @@ TEST_CASE("GenShader: MDL Shader Generation", "[genmdl]") mx::FilePathVec testRootPaths; testRootPaths.push_back(searchPath.find("resources/Materials/TestSuite")); testRootPaths.push_back(searchPath.find("resources/Materials/Examples/StandardSurface")); + testRootPaths.push_back(searchPath.find("resources/Materials/Examples/UsdPreviewSurface")); const mx::FilePath logPath("genmdl_mdl_generate_test.txt"); From 6fd2dc2f3ebea66afa705c24cc795aa9e8f64420 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 25 Nov 2024 14:03:35 -0800 Subject: [PATCH 23/76] Remove unimplemented nodes from libraries (#2120) This changelist removes the unimplemented 'ambientocclusion', 'arrayappend', and 'curveadjust' nodes from the MaterialX data libraries, aligning the data libraries with the current 1.39 specification. Additionally, this change removes hardcoded skip count checks from MaterialXTest, as these tests have not proven themselves to be a beneficial safeguard against regressions, and frequently trip up contributors to the MaterialX project. --- libraries/README.md | 3 -- .../stdlib/genglsl/stdlib_genglsl_impl.mtlx | 6 --- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 7 --- .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 4 -- .../genosl/mx_ambientocclusion_float.osl | 5 -- .../stdlib/genosl/stdlib_genosl_impl.mtlx | 7 --- libraries/stdlib/stdlib_defs.mtlx | 53 ------------------- python/Scripts/genmdl.py | 8 +-- .../mdl/materialx/stdlib_1_6.mdl | 17 ------ .../mdl/materialx/stdlib_1_8.mdl | 1 - .../mdl/materialx/stdlib_1_9.mdl | 1 - .../MaterialXGenGlsl/GenGlsl.cpp | 2 +- .../MaterialXTest/MaterialXGenGlsl/GenGlsl.h | 2 +- .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 2 +- source/MaterialXTest/MaterialXGenMdl/GenMdl.h | 2 +- .../MaterialXTest/MaterialXGenMsl/GenMsl.cpp | 2 +- source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 2 +- .../MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 2 +- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 2 +- .../MaterialXGenShader/GenShaderUtil.cpp | 6 +-- .../MaterialXGenShader/GenShaderUtil.h | 3 +- .../MaterialXRenderOsl/GenReference.cpp | 3 +- 22 files changed, 12 insertions(+), 128 deletions(-) delete mode 100644 libraries/stdlib/genosl/mx_ambientocclusion_float.osl diff --git a/libraries/README.md b/libraries/README.md index 15916f76e2..0ace221bcc 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -74,7 +74,4 @@ This folder contains the standard data libraries for MaterialX, providing declar - Basic GLSL and MSL `lightshader` node definitions and implementations are provided for the following light types: - point, directional, spot - Shader generation does not currently support: - - `ambientocclusion` node. - - `arrayappend` node. - - `curveadjust` node. - `displacementshader` and `volumeshader` nodes for hardware shading targets (GLSL, MSL). diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index 69f8f9a7f8..ad3a21e9cf 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -129,12 +129,6 @@ - - - - - - diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index b190937c41..6ac2b862dd 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -131,13 +131,6 @@ - - - - - - - diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index afdfb2cfbb..3cb99052cf 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -45,10 +45,6 @@ - - - - diff --git a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl b/libraries/stdlib/genosl/mx_ambientocclusion_float.osl deleted file mode 100644 index 10baf0b736..0000000000 --- a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_ambientocclusion_float(float coneangle, float maxdistance, output float result) -{ - // This node is a stub and does not currently operate to specification - result = 0; -} diff --git a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx index 716e1072d7..db318976c5 100644 --- a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -131,13 +131,6 @@ - - - - - - - diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 943e36ec88..e6f8d431e7 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -1354,21 +1354,6 @@ - - - - - - - - - - - @@ -2899,44 +2884,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp index b77eebbd86..a72207c581 100644 --- a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp +++ b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp @@ -37,51 +37,6 @@ void ClosureLayerNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& ShaderNode* top = topInput->getConnection()->getNode(); ShaderNode* base = baseInput->getConnection()->getNode(); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - ClosureContext* cct = context.getClosureContext(); - - // Evaluate top and base nodes and combine their result - // according to throughput. - // - // TODO: In the BSDF over BSDF case should we emit code - // to check the top throughput amount before calling - // the base BSDF? - - // Make sure the connections are sibling nodes and not the graph interface. - if (top->getParent() == node.getParent()) - { - // If this layer node has closure parameters set, - // we pass this on to the top component only. - ScopedSetClosureParams setParams(&node, top, cct); - shadergen.emitFunctionCall(*top, context, stage); - } - if (base->getParent() == node.getParent()) - { - shadergen.emitFunctionCall(*base, context, stage); - } - - // Get the result variables. - const string& topResult = topInput->getConnection()->getVariable(); - const string& baseResult = baseInput->getConnection()->getVariable(); - - // Calculate the layering result. - emitOutputVariables(node, context, stage); - if (base->getOutput()->getType() == Type::VDF) - { - // Combining a surface closure with a volumetric closure is simply done with the add operator in OSL. - shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult, stage); - // Just pass the throughput along. - shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput", stage); - } - else - { - shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult + ".response * " + topResult + ".throughput", stage); - shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput * " + baseResult + ".throughput", stage); - } - -#else - // Emit the function call for top and base layer. // Make sure the connections are sibling nodes and not the graph interface. if (top->getParent() == node.getParent()) @@ -102,8 +57,6 @@ void ClosureLayerNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& shadergen.emitOutput(output, true, false, context, stage); shadergen.emitString(" = layer(" + topResult + ", " + baseResult + ")", stage); shadergen.emitLineEnd(stage); - -#endif // MATERIALX_OSL_LEGACY_CLOSURES } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index d0d9d96cba..ff8cad36f5 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -45,22 +45,6 @@ OslShaderGenerator::OslShaderGenerator() : registerImplementation("IM_layer_bsdf_" + OslShaderGenerator::TARGET, ClosureLayerNodeOsl::create); registerImplementation("IM_layer_vdf_" + OslShaderGenerator::TARGET, ClosureLayerNodeOsl::create); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - // - registerImplementation("IM_mix_bsdf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - registerImplementation("IM_mix_edf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - // - registerImplementation("IM_add_bsdf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - registerImplementation("IM_add_edf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - // - registerImplementation("IM_multiply_bsdfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_bsdfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - -#endif // MATERIALX_OSL_LEGACY_CLOSURES - // registerImplementation("IM_surface_" + OslShaderGenerator::TARGET, SurfaceNodeOsl::create); @@ -158,10 +142,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G const bool isSurfaceShaderOutput = singleOutput && singleOutput->getType() == Type::SURFACESHADER; -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - const bool isBsdfOutput = singleOutput && singleOutput->getType() == Type::BSDF; -#endif - if (isSurfaceShaderOutput) { // Special case for having 'surfaceshader' as final output type. @@ -170,16 +150,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G // to understand this output. emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); - } -#endif else { // Just emit all outputs the way they are declared. @@ -253,18 +223,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G emitLine(singleOutput->getVariable() + " = (" + result + ".bsdf + " + result + ".edf) * opacity_weight + transparent() * (1.0 - opacity_weight)", stage); emitScopeEnd(stage); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - const ShaderGraphOutputSocket* socket = graph.getOutputSocket(0); - const string result = getUpstreamResult(socket, context); - emitLine(singleOutput->getVariable() + " = " + result + ".response", stage); - } -#endif else { // Assign results to final outputs. diff --git a/source/MaterialXGenOsl/OslSyntax.cpp b/source/MaterialXGenOsl/OslSyntax.cpp index 797a891ce6..a85821c4fd 100644 --- a/source/MaterialXGenOsl/OslSyntax.cpp +++ b/source/MaterialXGenOsl/OslSyntax.cpp @@ -371,19 +371,6 @@ OslSyntax::OslSyntax() EMPTY_STRING, "struct textureresource { string filename; string colorspace; };")); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - registerTypeSyntax( - Type::BSDF, - std::make_shared( - "BSDF", - "BSDF(null_closure, color(1.0))", - "{ 0, color(1.0) }", - "closure color", - "struct BSDF { closure color response; color throughput; };")); - -#else - registerTypeSyntax( Type::BSDF, std::make_shared( @@ -393,8 +380,6 @@ OslSyntax::OslSyntax() "closure color", "#define BSDF closure color")); -#endif // MATERIALX_OSL_LEGACY_CLOSURES - registerTypeSyntax( Type::EDF, std::make_shared( diff --git a/source/MaterialXTest/CMakeLists.txt b/source/MaterialXTest/CMakeLists.txt index 4835787ed8..c3fae603dc 100644 --- a/source/MaterialXTest/CMakeLists.txt +++ b/source/MaterialXTest/CMakeLists.txt @@ -96,11 +96,6 @@ endif() add_custom_command(TARGET MaterialXTest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/../../libraries ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries) -if(MATERIALX_OSL_LEGACY_CLOSURES) - add_custom_command(TARGET MaterialXTest POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx) -endif() if(MATERIALX_BUILD_GEN_MDL) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../source/MaterialXGenMdl/mdl/" From 344705f0214332a8b7199832ff90aefb9b054200 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Tue, 26 Nov 2024 12:49:28 -0500 Subject: [PATCH 25/76] Fix mxvalidate to check for stdlib usage (#2122) Patch `mxvalidate.py` script to avoid trying to access an undefined object `stdlib` if not specified from the command line (default). --- python/Scripts/mxvalidate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/Scripts/mxvalidate.py b/python/Scripts/mxvalidate.py index 8cc1ee78fd..e0ccf34a4e 100755 --- a/python/Scripts/mxvalidate.py +++ b/python/Scripts/mxvalidate.py @@ -17,6 +17,7 @@ def main(): opts = parser.parse_args() # Load standard libraries if requested. + stdlib = None if opts.stdlib: stdlib = mx.createDocument() try: @@ -29,7 +30,8 @@ def main(): doc = mx.createDocument() try: mx.readFromXmlFile(doc, opts.inputFilename) - doc.setDataLibrary(stdlib) + if stdlib: + doc.setDataLibrary(stdlib) except mx.ExceptionFileMissing as err: print(err) sys.exit(0) From cbb63ec82de7be3cea6bc0c85f12223be1e87d5e Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 26 Nov 2024 16:26:27 -0800 Subject: [PATCH 26/76] Update MacOS version in GitHub CI (#2123) This changelist updates Python wheel generation to the `macos-14-large` environment in GitHub CI, as Python versions before 3.11 have been removed from the `macos-13` environment. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b2d5f182bf..3f67667550 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -389,7 +389,7 @@ jobs: fail-fast: false matrix: python-minor: ['7', '8', '9', '10', '11', '12'] - os: ['ubuntu-22.04', 'windows-2022', 'macos-13'] + os: ['ubuntu-22.04', 'windows-2022', 'macos-14-large'] steps: - name: Sync Repository From b6d473d01edcf2b61291e22f09ac182c32555a68 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 3 Dec 2024 17:28:54 -0800 Subject: [PATCH 27/76] Update changelog for recent work (#2129) --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fedc1ceaa..6fb0c98143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ ## [1.39.2] - Development +### Added +- Added support for the [Chiang Hair BSDF](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1968), with initial implementations in hardware shading languages and MDL. +- Added support for the [Disney Principled](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2004) shading model, implemented as a language-independent graph. +- Added support for [data library referencing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2054), enabling improved performance in shader generation. +- Added support for [custom structure types](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1831) in MaterialX. +- Added support for [functional equivalence](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2003) tests between MaterialX elements. +- Added support for [transmission effects](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2027) in the translation graph from Standard Surface to glTF PBR. +- Added support for [coated emission](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2087) in the translation graph from Standard Surface to UsdPreviewSurface. +- Added support for [Apple framework builds](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2020). +- Added support for [MDL 1.9](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2102) in shader generation. +- Added support for [viewdirection space](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2036) in hardware shading languages. +- Added a [combined version define](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2031) to MaterialX C++. +- Added a [release signing workflow](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2009) to GitHub Actions. +- Added documentation for [keyboard shortcuts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2026) in the MaterialX Viewer. + +### Changed +- Reduced duplication between the [MSL and GLSL implementations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2068) of nodes. + +### Fixed +- Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. +- Fixed [banding artifacts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1977) in the MaterialX Viewer on MacOS. +- Fixed a call to the [anisotropic_vdf closure](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2016) in OSL shader generation. + +### Removed +- Removed support for the [legacy OSL closures](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2121), focusing exclusively on the MaterialX-synchronized closures in OSL 1.12 and beyond. + ## [1.39.1] - 2024-09-03 ### Added From bfbf6729385a7820dc2ab00332b30b93eff6a3e8 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 4 Dec 2024 10:36:45 -0800 Subject: [PATCH 28/76] Static analysis fixes (#2130) This changelist addresses a handful of static analysis warnings flagged by PVS-Studio: - Add a missing reference to `rhs` in `ValueElement::isAttributeEquivalent`. - Remove unused variables and unneeded string copies in `StructTypeSyntax::getValue` and `GlslStructTypeSyntax::getValue`. - Simplify boolean logic in `ClosureLayerNodeMdl::emitFunctionCall`. - Declare an immutable array as a `std::array` in `Viewer::createDocumentationInterface`. --- source/MaterialXCore/Element.cpp | 2 +- source/MaterialXGenGlsl/GlslSyntax.cpp | 4 ++-- source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp | 2 +- source/MaterialXGenShader/Syntax.cpp | 7 ++----- source/MaterialXView/Viewer.cpp | 2 +- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 3bede2fe74..78c59e9efc 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -749,7 +749,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr else if (uiAttributes.find(attributeName) != uiAttributes.end()) { const string& uiAttribute = getAttribute(attributeName); - const string& rhsUiAttribute = getAttribute(attributeName); + const string& rhsUiAttribute = rhs->getAttribute(attributeName); ValuePtr uiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(uiAttribute, getType()) : nullptr; ValuePtr rhsUiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(rhsUiAttribute, getType()) : nullptr; if (uiValue && rhsUiValue) diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp index 651a4ab5ff..7054725b76 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.cpp +++ b/source/MaterialXGenGlsl/GlslSyntax.cpp @@ -400,8 +400,8 @@ string GlslStructTypeSyntax::getValue(const Value& value, bool /* uniform */) co result += separator; separator = ","; - auto memberTypeName = memberValue->getTypeString(); - auto memberTypeDesc = TypeDesc::get(memberTypeName); + const string& memberTypeName = memberValue->getTypeString(); + TypeDesc memberTypeDesc = TypeDesc::get(memberTypeName); // Recursively use the syntax to generate the output, so we can supported nested structs. result += _parentSyntax->getValue(memberTypeDesc, *memberValue, true); diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index 8949ae6cc0..5b187f80aa 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -128,7 +128,7 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& ShaderNode* fg = fgOutput ? fgOutput->getNode() : nullptr; ShaderNode* bg = bgOutput ? bgOutput->getNode() : nullptr; ShaderNode* mix = mixOutput ? mixOutput->getNode() : nullptr; - if ((fg && !bg) || (!fg && bg)) + if ((bool) fg != (bool) bg) { baseReceiverNode = fg ? fg : bg; // take the node that is valid top = baseReceiverNode; diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index b8eed3e9b8..81daa9e0a7 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -286,9 +286,6 @@ string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const { const AggregateValue& aggValue = static_cast(value); - auto typeDesc = TypeDesc::get(aggValue.getTypeString()); - auto structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); - string result = "{"; string separator = ""; @@ -297,8 +294,8 @@ string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const result += separator; separator = ";"; - auto memberTypeName = memberValue->getTypeString(); - auto memberTypeDesc = TypeDesc::get(memberTypeName); + const string& memberTypeName = memberValue->getTypeString(); + TypeDesc memberTypeDesc = TypeDesc::get(memberTypeName); // Recursively use the syntax to generate the output, so we can support nested structs. const string valueStr = _parentSyntax->getValue(memberTypeDesc, *memberValue, true); diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 46d03a1665..aefdf2d401 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -702,7 +702,7 @@ void Viewer::createDocumentationInterface(ng::ref parent) ng::Alignment::Minimum, 2, 2); gridLayout2->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); - const std::vector> KEYBOARD_SHORTCUTS = + const std::array, 16> KEYBOARD_SHORTCUTS = { std::make_pair("R", "Reload the current material from file. " "Hold SHIFT to reload all standard libraries as well."), From f9a4222c8251c1d8bf808e5a705f74b72531bb88 Mon Sep 17 00:00:00 2001 From: JGamache-autodesk <56274617+JGamache-autodesk@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:28:45 -0500 Subject: [PATCH 29/76] Consider subsurface color in dielectric albedo (#2105) I am experimenting with OpenPBR to UsdPreviewSurface export code in Maya and tried chaining the two translator graphs already provided in MaterialX. Results are quite good, except when the subsurface color is extremely different from the base color. This can be fixed by computing a dielectric base albedo that mixes the scaled base color and the subsurface color. --- libraries/bxdf/translation/standard_surface_to_usd.mtlx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/bxdf/translation/standard_surface_to_usd.mtlx b/libraries/bxdf/translation/standard_surface_to_usd.mtlx index 51c7d5fc6e..f1009e3a4c 100644 --- a/libraries/bxdf/translation/standard_surface_to_usd.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_usd.mtlx @@ -12,6 +12,8 @@ + + @@ -47,13 +49,18 @@ + + + + + - + From bf2804d21aae379937ebbefcef62f62c9604dc0b Mon Sep 17 00:00:00 2001 From: samip Date: Wed, 4 Dec 2024 17:13:56 -0800 Subject: [PATCH 30/76] Fix handling of missing scenes in the Web Viewer (#2124) JsViewerX attempted to use a cube when the selected GLTF file contained no model, but the code never added it to the scene. --- javascript/MaterialXView/source/viewer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index febe34c809..e558ad0bc9 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -90,14 +90,14 @@ export class Scene } this.#_rootNode = null; - const model = gltfData.scene; + let model = gltfData.scene; if (!model) { const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0xdddddd }); const cube = new THREE.Mesh(geometry, material); - obj = new Group(); - obj.add(geometry); + model = new Group(); + model.add(cube); } else { From f0f9eacd83cf60851882293a413b3077941f277a Mon Sep 17 00:00:00 2001 From: Krzysztof Jakubowski Date: Fri, 6 Dec 2024 00:33:20 +0100 Subject: [PATCH 31/76] Improve performance of graph traversal (#2023) In complex materials graph and shader graph edge iteration can be extremely slow, because some edges may be visited unnecessarily multiple times. This is especially noticeable in two functions: ShaderGraph::addUpstreamDependencies and ShaderGraph::optimize. This changelist optimizes graph edge iteration by marking and skipping edges that have previously been visited. --- source/MaterialXCore/Traversal.cpp | 10 ++++++++-- source/MaterialXCore/Traversal.h | 2 ++ source/MaterialXGenShader/ShaderGraph.cpp | 12 +++++++++--- source/MaterialXGenShader/ShaderGraph.h | 18 ++++++++++++++++++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/source/MaterialXCore/Traversal.cpp b/source/MaterialXCore/Traversal.cpp index c78b5825d4..285083da2e 100644 --- a/source/MaterialXCore/Traversal.cpp +++ b/source/MaterialXCore/Traversal.cpp @@ -113,7 +113,7 @@ GraphIterator& GraphIterator::operator++() // Traverse to the first upstream edge of this element. _stack.emplace_back(_upstreamElem, 0); Edge nextEdge = _upstreamElem->getUpstreamEdge(0); - if (nextEdge && nextEdge.getUpstreamElement()) + if (nextEdge && nextEdge.getUpstreamElement() && !skipOrMarkAsVisited(nextEdge)) { extendPathUpstream(nextEdge.getUpstreamElement(), nextEdge.getConnectingElement()); return *this; @@ -140,7 +140,7 @@ GraphIterator& GraphIterator::operator++() if (parentFrame.second + 1 < parentFrame.first->getUpstreamEdgeCount()) { Edge nextEdge = parentFrame.first->getUpstreamEdge(++parentFrame.second); - if (nextEdge && nextEdge.getUpstreamElement()) + if (nextEdge && nextEdge.getUpstreamElement() && !skipOrMarkAsVisited(nextEdge)) { extendPathUpstream(nextEdge.getUpstreamElement(), nextEdge.getConnectingElement()); return *this; @@ -177,6 +177,12 @@ void GraphIterator::returnPathDownstream(ElementPtr upstreamElem) _connectingElem = ElementPtr(); } +bool GraphIterator::skipOrMarkAsVisited(const Edge& edge) +{ + auto [it, inserted] = _visitedEdges.emplace(edge); + return !inserted; +} + // // InheritanceIterator methods // diff --git a/source/MaterialXCore/Traversal.h b/source/MaterialXCore/Traversal.h index a22d909cbe..08dcdaeaf8 100644 --- a/source/MaterialXCore/Traversal.h +++ b/source/MaterialXCore/Traversal.h @@ -316,12 +316,14 @@ class MX_CORE_API GraphIterator private: void extendPathUpstream(ElementPtr upstreamElem, ElementPtr connectingElem); void returnPathDownstream(ElementPtr upstreamElem); + bool skipOrMarkAsVisited(const Edge&); private: ElementPtr _upstreamElem; ElementPtr _connectingElem; ElementSet _pathElems; vector _stack; + std::set _visitedEdges; bool _prune; size_t _holdCount; }; diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index e9a3b50b79..8cc71567e4 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -916,7 +916,7 @@ void ShaderGraph::optimize() ShaderOutput* upstreamPort = outputSocket->getConnection(); if (upstreamPort && upstreamPort->getNode() != this) { - for (ShaderGraphEdge edge : ShaderGraph::traverseUpstream(upstreamPort)) + for (ShaderGraphEdge edge : traverseUpstream(upstreamPort)) { ShaderNode* node = edge.upstream->getNode(); if (usedNodesSet.count(node) == 0) @@ -1206,7 +1206,7 @@ ShaderGraphEdgeIterator& ShaderGraphEdgeIterator::operator++() ShaderInput* input = _upstream->getNode()->getInput(0); ShaderOutput* output = input->getConnection(); - if (output && !output->getNode()->isAGraph()) + if (output && !output->getNode()->isAGraph() && !skipOrMarkAsVisited({ output, input })) { extendPathUpstream(output, input); return *this; @@ -1234,7 +1234,7 @@ ShaderGraphEdgeIterator& ShaderGraphEdgeIterator::operator++() ShaderInput* input = parentFrame.first->getNode()->getInput(++parentFrame.second); ShaderOutput* output = input->getConnection(); - if (output && !output->getNode()->isAGraph()) + if (output && !output->getNode()->isAGraph() && !skipOrMarkAsVisited({ output, input })) { extendPathUpstream(output, input); return *this; @@ -1275,4 +1275,10 @@ void ShaderGraphEdgeIterator::returnPathDownstream(ShaderOutput* upstream) _downstream = nullptr; } +bool ShaderGraphEdgeIterator::skipOrMarkAsVisited(ShaderGraphEdge edge) +{ + auto [it, inserted] = _visitedEdges.emplace(edge); + return !inserted; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/ShaderGraph.h b/source/MaterialXGenShader/ShaderGraph.h index 6320d04296..77fd090b66 100644 --- a/source/MaterialXGenShader/ShaderGraph.h +++ b/source/MaterialXGenShader/ShaderGraph.h @@ -209,6 +209,22 @@ class MX_GENSHADER_API ShaderGraphEdge downstream(down) { } + + bool operator==(const ShaderGraphEdge& rhs) const + { + return upstream == rhs.upstream && downstream == rhs.downstream; + } + + bool operator!=(const ShaderGraphEdge& rhs) const + { + return !(*this == rhs); + } + + bool operator<(const ShaderGraphEdge& rhs) const + { + return std::tie(upstream, downstream) < std::tie(rhs.upstream, rhs.downstream); + } + ShaderOutput* upstream; ShaderInput* downstream; }; @@ -254,12 +270,14 @@ class MX_GENSHADER_API ShaderGraphEdgeIterator private: void extendPathUpstream(ShaderOutput* upstream, ShaderInput* downstream); void returnPathDownstream(ShaderOutput* upstream); + bool skipOrMarkAsVisited(ShaderGraphEdge); ShaderOutput* _upstream; ShaderInput* _downstream; using StackFrame = std::pair; std::vector _stack; std::set _path; + std::set _visitedEdges; }; MATERIALX_NAMESPACE_END From 9fcef07612dd1dfceb4293e2e5eb7074a3956418 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Thu, 5 Dec 2024 23:08:57 -0500 Subject: [PATCH 32/76] Allow for choice of font in Graph Editor (#2046) Allow the user to specify a true-type font file and size from the command line. --- source/MaterialXGraphEditor/Main.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/source/MaterialXGraphEditor/Main.cpp b/source/MaterialXGraphEditor/Main.cpp index 38c755cdd9..0c550dbdd1 100644 --- a/source/MaterialXGraphEditor/Main.cpp +++ b/source/MaterialXGraphEditor/Main.cpp @@ -30,6 +30,8 @@ const std::string options = " --path [FILEPATH] Specify an additional data search path location (e.g. '/projects/MaterialX'). This absolute path will be queried when locating data libraries, XInclude references, and referenced images.\n" " --library [FILEPATH] Specify an additional data library folder (e.g. 'vendorlib', 'studiolib'). This relative path will be appended to each location in the data search path when loading data libraries.\n" " --uiScale [FACTOR] Manually specify a UI scaling factor\n" + " --font [FILENAME] Specify the name of the custom font file to use. If not specified the default font will be used.\n" + " --fontSize [SIZE] Specify font size to use for the custom font. If not specified a default of 18 will be used.\n" " --captureFilename [FILENAME] Specify the filename to which the first rendered frame should be written\n" " --help Display the complete list of command-line options\n"; @@ -67,6 +69,8 @@ int main(int argc, char* const argv[]) int viewWidth = 256; int viewHeight = 256; float uiScale = 0.0f; + std::string fontFilename; + int fontSize = 18; std::string captureFilename; for (size_t i = 0; i < tokens.size(); i++) @@ -102,6 +106,14 @@ int main(int argc, char* const argv[]) { parseToken(nextToken, "float", uiScale); } + else if (token == "--font") + { + parseToken(nextToken, "string", fontFilename); + } + else if (token == "--fontSize") + { + parseToken(nextToken, "integer", fontSize); + } else if (token == "--captureFilename") { parseToken(nextToken, "string", captureFilename); @@ -172,7 +184,15 @@ int main(int argc, char* const argv[]) io.IniFilename = NULL; io.LogFilename = NULL; - io.Fonts->AddFontDefault(); + ImFont* customFont = nullptr; + if (!fontFilename.empty()) + { + customFont = io.Fonts->AddFontFromFileTTF(fontFilename.c_str(), fontSize); + } + if (!customFont) + { + io.Fonts->AddFontDefault(); + } // Setup Dear ImGui style ImGui::StyleColorsDark(); From 142460efb8f1d788b530fbbf5ba93fb26f06046a Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 6 Dec 2024 15:01:27 -0800 Subject: [PATCH 33/76] Simplify element equivalence interface (#2133) This changelist simplifies the interface of the Element::isEquivalent method in MaterialX C++, aligning it with the behavior of Element::validate and proposed use cases for element equivalence in JavaScript. --- source/MaterialXCore/Element.cpp | 68 +++++++++++-------- source/MaterialXCore/Element.h | 45 ++---------- .../MaterialXTest/MaterialXCore/Document.cpp | 19 ++---- .../PyMaterialX/PyMaterialXCore/PyElement.cpp | 18 +---- 4 files changed, 55 insertions(+), 95 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 78c59e9efc..5d0cf693d0 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -39,12 +39,6 @@ const string ValueElement::UI_ADVANCED_ATTRIBUTE = "uiadvanced"; const string ValueElement::UNIT_ATTRIBUTE = "unit"; const string ValueElement::UNITTYPE_ATTRIBUTE = "unittype"; const string ValueElement::UNIFORM_ATTRIBUTE = "uniform"; -const string ElementEquivalenceResult::ATTRIBUTE = "attribute"; -const string ElementEquivalenceResult::ATTRIBUTE_NAMES = "attribute names"; -const string ElementEquivalenceResult::CHILD_COUNT = "child count"; -const string ElementEquivalenceResult::CHILD_NAME = "child name"; -const string ElementEquivalenceResult::NAME = "name"; -const string ElementEquivalenceResult::CATEGORY = "category"; Element::CreatorMap Element::_creatorMap; @@ -375,19 +369,22 @@ bool Element::hasInheritanceCycle() const return false; } -bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, - ElementEquivalenceResultVec* results) const +bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, string* message) const { if (getName() != rhs->getName()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::NAME)); + if (message) + { + *message += "Name of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } if (getCategory() != rhs->getCategory()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::CATEGORY)); + if (message) + { + *message += "Category of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } @@ -413,14 +410,16 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& if (attributeNames != rhsAttributeNames) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE_NAMES)); + if (message) + { + *message += "Attribute names of '" + getNamePath() + "' differ from '" + rhs->getNamePath() + "\n"; + } return false; } for (const string& attr : rhsAttributeNames) { - if (!isAttributeEquivalent(rhs, attr, options, results)) + if (!isAttributeEquivalent(rhs, attr, options, message)) { return false; } @@ -447,8 +446,10 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& } if (children.size() != rhsChildren.size()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::CHILD_COUNT)); + if (message) + { + *message += "Child count of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } for (size_t i = 0; i < children.size(); i++) @@ -468,26 +469,29 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& rhsElement = rhs->getChild(childName); if (!rhsElement) { - if (results) - results->push_back(ElementEquivalenceResult(children[i]->getNamePath(), "", - ElementEquivalenceResult::CHILD_NAME, childName)); + if (message) + { + *message += "Child name `" + childName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } } } - if (!children[i]->isEquivalent(rhsElement, options, results)) + if (!children[i]->isEquivalent(rhsElement, options, message)) return false; } return true; } bool Element::isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, - const ElementEquivalenceOptions& /*options*/, ElementEquivalenceResultVec* results) const + const ElementEquivalenceOptions& /*options*/, string* message) const { if (getAttribute(attributeName) != rhs->getAttribute(attributeName)) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE, attributeName)); + if (message) + { + *message += "Attribute name `" + attributeName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } return true; @@ -710,7 +714,7 @@ const string& ValueElement::getActiveUnit() const } bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, - const ElementEquivalenceOptions& options, ElementEquivalenceResultVec* results) const + const ElementEquivalenceOptions& options, string* message) const { // Perform value comparisons bool performedValueComparison = false; @@ -737,8 +741,10 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr { if (thisValue->getValueString() != rhsValue->getValueString()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE, attributeName)); + if (message) + { + *message += "Attribute `" + attributeName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } } @@ -756,8 +762,10 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr { if (uiValue->getValueString() != rhsUiValue->getValueString()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE, attributeName)); + if (message) + { + *message += "Attribute `" + attributeName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } } @@ -769,7 +777,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr // If did not peform a value comparison, perform the default comparison if (!performedValueComparison) { - return Element::isAttributeEquivalent(rhs, attributeName, options, results); + return Element::isAttributeEquivalent(rhs, attributeName, options, message); } return true; diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 05eb2235f3..6b145a57b1 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -72,8 +72,6 @@ using ElementMap = std::unordered_map; using ElementPredicate = std::function; class ElementEquivalenceOptions; -class ElementEquivalenceResult; -using ElementEquivalenceResultVec = vector; /// @class Element /// The base class for MaterialX elements. @@ -608,21 +606,21 @@ class MX_CORE_API Element : public std::enable_shared_from_this /// criteria provided. /// @param rhs Element to compare against /// @param options Equivalence criteria - /// @param results Results of comparison if argument is specified. + /// @param message Optional text description of differences /// @return True if the elements are equivalent. False otherwise. - bool isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, - ElementEquivalenceResultVec* results = nullptr) const; + bool isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, + string* message = nullptr) const; /// Return true if the attribute on a given element is equivalent /// based on the equivalence criteria provided. /// @param rhs Element to compare against /// @param attributeName Name of attribute to compare /// @param options Equivalence criteria - /// @param results Results of comparison if argument is specified. + /// @param message Optional text description of differences /// @return True if the attribute on the elements are equivalent. False otherwise. virtual bool isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, const ElementEquivalenceOptions& options, - ElementEquivalenceResultVec* results = nullptr) const; + string* message = nullptr) const; /// @} /// @name Traversal @@ -1125,11 +1123,11 @@ class MX_CORE_API ValueElement : public TypedElement /// @param rhs Element to compare against /// @param attributeName Name of attribute to compare /// @param options Equivalence criteria - /// @param results Results of comparison if argument is specified. + /// @param message Optional text description of differences /// @return True if the attribute on the elements are equivalent. False otherwise. bool isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, const ElementEquivalenceOptions& options, - ElementEquivalenceResultVec* results = nullptr) const override; + string* message = nullptr) const override; /// @} /// @name Validation @@ -1353,35 +1351,6 @@ class MX_CORE_API StringResolver StringMap _geomNameMap; }; -/// @class ElementEquivalenceResult -/// A comparison result for the functional equivalence of two elements. -class MX_CORE_API ElementEquivalenceResult -{ - public: - ElementEquivalenceResult(const string& p1, const string& p2, const string& type, - const string& attrName = EMPTY_STRING) - { - path1 = p1; - path2 = p2; - differenceType = type; - attributeName = attrName; - } - ElementEquivalenceResult() = delete; - ~ElementEquivalenceResult() = default; - - string path1; - string path2; - string differenceType; - string attributeName; - - static const string ATTRIBUTE; - static const string ATTRIBUTE_NAMES; - static const string CHILD_COUNT; - static const string CHILD_NAME; - static const string NAME; - static const string CATEGORY; -}; - /// @class ElementEquivalenceOptions /// A set of options for comparing the functional equivalence of elements. class MX_CORE_API ElementEquivalenceOptions diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index b593969ccb..223aae5694 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -215,17 +215,16 @@ TEST_CASE("Document equivalence", "[document]") comment->setDocString("Comment 3"); mx::ElementEquivalenceOptions options; - mx::ElementEquivalenceResultVec results; + std::string message; // Check that this fails when not performing value comparisons options.performValueComparisons = false; - bool equivalent = doc->isEquivalent(doc2, options, &results); + bool equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(!equivalent); // Check attibute values options.performValueComparisons = true; - results.clear(); - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(equivalent); unsigned int currentPrecision = mx::Value::getFloatPrecision(); @@ -236,14 +235,13 @@ TEST_CASE("Document equivalence", "[document]") options.floatPrecision = currentPrecision; // Check attribute filtering of inputs - results.clear(); options.attributeExclusionList = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; for (mx::InputPtr floatInput : floatInputs) { floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, "0.9"); floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, "100.0"); } - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(equivalent); for (mx::InputPtr floatInput : floatInputs) { @@ -255,12 +253,10 @@ TEST_CASE("Document equivalence", "[document]") mx::ElementPtr mismatchElement = doc->getDescendant("mygraph/input_color4"); std::string previousName = mismatchElement->getName(); mismatchElement->setName("mismatch_color4"); - results.clear(); - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(!equivalent); mismatchElement->setName(previousName); - results.clear(); - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(equivalent); // Check for functional nodegraphs @@ -272,7 +268,6 @@ TEST_CASE("Document equivalence", "[document]") REQUIRE(nodeGraph2); doc2->addNodeDef("ND_mygraph"); nodeGraph2->setNodeDefString("ND_mygraph"); - results.clear(); - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(!equivalent); } diff --git a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp index 004fa0a670..05f858d4c3 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp @@ -31,9 +31,9 @@ void bindPyElement(py::module& mod) .def(py::self != py::self) .def("isEquivalent", [](const mx::Element& elem, mx::ConstElementPtr& rhs, const mx::ElementEquivalenceOptions& options) { - mx::ElementEquivalenceResultVec results; - bool res = elem.isEquivalent(rhs, options, &results); - return std::pair(res, results); + std::string message; + bool res = elem.isEquivalent(rhs, options, &message); + return std::pair(res, message); }) .def("setCategory", &mx::Element::setCategory) .def("getCategory", &mx::Element::getCategory) @@ -211,18 +211,6 @@ void bindPyElement(py::module& mod) py::class_(mod, "GenericElement") .def_readonly_static("CATEGORY", &mx::GenericElement::CATEGORY); - py::class_(mod, "ElementEquivalenceResult") - .def_readonly_static("ATTRIBUTE", &mx::ElementEquivalenceResult::ATTRIBUTE) - .def_readonly_static("ATTRIBUTE_NAMES", &mx::ElementEquivalenceResult::ATTRIBUTE_NAMES) - .def_readonly_static("CHILD_COUNT", &mx::ElementEquivalenceResult::CHILD_COUNT) - .def_readonly_static("CHILD_NAME", &mx::ElementEquivalenceResult::CHILD_NAME) - .def_readonly_static("NAME", &mx::ElementEquivalenceResult::NAME) - .def_readonly_static("CATEGORY", &mx::ElementEquivalenceResult::CATEGORY) - .def_readwrite("path1", &mx::ElementEquivalenceResult::path1) - .def_readwrite("path2", &mx::ElementEquivalenceResult::path2) - .def_readwrite("differenceType", &mx::ElementEquivalenceResult::differenceType) - .def_readwrite("attributeName", &mx::ElementEquivalenceResult::attributeName); - py::class_(mod, "ElementEquivalenceOptions") .def_readwrite("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) .def_readwrite("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) From e7f2840974761a852d856e6637e5901bb7b98f2f Mon Sep 17 00:00:00 2001 From: fnRaihanKibria <45946106+fnRaihanKibria@users.noreply.github.com> Date: Fri, 6 Dec 2024 23:13:18 +0000 Subject: [PATCH 34/76] Add checks for loops being created on nodes (#2029) Addressing issue #1932 The cause of the crash is a buffer overrun in ShaderGraph::topologicalSort() in the line `_nodeOrder[count++] = node;`. This is caused by a loop edge being present on the 'color_mix' node of the graph object this was called on, which made the sort algorithm malfunction. Unfortunately I was unable to determine in the time I have available why this loop is created. I didn't want to add a change that hides the underlying problem, which still needs to be fixed. Instead, this PR adds some checks to two locations in the code that throw exceptions when a case of a loop being created is detected, to aid in fixing the real issue and maybe help diagnosing other problems in the future. With this PR the graph editor does not crash any more, instead an error message "Upstream node 'color_mix' has itself as downstream node, creating a loop" is printed to console. --- source/MaterialXGenShader/ShaderGraph.cpp | 5 +++++ source/MaterialXGenShader/ShaderNode.cpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index 8cc71567e4..a8ec936014 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -138,6 +138,11 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, { // We have a node downstream ShaderNode* downstream = getNode(downstreamNode->getName()); + if (downstream == newNode) + { + throw ExceptionShaderGenError("Upstream node '" + downstream->getName() + "' has itself as downstream node, creating a loop"); + } + if (downstream && connectingElement) { ShaderInput* input = downstream->getInput(connectingElement->getName()); diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index d52810ffc4..12b9bbf548 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -57,6 +57,13 @@ void ShaderInput::makeConnection(ShaderOutput* src) if (src) { // Make the new connection. + if (src->getNode() == getNode() && !getNode()->isAGraph()) + { + throw ExceptionShaderGenError( + "Tried to create looping connection on node " + getNode()->getName() + + " from output: " + src->getFullName() + " to input: " + getFullName()); + } + _connection = src; src->_connections.push_back(this); } From 9be30a29102028b2d1ed3afd5c196d2cbe9da3ee Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 8 Dec 2024 11:08:36 -0800 Subject: [PATCH 35/76] Static analysis fixes (#2135) This changelist addresses a handful of static analysis warnings flagged by PVS-Studio: - Validate `downstream` before dereferencing in `ShaderGraph::createConnectedNodes`. - Pass a string argument by const reference in `StructTypeDesc::addMember`. - Avoid repeated calls to `Value::asA` in `Graph::setConstant`. --- source/MaterialXGenShader/ShaderGraph.cpp | 31 +++++++++++++---------- source/MaterialXGenShader/TypeDesc.cpp | 2 +- source/MaterialXGenShader/TypeDesc.h | 2 +- source/MaterialXGraphEditor/Graph.cpp | 30 ++++++++++++++-------- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index a8ec936014..c60910aaed 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -138,24 +138,27 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, { // We have a node downstream ShaderNode* downstream = getNode(downstreamNode->getName()); - if (downstream == newNode) + if (downstream) { - throw ExceptionShaderGenError("Upstream node '" + downstream->getName() + "' has itself as downstream node, creating a loop"); - } + if (downstream == newNode) + { + throw ExceptionShaderGenError("Upstream node '" + downstream->getName() + "' has itself as downstream node, creating a loop"); + } - if (downstream && connectingElement) - { - ShaderInput* input = downstream->getInput(connectingElement->getName()); - if (!input) + if (connectingElement) + { + ShaderInput* input = downstream->getInput(connectingElement->getName()); + if (!input) + { + throw ExceptionShaderGenError("Could not find an input named '" + connectingElement->getName() + + "' on downstream node '" + downstream->getName() + "'"); + } + input->makeConnection(output); + } + else { - throw ExceptionShaderGenError("Could not find an input named '" + connectingElement->getName() + - "' on downstream node '" + downstream->getName() + "'"); + throw ExceptionShaderGenError("Could not find downstream node ' " + downstreamNode->getName() + "'"); } - input->makeConnection(output); - } - else - { - throw ExceptionShaderGenError("Could not find downstream node ' " + downstreamNode->getName() + "'"); } } else diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp index 5d51680211..5ea0e31764 100644 --- a/source/MaterialXGenShader/TypeDesc.cpp +++ b/source/MaterialXGenShader/TypeDesc.cpp @@ -145,7 +145,7 @@ TYPEDESC_REGISTER_TYPE(MATERIAL, "material") // StructTypeDesc methods // -void StructTypeDesc::addMember(const string& name, TypeDesc type, string defaultValueStr) +void StructTypeDesc::addMember(const string& name, TypeDesc type, const string& defaultValueStr) { _members.emplace_back(StructTypeDesc::StructMemberTypeDesc(name, type, defaultValueStr)); } diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index 95d2851915..d19fea604a 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -255,7 +255,7 @@ class MX_GENSHADER_API StructTypeDesc /// Empty constructor. StructTypeDesc() noexcept{} - void addMember(const string& name, TypeDesc type, string defaultValueStr); + void addMember(const string& name, TypeDesc type, const string& defaultValueStr); void setTypeDesc(TypeDesc typedesc) { _typedesc = typedesc; } /// Return a type description by index. diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index d09961d42f..9e075b9dc4 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -926,7 +926,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert if (val && val->isA()) { // Update the value to the default for new nodes - float prev = val->asA(), temp = val->asA(); + float prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA() : 0.f; float max = maxVal ? maxVal->asA() : 100.f; float speed = (max - min) / 1000.0f; @@ -946,7 +947,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - int prev = val->asA(), temp = val->asA(); + int prev, temp; + prev = temp = val->asA(); int min = minVal ? minVal->asA() : 0; int max = maxVal ? maxVal->asA() : 100; float speed = (max - min) / 100.0f; @@ -966,7 +968,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Color3 prev = val->asA(), temp = val->asA(); + mx::Color3 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -990,7 +993,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Color4 prev = val->asA(), temp = val->asA(); + mx::Color4 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1016,7 +1020,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Vector2 prev = val->asA(), temp = val->asA(); + mx::Vector2 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1036,7 +1041,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Vector3 prev = val->asA(), temp = val->asA(); + mx::Vector3 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1056,7 +1062,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Vector4 prev = val->asA(), temp = val->asA(); + mx::Vector4 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1076,7 +1083,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - std::string prev = val->asA(), temp = val->asA(); + std::string prev, temp; + prev = temp = val->asA(); ImGui::InputText("##constant", &temp); // Set input value and update materials if different from previous value @@ -1094,7 +1102,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert if (val && val->isA()) { - std::string temp = val->asA(), prev = val->asA(); + std::string prev, temp; + prev = temp = val->asA(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.15f, .15f, .15f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.2f, .4f, .6f, 1.0f)); @@ -1142,7 +1151,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - bool prev = val->asA(), temp = val->asA(); + bool prev, temp; + prev = temp = val->asA(); ImGui::Checkbox("", &temp); // Set input value and update materials if different from previous value From 8929e07e7a3888b32656eb0ffef05b2d39b4381a Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 8 Dec 2024 16:32:51 -0800 Subject: [PATCH 36/76] Improve usage of setDataLibrary (#2136) This changelist improves the usage of Document::setDataLibrary in MaterialXRender functions, leveraging this more efficient alternative to Document::importLibrary where appropriate. --- source/MaterialXRender/ShaderMaterial.cpp | 6 ++---- source/MaterialXRender/Util.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/source/MaterialXRender/ShaderMaterial.cpp b/source/MaterialXRender/ShaderMaterial.cpp index c61c6d3c04..6fcc1a661d 100644 --- a/source/MaterialXRender/ShaderMaterial.cpp +++ b/source/MaterialXRender/ShaderMaterial.cpp @@ -68,10 +68,8 @@ bool ShaderMaterial::generateEnvironmentShader(GenContext& context, { // Read in the environment nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); - DocumentPtr envDoc = createDocument(); - readFromXmlFile(envDoc, filename); - doc->importLibrary(envDoc); + doc->setDataLibrary(stdLib); + readFromXmlFile(doc, filename); NodeGraphPtr envGraph = doc->getNodeGraph("envMap"); if (!envGraph) diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index c206514412..9aab6b4811 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -24,7 +24,7 @@ ShaderPtr createConstantShader(GenContext& context, { // Construct the constant color nodegraph DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); constant->setInputValue("value", color); @@ -41,7 +41,7 @@ ShaderPtr createDepthShader(GenContext& context, { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); OutputPtr output = nodeGraph->addOutput(); @@ -61,7 +61,7 @@ ShaderPtr createAlbedoTableShader(GenContext& context, { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); OutputPtr output = nodeGraph->addOutput(); @@ -82,7 +82,7 @@ ShaderPtr createEnvPrefilterShader(GenContext& context, { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); OutputPtr output = nodeGraph->addOutput(); @@ -104,7 +104,7 @@ ShaderPtr createBlurShader(GenContext& context, { // Construct the blur nodegraph DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr imageNode = nodeGraph->addNode("image", "image"); NodePtr blurNode = nodeGraph->addNode("blur", "blur"); From 12235809a1e26a7a80da9c990723e804fd6562fc Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 9 Dec 2024 09:57:53 -0800 Subject: [PATCH 37/76] Use setDataLibrary in Graph Editor (#2137) This changelist updates the Graph Editor to use Element::setDataLibrary rather than Element::importLibrary, improving the efficiency of document loading. Additionally, it removes an unused method and member variable from the RenderView class. --- source/MaterialXGraphEditor/Graph.cpp | 6 +++--- source/MaterialXGraphEditor/RenderView.cpp | 18 ++++-------------- source/MaterialXGraphEditor/RenderView.h | 4 ++-- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 9e075b9dc4..1c3dfa66ba 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -171,7 +171,7 @@ Graph::Graph(const std::string& materialFilename, // Create a renderer using the initial startup document. mx::FilePath captureFilename = "resources/Materials/Examples/example.png"; std::string envRadianceFilename = "resources/Lights/san_giuseppe_bridge_split.hdr"; - _renderer = std::make_shared(_graphDoc, meshFilename, envRadianceFilename, + _renderer = std::make_shared(_graphDoc, _stdLib, meshFilename, envRadianceFilename, _searchPath, viewWidth, viewHeight); _renderer->initialize(); for (const std::string& ext : _renderer->getImageHandler()->supportedExtensions()) @@ -249,7 +249,7 @@ mx::DocumentPtr Graph::loadDocument(const mx::FilePath& filename) if (!filename.isEmpty()) { mx::readFromXmlFile(doc, filename, _searchPath, &readOptions); - doc->importLibrary(_stdLib); + doc->setDataLibrary(_stdLib); std::string message; if (!doc->validate(&message)) { @@ -3050,7 +3050,7 @@ void Graph::clearGraph() _newLinks.clear(); _currPins.clear(); _graphDoc = mx::createDocument(); - _graphDoc->importLibrary(_stdLib); + _graphDoc->setDataLibrary(_stdLib); _currGraphElem = _graphDoc; if (_currUiNode != nullptr) diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index 92cd8f07c7..fe419c7908 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -108,6 +108,7 @@ void RenderView::setDocument(mx::DocumentPtr document) } RenderView::RenderView(mx::DocumentPtr doc, + mx::DocumentPtr stdLib, const std::string& meshFilename, const std::string& envRadianceFilename, const mx::FileSearchPath& searchPath, @@ -162,6 +163,7 @@ RenderView::RenderView(mx::DocumentPtr doc, _genContext.getOptions().shaderInterfaceType = mx::SHADER_INTERFACE_COMPLETE; setDocument(doc); + _stdLib = stdLib; } void RenderView::initialize() @@ -214,18 +216,6 @@ void RenderView::assignMaterial(mx::MeshPartitionPtr geometry, mx::GlslMaterialP } } -mx::ElementPredicate RenderView::getElementPredicate() -{ - return [this](mx::ConstElementPtr elem) - { - if (elem->hasSourceUri()) - { - return (_xincludeFiles.count(elem->getSourceUri()) == 0); - } - return true; - }; -} - void RenderView::updateGeometrySelections() { _geometryList.clear(); @@ -935,7 +925,7 @@ mx::ImagePtr RenderView::getShadowMap() { try { - mx::ShaderPtr hwShader = mx::createDepthShader(_genContext, _document, "__SHADOW_SHADER__"); + mx::ShaderPtr hwShader = mx::createDepthShader(_genContext, _stdLib, "__SHADOW_SHADER__"); _shadowMaterial = mx::GlslMaterial::create(); _shadowMaterial->generateShader(hwShader); } @@ -949,7 +939,7 @@ mx::ImagePtr RenderView::getShadowMap() { try { - mx::ShaderPtr hwShader = mx::createBlurShader(_genContext, _document, "__SHADOW_BLUR_SHADER__", "gaussian", 1.0f); + mx::ShaderPtr hwShader = mx::createBlurShader(_genContext, _stdLib, "__SHADOW_BLUR_SHADER__", "gaussian", 1.0f); _shadowBlurMaterial = mx::GlslMaterial::create(); _shadowBlurMaterial->generateShader(hwShader); } diff --git a/source/MaterialXGraphEditor/RenderView.h b/source/MaterialXGraphEditor/RenderView.h index 354e898ce1..c4c709dc9f 100644 --- a/source/MaterialXGraphEditor/RenderView.h +++ b/source/MaterialXGraphEditor/RenderView.h @@ -29,6 +29,7 @@ class RenderView { public: RenderView(mx::DocumentPtr doc, + mx::DocumentPtr stdLib, const std::string& meshFilename, const std::string& envRadianceFilename, const mx::FileSearchPath& searchPath, @@ -159,7 +160,6 @@ class RenderView { return _xincludeFiles; } - mx::ElementPredicate getElementPredicate(); // Request a capture of the current frame, writing it to the given filename. void requestFrameCapture(const mx::FilePath& filename) @@ -232,7 +232,6 @@ class RenderView void updateGeometrySelections(); mx::ImagePtr getShadowMap(); - mx::ImagePtr _renderMap; void renderFrame(); void renderScreenSpaceQuad(mx::GlslMaterialPtr material); @@ -268,6 +267,7 @@ class RenderView // Document management mx::DocumentPtr _document; + mx::DocumentPtr _stdLib; DocumentModifiers _modifiers; mx::StringSet _xincludeFiles; From 31d8240036ba45bf363414db83b6542d0c3eabac Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Mon, 9 Dec 2024 13:43:42 -0500 Subject: [PATCH 38/76] Improve input filtering in Graph Editor (#2134) - Move "show all inputs" to the top. - Make name field expand to right marge on panel. - Format the title of the property editor. - Remove extraneous "Inputs:" line since only inputs are displayed. --- source/MaterialXGraphEditor/Graph.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 1c3dfa66ba..aa04339469 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -3288,7 +3288,20 @@ void Graph::graphButtons() void Graph::propertyEditor() { + // Get parent dimensions + ImVec2 textPos = ImGui::GetCursorScreenPos(); // Position for the background + float parentWidth = ImGui::GetContentRegionAvail().x; // Available width in the parent + + // Draw the title bar + const ImGuiStyle& style = ImGui::GetStyle(); + ImVec4 menuBarBgColor = style.Colors[ImGuiCol_MenuBarBg]; + ImU32 bgColor = ImGui::ColorConvertFloat4ToU32(menuBarBgColor); // Convert to 32-bit color + ImDrawList* drawList = ImGui::GetWindowDrawList(); + drawList->AddRectFilled(textPos, + ImVec2(textPos.x + parentWidth, textPos.y + ImGui::GetTextLineHeight()), + bgColor); ImGui::Text("Node Property Editor"); + if (_currUiNode) { // Set and edit name @@ -3296,7 +3309,11 @@ void Graph::propertyEditor() ImGui::SameLine(); std::string original = _currUiNode->getName(); std::string temp = original; + float availableWidth = ImGui::GetContentRegionAvail().x; + ImGui::PushItemWidth(availableWidth); ImGui::InputText("##edit", &temp); + ImGui::PopItemWidth(); + std::string docString = "NodeDef Doc String: \n"; if (_currUiNode->getNode()) { @@ -3423,7 +3440,8 @@ void Graph::propertyEditor() ImGui::SetTooltip("%s", _currUiNode->getNode()->getNodeDef()->getDocString().c_str()); } - ImGui::Text("Inputs:"); + ImGui::Checkbox("Show all inputs", &_currUiNode->_showAllInputs); + int count = 0; for (UiPinPtr input : _currUiNode->inputPins) { @@ -3487,14 +3505,12 @@ void Graph::propertyEditor() ImGui::SetWindowFontScale(1.0f); } } - ImGui::Checkbox("Show all inputs", &_currUiNode->_showAllInputs); } else if (_currUiNode->getInput() != nullptr) { ImGui::Text("%s", _currUiNode->getCategory().c_str()); std::vector inputs = _currUiNode->inputPins; - ImGui::Text("Inputs:"); int count = static_cast(inputs.size()); if (count) @@ -3545,7 +3561,6 @@ void Graph::propertyEditor() { std::vector inputs = _currUiNode->inputPins; ImGui::Text("%s", _currUiNode->getCategory().c_str()); - ImGui::Text("Inputs:"); int count = 0; for (UiPinPtr input : inputs) { From bc2466e1856fed9415fcda4031dc1e069c247a90 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 9 Dec 2024 20:01:52 -0800 Subject: [PATCH 39/76] Use setDataLibrary in Web Viewer (#2138) This changelist updates the Web Viewer to use Document::setDataLibrary rather than Document::importLibrary, improving the efficiency of document loading. --- javascript/MaterialXView/source/viewer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index e558ad0bc9..77437b8c56 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -606,7 +606,7 @@ export class Material // Re-initialize document var startDocTime = performance.now(); var doc = mx.createDocument(); - doc.importLibrary(viewer.getLibrary()); + doc.setDataLibrary(viewer.getLibrary()); viewer.setDocument(doc); const fileloader = viewer.getFileLoader(); @@ -1491,7 +1491,7 @@ export class Viewer this.document = this.mx.createDocument(); this.stdlib = this.mx.loadStandardLibraries(this.genContext); - this.document.importLibrary(this.stdlib); + this.document.setDataLibrary(this.stdlib); this.initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml); From 95d26ff6355526b82a4a2d4ce7ba1d69d4d3f7f0 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 11 Dec 2024 07:03:31 -0800 Subject: [PATCH 40/76] Simplify shader generator exclusions (#2139) This changelist simplifies the shader generator exclusion lists used in unit testing, removing legacy exclusions that are no longer needed with the current data libraries. --- source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h | 7 +++---- source/MaterialXTest/MaterialXGenMdl/GenMdl.h | 5 ++--- source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 8 ++++---- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 4 ++-- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h index bc96ac0268..8d3e8c8720 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h @@ -51,10 +51,9 @@ class GlslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "screen", "displacementshader", "volumeshader", - "IM_constant_", "IM_dot_", "IM_geompropvalue_boolean", "IM_geompropvalue_string", - "IM_light_genglsl", "IM_point_light_genglsl", "IM_spot_light_genglsl", "IM_directional_light_genglsl", - "IM_angle", "volumematerial", "ND_volumematerial" + "volumeshader", "volumematerial", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", + "IM_light_", "IM_point_light_", "IM_spot_light_", "IM_directional_light_" }; ShaderGeneratorTester::getImplementationWhiteList(whiteList); } diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h index e51dbbd7e5..ff2be4205d 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h @@ -76,9 +76,8 @@ class MdlShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "backfacing", "screen", "displacementshader", - "volumeshader", "IM_constant_", "IM_dot_", "IM_geomattrvalue", "IM_angle", - "geompropvalue", "surfacematerial", "volumematerial", + "displacementshader", "volumeshader", "surfacematerial", "volumematerial", "geompropvalue", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geomattrvalue", "IM_absorption_vdf_", "IM_mix_vdf_", "IM_add_vdf_", "IM_multiply_vdf", "IM_measured_edf_", "IM_blackbody_", "IM_conical_edf_", "IM_displacement_", "IM_volume_", "IM_light_" diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h index c281abde1c..eea7b86acb 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h @@ -70,10 +70,10 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "backfacing", "screen", "displacementshader", - "volumeshader", "IM_constant_", "IM_dot_", "IM_geompropvalue_boolean", "IM_geompropvalue_string", - "IM_light_genmsl", "IM_point_light_genmsl", "IM_spot_light_genmsl", "IM_directional_light_genmsl", - "IM_angle", "surfacematerial", "volumematerial", "ND_surfacematerial", "ND_volumematerial", "ND_backface_util", "IM_backface_util_genmsl" + "displacementshader", "volumeshader", "surfacematerial", "volumematerial", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", + "IM_light_", "IM_point_light_", "IM_spot_light_", "IM_directional_light_", + "ND_surfacematerial", "ND_volumematerial" }; } }; diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h index cc97558e59..aa84a62218 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h @@ -63,8 +63,8 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "backfacing", "screen", "displacementshader", - "volumeshader", "IM_constant_", "IM_dot_", "IM_geompropvalue", "IM_angle", "ND_backface_util" + "displacementshader", "volumeshader", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue" }; ShaderGeneratorTester::getImplementationWhiteList(whiteList); } From d075eb28f3c0b15d90ef2198498107c7471edcd5 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 11 Dec 2024 07:16:51 -0800 Subject: [PATCH 41/76] Update changelog for recent work (#2140) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fb0c98143..8ab737cbe6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,11 +18,13 @@ - Added documentation for [keyboard shortcuts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2026) in the MaterialX Viewer. ### Changed +- Improved the performance of [graph traversal](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2023) by skipping edges that have already been visited. - Reduced duplication between the [MSL and GLSL implementations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2068) of nodes. ### Fixed - Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. - Fixed [banding artifacts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1977) in the MaterialX Viewer on MacOS. +- Fixed the handling of [missing scenes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2124) in the MaterialX Web Viewer. - Fixed a call to the [anisotropic_vdf closure](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2016) in OSL shader generation. ### Removed From ce1168abf62351215653ce0f3ed00c9c1c031501 Mon Sep 17 00:00:00 2001 From: Jonathan Feldstein Date: Wed, 11 Dec 2024 17:46:17 -0500 Subject: [PATCH 42/76] Initial graph implementation of ramp node (#1884) This change includes the ramp nodedef, ramp gradient nodedef and subsequent nodegraph implementations for these two nodedefs. The ramp node includes support for both linear, smoothstep and step interpolation. The ramp also supports up to 10 control points and the following ramp types: standard, radial, circular and box. --- libraries/stdlib/stdlib_defs.mtlx | 49 +++++++ libraries/stdlib/stdlib_ng.mtlx | 221 ++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index e6f8d431e7..8f86a03b44 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -465,6 +465,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c46e8a3ff7313f29e2c3674ba48273eea7552a22 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Wed, 11 Dec 2024 22:28:54 -0500 Subject: [PATCH 43/76] Add JavaScript bindings for element equivalence (#2126) Expose the `Element::isEquivalent()` + options structure API in Javascript. --- javascript/MaterialXTest/element.spec.js | 25 +++++++++++++++++++ .../JsMaterialX/JsMaterialXCore/JsElement.cpp | 24 ++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/javascript/MaterialXTest/element.spec.js b/javascript/MaterialXTest/element.spec.js index cbb672c5c2..bafee4d6af 100644 --- a/javascript/MaterialXTest/element.spec.js +++ b/javascript/MaterialXTest/element.spec.js @@ -164,3 +164,28 @@ describe('Element', () => }); }); }); + +describe('Equivalence', () => +{ + let mx, doc, doc2 + + before(async () => { + mx = await Module(); + doc = mx.createDocument(); + doc.addNodeGraph("graph"); + doc2 = mx.createDocument(); + doc2.addNodeGraph("graph1"); + }); + + it('Compare document equivalency', () => + { + let options = new mx.ElementEquivalenceOptions(); + let differences = {}; + options.performValueComparisons = false; + let result = doc.isEquivalent(doc2, options, differences); + expect(result).to.be.false; + expect(differences.message).to.not.be.empty; + result = doc.isEquivalent(doc2, options, undefined); + expect(result).to.be.false; + }); +}); diff --git a/source/JsMaterialX/JsMaterialXCore/JsElement.cpp b/source/JsMaterialX/JsMaterialXCore/JsElement.cpp index c912d036c1..31670ad090 100644 --- a/source/JsMaterialX/JsMaterialXCore/JsElement.cpp +++ b/source/JsMaterialX/JsMaterialXCore/JsElement.cpp @@ -35,11 +35,35 @@ namespace mx = MaterialX; EMSCRIPTEN_BINDINGS(element) { + ems::class_("ElementEquivalenceOptions") + .constructor<>() + .property("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) + .property("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) + .property("floatPrecision", &mx::ElementEquivalenceOptions::floatPrecision) + .function("setAttributeExclusionList", ems::optional_override([](mx::ElementEquivalenceOptions& self, const std::vector& exclusionList) + { + self.attributeExclusionList = std::set(exclusionList.begin(), exclusionList.end()); + })); + ems::class_("Element") .smart_ptr>("Element") .smart_ptr>("Element") // mx::ConstElementPtr .function("equals", ems::optional_override([](mx::Element& self, const mx::Element& rhs) { return self == rhs; })) .function("notEquals", ems::optional_override([](mx::Element& self, const mx::Element& rhs) { return self != rhs; })) + .function("isEquivalent", ems::optional_override([](mx::Element &self, const mx::Element& rhs, + const mx::ElementEquivalenceOptions& options, + ems::val message = ems::val::undefined()) + { + mx::ConstElementPtr rhsPtr = rhs.getSelf(); + std::string nativeMessage; + bool handleMessage = !message.isUndefined() && message.typeOf().as() == "object"; + bool res = self.isEquivalent(rhsPtr, options, handleMessage ? &nativeMessage : nullptr); + if (!res && handleMessage) + { + message.set("message", nativeMessage); + } + return res; + })) .function("setCategory", &mx::Element::setCategory) .function("getCategory", &mx::Element::getCategory) .function("setName", &mx::Element::setName) From 94ce95d7b814b188d6a2adc2aa3f521ed3a20643 Mon Sep 17 00:00:00 2001 From: krohmerNV <42233792+krohmerNV@users.noreply.github.com> Date: Thu, 12 Dec 2024 19:24:40 +0100 Subject: [PATCH 44/76] Add support for custom MDL nodes (#2125) The MDL generator is limited in a way that it only supported the mappings defined in the libraries/***lib/genmdl files. With this pull request we now fully support nodes. This comes in two flavors: 1. External .mdl file references: We allow to specify an MDL module located in an MDL search path using the `file` attribute. In combination with the `function` attribute a particular exported function can be selected. There is one aspect that needs to be considered when using this approach: - Input and output names defined in MaterialX could conflict with reserved names in MDL. Therefore, we add a `mxp_` prefix in case of such a conflict. The prefix is not applied in general because we want to be able to reference MDL modules without modifying them. 2. Inline MDL source code: By specifying the `sourcecode` attribute, MDL code can be added directly. The generator will inline this code into the generated MDL code, based on the interface of the corresponding node definition. Here, more aspects need to be considered: - all input and input names defined in MaterialX are prefixed with `mxp_` to keep things simple for authors that otherwise would need knowledge about the keywords in MDL. - because the source code parsed from the MaterialX document contains no line breaks, we need to forbid comments using `//`. Instead the `/* comment */` syntax can be used. - to keep these inline source code nodes portable, it is not allowed to import additional MDL modules --- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 58 +++- source/MaterialXGenMdl/MdlSyntax.cpp | 89 +++++- source/MaterialXGenMdl/MdlSyntax.h | 11 + .../Nodes/ClosureCompoundNodeMdl.cpp | 4 +- .../MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp | 8 +- .../MaterialXGenMdl/Nodes/CustomNodeMdl.cpp | 278 ++++++++++++++++++ source/MaterialXGenMdl/Nodes/CustomNodeMdl.h | 56 ++++ source/MaterialXGenMdl/Nodes/ImageNodeMdl.h | 2 +- .../MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp | 5 +- .../Nodes/SourceCodeNodeMdl.cpp | 62 ++-- .../MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h | 1 + .../MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp | 5 +- .../Nodes/SourceCodeNode.cpp | 24 +- .../MaterialXGenShader/Nodes/SourceCodeNode.h | 3 + .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 2 +- 15 files changed, 526 insertions(+), 82 deletions(-) create mode 100644 source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp create mode 100644 source/MaterialXGenMdl/Nodes/CustomNodeMdl.h diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index 71db0d7cf4..1bc65d5cc4 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -157,6 +158,24 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G emitLineEnd(stage, true); } + // Emit custom node imports for nodes in the graph + for (ShaderNode* node : graph.getNodes()) + { + const ShaderNodeImpl& impl = node->getImplementation(); + const CustomCodeNodeMdl* customNode = dynamic_cast(&impl); + if (customNode) + { + const string& importName = customNode->getQualifiedModuleName(); + if (!importName.empty()) + { + emitString("import ", stage); + emitString(importName, stage); + emitString("::*", stage); + emitLineEnd(stage, true); + } + } + } + // Add global constants and type definitions emitTypeDefinitions(context, stage); @@ -353,14 +372,31 @@ ShaderNodeImplPtr MdlShaderGenerator::getImplementation(const NodeDef& nodedef, impl = _implFactory.create(name); if (!impl) { - // Fall back to source code implementation. - if (outputType.isClosure()) + // When `file` and `function` are provided we consider this node a user node + const string file = implElement->getTypedAttribute("file"); + const string function = implElement->getTypedAttribute("function"); + // Or, if `sourcecode` is provided we consider this node a user node with inline implementation + // inline implementations are not supposed to have replacement markers + const string sourcecode = implElement->getTypedAttribute("sourcecode"); + if ((!file.empty() && !function.empty()) || (!sourcecode.empty() && sourcecode.find("{{") == string::npos)) + { + impl = CustomCodeNodeMdl::create(); + } + else if (file.empty() && sourcecode.empty()) { - impl = ClosureSourceCodeNodeMdl::create(); + throw ExceptionShaderGenError("No valid MDL implementation found for '" + name + "'"); } else { - impl = SourceCodeNodeMdl::create(); + // Fall back to source code implementation. + if (outputType.isClosure()) + { + impl = ClosureSourceCodeNodeMdl::create(); + } + else + { + impl = SourceCodeNodeMdl::create(); + } } } } @@ -386,6 +422,7 @@ string MdlShaderGenerator::getUpstreamResult(const ShaderInput* input, GenContex return ShaderGenerator::getUpstreamResult(input, context); } + const MdlSyntax& mdlSyntax = static_cast(getSyntax()); string variable; const ShaderNode* upstreamNode = upstreamOutput->getNode(); if (!upstreamNode->isAGraph() && upstreamNode->numOutputs() > 1) @@ -397,7 +434,18 @@ string MdlShaderGenerator::getUpstreamResult(const ShaderInput* input, GenContex } else { - variable = upstreamNode->getName() + "_result.mxp_" + upstreamOutput->getName(); + const string& fieldName = upstreamOutput->getName(); + const CustomCodeNodeMdl* upstreamCustomNodeMdl = dynamic_cast(&upstreamNode->getImplementation()); + if (upstreamCustomNodeMdl) + { + // Prefix the port name depending on the CustomCodeNode + variable = upstreamNode->getName() + "_result." + upstreamCustomNodeMdl->modifyPortName(fieldName, mdlSyntax); + } + else + { + // Existing implementations and none user defined structs will keep the prefix always to not break existing content + variable = upstreamNode->getName() + "_result." + mdlSyntax.modifyPortName(upstreamOutput->getName()); + } } } else diff --git a/source/MaterialXGenMdl/MdlSyntax.cpp b/source/MaterialXGenMdl/MdlSyntax.cpp index 0244a8352f..c0859f5ae2 100644 --- a/source/MaterialXGenMdl/MdlSyntax.cpp +++ b/source/MaterialXGenMdl/MdlSyntax.cpp @@ -29,6 +29,8 @@ TYPEDESC_REGISTER_TYPE(MDL_SCATTER_MODE, "scatter_mode") namespace { +const string MARKER_MDL_VERSION_SUFFIX = "MDL_VERSION_SUFFIX"; + class MdlFilenameTypeSyntax : public ScalarTypeSyntax { public: @@ -195,6 +197,8 @@ const StringVec MdlSyntax::FILTERTYPE_MEMBERS = { "box", "gaussian" }; const StringVec MdlSyntax::DISTRIBUTIONTYPE_MEMBERS = { "ggx" }; const StringVec MdlSyntax::SCATTER_MODE_MEMBERS = { "R", "T", "RT" }; +const string MdlSyntax::PORT_NAME_PREFIX = "mxp_"; + // // MdlSyntax methods // @@ -202,22 +206,40 @@ const StringVec MdlSyntax::SCATTER_MODE_MEMBERS = { "R", "T", "RT" }; MdlSyntax::MdlSyntax() { // Add in all reserved words and keywords in MDL + // Formatted as in the MDL Specification 1.9.2 for easy comparing registerReservedWords( - { // Reserved words - "annotation", "bool", "bool2", "bool3", "bool4", "break", "bsdf", "bsdf_measurement", "case", "cast", "color", "const", - "continue", "default", "do", "double", "double2", "double2x2", "double2x3", "double3", "double3x2", "double3x3", "double3x4", - "double4", "double4x3", "double4x4", "double4x2", "double2x4", "edf", "else", "enum", "export", "false", "float", "float2", - "float2x2", "float2x3", "float3", "float3x2", "float3x3", "float3x4", "float4", "float4x3", "float4x4", "float4x2", "float2x4", - "for", "hair_bsdf", "if", "import", "in", "int", "int2", "int3", "int4", "intensity_mode", "intensity_power", "intensity_radiant_exitance", - "let", "light_profile", "material", "material_emission", "material_geometry", "material_surface", "material_volume", "mdl", "module", - "package", "return", "string", "struct", "switch", "texture_2d", "texture_3d", "texture_cube", "texture_ptex", "true", "typedef", "uniform", - "using", "varying", "vdf", "while", - // Reserved for future use - "auto", "catch", "char", "class", "const_cast", "delete", "dynamic_cast", "explicit", "extern", "external", "foreach", "friend", "goto", - "graph", "half", "half2", "half2x2", "half2x3", "half3", "half3x2", "half3x3", "half3x4", "half4", "half4x3", "half4x4", "half4x2", "half2x4", - "inline", "inout", "lambda", "long", "mutable", "namespace", "native", "new", "operator", "out", "phenomenon", "private", "protected", "public", - "reinterpret_cast", "sampler", "shader", "short", "signed", "sizeof", "static", "static_cast", "technique", "template", "this", "throw", "try", - "typeid", "typename", "union", "unsigned", "virtual", "void", "volatile", "wchar_t" }); + { // Reserved words + "annotation", "double2", "float", "in", "operator", + "auto", "double2x2", "float2", "int", "package", + "bool", "double2x3", "float2x2", "int2", "return", + "bool2", "double3", "float2x3", "int3", "string", + "bool3", "double3x2", "float3", "int4", "struct", + "bool4", "double3x3", "float3x2", "intensity_mode", "struct_category", + "break", "double3x4", "float3x3", "intensity_power", "switch", + "bsdf", "double4", "float3x4", "intensity_radiant_exitance", "texture_2d", + "bsdf_measurement", "double4x3", "float4", "let", "texture_3d", + "case", "double4x4", "float4x3", "light_profile", "texture_cube", + "cast", "double4x2", "float4x4", "material", "texture_ptex", + "color", "double2x4", "float4x2", "material_emission", "true", + "const", "edf", "float2x4", "material_geometry", "typedef", + "continue", "else", "for", "material_surface", "uniform", + "declarative", "enum", "hair_bsdf", "material_volume", "using", + "default", "export", "if", "mdl", "varying", + "do", "false", "import", "module", "vdf", + "double", "while", + + // Reserved for future use + "catch", "friend", "half3x4", "mutable", "sampler", "throw", + "char", "goto", "half4", "namespace", "shader", "try", + "class", "graph", "half4x3", "native", "short", "typeid", + "const_cast", "half", "half4x4", "new", "signed", "typename", + "delete", "half2", "half4x2", "out", "sizeof", "union", + "dynamic_cast", "half2x2", "half2x4", "phenomenon", "static", "unsigned", + "explicit", "half2x3", "inline", "private", "static_cast", "virtual", + "extern", "half3", "inout", "protected", "technique", "void", + "external", "half3x2", "lambda", "public", "template", "volatile", + "foreach", "half3x3", "long", "reinterpret_cast", "this", "wchar_t", + }); // Register restricted tokens in MDL StringMap tokens; @@ -533,4 +555,41 @@ void MdlSyntax::makeValidName(string& name) const } } +string MdlSyntax::modifyPortName(const string& word) const +{ + return PORT_NAME_PREFIX + word; +} + +string MdlSyntax::replaceSourceCodeMarkers(const string& nodeName, const string& soureCode, std::function lambda) const +{ + // An inline function call + // Replace tokens of the format "{{}}" + static const string prefix("{{"); + static const string postfix("}}"); + + size_t pos = 0; + size_t i = soureCode.find_first_of(prefix); + StringVec code; + while (i != string::npos) + { + code.push_back(soureCode.substr(pos, i - pos)); + size_t j = soureCode.find_first_of(postfix, i + 2); + if (j == string::npos) + { + throw ExceptionShaderGenError("Malformed inline expression in implementation for node " + nodeName); + } + const string marker = soureCode.substr(i + 2, j - i - 2); + code.push_back(lambda(marker)); + pos = j + 2; + i = soureCode.find_first_of(prefix, pos); + } + code.push_back(soureCode.substr(pos)); + return joinStrings(code, EMPTY_STRING); +} + +const string MdlSyntax::getMdlVersionSuffixMarker() const +{ + return MARKER_MDL_VERSION_SUFFIX; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/MdlSyntax.h b/source/MaterialXGenMdl/MdlSyntax.h index e282cefeca..48fd6214c0 100644 --- a/source/MaterialXGenMdl/MdlSyntax.h +++ b/source/MaterialXGenMdl/MdlSyntax.h @@ -53,6 +53,7 @@ class MX_GENMDL_API MdlSyntax : public Syntax static const StringVec FILTERTYPE_MEMBERS; static const StringVec DISTRIBUTIONTYPE_MEMBERS; static const StringVec SCATTER_MODE_MEMBERS; + static const string PORT_NAME_PREFIX; // Applied to input and output names to avoid collisions with reserved words in MDL /// Get an type description for an enumeration based on member value TypeDesc getEnumeratedType(const string& value) const; @@ -63,6 +64,16 @@ class MX_GENMDL_API MdlSyntax : public Syntax /// Modify the given name string to remove any invalid characters or tokens. void makeValidName(string& name) const override; + + /// To avoid collisions with reserved names in MDL, input and output names are prefixed. + string modifyPortName(const string& word) const; + + /// Replaces all markers in a source code string indicated by {{...}}. + /// The replacement is defined by a callback function. + string replaceSourceCodeMarkers(const string& nodeName, const string& soureCode, std::function lambda) const; + + /// Get the MDL language versing marker: {{MDL_VERSION_SUFFIX}}. + const string getMdlVersionSuffixMarker() const; }; namespace Type diff --git a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp index 0a2004cd71..59b488c875 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp @@ -4,6 +4,7 @@ // #include +#include #include #include @@ -29,6 +30,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& mdlSyntax = static_cast(shadergen.getSyntax()); // Emit functions for all child nodes shadergen.emitFunctionDefinitions(*_rootGraph, context, stage); @@ -146,7 +148,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { const string result = shadergen.getUpstreamResult(output, context); - shadergen.emitLine(resultVariableName + ".mxp_" + output->getName() + " = " + result, stage); + shadergen.emitLine(resultVariableName + mdlSyntax.modifyPortName(output->getName()) + " = " + result, stage); } shadergen.emitLine("return " + resultVariableName, stage); } diff --git a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp index 80c449e507..2dab721e24 100644 --- a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -46,6 +47,7 @@ void CompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); const bool isMaterialExpr = (_rootGraph->hasClassification(ShaderNode::Classification::CLOSURE) || _rootGraph->hasClassification(ShaderNode::Classification::SHADER)); @@ -83,7 +85,7 @@ void CompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { const string result = shadergen.getUpstreamResult(output, context); - shadergen.emitLine(resultVariableName + ".mxp_" + output->getName() + " = " + result, stage); + shadergen.emitLine(resultVariableName + "." + syntax.modifyPortName(output->getName()) + " = " + result, stage); } shadergen.emitLine("return " + resultVariableName, stage); } @@ -180,7 +182,7 @@ void CompoundNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& conte void CompoundNodeMdl::emitFunctionSignature(const ShaderNode&, GenContext& context, ShaderStage& stage) const { const ShaderGenerator& shadergen = context.getShaderGenerator(); - const Syntax& syntax = shadergen.getSyntax(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); if (!_returnStruct.empty()) { @@ -208,7 +210,7 @@ void CompoundNodeMdl::emitFunctionSignature(const ShaderNode&, GenContext& conte shadergen.emitScopeBegin(stage, Syntax::CURLY_BRACKETS); for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { - shadergen.emitLine(syntax.getTypeName(output->getType()) + " mxp_" + output->getName(), stage); + shadergen.emitLine(syntax.getTypeName(output->getType()) + " " + syntax.modifyPortName(output->getName()), stage); } shadergen.emitScopeEnd(stage, true); shadergen.emitLineBreak(stage); diff --git a/source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp new file mode 100644 index 0000000000..7215b90256 --- /dev/null +++ b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp @@ -0,0 +1,278 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include + +#include +#include +#include +#include +#include + +MATERIALX_NAMESPACE_BEGIN + +ShaderNodeImplPtr CustomCodeNodeMdl::create() +{ + return std::make_shared(); +} + +const string& CustomCodeNodeMdl::getQualifiedModuleName() const +{ + return _qualifiedModuleName; +} + +string CustomCodeNodeMdl::modifyPortName(const string& name, const MdlSyntax& syntax) const +{ + if (_useExternalSourceCode) + { + const StringSet& reservedWords = syntax.getReservedWords(); + if (reservedWords.find(name) == reservedWords.end()) + { + // Use existing MDL parameter names if they don't collide with a reserved word. + // This allows us to reference MDL existing functions without changing the MDL source code. + return name; + } + } + return syntax.modifyPortName(name); +} + +void CustomCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& context) +{ + SourceCodeNodeMdl::initialize(element, context); + if (_inlined) + { + _useExternalSourceCode = false; + initializeForInlineSourceCode(element, context); + } + else + { + _useExternalSourceCode = true; + initializeForExternalSourceCode(element, context); + } +} + +void CustomCodeNodeMdl::initializeForInlineSourceCode(const InterfaceElement& element, GenContext& context) +{ + const Implementation& impl = static_cast(element); + // Store the inline source because the `_functionSource` is used for the function call template string + // that matched the regular MaterialX to MDL function mapping. + _inlineSourceCode = impl.getAttribute("sourcecode"); + if (_inlineSourceCode.empty()) + { + throw ExceptionShaderGenError("No source code was specified for the implementation '" + impl.getName() + "'"); + } + if (_inlineSourceCode.find("//") != string::npos) + { + throw ExceptionShaderGenError("Source code contains unsupported comments '//', please use '/* comment */' instead in '" + impl.getName() + "'"); + } + + NodeDefPtr nodeDef = impl.getNodeDef(); + _inlineFunctionName = nodeDef->getName(); + _hash = std::hash{}(_inlineFunctionName); // make sure we emit the function definition only once + + const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); + // Construct the function call template string + initializeFunctionCallTemplateString(syntax, *nodeDef); + // Collect information about output names and defaults + initializeOutputDefaults(syntax, *nodeDef); +} + +void CustomCodeNodeMdl::initializeForExternalSourceCode(const InterfaceElement& element, GenContext& context) +{ + // Format the function source in a way that the ShaderCodeNodeMdl (the base class of the current one) can deal with it + const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); + const string uniformPrefix = syntax.getUniformQualifier() + " "; + + // Map `file` to a qualified MDL module name + const Implementation& impl = static_cast(element); + string moduleName = impl.getAttribute("file"); + if (moduleName.empty()) + { + throw ExceptionShaderGenError("No source file was specified for the implementation '" + impl.getName() + "'"); + } + if (_functionName.empty()) + { + throw ExceptionShaderGenError("No function name was specified for the implementation '" + impl.getName() + "'"); + } + + string mdlModuleName = replaceSubstrings(moduleName, { { "/", "::" } }); + if (!stringStartsWith(mdlModuleName, "::")) + { + mdlModuleName = "::" + mdlModuleName; + } + + if (!stringEndsWith(mdlModuleName, ".mdl")) + { + throw ExceptionShaderGenError("Referenced source file is not an MDL module: '" + moduleName + + "' used by implementation '" + impl.getName() + "'"); + } + else + { + mdlModuleName = mdlModuleName.substr(0, mdlModuleName.size() - 4); + } + const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); + _qualifiedModuleName = syntax.replaceSourceCodeMarkers(element.getName(), mdlModuleName, + [&versionSuffix, &syntax](const string& marker) + { + return marker == syntax.getMdlVersionSuffixMarker() ? versionSuffix : marker; + }); + + NodeDefPtr nodeDef = impl.getNodeDef(); + // Construct the function call template string + initializeFunctionCallTemplateString(syntax, *nodeDef); + // Collect information about output names and defaults + initializeOutputDefaults(syntax, *nodeDef); +} + +void CustomCodeNodeMdl::initializeFunctionCallTemplateString(const MdlSyntax& syntax, const NodeDef& nodeDef) +{ + // Construct the fully qualified function name for external functions + if (_useExternalSourceCode) + { + _functionSource = _qualifiedModuleName.substr(2) + "::" + _functionName + "("; + } + // or simple name for local functions + else + { + _functionSource = _inlineFunctionName + "("; + } + + // Function parameters + string delim = EMPTY_STRING; + for (const InputPtr& input : nodeDef.getInputs()) + { + string inputName = modifyPortName(input->getName(), syntax); + _functionSource += delim + inputName + ": {{" + input->getName() + "}}"; + if (delim == EMPTY_STRING) + delim = Syntax::COMMA + " "; + } + _functionSource += ")"; + _inlined = true; +} + +void CustomCodeNodeMdl::initializeOutputDefaults(const MdlSyntax&, const NodeDef& nodeDef) +{ + for (const OutputPtr& output : nodeDef.getOutputs()) + { + _outputDefaults.push_back(output->getValue()); + } +} + +void CustomCodeNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const +{ + // No source code printing for externally defined functions + if (_useExternalSourceCode) + { + return; + } + + const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); + shadergen.emitComment("generated code for implementation: '" + node.getImplementation().getName() + "'", stage); + + // Function return type + struct Field + { + string name; + string type_name; + string default_value; + }; + vector outputs; + size_t i = 0; + for (const ShaderOutput* output : node.getOutputs()) + { + string name = modifyPortName(output->getName(), syntax); + TypeDesc type = output->getType(); + const ValuePtr defaultValue = _outputDefaults[i]; + outputs.push_back({ + name, + syntax.getTypeName(type), + defaultValue ? syntax.getValue(type, *defaultValue.get()) : syntax.getDefaultValue(type) + }); + ++i; + } + + size_t numOutputs = node.getOutputs().size(); + string returnTypeName; + if (numOutputs == 1) + { + returnTypeName = outputs.back().type_name; + } + else + { + returnTypeName = _inlineFunctionName + "_return_type"; + shadergen.emitLine("struct " + returnTypeName, stage, false); + shadergen.emitScopeBegin(stage, Syntax::CURLY_BRACKETS); + for (const auto& field : outputs) + { + // ignore the default values here, they have to be initialized in the body + shadergen.emitLine(field.type_name + " " + field.name, stage); + } + shadergen.emitScopeEnd(stage, Syntax::CURLY_BRACKETS); + shadergen.emitLineEnd(stage, false); + } + // Signature + shadergen.emitString(returnTypeName + " " + _inlineFunctionName, stage); + { + // Function parameters + shadergen.emitScopeBegin(stage, Syntax::PARENTHESES); + size_t paramCount = node.getInputs().size(); + const string uniformPrefix = syntax.getUniformQualifier() + " "; + for (const ShaderInput* input : node.getInputs()) + { + const string& qualifier = input->isUniform() || input->getType() == Type::FILENAME ? uniformPrefix : EMPTY_STRING; + const string& type = syntax.getTypeName(input->getType()); + const string name = modifyPortName(input->getName(), syntax); + const string& delim = --paramCount == 0 ? EMPTY_STRING : Syntax::COMMA; + shadergen.emitString(" " + qualifier + type + " " + name + delim + Syntax::NEWLINE, stage); + } + shadergen.emitScopeEnd(stage, false, true); + } + { + // Function body + shadergen.emitScopeBegin(stage, Syntax::CURLY_BRACKETS); + + // Out variable initialization + shadergen.emitComment("initialize outputs:", stage); + for (const auto& field : outputs) + { + shadergen.emitLine(field.type_name + " " + field.name + " = " + field.default_value, stage); + } + + // User defined code + shadergen.emitComment("inlined shader source code:", stage); + shadergen.emitLine(_inlineSourceCode, stage, false); + + // Output packing + shadergen.emitComment("pack (in case of multiple outputs) and return outputs:", stage); + if (numOutputs == 1) + { + shadergen.emitLine("return " + outputs.back().name, stage, true); + } + else + { + // Return a constructor call of the return struct type + shadergen.emitString(" return " + returnTypeName + "(", stage); + string delim = EMPTY_STRING; + for (const auto& field : outputs) + { + shadergen.emitString(delim + field.name, stage); + if (delim == EMPTY_STRING) + delim = Syntax::COMMA + " "; + } + shadergen.emitString(")", stage); + shadergen.emitLineEnd(stage, true); + } + shadergen.emitScopeEnd(stage, false, true); + } + shadergen.emitLine("", stage, false); // empty line for spacing +} + +MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/CustomNodeMdl.h b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.h new file mode 100644 index 0000000000..daf4c873a5 --- /dev/null +++ b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.h @@ -0,0 +1,56 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef MATERIALX_CUSTOMNODEMDL_H +#define MATERIALX_CUSTOMNODEMDL_H + +#include + +MATERIALX_NAMESPACE_BEGIN + +class MdlSyntax; +class NodeDef; + +/// Node to handle user defined implementations in external MDL files or using the inline `sourcecode` attribute. +class MX_GENMDL_API CustomCodeNodeMdl : public SourceCodeNodeMdl +{ + public: + static ShaderNodeImplPtr create(); + void initialize(const InterfaceElement& element, GenContext& context) override; + void emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; + + /// Get the MDL qualified name of the externally references user module. + /// It's used for import statements and functions calls in the generated target code. + const string& getQualifiedModuleName() const; + + /// To avoid collisions with reserved names in MDL, input and output names are prefixed. + /// In the `sourcecode` case all inputs and outputs are prefixed so authors don't need knowledge about reserved words in MDL. + /// In the `file` and `function` case, only reserved names are prefixed to support existing MDL implementations without changes. + string modifyPortName(const string& name, const MdlSyntax& syntax) const; + + protected: + /// Initialize function for nodes that use the inline `sourcecode` attribute. + void initializeForInlineSourceCode(const InterfaceElement& element, GenContext& context); + + /// Initialize function for nodes that use the `file` and `function` attribute. + void initializeForExternalSourceCode(const InterfaceElement& element, GenContext& context); + + /// Computes the function call string with replacement markers use by base class. + void initializeFunctionCallTemplateString(const MdlSyntax& syntax, const NodeDef& node); + + /// Keep track of the default values needed for the inline `sourcecode` case. + void initializeOutputDefaults(const MdlSyntax& syntax, const NodeDef& node); + + std::vector _outputDefaults; ///< store default values of the node definition + + bool _useExternalSourceCode; // Indicates that `file` and `function` are used by this node implementation + string _inlineFunctionName; // Name of the functionDefinition to emit + string _inlineSourceCode; // The actual inline source code + string _qualifiedModuleName; // MDL qualified name derived from the `file` attribute +}; + +MATERIALX_NAMESPACE_END + +#endif diff --git a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h index fe88b2ce09..8363c6f4fa 100644 --- a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h @@ -18,7 +18,7 @@ class MX_GENMDL_API ImageNodeMdl : public SourceCodeNodeMdl using BASE = SourceCodeNodeMdl; public: - static const string FLIP_V; ///< the empty string "" + static const string FLIP_V; ///< name of the additional parameter "flip_v" static ShaderNodeImplPtr create(); diff --git a/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp index d13aa2871f..6891fc1778 100644 --- a/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ void MaterialNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& cont const ShaderGenerator& shadergen = context.getShaderGenerator(); const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); + const MdlSyntax& mdlSyntax = static_cast(shadergen.getSyntax()); // Emit the function call for upstream surface shader. const ShaderNode* surfaceshaderNode = surfaceshaderInput->getConnection()->getNode(); @@ -50,8 +52,7 @@ void MaterialNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& cont for (ShaderInput* input : node.getInputs()) { shadergen.emitString(delim, stage); - shadergen.emitString("mxp_", stage); - shadergen.emitString(input->getName(), stage); + shadergen.emitString(mdlSyntax.modifyPortName(input->getName()), stage); shadergen.emitString(": ", stage); shadergen.emitInput(input, context, stage); delim = ", "; diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp index f237a0db54..5547ae309d 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp @@ -13,51 +13,28 @@ #include #include +#include + #include MATERIALX_NAMESPACE_BEGIN -namespace // anonymous -{ -const string MARKER_MDL_VERSION_SUFFIX = "MDL_VERSION_SUFFIX"; - -StringVec replaceSourceCodeMarkers(const string& nodeName, const string& soureCode, std::function lambda) +ShaderNodeImplPtr SourceCodeNodeMdl::create() { - // An inline function call - // Replace tokens of the format "{{}}" - static const string prefix("{{"); - static const string postfix("}}"); - - size_t pos = 0; - size_t i = soureCode.find_first_of(prefix); - StringVec code; - while (i != string::npos) - { - code.push_back(soureCode.substr(pos, i - pos)); - size_t j = soureCode.find_first_of(postfix, i + 2); - if (j == string::npos) - { - throw ExceptionShaderGenError("Malformed inline expression in implementation for node " + nodeName); - } - const string marker = soureCode.substr(i + 2, j - i - 2); - code.push_back(lambda(marker)); - pos = j + 2; - i = soureCode.find_first_of(prefix, pos); - } - code.push_back(soureCode.substr(pos)); - return code; + return std::make_shared(); } -} // anonymous namespace - -ShaderNodeImplPtr SourceCodeNodeMdl::create() +void SourceCodeNodeMdl::resolveSourceCode(const InterfaceElement& /*element*/, GenContext& /*context*/) { - return std::make_shared(); + // Initialize without fetching the source code from file. + // The resolution of MDL modules is done by the MDL compiler when loading the generated source code. + // All references MDL modules must be accessible via MDL search paths set up by the consuming application. } void SourceCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& context) { SourceCodeNode::initialize(element, context); + const MdlSyntax& syntax = static_cast(context.getShaderGenerator().getSyntax()); const Implementation& impl = static_cast(element); NodeDefPtr nodeDef = impl.getNodeDef(); @@ -77,11 +54,10 @@ void SourceCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& const ShaderGenerator& shadergen = context.getShaderGenerator(); const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); - StringVec code = replaceSourceCodeMarkers(getName(), functionName, [&versionSuffix](const string& marker) + functionName = syntax.replaceSourceCodeMarkers(getName(), functionName, [&versionSuffix, syntax](const string& marker) { - return marker == MARKER_MDL_VERSION_SUFFIX ? versionSuffix : EMPTY_STRING; + return marker == syntax.getMdlVersionSuffixMarker() ? versionSuffix : EMPTY_STRING; }); - functionName = std::accumulate(code.begin(), code.end(), EMPTY_STRING); _returnStruct = functionName + "__result"; } else @@ -103,12 +79,13 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); if (_inlined) { + const MdlSyntax& syntax = static_cast(shadergenMdl.getSyntax()); const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); - StringVec code = replaceSourceCodeMarkers(node.getName(), _functionSource, - [&shadergenMdl, &context, &node, &versionSuffix](const string& marker) + string code = syntax.replaceSourceCodeMarkers(node.getName(), _functionSource, + [&shadergenMdl, &context, &node, &versionSuffix, syntax](const string& marker) { // Special handling for the version suffix of MDL source code modules. - if (marker == MARKER_MDL_VERSION_SUFFIX) + if (marker == syntax.getMdlVersionSuffixMarker()) { return versionSuffix; } @@ -131,7 +108,7 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con // Emit the struct multioutput. const string resultVariableName = node.getName() + "_result"; shadergen.emitLineBegin(stage); - shadergen.emitString(_returnStruct + " " + resultVariableName + " = ", stage); + shadergen.emitString("auto " + resultVariableName + " = ", stage); } else { @@ -141,10 +118,7 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con shadergen.emitString(" = ", stage); } - for (const string& c : code) - { - shadergen.emitString(c, stage); - } + shadergen.emitString(code, stage); shadergen.emitLineEnd(stage); } else @@ -156,7 +130,7 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con // Emit the struct multioutput. const string resultVariableName = node.getName() + "_result"; shadergen.emitLineBegin(stage); - shadergen.emitString(_returnStruct + " " + resultVariableName + " = ", stage); + shadergen.emitString("auto " + resultVariableName + " = ", stage); } else { diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h index 23c47e6249..7f595704cc 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h @@ -25,6 +25,7 @@ class MX_GENMDL_API SourceCodeNodeMdl : public SourceCodeNode void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; protected: + void resolveSourceCode(const InterfaceElement& element, GenContext& context) override; string _returnStruct; }; diff --git a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp index dd0444d129..8904d835f4 100644 --- a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -55,6 +56,7 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { const MdlShaderGenerator& shadergen = static_cast(context.getShaderGenerator()); + const MdlSyntax& mdlSyntax = static_cast(shadergen.getSyntax()); // Emit calls for the closure dependencies upstream from this node. shadergen.emitDependentFunctionCalls(node, context, stage, ShaderNode::Classification::CLOSURE); @@ -84,8 +86,7 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex for (ShaderInput* input : node.getInputs()) { shadergen.emitString(delim, stage); - shadergen.emitString("mxp_", stage); - shadergen.emitString(input->getName(), stage); + shadergen.emitString(mdlSyntax.modifyPortName(input->getName()), stage); shadergen.emitString(": ", stage); shadergen.emitInput(input, context, stage); delim = ", "; diff --git a/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp b/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp index 936edf9b46..32fc345354 100644 --- a/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp +++ b/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp @@ -25,6 +25,20 @@ ShaderNodeImplPtr SourceCodeNode::create() return std::make_shared(); } +void SourceCodeNode::resolveSourceCode(const InterfaceElement& element, GenContext& context) +{ + const Implementation& impl = static_cast(element); + + FilePath localPath = FilePath(impl.getActiveSourceUri()).getParentPath(); + _sourceFilename = context.resolveSourceFile(impl.getAttribute("file"), localPath); + _functionSource = readFile(_sourceFilename); + if (_functionSource.empty()) + { + throw ExceptionShaderGenError("Failed to get source code from file '" + _sourceFilename.asString() + + "' used by implementation '" + impl.getName() + "'"); + } +} + void SourceCodeNode::initialize(const InterfaceElement& element, GenContext& context) { ShaderNodeImpl::initialize(element, context); @@ -40,19 +54,13 @@ void SourceCodeNode::initialize(const InterfaceElement& element, GenContext& con _functionSource = impl.getAttribute("sourcecode"); if (_functionSource.empty()) { - FilePath localPath = FilePath(impl.getActiveSourceUri()).getParentPath(); - _sourceFilename = context.resolveSourceFile(impl.getAttribute("file"), localPath); - _functionSource = readFile(_sourceFilename); - if (_functionSource.empty()) - { - throw ExceptionShaderGenError("Failed to get source code from file '" + _sourceFilename.asString() + - "' used by implementation '" + impl.getName() + "'"); - } + resolveSourceCode(element, context); } // Find the function name to use // If no function is given the source will be inlined. _functionName = impl.getAttribute("function"); + _inlined = _functionName.empty(); if (!_inlined) { diff --git a/source/MaterialXGenShader/Nodes/SourceCodeNode.h b/source/MaterialXGenShader/Nodes/SourceCodeNode.h index a208185a8d..6169dc0f61 100644 --- a/source/MaterialXGenShader/Nodes/SourceCodeNode.h +++ b/source/MaterialXGenShader/Nodes/SourceCodeNode.h @@ -26,6 +26,9 @@ class MX_GENSHADER_API SourceCodeNode : public ShaderNodeImpl void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; protected: + /// Resolve the source file and read the source code during the initialization of the node. + virtual void resolveSourceCode(const InterfaceElement& element, GenContext& context); + bool _inlined; string _functionName; string _functionSource; diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index 4bec0016de..610b237163 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -270,7 +270,7 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so CHECK(returnValue == 0); } - if (!renderExec.empty()) // render if renderer is availabe + if (!renderExec.empty()) // render if renderer is available { std::string renderCommand = renderExec; From c1749600cd3f900876f87add0a71ca47e84296a7 Mon Sep 17 00:00:00 2001 From: JGamache-autodesk <56274617+JGamache-autodesk@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:17:43 -0500 Subject: [PATCH 45/76] Adjust Windows DLL search path for Python 3.8+ (#1440) Fixes #1439 Required by python/cpython#80266 --- python/MaterialX/__init__.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/python/MaterialX/__init__.py b/python/MaterialX/__init__.py index bd3999fe36..609e42eae6 100644 --- a/python/MaterialX/__init__.py +++ b/python/MaterialX/__init__.py @@ -1,3 +1,24 @@ +# Python 3.8+ on Windows: DLL search paths for dependent +# shared libraries +# Refs.: +# - https://github.com/python/cpython/issues/80266 +# - https://docs.python.org/3.8/library/os.html#os.add_dll_directory +import os +import sys +if sys.platform == "win32" and sys.version_info >= (3, 8): + import importlib.metadata + try: + importlib.metadata.version('MaterialX') + except importlib.metadata.PackageNotFoundError: + # On a non-pip installation, this file is in %INSTALLDIR%\python\MaterialX + # We need to add %INSTALLDIR%\bin to the DLL path. + mxdir = os.path.dirname(__file__) + pydir = os.path.split(mxdir)[0] + installdir = os.path.split(pydir)[0] + bindir = os.path.join(installdir, "bin") + if os.path.exists(bindir): + os.add_dll_directory(bindir) + from .main import * from .colorspace import * From e6e3ef550367bf05addcd0d7d3009a7b3337d73a Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Fri, 13 Dec 2024 18:04:21 -0800 Subject: [PATCH 46/76] Additional cleanup from OSL legacy closure removal (#2142) #2121 removed the OSL legacy closures - but we can simplify the data library installation a little more now they are gone. --- libraries/CMakeLists.txt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 6852090932..2b2097e203 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,10 +1,7 @@ if(NOT SKBUILD) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}" - PATTERN "CMakeLists.txt" EXCLUDE - PATTERN "pbrlib_genosl_impl.*" EXCLUDE) - install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.mtlx" - DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) + PATTERN "CMakeLists.txt" EXCLUDE) endif() set(MATERIALX_PYTHON_LIBRARIES_PATH "${MATERIALX_PYTHON_FOLDER_NAME}/${MATERIALX_INSTALL_STDLIB_PATH}") @@ -15,8 +12,5 @@ endif() if(MATERIALX_BUILD_PYTHON) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}" - PATTERN "CMakeLists.txt" EXCLUDE - PATTERN "pbrlib_genosl_impl.*" EXCLUDE) - install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.mtlx" - DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) + PATTERN "CMakeLists.txt" EXCLUDE) endif() From b1b94b658e88a90637fe65321818fb21bbc75670 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 13 Dec 2024 18:30:40 -0800 Subject: [PATCH 47/76] Extend fuzz testing to Examples folder (#2143) This changelist extends fuzz testing from Examples/StandardSurface to the full Examples folder, providing a broader set of input materials. --- .../MaterialXTest/MaterialXFormat/XmlIo.cpp | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/source/MaterialXTest/MaterialXFormat/XmlIo.cpp b/source/MaterialXTest/MaterialXFormat/XmlIo.cpp index 6d3bb7868f..fb6f824c6c 100644 --- a/source/MaterialXTest/MaterialXFormat/XmlIo.cpp +++ b/source/MaterialXTest/MaterialXFormat/XmlIo.cpp @@ -265,42 +265,45 @@ TEST_CASE("Comments and newlines", "[xmlio]") TEST_CASE("Fuzz testing", "[xmlio]") { mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); - mx::FilePath examplesPath = searchPath.find("resources/Materials/Examples/StandardSurface"); + mx::FilePath examplesPath = searchPath.find("resources/Materials/Examples"); std::mt19937 rng(0); std::uniform_int_distribution randChar(0, 255); - for (const mx::FilePath& filename : examplesPath.getFilesInDirectory(mx::MTLX_EXTENSION)) + for (const mx::FilePath& path : examplesPath.getSubDirectories()) { - // Read the example file into an XML string buffer. - const std::string origString = mx::readFile(examplesPath / filename); - REQUIRE(origString.size() > 0); - std::uniform_int_distribution randPos(0, origString.size() - 1); - - // Iterate over test runs. - for (size_t testRun = 0; testRun < 256; testRun++) + for (const mx::FilePath& filename : path.getFilesInDirectory(mx::MTLX_EXTENSION)) { - std::string editString = origString; + // Read the example file into an XML string buffer. + const std::string origString = mx::readFile(path / filename); + REQUIRE(origString.size() > 0); + std::uniform_int_distribution randPos(0, origString.size() - 1); - // Iterate over string edits. - for (size_t editIndex = 0; editIndex < 32; editIndex++) + // Iterate over test runs. + for (size_t testRun = 0; testRun < 256; testRun++) { - // Randomly alter one character in the document. - size_t charIndex = randPos(rng); - size_t newChar = randChar(rng); - editString[charIndex] = (char) newChar; - - // Attempt to interpret the edited string as a document, allowing only MaterialX exceptions. - mx::DocumentPtr doc = mx::createDocument(); - try - { - mx::readFromXmlString(doc, editString, searchPath); - doc->validate(); - } - catch (const mx::Exception&) + std::string editString = origString; + + // Iterate over string edits. + for (size_t editIndex = 0; editIndex < 32; editIndex++) { - // On a MaterialX exception, proceed to the next test run. - break; + // Randomly alter one character in the document. + size_t charIndex = randPos(rng); + size_t newChar = randChar(rng); + editString[charIndex] = (char) newChar; + + // Attempt to interpret the edited string as a document, allowing only MaterialX exceptions. + mx::DocumentPtr doc = mx::createDocument(); + try + { + mx::readFromXmlString(doc, editString, searchPath); + doc->validate(); + } + catch (const mx::Exception&) + { + // On a MaterialX exception, proceed to the next test run. + break; + } } } } From 81ed31d43026cc0e475bbdf9b040ccbc17ba60bc Mon Sep 17 00:00:00 2001 From: Chris Rydalch Date: Fri, 13 Dec 2024 21:52:58 -0600 Subject: [PATCH 48/76] Add support for geompropvalueuniform node (#2092) Adds a string-/filename-friendly primvar/geompropvalue node, as was proposed for 1.39. --- .../Specification/MaterialX.Proposals.md | 6 ----- .../Specification/MaterialX.Specification.md | 6 +++++ libraries/bxdf/usd_preview_surface.mtlx | 22 ++++++++++++++----- .../stdlib/genglsl/stdlib_genglsl_impl.mtlx | 5 ++++- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 5 ++++- .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 5 ++++- .../stdlib/genosl/stdlib_genosl_impl.mtlx | 5 ++++- libraries/stdlib/stdlib_defs.mtlx | 21 +++++++++++++----- .../stdlib/geometric/geompropvalue.mtlx | 8 +++---- .../MaterialXGenGlsl/GlslShaderGenerator.cpp | 1 + source/MaterialXGenMsl/MslShaderGenerator.cpp | 2 ++ .../MaterialXTest/MaterialXGenGlsl/GenGlsl.h | 2 +- source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 2 +- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 2 +- 14 files changed, 65 insertions(+), 27 deletions(-) diff --git a/documents/Specification/MaterialX.Proposals.md b/documents/Specification/MaterialX.Proposals.md index d387d28718..1aaa930923 100644 --- a/documents/Specification/MaterialX.Proposals.md +++ b/documents/Specification/MaterialX.Proposals.md @@ -219,12 +219,6 @@ In #1201 it was decided that separate periodic versions of all of the noises is * **`bump`**: Existing node, proposal to add a vector3 `bitangent` input - - -* **`geompropvalueuniform`**: the value of the specified uniform geometric property (defined using <geompropdef>) of the currently-bound geometry. This node's type must match that of the referenced geomprop. - * `geomprop` (uniform string): the geometric property to be referenced. - * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. - Note: when <geompropvalueuniform> is added, the text in the first paragraph of the Specification about Node Inputs should be revised to include "<geompropvalueuniform>" as an example of "or any other node whose output is explicitly declared to be uniform". diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 65027694d8..4ad29dc963 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -1091,6 +1091,12 @@ Standard Geometric nodes: * `geomprop` (uniform string): the geometric property to be referenced. * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. + + +* **`geompropvalueuniform`**: the value of the specified uniform geometric property (defined using <geompropdef>) of the currently-bound geometry. This node's type must match that of the referenced geomprop. + * `geomprop` (uniform string): the geometric property to be referenced. + * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. + Additionally, the `geomcolor` and `geompropvalue` nodes for color3/color4-type properties can take a `colorspace` attribute to declare what colorspace the color property value is in; the default is "none" for no colorspace declaration (and hence no colorspace conversion). diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index 4abdb91d9f..afc6954af9 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -62,8 +62,13 @@ - - + + + + + + + @@ -359,11 +364,18 @@ - + - - + + + + + + + + + diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index ad3a21e9cf..0625d17a25 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -157,7 +157,6 @@ - @@ -165,6 +164,10 @@ + + + + diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index 6ac2b862dd..05dbc995d6 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -159,7 +159,6 @@ - @@ -167,6 +166,10 @@ + + + + diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index 3cb99052cf..ea09880543 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -73,7 +73,6 @@ - @@ -81,6 +80,10 @@ + + + + diff --git a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx index db318976c5..bd2e2540b5 100644 --- a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -159,7 +159,6 @@ - @@ -167,6 +166,10 @@ + + + + diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 8f86a03b44..7e6be9b050 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -1355,11 +1355,6 @@ - - - - - @@ -1391,6 +1386,22 @@ + + + + + + + + + + + + + registerImplementation("IM_frame_float_" + GlslShaderGenerator::TARGET, HwFrameNode::create); diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index 9511fac7ba..d886d43e96 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -86,6 +86,8 @@ MslShaderGenerator::MslShaderGenerator() : registerImplementation(elementNames, GeomPropValueNodeMsl::create); registerImplementation("IM_geompropvalue_boolean_" + MslShaderGenerator::TARGET, GeomPropValueNodeMslAsUniform::create); registerImplementation("IM_geompropvalue_string_" + MslShaderGenerator::TARGET, GeomPropValueNodeMslAsUniform::create); + registerImplementation("IM_geompropvalue_filename_" + MslShaderGenerator::TARGET, GeomPropValueNodeMslAsUniform::create); + // registerImplementation("IM_frame_float_" + MslShaderGenerator::TARGET, HwFrameNode::create); diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h index 8d3e8c8720..9db87197f1 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h @@ -52,7 +52,7 @@ class GlslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester whiteList = { "volumeshader", "volumematerial", - "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", "IM_geompropvalue_filename", "IM_light_", "IM_point_light_", "IM_spot_light_", "IM_directional_light_" }; ShaderGeneratorTester::getImplementationWhiteList(whiteList); diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h index eea7b86acb..c159919773 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h @@ -71,7 +71,7 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester whiteList = { "displacementshader", "volumeshader", "surfacematerial", "volumematerial", - "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", "IM_geompropvalue_filename", "IM_light_", "IM_point_light_", "IM_spot_light_", "IM_directional_light_", "ND_surfacematerial", "ND_volumematerial" }; diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h index aa84a62218..d36c571a82 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h @@ -64,7 +64,7 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester whiteList = { "displacementshader", "volumeshader", - "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue" + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue", "IM_geompropvalueuniform" }; ShaderGeneratorTester::getImplementationWhiteList(whiteList); } From ecd3479b5f994794d90514c2ba52566ca722fde4 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 14 Dec 2024 10:14:14 -0800 Subject: [PATCH 49/76] Update minimum OSL version (#2144) This changelist updates the minimum OSL version in our documentation, mirroring recent codebase changes in https://github.com/AcademySoftwareFoundation/MaterialX/pull/2121. --- source/MaterialXTest/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/MaterialXTest/README.md b/source/MaterialXTest/README.md index 6de3064ec8..91b6da633e 100644 --- a/source/MaterialXTest/README.md +++ b/source/MaterialXTest/README.md @@ -62,7 +62,7 @@ When rendering tests are enabled through the `MATERIALX_TEST_RENDER` option, the - `MATERIALX_OSL_BINARY_OSLC`: Path to the OSL compiler binary (e.g. `oslc.exe`). - `MATERIALX_OSL_BINARY_TESTRENDER`: Path to the OSL test render binary (e.g. `testrender.exe`). - `MATERIALX_OSL_INCLUDE_PATH`: Path to the OSL shader include folder, which contains headers such as `stdosl.h`. - - OSL versions 1.9.10 and later are supported. + - OSL versions 1.12.6 and later are supported. - `MDL` : - Set the following build options to enable MDL support: - `MATERIALX_MDLC_EXECUTABLE`: Full path to the MDL compiler binary (e.g. `mdlc.exe'). From e5a9e359331382ba7b501e5bba5ba0a4d82d1caa Mon Sep 17 00:00:00 2001 From: Chris Rydalch Date: Sat, 14 Dec 2024 12:46:56 -0600 Subject: [PATCH 50/76] Enhance Worley noise with solid cells option (#2119) Adds a new control to `worley2d` and `worley3d`, which allows artists to choose between a distance for each cell (the default) and solid values for each cell. This allows for more patterns to be expressed in materials (i.e. flakes). --- .../Specification/MaterialX.Specification.md | 2 + libraries/stdlib/genglsl/lib/mx_noise.glsl | 141 +++++++++++++----- .../genglsl/mx_worleynoise2d_float.glsl | 4 +- .../genglsl/mx_worleynoise2d_vector2.glsl | 4 +- .../genglsl/mx_worleynoise2d_vector3.glsl | 4 +- .../genglsl/mx_worleynoise3d_float.glsl | 4 +- .../genglsl/mx_worleynoise3d_vector2.glsl | 4 +- .../genglsl/mx_worleynoise3d_vector3.glsl | 4 +- libraries/stdlib/stdlib_defs.mtlx | 6 + 9 files changed, 126 insertions(+), 47 deletions(-) diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 4ad29dc963..52763fd321 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -888,12 +888,14 @@ Standard Noise nodes: * **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. + * `style` (integer): the output style, one of "distance" (distance to the cell center), or "solid" (constant value for each cell). * `texcoord` (vector2): the 2D position at which the noise is evaluated. Default is to use the first set of texture coordinates. * **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. + * `style` (integer): the output style, one of "distance" (distance to the cell center), or "solid" (constant value for each cell). Default is "distance". * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. diff --git a/libraries/stdlib/genglsl/lib/mx_noise.glsl b/libraries/stdlib/genglsl/lib/mx_noise.glsl index 3212481d1d..b48475bc11 100644 --- a/libraries/stdlib/genglsl/lib/mx_noise.glsl +++ b/libraries/stdlib/genglsl/lib/mx_noise.glsl @@ -437,7 +437,7 @@ vec4 mx_fractal_noise_vec4(vec3 p, int octaves, float lacunarity, float diminish return vec4(c, f); } -float mx_worley_distance(vec2 p, int x, int y, int xoff, int yoff, float jitter, int metric) +vec2 mx_worley_cell_position(int x, int y, int xoff, int yoff, float jitter) { vec3 tmp = mx_cell_noise_vec3(vec2(x+xoff, y+yoff)); vec2 off = vec2(tmp.x, tmp.y); @@ -445,8 +445,24 @@ float mx_worley_distance(vec2 p, int x, int y, int xoff, int yoff, float jitter, off -= 0.5f; off *= jitter; off += 0.5f; + + return vec2(float(x), float(y)) + off; +} + +vec3 mx_worley_cell_position(int x, int y, int z, int xoff, int yoff, int zoff, float jitter) +{ + vec3 off = mx_cell_noise_vec3(vec3(x+xoff, y+yoff, z+zoff)); + + off -= 0.5f; + off *= jitter; + off += 0.5f; + + return vec3(float(x), float(y), float(z)) + off; +} - vec2 cellpos = vec2(float(x), float(y)) + off; +float mx_worley_distance(vec2 p, int x, int y, int xoff, int yoff, float jitter, int metric) +{ + vec2 cellpos = mx_worley_cell_position(x, y, xoff, yoff, jitter); vec2 diff = cellpos - p; if (metric == 2) return abs(diff.x) + abs(diff.y); // Manhattan distance @@ -458,13 +474,7 @@ float mx_worley_distance(vec2 p, int x, int y, int xoff, int yoff, float jitter, float mx_worley_distance(vec3 p, int x, int y, int z, int xoff, int yoff, int zoff, float jitter, int metric) { - vec3 off = mx_cell_noise_vec3(vec3(x+xoff, y+yoff, z+zoff)); - - off -= 0.5f; - off *= jitter; - off += 0.5f; - - vec3 cellpos = vec3(float(x), float(y), float(z)) + off; + vec3 cellpos = mx_worley_cell_position(x, y, z, xoff, yoff, zoff, jitter); vec3 diff = cellpos - p; if (metric == 2) return abs(diff.x) + abs(diff.y) + abs(diff.z); // Manhattan distance @@ -474,38 +484,53 @@ float mx_worley_distance(vec3 p, int x, int y, int z, int xoff, int yoff, int zo return dot(diff, diff); } -float mx_worley_noise_float(vec2 p, float jitter, int metric) +float mx_worley_noise_float(vec2 p, float jitter, int style, int metric) { int X, Y; + float dist; vec2 localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); float sqdist = 1e6f; // Some big number for jitter > 1 (not all GPUs may be IEEE) + vec2 minpos = vec2(0,0); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); - sqdist = min(sqdist, dist); + vec2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; + if(dist < sqdist) + { + sqdist = dist; + minpos = cellpos; + } } } - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; + if (style == 1) + return mx_cell_noise_float(minpos + p); + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -vec2 mx_worley_noise_vec2(vec2 p, float jitter, int metric) +vec2 mx_worley_noise_vec2(vec2 p, float jitter, int style, int metric) { int X, Y; vec2 localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); vec2 sqdist = vec2(1e6f, 1e6f); + vec2 minpos = vec2(0,0); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); + vec2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; if (dist < sqdist.x) { sqdist.y = sqdist.x; sqdist.x = dist; + minpos = cellpos; } else if (dist < sqdist.y) { @@ -513,26 +538,37 @@ vec2 mx_worley_noise_vec2(vec2 p, float jitter, int metric) } } } - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; + if (style == 1) + { + vec3 tmp = mx_cell_noise_vec3(minpos + p); + return vec2(tmp.x,tmp.y); + } + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -vec3 mx_worley_noise_vec3(vec2 p, float jitter, int metric) +vec3 mx_worley_noise_vec3(vec2 p, float jitter, int style, int metric) { int X, Y; vec2 localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); vec3 sqdist = vec3(1e6f, 1e6f, 1e6f); + vec2 minpos = vec2(0,0); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); + vec2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; if (dist < sqdist.x) { sqdist.z = sqdist.y; sqdist.y = sqdist.x; sqdist.x = dist; + minpos = cellpos; } else if (dist < sqdist.y) { @@ -545,16 +581,22 @@ vec3 mx_worley_noise_vec3(vec2 p, float jitter, int metric) } } } - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; + if (style == 1) + return mx_cell_noise_vec3(minpos + p); + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -float mx_worley_noise_float(vec3 p, float jitter, int metric) +float mx_worley_noise_float(vec3 p, float jitter, int style, int metric) { int X, Y, Z; vec3 localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); float sqdist = 1e6f; + vec3 minpos = vec3(0,0,0); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) @@ -562,20 +604,31 @@ float mx_worley_noise_float(vec3 p, float jitter, int metric) for (int z = -1; z <= 1; ++z) { float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); - sqdist = min(sqdist, dist); + vec3 cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; + if(dist < sqdist) + { + sqdist = dist; + minpos = cellpos; + } } } } - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; + if (style == 1) + return mx_cell_noise_float(minpos + p); + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -vec2 mx_worley_noise_vec2(vec3 p, float jitter, int metric) +vec2 mx_worley_noise_vec2(vec3 p, float jitter, int style, int metric) { int X, Y, Z; vec3 localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); vec2 sqdist = vec2(1e6f, 1e6f); + vec3 minpos = vec3(0,0,0); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) @@ -583,10 +636,12 @@ vec2 mx_worley_noise_vec2(vec3 p, float jitter, int metric) for (int z = -1; z <= 1; ++z) { float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); + vec3 cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; if (dist < sqdist.x) { sqdist.y = sqdist.x; sqdist.x = dist; + minpos = cellpos; } else if (dist < sqdist.y) { @@ -595,16 +650,25 @@ vec2 mx_worley_noise_vec2(vec3 p, float jitter, int metric) } } } - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; + if (style == 1) + { + vec3 tmp = mx_cell_noise_vec3(minpos + p); + return vec2(tmp.x,tmp.y); + } + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -vec3 mx_worley_noise_vec3(vec3 p, float jitter, int metric) +vec3 mx_worley_noise_vec3(vec3 p, float jitter, int style, int metric) { int X, Y, Z; vec3 localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); vec3 sqdist = vec3(1e6f, 1e6f, 1e6f); + vec3 minpos = vec3(0,0,0); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) @@ -612,11 +676,13 @@ vec3 mx_worley_noise_vec3(vec3 p, float jitter, int metric) for (int z = -1; z <= 1; ++z) { float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); + vec3 cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; if (dist < sqdist.x) { sqdist.z = sqdist.y; sqdist.y = sqdist.x; sqdist.x = dist; + minpos = cellpos; } else if (dist < sqdist.y) { @@ -630,7 +696,12 @@ vec3 mx_worley_noise_vec3(vec3 p, float jitter, int metric) } } } - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; + if (style == 1) + return mx_cell_noise_vec3(minpos + p); + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } diff --git a/libraries/stdlib/genglsl/mx_worleynoise2d_float.glsl b/libraries/stdlib/genglsl/mx_worleynoise2d_float.glsl index 75368e4f38..a69bc80b0c 100644 --- a/libraries/stdlib/genglsl/mx_worleynoise2d_float.glsl +++ b/libraries/stdlib/genglsl/mx_worleynoise2d_float.glsl @@ -1,6 +1,6 @@ #include "lib/mx_noise.glsl" -void mx_worleynoise2d_float(vec2 texcoord, float jitter, out float result) +void mx_worleynoise2d_float(vec2 texcoord, float jitter, int style, out float result) { - result = mx_worley_noise_float(texcoord, jitter, 0); + result = mx_worley_noise_float(texcoord, jitter, style, 0); } diff --git a/libraries/stdlib/genglsl/mx_worleynoise2d_vector2.glsl b/libraries/stdlib/genglsl/mx_worleynoise2d_vector2.glsl index 1a63c0c220..fca38efbde 100644 --- a/libraries/stdlib/genglsl/mx_worleynoise2d_vector2.glsl +++ b/libraries/stdlib/genglsl/mx_worleynoise2d_vector2.glsl @@ -1,6 +1,6 @@ #include "lib/mx_noise.glsl" -void mx_worleynoise2d_vector2(vec2 texcoord, float jitter, out vec2 result) +void mx_worleynoise2d_vector2(vec2 texcoord, float jitter, int style, out vec2 result) { - result = mx_worley_noise_vec2(texcoord, jitter, 0); + result = mx_worley_noise_vec2(texcoord, jitter, style, 0); } diff --git a/libraries/stdlib/genglsl/mx_worleynoise2d_vector3.glsl b/libraries/stdlib/genglsl/mx_worleynoise2d_vector3.glsl index ee4ce42b58..2aff692834 100644 --- a/libraries/stdlib/genglsl/mx_worleynoise2d_vector3.glsl +++ b/libraries/stdlib/genglsl/mx_worleynoise2d_vector3.glsl @@ -1,6 +1,6 @@ #include "lib/mx_noise.glsl" -void mx_worleynoise2d_vector3(vec2 texcoord, float jitter, out vec3 result) +void mx_worleynoise2d_vector3(vec2 texcoord, float jitter, int style, out vec3 result) { - result = mx_worley_noise_vec3(texcoord, jitter, 0); + result = mx_worley_noise_vec3(texcoord, jitter, style, 0); } diff --git a/libraries/stdlib/genglsl/mx_worleynoise3d_float.glsl b/libraries/stdlib/genglsl/mx_worleynoise3d_float.glsl index 738d2f6a77..ad43dee954 100644 --- a/libraries/stdlib/genglsl/mx_worleynoise3d_float.glsl +++ b/libraries/stdlib/genglsl/mx_worleynoise3d_float.glsl @@ -1,6 +1,6 @@ #include "lib/mx_noise.glsl" -void mx_worleynoise3d_float(vec3 position, float jitter, out float result) +void mx_worleynoise3d_float(vec3 position, float jitter, int style, out float result) { - result = mx_worley_noise_float(position, jitter, 0); + result = mx_worley_noise_float(position, jitter, style, 0); } diff --git a/libraries/stdlib/genglsl/mx_worleynoise3d_vector2.glsl b/libraries/stdlib/genglsl/mx_worleynoise3d_vector2.glsl index 22bfe8d03d..c124d3a3eb 100644 --- a/libraries/stdlib/genglsl/mx_worleynoise3d_vector2.glsl +++ b/libraries/stdlib/genglsl/mx_worleynoise3d_vector2.glsl @@ -1,6 +1,6 @@ #include "lib/mx_noise.glsl" -void mx_worleynoise3d_vector2(vec3 position, float jitter, out vec2 result) +void mx_worleynoise3d_vector2(vec3 position, float jitter, int style, out vec2 result) { - result = mx_worley_noise_vec2(position, jitter, 0); + result = mx_worley_noise_vec2(position, jitter, style, 0); } diff --git a/libraries/stdlib/genglsl/mx_worleynoise3d_vector3.glsl b/libraries/stdlib/genglsl/mx_worleynoise3d_vector3.glsl index ac6f7121c6..b96086269c 100644 --- a/libraries/stdlib/genglsl/mx_worleynoise3d_vector3.glsl +++ b/libraries/stdlib/genglsl/mx_worleynoise3d_vector3.glsl @@ -1,6 +1,6 @@ #include "lib/mx_noise.glsl" -void mx_worleynoise3d_vector3(vec3 position, float jitter, out vec3 result) +void mx_worleynoise3d_vector3(vec3 position, float jitter, int style, out vec3 result) { - result = mx_worley_noise_vec3(position, jitter, 0); + result = mx_worley_noise_vec3(position, jitter, style, 0); } diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 7e6be9b050..6cebca7faf 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -1002,16 +1002,19 @@ + + + @@ -1022,16 +1025,19 @@ + + + From 13892cb13ed9d2850c2b70258a40713b0112d224 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 15 Dec 2024 10:18:35 -0800 Subject: [PATCH 51/76] Fix edge case with editor pasting (#2145) This changelist fixes the edge case of pasting with an empty copy buffer in the Graph Editor. Previously, this action would have an unintended effect on node positions, and it now has no impact on the graph. --- source/MaterialXGraphEditor/Graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index aa04339469..d0602e45ec 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -4045,8 +4045,8 @@ void Graph::drawGraph(ImVec2 mousePos) for (std::map::iterator iter = _copiedNodes.begin(); iter != _copiedNodes.end(); iter++) { copyUiNode(iter->first); + _addNewNode = true; } - _addNewNode = true; } else { From d4ee66c52b96ba581d94ef5160c79169111716c7 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 15 Dec 2024 10:59:13 -0800 Subject: [PATCH 52/76] Update changelog for recent work (#2146) --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ab737cbe6..16531b7a54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,12 @@ ### Added - Added support for the [Chiang Hair BSDF](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1968), with initial implementations in hardware shading languages and MDL. - Added support for the [Disney Principled](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2004) shading model, implemented as a language-independent graph. +- Added support for [ramp curve adjustments](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1884), using a graph-based ramp node with ten control points. +- Added support for [Worley noise with solid cells](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2119), opening up new artistic options for metal flake shaders. - Added support for [data library referencing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2054), enabling improved performance in shader generation. - Added support for [custom structure types](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1831) in MaterialX. - Added support for [functional equivalence](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2003) tests between MaterialX elements. +- Added support for [geompropvalueuniform nodes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2092), improving functional parity between MaterialX and USD. - Added support for [transmission effects](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2027) in the translation graph from Standard Surface to glTF PBR. - Added support for [coated emission](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2087) in the translation graph from Standard Surface to UsdPreviewSurface. - Added support for [Apple framework builds](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2020). @@ -20,6 +23,7 @@ ### Changed - Improved the performance of [graph traversal](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2023) by skipping edges that have already been visited. - Reduced duplication between the [MSL and GLSL implementations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2068) of nodes. +- Raised the [minimum OSL version](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2144) to v1.12.6 in OSL shader generation. ### Fixed - Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. From 31ca71b8ec77fc4336c4b30b51e5328e23daaefa Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 16 Dec 2024 11:26:31 -0800 Subject: [PATCH 53/76] Add null checks to UiPin methods (#2147) This changelist adds null checks to the UiPin::addConnection and UiPin::deleteConnection methods in the Graph Editor, providing additional protection against crashes. --- source/MaterialXGraphEditor/UiNode.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/MaterialXGraphEditor/UiNode.h b/source/MaterialXGraphEditor/UiNode.h index 06d0281676..e4ce11d5ed 100644 --- a/source/MaterialXGraphEditor/UiNode.h +++ b/source/MaterialXGraphEditor/UiNode.h @@ -85,6 +85,11 @@ class UiPin void addConnection(UiPinPtr pin) { + if (!pin) + { + return; + } + for (size_t i = 0; i < _connections.size(); i++) { if (_connections[i]->_pinId == pin->_pinId) @@ -97,6 +102,11 @@ class UiPin void deleteConnection(UiPinPtr pin) { + if (!pin) + { + return; + } + for (size_t i = 0; i < _connections.size(); i++) { if (_connections[i]->_pinId == pin->_pinId) @@ -115,7 +125,6 @@ class UiPin { pin->setConnected(false); } - return; } const std::vector& getConnections() From af74b61ec2acf81ffe5d063448a7b80c9f1fd7e1 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 16 Dec 2024 17:22:14 -0800 Subject: [PATCH 54/76] Add fallbacks for findUniform methods (#2150) This changelist adds fallbacks to the GlslMaterial::findUniform and MslMaterial::findUniform methods, allowing them to find matches for uniforms that don't yet have a full path. This addresses issue https://github.com/AcademySoftwareFoundation/MaterialX/issues/1782. --- source/MaterialXRenderGlsl/GlslMaterial.cpp | 7 +++++++ source/MaterialXRenderMsl/MslMaterial.mm | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index 064ab898ff..b80699750e 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -331,6 +331,13 @@ ShaderPort* GlslMaterial::findUniform(const std::string& path) const { return (port && stringEndsWith(port->getPath(), path)); }); + if (!port) + { + port = publicUniforms->find([path](ShaderPort* port) + { + return (port && stringEndsWith(path, port->getName())); + }); + } // Check if the uniform exists in the shader program if (port && !_glProgram->getUniformsList().count(port->getVariable())) diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm index eb13ea7900..c16cc0cc0e 100644 --- a/source/MaterialXRenderMsl/MslMaterial.mm +++ b/source/MaterialXRenderMsl/MslMaterial.mm @@ -292,6 +292,13 @@ { return (port && stringEndsWith(port->getPath(), path)); }); + if (!port) + { + port = publicUniforms->find([path](ShaderPort* port) + { + return (port && stringEndsWith(path, port->getName())); + }); + } // Check if the uniform exists in the shader program if (port && !_glProgram->getUniformsList().count( From 1d6f148f33ad410dc9ebb9e372e03bf22e5b609f Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Fri, 20 Dec 2024 10:08:29 -0800 Subject: [PATCH 55/76] Refine MaterialX render module build configuration (#1970) Add more refined control over building MaterialX render modules. Specifically USD only needs the core render module in some build configurations (iOS). Also add a guard to ensure that MaterialXGenGlsl is built if MaterialXGenMsl is built, because of the dependency in the data library. USD uses `MaterialX::GlslShaderGenerator::TARGET` to locate those resources. --- CMakeLists.txt | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 569cceeebd..bfba3a25bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ option(MATERIALX_BUILD_GEN_OSL "Build the OSL shader generator back-end." ON) option(MATERIALX_BUILD_GEN_MDL "Build the MDL shader generator back-end." ON) option(MATERIALX_BUILD_GEN_MSL "Build the MSL shader generator back-end." ON) option(MATERIALX_BUILD_RENDER "Build the MaterialX Render modules." ON) +option(MATERIALX_BUILD_RENDER_PLATFORMS "Build platform-specific render modules for each shader generator." ON) option(MATERIALX_BUILD_OIIO "Build OpenImageIO support for MaterialXRender." OFF) option(MATERIALX_BUILD_TESTS "Build unit tests." OFF) option(MATERIALX_BUILD_BENCHMARK_TESTS "Build benchmark tests." OFF) @@ -104,6 +105,11 @@ if (MATERIALX_BUILD_JS) set(MATERIALX_BUILD_TESTS OFF) endif() +if(MATERIALX_BUILD_GEN_MSL) + # All hardware shading languages currently depend on the GLSL shader generator. + set(MATERIALX_BUILD_GEN_GLSL ON) +endif() + set(MATERIALX_PYTHON_VERSION "" CACHE STRING "Python version to be used in building the MaterialX Python package (e.g. '3.9').") set(MATERIALX_PYTHON_EXECUTABLE "" CACHE FILEPATH @@ -160,6 +166,7 @@ mark_as_advanced(MATERIALX_BUILD_GEN_OSL) mark_as_advanced(MATERIALX_BUILD_GEN_MDL) mark_as_advanced(MATERIALX_BUILD_GEN_MSL) mark_as_advanced(MATERIALX_BUILD_RENDER) +mark_as_advanced(MATERIALX_BUILD_RENDER_PLATFORMS) mark_as_advanced(MATERIALX_BUILD_OIIO) mark_as_advanced(MATERIALX_BUILD_BENCHMARK_TESTS) mark_as_advanced(MATERIALX_BUILD_SHARED_LIBS) @@ -465,15 +472,22 @@ endif() # Add rendering and viewer subdirectories if(MATERIALX_BUILD_RENDER) add_subdirectory(source/MaterialXRender) - add_subdirectory(source/MaterialXRenderHw) - if (MATERIALX_BUILD_GEN_GLSL) - add_subdirectory(source/MaterialXRenderGlsl) - endif() - if (APPLE AND MATERIALX_BUILD_GEN_MSL) - add_subdirectory(source/MaterialXRenderMsl) - endif() - if (MATERIALX_BUILD_GEN_OSL) - add_subdirectory(source/MaterialXRenderOsl) + if(MATERIALX_BUILD_RENDER_PLATFORMS) + set(MATERIALX_BUILD_RENDER_HW OFF) + if(MATERIALX_BUILD_GEN_GLSL AND NOT MATERIALX_BUILD_APPLE_EMBEDDED) + set(MATERIALX_BUILD_RENDER_HW ON) + add_subdirectory(source/MaterialXRenderGlsl) + endif() + if(MATERIALX_BUILD_GEN_MSL AND APPLE) + set(MATERIALX_BUILD_RENDER_HW ON) + add_subdirectory(source/MaterialXRenderMsl) + endif() + if(MATERIALX_BUILD_RENDER_HW) + add_subdirectory(source/MaterialXRenderHw) + endif() + if(MATERIALX_BUILD_GEN_OSL) + add_subdirectory(source/MaterialXRenderOsl) + endif() endif() if(MATERIALX_BUILD_VIEWER) add_subdirectory(source/MaterialXView) From cab1b26f7cae9d70ac1c301dc9baa4edc1944d2d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 20 Dec 2024 13:16:31 -0800 Subject: [PATCH 56/76] Improve specification of geometric spaces (#2151) - Centralize the list of supported geometric spaces in a new `Geometric Spaces` section. - Remove `tangent` and `common` from the list of geometric spaces, as they are not supported in the codebase, and more design discussion would be needed to propose their addition. - Remove the `space` input from `heighttonormal`, as it's not supported in the codebase, and more design discussion would be needed to propose its addition. --- .../Specification/MaterialX.Specification.md | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 52763fd321..2e67024c58 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -56,6 +56,7 @@ This document describes the core MaterialX specification. Companion documents [   [Noise Nodes](#noise-nodes)   [Shape Nodes](#shape-nodes)   [Geometric Nodes](#geometric-nodes) +   [Geometric Spaces](#geometric-spaces)   [Application Nodes](#application-nodes)  [Standard Operator Nodes](#standard-operator-nodes) @@ -1050,23 +1051,23 @@ Standard Geometric nodes: * **`position`**: the coordinates associated with the currently-processed data, as defined in a specific coordinate space. This node must be of type vector3. - * `space` (uniform string): the name of the coordinate space in which the position is defined. Default is "object", see below for details. + * `space` (uniform string): the name of the coordinate space in which the position is defined. Default is "object", see [Geometric Spaces](#geometric-spaces) for supported options. * **`normal`**: the geometric normal associated with the currently-processed data, as defined in a specific coordinate space. This node must be of type vector3. - * `space` (uniform string): the name of the coordinate space in which the normal vector is defined. Default is "object", see below for details. + * `space` (uniform string): the name of the coordinate space in which the normal vector is defined. Default is "object", see [Geometric Spaces](#geometric-spaces) for supported options. * **`tangent`**: the geometric tangent vector associated with the currently-processed data, as defined in a specific coordinate space. This node must be of type vector3. - * `space` (uniform string): the name of the coordinate space in which the tangent vector is defined. Default is "object", see below for details. + * `space` (uniform string): the name of the coordinate space in which the tangent vector is defined. Default is "object", see [Geometric Spaces](#geometric-spaces) for supported options. * `index` (uniform integer): the index of the texture coordinates against which the tangent is computed. The default index is 0. * **`bitangent`**: the geometric bitangent vector associated with the currently-processed data, as defined in a specific coordinate space. This node must be of type vector3. - * `space` (uniform string): the name of the coordinate space in which the bitangent vector is defined. Default is "object", see below for details. + * `space` (uniform string): the name of the coordinate space in which the bitangent vector is defined. Default is "object", see [Geometric Spaces](#geometric-spaces) for supported options. * `index` (uniform integer): the index of the texture coordinates against which the tangent is computed. The default index is 0. @@ -1102,17 +1103,13 @@ Standard Geometric nodes: Additionally, the `geomcolor` and `geompropvalue` nodes for color3/color4-type properties can take a `colorspace` attribute to declare what colorspace the color property value is in; the default is "none" for no colorspace declaration (and hence no colorspace conversion). - +#### Geometric Spaces The following values are supported by the `space` inputs of Geometric nodes and when transforming from one space to another: - * "model": The local coordinate space of the geometry, before any local deformations or global transforms have been applied. * "object": The local coordinate space of the geometry, after local deformations have been applied, but before any global transforms. * "world": The global coordinate space of the geometry, after local deformations and global transforms have been applied. -* "tangent": A coordinate space defined by the tangent, bitangent and normal vectors of the geometry. - -Applications may also reference other renderer-specific named spaces, at the expense of portability. @@ -1343,21 +1340,21 @@ Math nodes have one or two spatially-varying inputs, and are used to perform a m * **`transformpoint`**: transform the incoming vector3 coordinate from one specified space to another; cannot be used on any other stream type. * `in` (vector3): the input coordinate vector. - * `fromspace` (uniform string): the name of a vector space understood by the rendering target to transform the `in` point from; may be empty to specify the renderer's working or "common" space. + * `fromspace` (uniform string): the name of a vector space understood by the rendering target to transform the `in` point from; see [Geometric Spaces](#geometric-spaces) for supported options. * `tospace` (uniform string): the name of a vector space understood by the rendering target for the space to transform the `in` point to. * **`transformvector`**: transform the incoming vector3 vector from one specified space to another; cannot be used on any other stream type. * `in` (vector3): the input vector. - * `fromspace` (uniform string): the name of a vector space understood by the rendering target to transform the `in` point from; may be empty to specify the renderer's working or "common" space. + * `fromspace` (uniform string): the name of a vector space understood by the rendering target to transform the `in` point from; see [Geometric Spaces](#geometric-spaces) for supported options. * `tospace` (uniform string): the name of a vector space understood by the rendering target for the space to transform the `in` point to. * **`transformnormal`**: transform the incoming vector3 normal from one specified space to another; cannot be used on any other stream type. * `in` (vector3): the input normal vector; default is (0,0,1). - * `fromspace` (uniform string): the name of a vector space understood by the rendering target to transform the `in` point from; may be empty to specify the renderer's working or "common" space. + * `fromspace` (uniform string): the name of a vector space understood by the rendering target to transform the `in` point from; see [Geometric Spaces](#geometric-spaces) for supported options. * `tospace` (uniform string): the name of a vector space understood by the rendering target for the space to transform the `in` point to. @@ -1782,7 +1779,6 @@ Convolution nodes have one input named "in", and apply a defined convolution fun * **`heighttonormal`**: convert a scalar height map to a normal map of type vector3. * `in` (float): the input value or nodename * `scale` (float): the scale of normal map deflections relative to the gradient of the height map. Default is 1.0. - * `space` (string): the space in which the output normal map vector should be; defaults to "tangent". From 73f5f393f61f4f62dc99fa76d466d1e5d74a7640 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 20 Dec 2024 15:44:01 -0800 Subject: [PATCH 57/76] Updates for OSL shader generation (#2153) This changelist updates OSL shader generation to account for recent feature contributions (e.g. worleynoise, geompropvalueuniform), allowing render comparisons to complete successfully. --- libraries/stdlib/genosl/mx_worleynoise2d_float.osl | 2 +- libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl | 2 +- libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl | 2 +- libraries/stdlib/genosl/mx_worleynoise3d_float.osl | 2 +- libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl | 2 +- libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl | 2 +- source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp | 3 ++- 7 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/stdlib/genosl/mx_worleynoise2d_float.osl b/libraries/stdlib/genosl/mx_worleynoise2d_float.osl index a6289c8a01..bb7615db9f 100644 --- a/libraries/stdlib/genosl/mx_worleynoise2d_float.osl +++ b/libraries/stdlib/genosl/mx_worleynoise2d_float.osl @@ -1,4 +1,4 @@ -void mx_worleynoise2d_float(vector2 texcoord, float jitter, output float result) +void mx_worleynoise2d_float(vector2 texcoord, float jitter, int style, output float result) { result = mx_worley_noise_float(texcoord, jitter, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl b/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl index b523187da0..c96c278cc6 100644 --- a/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl +++ b/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl @@ -1,4 +1,4 @@ -void mx_worleynoise2d_vector2(vector2 texcoord, float jitter, output vector2 result) +void mx_worleynoise2d_vector2(vector2 texcoord, float jitter, int style, output vector2 result) { result = mx_worley_noise_vector2(texcoord, jitter, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl b/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl index b5f468a8c9..bd63e23ccc 100644 --- a/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl +++ b/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl @@ -1,4 +1,4 @@ -void mx_worleynoise2d_vector3(vector2 texcoord, float jitter, output vector result) +void mx_worleynoise2d_vector3(vector2 texcoord, float jitter, int style, output vector result) { result = mx_worley_noise_vector3(texcoord, jitter, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise3d_float.osl b/libraries/stdlib/genosl/mx_worleynoise3d_float.osl index b328fc7522..bfa7e209f7 100644 --- a/libraries/stdlib/genosl/mx_worleynoise3d_float.osl +++ b/libraries/stdlib/genosl/mx_worleynoise3d_float.osl @@ -1,4 +1,4 @@ -void mx_worleynoise3d_float(vector position, float jitter, output float result) +void mx_worleynoise3d_float(vector position, float jitter, int style, output float result) { result = mx_worley_noise_float(position, jitter, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl b/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl index 69c16bbc46..a83e5c4123 100644 --- a/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl +++ b/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl @@ -1,4 +1,4 @@ -void mx_worleynoise3d_vector2(vector position, float jitter, output vector2 result) +void mx_worleynoise3d_vector2(vector position, float jitter, int style, output vector2 result) { result = mx_worley_noise_vector2(position, jitter, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl b/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl index d06d1f6bef..34a1540689 100644 --- a/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl +++ b/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl @@ -1,4 +1,4 @@ -void mx_worleynoise3d_vector3(vector position, float jitter, output vector result) +void mx_worleynoise3d_vector3(vector position, float jitter, int style, output vector result) { result = mx_worley_noise_vector3(position, jitter, 0); } diff --git a/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp b/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp index 05c83ae82e..a682874126 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp +++ b/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp @@ -65,7 +65,8 @@ TEST_CASE("GenReference: OSL Reference", "[genreference]") // Generate reference shaders. // Ignore the following nodes: const mx::StringSet ignoreNodeList = { "surfacematerial", "volumematerial", - "constant_filename", "dot_filename"}; + "constant_filename", "dot_filename", + "geompropvalueuniform_filename" }; bool failedGeneration = false; for (const mx::NodeDefPtr& nodedef : stdlib->getNodeDefs()) From 894b479dbfe300bd52284b9b7ed038d75623dbe6 Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Sun, 29 Dec 2024 09:49:02 -0800 Subject: [PATCH 58/76] Update OSL Worley noise implementation (#2155) #2119 added a new `style` parameter to Worley noise - this PR adds corresponding support to the OSL backend - mirroring behavior from the GLSL code generator. --- libraries/stdlib/genosl/include/mx_funcs.h | 269 ++++++++++++------ .../stdlib/genosl/mx_worleynoise2d_float.osl | 2 +- .../genosl/mx_worleynoise2d_vector2.osl | 2 +- .../genosl/mx_worleynoise2d_vector3.osl | 2 +- .../stdlib/genosl/mx_worleynoise3d_float.osl | 2 +- .../genosl/mx_worleynoise3d_vector2.osl | 2 +- .../genosl/mx_worleynoise3d_vector3.osl | 2 +- 7 files changed, 195 insertions(+), 86 deletions(-) diff --git a/libraries/stdlib/genosl/include/mx_funcs.h b/libraries/stdlib/genosl/include/mx_funcs.h index 6d371575a6..cd5b27cb5f 100644 --- a/libraries/stdlib/genosl/include/mx_funcs.h +++ b/libraries/stdlib/genosl/include/mx_funcs.h @@ -356,36 +356,41 @@ vector4 mx_fbm(point position, int octaves, float lacunarity, float diminish, st return vector4 (c[0], c[1], c[2], f); } +vector2 mx_worley_cell_position(int x, int y, int xoff, int yoff, float jitter) +{ + vector tmp = cellnoise(x+xoff, y+yoff); + vector2 off = vector2(tmp.x, tmp.y); + off -= 0.5; + off *= jitter; + off += 0.5; + return vector2(x, y) + off; +} -void mx_split_float(output float x, output int ix) +vector mx_worley_cell_position(int x, int y, int z, int xoff, int yoff, int zoff, float jitter) { - ix = int(floor(x)); - x -= ix; + vector off = cellnoise(vector(x+xoff, y+yoff, z+zoff)); + off -= 0.5; + off *= jitter; + off += 0.5; + return vector(x,y,z) + off; } float mx_worley_distance(vector2 p, int x, int y, int X, int Y, float jitter, int metric) { - vector o = cellnoise(x+X, y+Y); - o = (o - .5)*jitter + .5; - float cposx = x + o[0]; - float cposy = y + o[1]; - float diffx = cposx - p.x; - float diffy = cposy - p.y; + vector2 cellpos = mx_worley_cell_position(x,y,X,Y,jitter); + vector2 diff = cellpos - p; if (metric == 2) - return abs(diffx) + abs(diffy); // Manhattan distance + return abs(diff.x) + abs(diff.y); // Manhattan distance if (metric == 3) - return max(abs(diffx), abs(diffy)); // Chebyshev distance - return diffx*diffx + diffy*diffy; // Euclidean or distance^2 + return max(abs(diff.x), abs(diff.y)); // Chebyshev distance + return diff.x*diff.x + diff.y*diff.y; // Euclidean or distance^2 } float mx_worley_distance(vector p, int x, int y, int z, int X, int Y, int Z, float jitter, int metric) { - vector o = cellnoise(vector(x+X, y+Y, z+Z)); - o = (o - .5)*jitter + .5; - vector cpos = vector(x, y, z) + o; - vector diff = cpos - p; - + vector cellpos = mx_worley_cell_position(x,y,z,X,Y,Z,jitter); + vector diff = cellpos - p; if (metric == 2) return abs(diff[0]) + abs(diff[1]); // Manhattan distance if (metric == 3) @@ -425,140 +430,244 @@ void mx_sort_distance(float dist, output vector result) } } -float mx_worley_noise_float(vector2 p, float jitter, int metric) +// return floor as well as the fractional remainder +float mx_floorfrac(float x, output int i) +{ + i = (int)floor(x); + return x - float(i); +} + +float mx_worley_noise_float(vector2 p, float jitter, int style, int metric) { int X, Y; - vector2 seed = p; - float result = 1e6; + float sqdist = 1e6; + vector2 localpos = vector2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); + vector2 minpos = vector2(0.0, 0.0); - mx_split_float(seed.x, X); - mx_split_float(seed.y, Y); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { - float d = mx_worley_distance(seed, x, y, X, Y, jitter, metric); - result = min(result, d); + float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); + vector2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; + if (dist < sqdist) + { + sqdist = dist; + minpos = cellpos; + } } } - if (metric == 0) - result = sqrt(result); - return result; + if (style == 1) + { + vector2 tmpP = minpos + p; + return cellnoise(tmpP.x, tmpP.y); + } + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -vector2 mx_worley_noise_vector2(vector2 p, float jitter, int metric) +vector2 mx_worley_noise_vector2(vector2 p, float jitter, int style, int metric) { int X, Y; - vector2 seed = p; - vector2 result = vector2(1e6, 1e6); + vector2 sqdist = vector2(1e6, 1e6); + vector2 localpos = vector2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); + vector2 minpos = vector2(0.0, 0.0); - mx_split_float(seed.x, X); - mx_split_float(seed.y, Y); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { - float d = mx_worley_distance(seed, x, y, X, Y, jitter, metric); - mx_sort_distance(d, result); + float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); + vector2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; + if (dist < sqdist.x) + { + sqdist.y = sqdist.x; + sqdist.x = dist; + minpos = cellpos; + } + else if (dist < sqdist.y) + { + sqdist.y = dist; + } } } - if (metric == 0) - result = sqrt(result); - return result; + + if (style == 1) + { + vector2 tmpP = minpos + p; + vector tmp = cellnoise(tmpP.x, tmpP.y); + return vector2(tmp.x, tmp.y); + } + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -vector mx_worley_noise_vector3(vector2 p, float jitter, int metric) +vector mx_worley_noise_vector3(vector2 p, float jitter, int style, int metric) { int X, Y; - vector2 seed = p; - vector result = vector(1e6, 1e6, 1e6); + vector sqdist = vector(1e6, 1e6, 1e6); + vector2 localpos = vector2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); + vector2 minpos = vector2(0.0, 0.0); - mx_split_float(seed.x, X); - mx_split_float(seed.y, Y); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { - float d = mx_worley_distance(seed, x, y, X, Y, jitter, metric); - mx_sort_distance(d, result); + float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); + vector2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; + if (dist < sqdist.x) + { + sqdist.z = sqdist.y; + sqdist.y = sqdist.x; + sqdist.x = dist; + minpos = cellpos; + } + else if (dist < sqdist.y) + { + sqdist.z = sqdist.y; + sqdist.y = dist; + } + else if (dist < sqdist.z) + { + sqdist.z = dist; + } } } - if (metric == 0) - result = sqrt(result); - return result; + if (style == 1) + { + vector2 tmpP = minpos + p; + return cellnoise(tmpP.x, tmpP.y); + } + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -float mx_worley_noise_float(vector p, float jitter, int metric) +float mx_worley_noise_float(vector p, float jitter, int style, int metric) { int X, Y, Z; vector seed = p; - float result = 1e6; - - mx_split_float(seed[0], X); - mx_split_float(seed[1], Y); - mx_split_float(seed[2], Z); + float sqdist = 1e6; + vector localpos = vector(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); + vector minpos = vector(0.0, 0.0, 0.0); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { for (int z = -1; z <= 1; ++z) { - float d = mx_worley_distance(seed, x, y, z, X, Y, Z, jitter, metric); - result = min(result, d); + float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); + vector cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; + if(dist < sqdist) + { + sqdist = dist; + minpos = cellpos; + } } } } - if (metric == 0) - result = sqrt(result); - return result; + if (style == 1) + return cellnoise(minpos + p); + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -vector2 mx_worley_noise_vector2(vector p, float jitter, int metric) +vector2 mx_worley_noise_vector2(vector p, float jitter, int style, int metric) { int X, Y, Z; - vector seed = p; - vector2 result = vector2(1e6, 1e6); + vector2 sqdist = vector2(1e6, 1e6); + vector localpos = vector(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); + vector minpos = vector(0.0, 0.0, 0.0); - mx_split_float(seed[0], X); - mx_split_float(seed[1], Y); - mx_split_float(seed[2], Z); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { for (int z = -1; z <= 1; ++z) { - float d = mx_worley_distance(seed, x, y, z, X, Y, Z, jitter, metric); - mx_sort_distance(d, result); + float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); + vector cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; + if (dist < sqdist.x) + { + sqdist.y = sqdist.x; + sqdist.x = dist; + minpos = cellpos; + } + else if (dist < sqdist.y) + { + sqdist.y = dist; + } } } } - if (metric == 0) - result = sqrt(result); - return result; + if (style == 1) + { + vector tmp = cellnoise(minpos + p); + return vector2(tmp.x,tmp.y); + } + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } -vector mx_worley_noise_vector3(vector p, float jitter, int metric) +vector mx_worley_noise_vector3(vector p, float jitter, int style, int metric) { int X, Y, Z; - vector result = 1e6; - vector seed = p; + vector sqdist = 1e6; + vector localpos = vector(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); + vector minpos = vector(0.0, 0.0, 0.0); - mx_split_float(seed[0], X); - mx_split_float(seed[1], Y); - mx_split_float(seed[2], Z); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { for (int z = -1; z <= 1; ++z) { - float d = mx_worley_distance(seed, x, y, z, X, Y, Z, jitter, metric); - mx_sort_distance(d, result); + float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); + vector cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; + if (dist < sqdist.x) + { + sqdist.z = sqdist.y; + sqdist.y = sqdist.x; + sqdist.x = dist; + minpos = cellpos; + } + else if (dist < sqdist.y) + { + sqdist.z = sqdist.y; + sqdist.y = dist; + } + else if (dist < sqdist.z) + { + sqdist.z = dist; + } } } } - if (metric == 0) - result = sqrt(result); - return result; + if (style == 1) + return cellnoise(minpos + p); + else + { + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; + } } diff --git a/libraries/stdlib/genosl/mx_worleynoise2d_float.osl b/libraries/stdlib/genosl/mx_worleynoise2d_float.osl index bb7615db9f..1b98e316af 100644 --- a/libraries/stdlib/genosl/mx_worleynoise2d_float.osl +++ b/libraries/stdlib/genosl/mx_worleynoise2d_float.osl @@ -1,4 +1,4 @@ void mx_worleynoise2d_float(vector2 texcoord, float jitter, int style, output float result) { - result = mx_worley_noise_float(texcoord, jitter, 0); + result = mx_worley_noise_float(texcoord, jitter, style, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl b/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl index c96c278cc6..6d6be62d22 100644 --- a/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl +++ b/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl @@ -1,4 +1,4 @@ void mx_worleynoise2d_vector2(vector2 texcoord, float jitter, int style, output vector2 result) { - result = mx_worley_noise_vector2(texcoord, jitter, 0); + result = mx_worley_noise_vector2(texcoord, jitter, style, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl b/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl index bd63e23ccc..00ae3a5eae 100644 --- a/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl +++ b/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl @@ -1,4 +1,4 @@ void mx_worleynoise2d_vector3(vector2 texcoord, float jitter, int style, output vector result) { - result = mx_worley_noise_vector3(texcoord, jitter, 0); + result = mx_worley_noise_vector3(texcoord, jitter, style, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise3d_float.osl b/libraries/stdlib/genosl/mx_worleynoise3d_float.osl index bfa7e209f7..0386075740 100644 --- a/libraries/stdlib/genosl/mx_worleynoise3d_float.osl +++ b/libraries/stdlib/genosl/mx_worleynoise3d_float.osl @@ -1,4 +1,4 @@ void mx_worleynoise3d_float(vector position, float jitter, int style, output float result) { - result = mx_worley_noise_float(position, jitter, 0); + result = mx_worley_noise_float(position, jitter, style, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl b/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl index a83e5c4123..314dde0d45 100644 --- a/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl +++ b/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl @@ -1,4 +1,4 @@ void mx_worleynoise3d_vector2(vector position, float jitter, int style, output vector2 result) { - result = mx_worley_noise_vector2(position, jitter, 0); + result = mx_worley_noise_vector2(position, jitter, style, 0); } diff --git a/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl b/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl index 34a1540689..5cfce1904d 100644 --- a/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl +++ b/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl @@ -1,4 +1,4 @@ void mx_worleynoise3d_vector3(vector position, float jitter, int style, output vector result) { - result = mx_worley_noise_vector3(position, jitter, 0); + result = mx_worley_noise_vector3(position, jitter, style, 0); } From 59c543980ae2ae9ce948f2f4953cbdc15309c088 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 29 Dec 2024 09:58:16 -0800 Subject: [PATCH 59/76] Add filtering properties to OSL textures (#2158) This changelist adds filtering properties to texture calls in OSL shader generation, improving the visual consistency between generated OSL and other shading languages. Previously, the "interp" property was omitted from texture calls in generated OSL, causing the default "smartcubic" filtering mode to be used. --- libraries/stdlib/genosl/mx_image_color3.osl | 6 +++++- libraries/stdlib/genosl/mx_image_color4.osl | 7 +++++-- libraries/stdlib/genosl/mx_image_float.osl | 5 ++++- libraries/stdlib/genosl/mx_image_vector2.osl | 5 ++++- libraries/stdlib/genosl/mx_image_vector3.osl | 5 ++++- libraries/stdlib/genosl/mx_image_vector4.osl | 6 ++++-- 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/libraries/stdlib/genosl/mx_image_color3.osl b/libraries/stdlib/genosl/mx_image_color3.osl index 89ba94f376..ff2902da55 100644 --- a/libraries/stdlib/genosl/mx_image_color3.osl +++ b/libraries/stdlib/genosl/mx_image_color3.osl @@ -12,5 +12,9 @@ void mx_image_color3(textureresource file, string layer, color default_value, ve color missingColor = default_value; vector2 st = mx_transform_uv(texcoord); - out = texture(file.filename, st.x, st.y, "subimage", layer, "missingcolor", missingColor, "swrap", uaddressmode, "twrap", vaddressmode, "colorspace", file.colorspace); + out = texture(file.filename, st.x, st.y, + "subimage", layer, "interp", filtertype, + "missingcolor", missingColor, + "swrap", uaddressmode, "twrap", vaddressmode, + "colorspace", file.colorspace); } diff --git a/libraries/stdlib/genosl/mx_image_color4.osl b/libraries/stdlib/genosl/mx_image_color4.osl index 261108b5b4..1a5d9979c3 100644 --- a/libraries/stdlib/genosl/mx_image_color4.osl +++ b/libraries/stdlib/genosl/mx_image_color4.osl @@ -14,8 +14,11 @@ void mx_image_color4(textureresource file, string layer, color4 default_value, v float missingAlpha = default_value.a; vector2 st = mx_transform_uv(texcoord); float alpha; - color rgb = texture(file.filename, st.x, st.y, "alpha", alpha, "subimage", layer, - "missingcolor", missingColor, "missingalpha", missingAlpha, "swrap", uaddressmode, "twrap", vaddressmode, "colorspace", file.colorspace); + color rgb = texture(file.filename, st.x, st.y, "alpha", alpha, + "subimage", layer, "interp", filtertype, + "missingcolor", missingColor, "missingalpha", missingAlpha, + "swrap", uaddressmode, "twrap", vaddressmode, + "colorspace", file.colorspace); out = color4(rgb, alpha); } diff --git a/libraries/stdlib/genosl/mx_image_float.osl b/libraries/stdlib/genosl/mx_image_float.osl index 8cbadb35e2..2cdbb9fb27 100644 --- a/libraries/stdlib/genosl/mx_image_float.osl +++ b/libraries/stdlib/genosl/mx_image_float.osl @@ -12,6 +12,9 @@ void mx_image_float(textureresource file, string layer, float default_value, vec color missingColor = color(default_value); vector2 st = mx_transform_uv(texcoord); - color rgb = texture(file.filename, st.x, st.y, "subimage", layer, "missingcolor", missingColor, "swrap", uaddressmode, "twrap", vaddressmode); + color rgb = texture(file.filename, st.x, st.y, + "subimage", layer, "interp", filtertype, + "missingcolor", missingColor, + "swrap", uaddressmode, "twrap", vaddressmode); out = rgb[0]; } diff --git a/libraries/stdlib/genosl/mx_image_vector2.osl b/libraries/stdlib/genosl/mx_image_vector2.osl index 3aadbefc23..67c1ae270b 100644 --- a/libraries/stdlib/genosl/mx_image_vector2.osl +++ b/libraries/stdlib/genosl/mx_image_vector2.osl @@ -12,7 +12,10 @@ void mx_image_vector2(textureresource file, string layer, vector2 default_value, color missingColor = color(default_value.x, default_value.y, 0.0); vector2 st = mx_transform_uv(texcoord); - color rgb = texture(file.filename, st.x, st.y, "subimage", layer, "missingcolor", missingColor, "swrap", uaddressmode, "twrap", vaddressmode); + color rgb = texture(file.filename, st.x, st.y, + "subimage", layer, "interp", filtertype, + "missingcolor", missingColor, + "swrap", uaddressmode, "twrap", vaddressmode); out.x = rgb[0]; out.y = rgb[1]; } diff --git a/libraries/stdlib/genosl/mx_image_vector3.osl b/libraries/stdlib/genosl/mx_image_vector3.osl index a180107fcf..63f363e957 100644 --- a/libraries/stdlib/genosl/mx_image_vector3.osl +++ b/libraries/stdlib/genosl/mx_image_vector3.osl @@ -12,5 +12,8 @@ void mx_image_vector3(textureresource file, string layer, vector default_value, color missingColor = default_value; vector2 st = mx_transform_uv(texcoord); - out = texture(file.filename, st.x, st.y, "subimage", layer, "missingcolor", missingColor, "swrap", uaddressmode, "twrap", vaddressmode); + out = texture(file.filename, st.x, st.y, + "subimage", layer, "interp", filtertype, + "missingcolor", missingColor, + "swrap", uaddressmode, "twrap", vaddressmode); } diff --git a/libraries/stdlib/genosl/mx_image_vector4.osl b/libraries/stdlib/genosl/mx_image_vector4.osl index bf5f6d1903..eba820a241 100644 --- a/libraries/stdlib/genosl/mx_image_vector4.osl +++ b/libraries/stdlib/genosl/mx_image_vector4.osl @@ -14,8 +14,10 @@ void mx_image_vector4(textureresource file, string layer, vector4 default_value, float missingAlpha = default_value.w; vector2 st = mx_transform_uv(texcoord); float alpha; - color rgb = texture(file.filename, st.x, st.y, "alpha", alpha, "subimage", layer, - "missingcolor", missingColor, "missingalpha", missingAlpha, "swrap", uaddressmode, "twrap", vaddressmode); + color rgb = texture(file.filename, st.x, st.y, "alpha", alpha, + "subimage", layer, "interp", filtertype, + "missingcolor", missingColor, "missingalpha", missingAlpha, + "swrap", uaddressmode, "twrap", vaddressmode); out = vector4(rgb[0], rgb[1], rgb[2], alpha); } From 8ba75306c86f4dc2d2bbbc44e728830babba163a Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 29 Dec 2024 11:29:04 -0800 Subject: [PATCH 60/76] Add image downsample method (#2159) This changelist adds an Image::applyBoxDownsample method, allowing images to be downsampled by an integer factor using a box filter. --- source/MaterialXRender/Image.cpp | 29 +++++++++++++++++++ source/MaterialXRender/Image.h | 4 +++ .../PyMaterialX/PyMaterialXRender/PyImage.cpp | 1 + 3 files changed, 34 insertions(+) diff --git a/source/MaterialXRender/Image.cpp b/source/MaterialXRender/Image.cpp index eec4461aea..50ea299195 100644 --- a/source/MaterialXRender/Image.cpp +++ b/source/MaterialXRender/Image.cpp @@ -528,6 +528,35 @@ ImagePtr Image::applyGaussianBlur() return blurImage2; } +ImagePtr Image::applyBoxDownsample(unsigned int factor) +{ + factor = std::max(factor, (unsigned int) 2); + + ImagePtr sampleImage = Image::create(getWidth() / factor, getHeight() / factor, getChannelCount(), getBaseType()); + sampleImage->createResourceBuffer(); + + for (int y = 0; y < (int) sampleImage->getHeight(); y++) + { + for (int x = 0; x < (int) sampleImage->getWidth(); x++) + { + Color4 sampleColor; + for (int dy = 0; dy < (int) factor; dy++) + { + int sy = std::min(std::max(y * (int) factor + dy, 0), (int) getHeight() - 1); + for (int dx = 0; dx < (int) factor; dx++) + { + int sx = std::min(std::max(x * (int) factor + dx, 0), (int) getWidth() - 1); + sampleColor += getTexelColor(sx, sy); + } + } + sampleColor /= (float) (factor * factor); + sampleImage->setTexelColor(x, y, sampleColor); + } + } + + return sampleImage; +} + ImagePair Image::splitByLuminance(float luminance) { ImagePtr underflowImage = Image::create(getWidth(), getHeight(), getChannelCount(), getBaseType()); diff --git a/source/MaterialXRender/Image.h b/source/MaterialXRender/Image.h index 43bbbed123..76e1b88eee 100644 --- a/source/MaterialXRender/Image.h +++ b/source/MaterialXRender/Image.h @@ -148,6 +148,10 @@ class MX_RENDER_API Image /// Apply a 7x7 Gaussian blur to this image, returning a new blurred image. ImagePtr applyGaussianBlur(); + /// Downsample this image by an integer factor using a box filter, + /// returning the new reduced image. + ImagePtr applyBoxDownsample(unsigned int factor); + /// Split this image by the given luminance threshold, returning the /// resulting underflow and overflow images. ImagePair splitByLuminance(float luminance); diff --git a/source/PyMaterialX/PyMaterialXRender/PyImage.cpp b/source/PyMaterialX/PyMaterialXRender/PyImage.cpp index c1d2a74db0..2c9a932340 100644 --- a/source/PyMaterialX/PyMaterialXRender/PyImage.cpp +++ b/source/PyMaterialX/PyMaterialXRender/PyImage.cpp @@ -38,6 +38,7 @@ void bindPyImage(py::module& mod) .def("copy", &mx::Image::copy) .def("applyBoxBlur", &mx::Image::applyBoxBlur) .def("applyGaussianBlur", &mx::Image::applyGaussianBlur) + .def("applyBoxDownsample", &mx::Image::applyBoxDownsample) .def("splitByLuminance", &mx::Image::splitByLuminance) .def("setResourceBuffer", &mx::Image::setResourceBuffer) .def("getResourceBuffer", &mx::Image::getResourceBuffer) From 32ff2903e5432ae8c121be2ad1fa957f338f6a2e Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 29 Dec 2024 15:39:59 -0800 Subject: [PATCH 61/76] Improvements to render tests (#2160) - Display image statistics when image differencing is enabled in render tests. - Add supersampling to hardware shading languages when reference quality is enabled. - Improve camera alignment across shading languages. - Remove legacy render test options for clarity. --- python/MaterialXTest/tests_to_html.bat | 2 +- python/MaterialXTest/tests_to_html.py | 25 +++--- resources/Materials/TestSuite/_options.mtlx | 18 ++-- .../MaterialXGenShader/GenShaderUtil.cpp | 38 +------- .../MaterialXGenShader/GenShaderUtil.h | 12 --- .../MaterialXRenderGlsl/RenderGlsl.cpp | 54 +++++------ .../MaterialXRenderMsl/RenderMsl.mm | 55 +++++------- .../MaterialXRenderOsl/RenderOsl.cpp | 89 ++++++++----------- .../Utilities/scene_template.xml | 2 +- 9 files changed, 99 insertions(+), 196 deletions(-) diff --git a/python/MaterialXTest/tests_to_html.bat b/python/MaterialXTest/tests_to_html.bat index 92f44ec240..5e38ddc163 100644 --- a/python/MaterialXTest/tests_to_html.bat +++ b/python/MaterialXTest/tests_to_html.bat @@ -1,2 +1,2 @@ @echo off -python tests_to_html.py -i1 ../../build %* +python tests_to_html.py -i1 ../../build %* -d diff --git a/python/MaterialXTest/tests_to_html.py b/python/MaterialXTest/tests_to_html.py index 05269b5dbe..69b0b0b070 100644 --- a/python/MaterialXTest/tests_to_html.py +++ b/python/MaterialXTest/tests_to_html.py @@ -6,13 +6,13 @@ import argparse try: - # Use pip to install Pillow and Image to enable image diffs - from PIL import Image, ImageChops + # Install pillow via pip to enable image differencing and statistics. + from PIL import Image, ImageChops, ImageStat DIFF_ENABLED = True except Exception: DIFF_ENABLED = False -def createDiff(image1Path, image2Path, imageDiffPath): +def computeDiff(image1Path, image2Path, imageDiffPath): try: if os.path.exists(imageDiffPath): os.remove(imageDiffPath) @@ -29,6 +29,8 @@ def createDiff(image1Path, image2Path, imageDiffPath): image2 = Image.open(image2Path).convert('RGB') diff = ImageChops.difference(image1, image2) diff.save(imageDiffPath) + diffStat = ImageStat.Stat(diff) + return sum(diffStat.rms) / (3.0 * 255.0) except Exception: if os.path.exists(imageDiffPath): os.remove(imageDiffPath) @@ -144,9 +146,8 @@ def main(args=None): fullPath1 = os.path.join(path1, file1) if file1 else None fullPath2 = os.path.join(path2, file2) if file2 else None fullPath3 = os.path.join(path3, file3) if file3 else None - diffPath1 = None - diffPath2 = None - diffPath3 = None + diffPath1 = diffPath2 = diffPath3 = None + diffRms1 = diffRms2 = diffRms3 = None if curPath != path1: if curPath != "": @@ -157,13 +158,13 @@ def main(args=None): if file1 and file2 and DIFF_ENABLED and args.CREATE_DIFF: diffPath1 = fullPath1[0:-8] + "_" + args.lang1 + "-1_vs_" + args.lang2 + "-2_diff.png" - createDiff(fullPath1, fullPath2, diffPath1) + diffRms1 = computeDiff(fullPath1, fullPath2, diffPath1) if useThirdLang and file1 and file3 and DIFF_ENABLED and args.CREATE_DIFF: diffPath2 = fullPath1[0:-8] + "_" + args.lang1 + "-1_vs_" + args.lang3 + "-3_diff.png" - createDiff(fullPath1, fullPath3, diffPath2) + diffRms2 = computeDiff(fullPath1, fullPath3, diffPath2) diffPath3 = fullPath1[0:-8] + "_" + args.lang2 + "-2_vs_" + args.lang3 + "-3_diff.png" - createDiff(fullPath2, fullPath3, diffPath3) + diffRms3 = computeDiff(fullPath2, fullPath3, diffPath3) def prependFileUri(filepath: str) -> str: if os.path.isabs(filepath): @@ -203,11 +204,11 @@ def prependFileUri(filepath: str) -> str: fh.write("
(" + str(datetime.datetime.fromtimestamp(os.path.getmtime(fullPath3))) + ")") fh.write("\n") if diffPath1: - fh.write("Difference " + args.lang1 + " vs. " + args.lang2 + " \n") + fh.write("" + args.lang1.upper() + " vs. " + args.lang2.upper() + " (RMS " + "%.5f" % diffRms1 + ") \n") if diffPath2: - fh.write("Difference " + args.lang1 + " vs. " + args.lang3 + " \n") + fh.write("" + args.lang1.upper() + " vs. " + args.lang3.upper() + " (RMS " + "%.5f" % diffRms2 + ") \n") if diffPath3: - fh.write("Difference " + args.lang2 + " vs. " + args.lang3 + " \n") + fh.write("" + args.lang2.upper() + " vs. " + args.lang3.upper() + " (RMS " + "%.5f" % diffRms3 + ") \n") fh.write("\n") fh.write("\n") diff --git a/resources/Materials/TestSuite/_options.mtlx b/resources/Materials/TestSuite/_options.mtlx index b437394775..d018c464bc 100644 --- a/resources/Materials/TestSuite/_options.mtlx +++ b/resources/Materials/TestSuite/_options.mtlx @@ -33,21 +33,9 @@ --> - - - - - - - - - - - - @@ -76,7 +64,11 @@ - +
diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 40f89c001f..858fc39a97 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -921,11 +921,7 @@ void TestSuiteOptions::print(std::ostream& output) const output << "\tCheck Implementation Usage Count: " << checkImplCount << std::endl; output << "\tDump Generated Code: " << dumpGeneratedCode << std::endl; output << "\tShader Interfaces: " << shaderInterfaces << std::endl; - output << "\tValidate Element To Render: " << validateElementToRender << std::endl; - output << "\tCompile code: " << compileCode << std::endl; - output << "\tRender Images: " << renderImages << std::endl; output << "\tRender Size: " << renderSize[0] << "," << renderSize[1] << std::endl; - output << "\tSave Images: " << saveImages << std::endl; output << "\tDump uniforms and Attributes " << dumpUniformsAndAttributes << std::endl; output << "\tRender Geometry: " << renderGeometry.asString() << std::endl; output << "\tEnable Direct Lighting: " << enableDirectLighting << std::endl; @@ -947,11 +943,7 @@ bool TestSuiteOptions::readOptions(const std::string& optionFile) const std::string TARGETS_STRING("targets"); const std::string LIGHT_FILES_STRING("lightFiles"); const std::string SHADER_INTERFACES_STRING("shaderInterfaces"); - const std::string VALIDATE_ELEMENT_TO_RENDER_STRING("validateElementToRender"); - const std::string COMPILE_CODE_STRING("compileCode"); - const std::string RENDER_IMAGES_STRING("renderImages"); const std::string RENDER_SIZE_STRING("renderSize"); - const std::string SAVE_IMAGES_STRING("saveImages"); const std::string DUMP_UNIFORMS_AND_ATTRIBUTES_STRING("dumpUniformsAndAttributes"); const std::string CHECK_IMPL_COUNT_STRING("checkImplCount"); const std::string DUMP_GENERATED_CODE_STRING("dumpGeneratedCode"); @@ -998,26 +990,10 @@ bool TestSuiteOptions::readOptions(const std::string& optionFile) { shaderInterfaces = val->asA(); } - else if (name == VALIDATE_ELEMENT_TO_RENDER_STRING) - { - validateElementToRender = val->asA(); - } - else if (name == COMPILE_CODE_STRING) - { - compileCode = val->asA(); - } - else if (name == RENDER_IMAGES_STRING) - { - renderImages = val->asA(); - } else if (name == RENDER_SIZE_STRING) { renderSize = val->asA(); } - else if (name == SAVE_IMAGES_STRING) - { - saveImages = val->asA(); - } else if (name == DUMP_UNIFORMS_AND_ATTRIBUTES_STRING) { dumpUniformsAndAttributes = val->asA(); @@ -1082,23 +1058,11 @@ bool TestSuiteOptions::readOptions(const std::string& optionFile) } } - // Disable render and save of images if not compiled code will be generated - if (!compileCode) - { - renderImages = false; - saveImages = false; - } - // Disable saving images, if no images are to be produced - if (!renderImages) - { - saveImages = false; - } - // Disable direct lighting + // Handle direct and indirect lighting toggles. if (!enableDirectLighting) { lightFiles.clear(); } - // Disable indirect lighting if (!enableIndirectLighting) { radianceIBLPath.assign(mx::EMPTY_STRING); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h index d4876a03f7..e44df13efd 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h @@ -88,21 +88,9 @@ class TestSuiteOptions // - 1 = run reduced only. int shaderInterfaces = 2; - // Validate element before attempting to generate code. Default is false. - bool validateElementToRender = false; - - // Perform source code compilation validation test - bool compileCode = true; - - // Perform rendering validation test - bool renderImages = true; - // Render size mx::Vector2 renderSize = { 512, 512 }; - // Perform saving of image. - bool saveImages = true; - // Set this to be true if it is desired to dump out uniform and attribut information to the logging file. bool dumpUniformsAndAttributes = true; diff --git a/source/MaterialXTest/MaterialXRenderGlsl/RenderGlsl.cpp b/source/MaterialXTest/MaterialXRenderGlsl/RenderGlsl.cpp index 01e0875727..9cfd3f4197 100644 --- a/source/MaterialXTest/MaterialXRenderGlsl/RenderGlsl.cpp +++ b/source/MaterialXTest/MaterialXRenderGlsl/RenderGlsl.cpp @@ -168,17 +168,6 @@ bool GlslShaderRenderTester::runRenderer(const std::string& shaderName, const mx::ShaderGenerator& shadergen = context.getShaderGenerator(); mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); - // Perform validation if requested - if (testOptions.validateElementToRender) - { - std::string message; - if (!element->validate(&message)) - { - log << "Element is invalid: " << message << std::endl; - return false; - } - } - std::vector optionsList; getGenerationOptions(testOptions, context.getOptions(), optionsList); @@ -247,11 +236,6 @@ bool GlslShaderRenderTester::runRenderer(const std::string& shaderName, file.close(); } - if (!testOptions.compileCode) - { - return false; - } - // Validate MaterialX::GlslProgramPtr program = _renderer->getProgram(); bool validated = false; @@ -356,27 +340,31 @@ bool GlslShaderRenderTester::runRenderer(const std::string& shaderName, } } - if (testOptions.renderImages) + int supersampleFactor = testOptions.enableReferenceQuality ? 8 : 1; + { - { - mx::ScopedTimer renderTimer(&profileTimes.languageTimes.renderTime); - _renderer->getImageHandler()->setSearchPath(imageSearchPath); - _renderer->setSize(static_cast(testOptions.renderSize[0]), static_cast(testOptions.renderSize[1])); - _renderer->render(); - } + mx::ScopedTimer renderTimer(&profileTimes.languageTimes.renderTime); + _renderer->getImageHandler()->setSearchPath(imageSearchPath); + unsigned int width = (unsigned int) testOptions.renderSize[0] * supersampleFactor; + unsigned int height = (unsigned int) testOptions.renderSize[1] * supersampleFactor; + _renderer->setSize(width, height); + _renderer->render(); + } - if (testOptions.saveImages) + { + mx::ScopedTimer ioTimer(&profileTimes.languageTimes.imageSaveTime); + std::string fileName = shaderPath + "_glsl.png"; + mx::ImagePtr image = _renderer->captureImage(); + if (image) { - mx::ScopedTimer ioTimer(&profileTimes.languageTimes.imageSaveTime); - std::string fileName = shaderPath + "_glsl.png"; - mx::ImagePtr image = _renderer->captureImage(); - if (image) + if (supersampleFactor > 1) { - _renderer->getImageHandler()->saveImage(fileName, image, true); - if (imageVec) - { - imageVec->push_back(image); - } + image = image->applyBoxDownsample(supersampleFactor); + } + _renderer->getImageHandler()->saveImage(fileName, image, true); + if (imageVec) + { + imageVec->push_back(image); } } } diff --git a/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm b/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm index be5b8aa616..d276d5b1cc 100644 --- a/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm +++ b/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm @@ -104,6 +104,7 @@ bool runRenderer(const std::string& shaderName, _lightHandler->setEnvRadianceMap(envRadiance); _lightHandler->setEnvIrradianceMap(envIrradiance); _lightHandler->setEnvSampleCount(options.enableReferenceQuality ? 4096 : 1024); + _lightHandler->setRefractionTwoSided(true); } // @@ -175,17 +176,6 @@ bool runRenderer(const std::string& shaderName, const mx::ShaderGenerator& shadergen = context.getShaderGenerator(); - // Perform validation if requested - if (testOptions.validateElementToRender) - { - std::string message; - if (!element->validate(&message)) - { - log << "Element is invalid: " << message << std::endl; - return false; - } - } - std::vector optionsList; getGenerationOptions(testOptions, context.getOptions(), optionsList); @@ -254,11 +244,6 @@ bool runRenderer(const std::string& shaderName, file.close(); } - if (!testOptions.compileCode) - { - return false; - } - // Validate bool validated = false; try @@ -362,27 +347,31 @@ bool runRenderer(const std::string& shaderName, } } - if (testOptions.renderImages) + int supersampleFactor = testOptions.enableReferenceQuality ? 8 : 1; + { - { - mx::ScopedTimer renderTimer(&profileTimes.languageTimes.renderTime); - _renderer->getImageHandler()->setSearchPath(mx::getDefaultDataSearchPath()); - _renderer->setSize(static_cast(testOptions.renderSize[0]), static_cast(testOptions.renderSize[1])); - _renderer->render(); - } + mx::ScopedTimer renderTimer(&profileTimes.languageTimes.renderTime); + _renderer->getImageHandler()->setSearchPath(mx::getDefaultDataSearchPath()); + unsigned int width = (unsigned int) testOptions.renderSize[0] * supersampleFactor; + unsigned int height = (unsigned int) testOptions.renderSize[1] * supersampleFactor; + _renderer->setSize(width, height); + _renderer->render(); + } - if (testOptions.saveImages) + { + mx::ScopedTimer ioTimer(&profileTimes.languageTimes.imageSaveTime); + std::string fileName = shaderPath + "_msl.png"; + mx::ImagePtr image = _renderer->captureImage(); + if (image) { - mx::ScopedTimer ioTimer(&profileTimes.languageTimes.imageSaveTime); - std::string fileName = shaderPath + "_msl.png"; - mx::ImagePtr image = _renderer->captureImage(); - if (image) + if (supersampleFactor > 1) { - _renderer->getImageHandler()->saveImage(fileName, image, true); - if (imageVec) - { - imageVec->push_back(image); - } + image = image->applyBoxDownsample(supersampleFactor); + } + _renderer->getImageHandler()->saveImage(fileName, image, true); + if (imageVec) + { + imageVec->push_back(image); } } } diff --git a/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp b/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp index 4dad5227b1..7684d62a03 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp +++ b/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp @@ -192,17 +192,6 @@ bool OslShaderRenderTester::runRenderer(const std::string& shaderName, mx::ShaderGenerator& shadergen = context.getShaderGenerator(); - // Perform validation if requested - if (testOptions.validateElementToRender) - { - std::string message; - if (!element->validate(&message)) - { - log << "Element is invalid: " << message << std::endl; - return false; - } - } - std::vector optionsList; getGenerationOptions(testOptions, context.getOptions(), optionsList); @@ -267,11 +256,6 @@ bool OslShaderRenderTester::runRenderer(const std::string& shaderName, file.close(); } - if (!testOptions.compileCode) - { - return false; - } - // Validate bool validated = false; try @@ -288,55 +272,52 @@ bool OslShaderRenderTester::runRenderer(const std::string& shaderName, _renderer->createProgram(shader); } - if (testOptions.renderImages) - { - _renderer->setSize(static_cast(testOptions.renderSize[0]), static_cast(testOptions.renderSize[1])); + _renderer->setSize(static_cast(testOptions.renderSize[0]), static_cast(testOptions.renderSize[1])); - const mx::ShaderStage& stage = shader->getStage(mx::Stage::PIXEL); + const mx::ShaderStage& stage = shader->getStage(mx::Stage::PIXEL); - // Bind IBL image name overrides. - mx::StringVec envOverrides; - std::string envmap_filename("string envmap_filename \""); - envmap_filename += testOptions.radianceIBLPath; - envmap_filename += "\";\n"; - envOverrides.push_back(envmap_filename); + // Bind IBL image name overrides. + mx::StringVec envOverrides; + std::string envmap_filename("string envmap_filename \""); + envmap_filename += testOptions.radianceIBLPath; + envmap_filename += "\";\n"; + envOverrides.push_back(envmap_filename); - _renderer->setEnvShaderParameterOverrides(envOverrides); + _renderer->setEnvShaderParameterOverrides(envOverrides); - const mx::VariableBlock& outputs = stage.getOutputBlock(mx::OSL::OUTPUTS); - if (outputs.size() > 0) - { - const mx::ShaderPort* output = outputs[0]; - const mx::TypeSyntax& typeSyntax = shadergen.getSyntax().getTypeSyntax(output->getType()); + const mx::VariableBlock& outputs = stage.getOutputBlock(mx::OSL::OUTPUTS); + if (outputs.size() > 0) + { + const mx::ShaderPort* output = outputs[0]; + const mx::TypeSyntax& typeSyntax = shadergen.getSyntax().getTypeSyntax(output->getType()); - const std::string& outputName = output->getVariable(); - const std::string& outputType = typeSyntax.getTypeAlias().empty() ? typeSyntax.getName() : typeSyntax.getTypeAlias(); - const std::string& sceneTemplateFile = "scene_template.xml"; + const std::string& outputName = output->getVariable(); + const std::string& outputType = typeSyntax.getTypeAlias().empty() ? typeSyntax.getName() : typeSyntax.getTypeAlias(); + const std::string& sceneTemplateFile = "scene_template.xml"; - // Set shader output name and type to use - _renderer->setOslShaderOutput(outputName, outputType); + // Set shader output name and type to use + _renderer->setOslShaderOutput(outputName, outputType); - // Set scene template file. For now we only have the constant color scene file - mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); - mx::FilePath sceneTemplatePath = searchPath.find("resources/Utilities/"); - sceneTemplatePath = sceneTemplatePath / sceneTemplateFile; - _renderer->setOslTestRenderSceneTemplateFile(sceneTemplatePath.asString()); + // Set scene template file. For now we only have the constant color scene file + mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); + mx::FilePath sceneTemplatePath = searchPath.find("resources/Utilities/"); + sceneTemplatePath = sceneTemplatePath / sceneTemplateFile; + _renderer->setOslTestRenderSceneTemplateFile(sceneTemplatePath.asString()); - // Validate rendering + // Validate rendering + { + mx::ScopedTimer renderTimer(&profileTimes.languageTimes.renderTime); + _renderer->render(); + if (imageVec) { - mx::ScopedTimer renderTimer(&profileTimes.languageTimes.renderTime); - _renderer->render(); - if (imageVec) - { - imageVec->push_back(_renderer->captureImage()); - } + imageVec->push_back(_renderer->captureImage()); } } - else - { - CHECK(false); - log << ">> Shader has no output to render from\n"; - } + } + else + { + CHECK(false); + log << ">> Shader has no output to render from\n"; } validated = true; diff --git a/source/MaterialXTest/MaterialXRenderOsl/Utilities/scene_template.xml b/source/MaterialXTest/MaterialXRenderOsl/Utilities/scene_template.xml index 00edeba72e..5f9cf11c71 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/Utilities/scene_template.xml +++ b/source/MaterialXTest/MaterialXRenderOsl/Utilities/scene_template.xml @@ -1,6 +1,6 @@ - + From 2582e66e6ddb9390b2b063ec3180b8c7692df982 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 30 Dec 2024 13:22:37 -0800 Subject: [PATCH 62/76] Increase OSL samples in reference renders (#2161) This changelist increases the number of OSL samples in reference-quality renders, improving the visual parity between OSL and other languages in MaterialX render tests. Additionally, it pares down the list of document paths for MaterialX render tests, reducing the resulting PDF document to a size that can be directly shared on Slack. --- resources/Materials/TestSuite/_options.mtlx | 2 +- source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/Materials/TestSuite/_options.mtlx b/resources/Materials/TestSuite/_options.mtlx index d018c464bc..234b6eaaa0 100644 --- a/resources/Materials/TestSuite/_options.mtlx +++ b/resources/Materials/TestSuite/_options.mtlx @@ -62,7 +62,7 @@ - + - + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx index defa4c4bbd..fffecc11af 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx @@ -7,7 +7,7 @@ - + @@ -31,7 +31,7 @@ - + diff --git a/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx b/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx index 62c6033222..35039cf350 100644 --- a/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx +++ b/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx @@ -13,7 +13,7 @@ - + @@ -27,6 +27,6 @@ - + diff --git a/resources/Materials/TestSuite/stdlib/color_management/color_management.mtlx b/resources/Materials/TestSuite/stdlib/color_management/color_management.mtlx index fb9825cd12..63f97e2723 100644 --- a/resources/Materials/TestSuite/stdlib/color_management/color_management.mtlx +++ b/resources/Materials/TestSuite/stdlib/color_management/color_management.mtlx @@ -7,77 +7,77 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -87,7 +87,7 @@ - + @@ -97,7 +97,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -117,7 +117,7 @@ - + @@ -127,7 +127,7 @@ - + @@ -137,7 +137,7 @@ - + @@ -147,7 +147,7 @@ - + @@ -157,7 +157,7 @@ - + @@ -167,7 +167,7 @@ - + @@ -177,7 +177,7 @@ - + @@ -187,6 +187,6 @@ - + diff --git a/source/MaterialXTest/MaterialXRenderOsl/Utilities/scene_template.xml b/source/MaterialXTest/MaterialXRenderOsl/Utilities/scene_template.xml index 5f9cf11c71..e5467b76ff 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/Utilities/scene_template.xml +++ b/source/MaterialXTest/MaterialXRenderOsl/Utilities/scene_template.xml @@ -1,6 +1,6 @@ - + From d114ab795c0ad780b2dfce0c2b6ca3b4993dff65 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 3 Jan 2025 11:31:01 -0800 Subject: [PATCH 64/76] Improvements to heighttonormal node (#2165) - Improve the specification of the `heighttonormal` node, clarifying that its output contains tangent-space vectors encoded in the [0-1] range. - Improve the OSL implementation of the `heighttonormal` node, leveraging the built-in partial derivative instructions to compute the gradient at each surface point. - Simplify example material filenames to improve layout in render tests. - Add convolution nodes to the list of standard render tests. --- documents/Specification/MaterialX.Specification.md | 2 +- .../stdlib/genosl/mx_heighttonormal_vector3.osl | 7 +++++-- resources/Materials/TestSuite/_options.mtlx | 2 +- .../TestSuite/stdlib/convolution/blur.mtlx | 14 +++++++------- .../stdlib/convolution/heighttonormal.mtlx | 8 ++++---- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 2e67024c58..d49f9c17a7 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -1776,7 +1776,7 @@ Convolution nodes have one input named "in", and apply a defined convolution fun -* **`heighttonormal`**: convert a scalar height map to a normal map of type vector3. +* **`heighttonormal`**: convert a scalar height map to a tangent-space normal map of type vector3. The output normal map is encoded with all channels in the [0-1] range, enabling its storage in unsigned image formats. * `in` (float): the input value or nodename * `scale` (float): the scale of normal map deflections relative to the gradient of the height map. Default is 1.0. diff --git a/libraries/stdlib/genosl/mx_heighttonormal_vector3.osl b/libraries/stdlib/genosl/mx_heighttonormal_vector3.osl index c7b3396c84..ee898cf1ba 100644 --- a/libraries/stdlib/genosl/mx_heighttonormal_vector3.osl +++ b/libraries/stdlib/genosl/mx_heighttonormal_vector3.osl @@ -1,5 +1,8 @@ void mx_heighttonormal_vector3(float in, float scale, output vector result) { - point htP = P + normalize(N) * in * scale; - result = normalize(calculatenormal(htP)); + float dx = -Dx(in); + float dy = Dy(in); + float dz = max(scale, 1.0E-05) * sqrt(max(1.0 - dx*dx - dy*dy, 1.0E-05)); + vector dir = normalize(vector(dx, dy, dz)); + result = dir * vector(0.5) + vector(0.5); } diff --git a/resources/Materials/TestSuite/_options.mtlx b/resources/Materials/TestSuite/_options.mtlx index 234b6eaaa0..298f16f0c3 100644 --- a/resources/Materials/TestSuite/_options.mtlx +++ b/resources/Materials/TestSuite/_options.mtlx @@ -62,7 +62,7 @@ - + - + @@ -16,6 +16,7 @@ + @@ -157,10 +158,16 @@ + + + + + + - + @@ -278,10 +285,21 @@ + + + + + + + + + + + - + diff --git a/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx b/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx index 62317197b1..5fa69b7db1 100644 --- a/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx +++ b/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx @@ -10,6 +10,7 @@ + From 878e087a6dbaba5f74aced3cf6eb34b16258238a Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 7 Jan 2025 08:23:30 -0800 Subject: [PATCH 70/76] Update changelog for recent work (#2174) --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16531b7a54..908a2e8fad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - Added support for [Apple framework builds](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2020). - Added support for [MDL 1.9](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2102) in shader generation. - Added support for [viewdirection space](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2036) in hardware shading languages. +- Added support for [image downsampling](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2159) in MaterialXRender. +- Added support for [image difference statistics](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2160) in render tests. - Added a [combined version define](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2031) to MaterialX C++. - Added a [release signing workflow](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2009) to GitHub Actions. - Added documentation for [keyboard shortcuts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2026) in the MaterialX Viewer. @@ -23,12 +25,16 @@ ### Changed - Improved the performance of [graph traversal](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2023) by skipping edges that have already been visited. - Reduced duplication between the [MSL and GLSL implementations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2068) of nodes. +- Updated the [UsdPreviewSurface shading model](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2084) to v2.6, maintaining the visual interpretation of existing assets. - Raised the [minimum OSL version](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2144) to v1.12.6 in OSL shader generation. ### Fixed - Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. - Fixed [banding artifacts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1977) in the MaterialX Viewer on MacOS. - Fixed the handling of [missing scenes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2124) in the MaterialX Web Viewer. +- Fixed an edge case for [node pasting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2145) in the Graph Editor. +- Fixed the implementation of [texture filtering](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2158) in OSL shader generation. +- Fixed the implementation of the [heighttonormal node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2165) in OSL shader generation. - Fixed a call to the [anisotropic_vdf closure](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2016) in OSL shader generation. ### Removed From 66213f49c44ac482166eb433da6db570401803e1 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 8 Jan 2025 08:02:02 -0800 Subject: [PATCH 71/76] Update changelog for release candidate (#2175) --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 908a2e8fad..0bc0c72444 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,11 @@ # Change Log -## [1.39.2] - Development +## [1.39.2] - Release Candidate ### Added - Added support for the [Chiang Hair BSDF](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1968), with initial implementations in hardware shading languages and MDL. - Added support for the [Disney Principled](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2004) shading model, implemented as a language-independent graph. -- Added support for [ramp curve adjustments](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1884), using a graph-based ramp node with ten control points. +- Added support for [generic color ramps](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1884), using a graph-based ramp node with ten control points. - Added support for [Worley noise with solid cells](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2119), opening up new artistic options for metal flake shaders. - Added support for [data library referencing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2054), enabling improved performance in shader generation. - Added support for [custom structure types](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1831) in MaterialX. @@ -32,7 +32,7 @@ - Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. - Fixed [banding artifacts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1977) in the MaterialX Viewer on MacOS. - Fixed the handling of [missing scenes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2124) in the MaterialX Web Viewer. -- Fixed an edge case for [node pasting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2145) in the Graph Editor. +- Fixed an edge case for [node pasting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2145) in the MaterialX Graph Editor. - Fixed the implementation of [texture filtering](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2158) in OSL shader generation. - Fixed the implementation of the [heighttonormal node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2165) in OSL shader generation. - Fixed a call to the [anisotropic_vdf closure](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2016) in OSL shader generation. From b02811974217dbb08fedaff5a8749ead53dfb4e8 Mon Sep 17 00:00:00 2001 From: Chris Rydalch Date: Thu, 9 Jan 2025 16:54:09 -0600 Subject: [PATCH 72/76] Promote Worley style control to Unified Noise nodes (#2177) In PR #2119 I'd forgotten to include Worley's new cell styles on the Unified Noise node graphs. --- libraries/stdlib/stdlib_defs.mtlx | 2 ++ libraries/stdlib/stdlib_ng.mtlx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 6cebca7faf..7fadecf5e5 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -1070,6 +1070,7 @@ + @@ -1089,6 +1090,7 @@ + diff --git a/libraries/stdlib/stdlib_ng.mtlx b/libraries/stdlib/stdlib_ng.mtlx index 1cb8b6316d..d9474fd878 100644 --- a/libraries/stdlib/stdlib_ng.mtlx +++ b/libraries/stdlib/stdlib_ng.mtlx @@ -1818,6 +1818,7 @@ + @@ -1888,6 +1889,7 @@ + From 2fb812a104e0671ae77a77acba05a412852e76f9 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 12 Jan 2025 17:20:14 -0800 Subject: [PATCH 73/76] Simplify BSDF switches in OSL (#2179) This changelist simplifies the logic for reflection/transmission switches in the OSL implementations of `dielectric_bsdf` and `generalized_schlick_bsdf`. --- libraries/pbrlib/genosl/mx_dielectric_bsdf.osl | 15 +++------------ .../pbrlib/genosl/mx_generalized_schlick_bsdf.osl | 15 +++------------ 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl b/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl index fe570e1546..5d465ea745 100644 --- a/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl +++ b/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl @@ -1,15 +1,6 @@ void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) { - if (scatter_mode == "R") - { - bsdf = weight * dielectric_bsdf(N, U, tint, color(0.0), roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); - } - else if (scatter_mode == "T") - { - bsdf = weight * dielectric_bsdf(N, U, color(0.0), tint, roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); - } - else - { - bsdf = weight * dielectric_bsdf(N, U, tint, tint, roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); - } + color reflection_tint = (scatter_mode == "T") ? color(0.0) : tint; + color transmission_tint = (scatter_mode == "R") ? color(0.0) : tint; + bsdf = weight * dielectric_bsdf(N, U, reflection_tint, transmission_tint, roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); } diff --git a/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl b/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl index 53919e8518..9a05300b67 100644 --- a/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl +++ b/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl @@ -1,15 +1,6 @@ void mx_generalized_schlick_bsdf(float weight, color color0, color color82, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) { - if (scatter_mode == "R") - { - bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(0.0), roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); - } - else if (scatter_mode == "T") - { - bsdf = weight * generalized_schlick_bsdf(N, U, color(0.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); - } - else - { - bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); - } + color reflection_tint = (scatter_mode == "T") ? color(0.0) : color(1.0); + color transmission_tint = (scatter_mode == "R") ? color(0.0) : color(1.0); + bsdf = weight * generalized_schlick_bsdf(N, U, reflection_tint, transmission_tint, roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); } From c5811b62782eddc50ba96306576ba0a3d8eb3272 Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Thu, 16 Jan 2025 18:12:15 +0200 Subject: [PATCH 74/76] Spelling and spacing fixes (#2184) This changelist implements spelling and spacing fixes across the MaterialX repository, leveraging the `codespell` project and manual inspection. --- GOVERNANCE.md | 6 +++--- documents/DeveloperGuide/GraphEditor.md | 20 +++++++++---------- documents/DeveloperGuide/ShaderGeneration.md | 4 ++-- documents/DeveloperGuide/Viewer.md | 2 +- documents/Specification/MaterialX.GeomExts.md | 4 ++-- documents/Specification/MaterialX.PBRSpec.md | 2 +- .../Specification/MaterialX.Specification.md | 2 +- documents/Specification/README.md | 4 ++-- javascript/MaterialXView/source/viewer.js | 2 +- javascript/README.md | 6 +++--- libraries/bxdf/lama/lama_conductor.mtlx | 4 ++-- libraries/bxdf/lama/lama_dielectric.mtlx | 6 +++--- .../bxdf/lama/lama_generalized_schlick.mtlx | 6 +++--- libraries/bxdf/lama/lama_iridescence.mtlx | 2 +- libraries/cmlib/cmlib_ng.mtlx | 8 ++++---- .../pbrlib/genglsl/mx_chiang_hair_bsdf.glsl | 4 ++-- libraries/stdlib/genglsl/lib/mx_hsv.glsl | 2 +- libraries/stdlib/genglsl/lib/mx_noise.glsl | 6 +++--- libraries/stdlib/stdlib_defs.mtlx | 4 ++-- pyproject.toml | 2 +- python/MaterialX/_scripts/README.md | 2 +- python/MaterialX/main.py | 2 +- python/Scripts/baketextures.py | 2 +- python/Scripts/genmdl.py | 20 +++++++++---------- python/Scripts/translateshader.py | 2 +- resources/Materials/TestSuite/_options.mtlx | 2 +- .../TestSuite/stdlib/texture/ramp.mtlx | 2 +- .../JsMaterialXGenShader/JsGenContext.cpp | 2 +- source/MaterialXCore/Element.cpp | 4 ++-- source/MaterialXCore/Element.h | 6 +++--- source/MaterialXCore/Interface.h | 2 +- source/MaterialXCore/Node.h | 2 +- source/MaterialXCore/Unit.h | 2 +- source/MaterialXCore/Version.cpp | 2 +- .../Nodes/HeightToNormalNodeGlsl.h | 2 +- .../Nodes/LightCompoundNodeGlsl.cpp | 2 +- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 6 +++--- source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp | 2 +- .../Nodes/ClosureCompoundNodeMdl.cpp | 6 +++--- .../MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp | 2 +- .../Nodes/HeightToNormalNodeMdl.h | 2 +- .../MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp | 2 +- .../MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp | 2 +- source/MaterialXGenMdl/mdl/materialx/core.mdl | 6 +++--- .../MaterialXGenMdl/mdl/materialx/noise.mdl | 6 +++--- source/MaterialXGenMsl/MslShaderGenerator.cpp | 4 ++-- .../Nodes/HeightToNormalNodeMsl.h | 2 +- .../Nodes/LightCompoundNodeMsl.cpp | 2 +- .../MaterialXGenOsl/Nodes/MaterialNodeOsl.cpp | 2 +- source/MaterialXGenOsl/OslShaderGenerator.cpp | 6 +++--- .../MaterialXGenShader/HwShaderGenerator.cpp | 4 ++-- source/MaterialXGenShader/HwShaderGenerator.h | 2 +- source/MaterialXGenShader/Nodes/BlurNode.h | 2 +- .../Nodes/ClosureCompoundNode.cpp | 4 ++-- .../Nodes/ClosureSourceCodeNode.h | 2 +- .../MaterialXGenShader/Nodes/HwImageNode.cpp | 2 +- .../MaterialXGenShader/Nodes/MaterialNode.cpp | 2 +- .../MaterialXGenShader/Nodes/SourceCodeNode.h | 2 +- source/MaterialXGenShader/ShaderGraph.cpp | 2 +- source/MaterialXGenShader/ShaderGraph.h | 2 +- source/MaterialXGenShader/ShaderNodeImpl.cpp | 2 +- source/MaterialXGenShader/ShaderNodeImpl.h | 2 +- source/MaterialXGenShader/ShaderStage.cpp | 2 +- source/MaterialXGenShader/ShaderStage.h | 2 +- source/MaterialXGenShader/Syntax.h | 2 +- source/MaterialXGenShader/UnitSystem.cpp | 6 +++--- source/MaterialXGenShader/UnitSystem.h | 4 ++-- source/MaterialXGenShader/Util.h | 4 ++-- source/MaterialXGraphEditor/Graph.cpp | 8 ++++---- source/MaterialXGraphEditor/Graph.h | 4 ++-- source/MaterialXRender/Camera.h | 4 ++-- source/MaterialXRender/Image.h | 2 +- source/MaterialXRender/ImageHandler.h | 2 +- source/MaterialXRender/TextureBaker.h | 2 +- source/MaterialXRenderGlsl/GlslProgram.cpp | 2 +- .../MslPipelineStateObject.h | 2 +- source/MaterialXRenderOsl/OslRenderer.h | 2 +- .../MaterialXTest/MaterialXCore/Document.cpp | 2 +- .../MaterialXGenShader/GenShaderUtil.cpp | 2 +- .../MaterialXGenShader/GenShaderUtil.h | 4 ++-- .../MaterialXRender/RenderUtil.cpp | 2 +- .../MaterialXRender/RenderUtil.h | 4 ++-- .../MaterialXRenderGlsl/RenderGlsl.cpp | 4 ++-- .../MaterialXRenderMsl/RenderMsl.mm | 4 ++-- source/MaterialXTest/README.md | 4 ++-- source/MaterialXView/CMakeLists.txt | 2 +- 86 files changed, 153 insertions(+), 153 deletions(-) diff --git a/GOVERNANCE.md b/GOVERNANCE.md index cbf17d62e5..e77b216a33 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -10,12 +10,12 @@ TSC responsibilities include, but are not limited to: - Discussions, seeking consensus, and where necessary, voting on technical matters relating to MaterialX that affect multiple projects. -- Maintainance and administration of the MaterialX GitHub repository. +- Maintenance and administration of the MaterialX GitHub repository. - Coordinating technical direction of the project. -- Coordinatng marketing, events, and communications regarding MaterialX. +- Coordinating marketing, events, and communications regarding MaterialX. Within the TSC there are two key subgroups: **Voting Members**, who take on -formal responsibiities for maintaining the MaterialX project and vote when +formal responsibilities for maintaining the MaterialX project and vote when decisions are required; and **Stakeholders**, who represent specific teams and companies in the industry and speak on their behalf in MaterialX discussions. diff --git a/documents/DeveloperGuide/GraphEditor.md b/documents/DeveloperGuide/GraphEditor.md index 394754c309..02db8b6f8a 100644 --- a/documents/DeveloperGuide/GraphEditor.md +++ b/documents/DeveloperGuide/GraphEditor.md @@ -1,4 +1,4 @@ -# MaterialX Graph Editor +# MaterialX Graph Editor The MaterialX Graph Editor is an example application for visualizing, creating, and editing MaterialX graphs. It utilizes the ImGui framework as well as additional ImGui extensions such as the Node Editor. @@ -14,7 +14,7 @@ Select the `MATERIALX_BUILD_GRAPH_EDITOR` option in CMake to build the MaterialX ## Summary of Graph Editor Features 1. **`Load Material`**: Load a material document in the MTLX format. -2. **`Save Material`**: Save out a graph as a mterial document in MTLX format. +2. **`Save Material`**: Save out a graph as a material document in MTLX format. 3. **`New Material`**: Clear all information to set up for the creation of a new material 4. **`Node Property Editor`**: View or edit properties of the selected node. 5. **`Render View`**: View the rendered material. @@ -23,35 +23,35 @@ Select the `MATERIALX_BUILD_GRAPH_EDITOR` option in CMake to build the MaterialX To display a new material and graph, click the `Load Material` button and and navigate to the [Materials/Examples](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples) folder, which contains a selection of materials in the MTLX format, and select a document to load. The Graph Editor will display the graph hierarchy of the selected document for visualization and editing. -To save out changes to the graphs as MTLX files click the `Save Material` button. This will save the position of the nodes in the graph for future use as well. +To save out changes to the graphs as MTLX files click the `Save Material` button. This will save the position of the nodes in the graph for future use as well. ## Editor Window -The MaterialX document is displayed as nodes in the Editor window. When a file is intially loaded the material node, surface shader node, and any enclosing nodegraphs will be displayed. Double-clicking on a nodegraph, or any node defined as a subgraph, will display the contents of that graph. +The MaterialX document is displayed as nodes in the Editor window. When a file is initially loaded the material node, surface shader node, and any enclosing nodegraphs will be displayed. Double-clicking on a nodegraph, or any node defined as a subgraph, will display the contents of that graph. The current graph hierarchy is displayed above the editor. To back up and out of a subgraph click the `<` button to the left of the graph names. -Each node and nodegraph displays its name and pins for all of its inputs and outputs. Nodes can be connected by clicking on the output pin of one node and connecting it to the input pin of another node, thus creating a link. Links can only be created if the input and output pins have the same type, as designated by the color of the pin. When a new link is created the material in the render view will automatically be updated. +Each node and nodegraph displays its name and pins for all of its inputs and outputs. Nodes can be connected by clicking on the output pin of one node and connecting it to the input pin of another node, thus creating a link. Links can only be created if the input and output pins have the same type, as designated by the color of the pin. When a new link is created the material in the render view will automatically be updated. -Using the tab key on the editor allows the user to add a certain node by bringing up the `Add Node` pop-up. The nodes are organized in the pop-up window based on their node group but a specfic node can also be searched for by name. To create a nodegraph select `Node Graph` in the `Add Node` popup and dive into the node in order to add nodes inside of it and populate it. +Using the tab key on the editor allows the user to add a certain node by bringing up the `Add Node` pop-up. The nodes are organized in the pop-up window based on their node group but a specific node can also be searched for by name. To create a nodegraph select `Node Graph` in the `Add Node` popup and dive into the node in order to add nodes inside of it and populate it. -In order to connect to the nodegraph to a shader add output nodes inside the nodegraph then travel back up outside the nodegraph and connect the corresponding output pin to the surface shader. By default, the nodegraph does not contain any output nodes or pins. +In order to connect to the nodegraph to a shader add output nodes inside the nodegraph then travel back up outside the nodegraph and connect the corresponding output pin to the surface shader. By default, the nodegraph does not contain any output nodes or pins. Another type of node present in the `Add Node` pop-up is the group, or background node. This background node can be used to group specific nodes and label by them by dragging them on to the background node. -To search the editor window for a specific node use `CTRL` + `F` to bring up the search bar. +To search the editor window for a specific node use `CTRL` + `F` to bring up the search bar. ## Node Property Editor When a node is selected in the graph, its information is displayed on the left-hand column in the `Node Property Editor`. This editor displays the name of the node, its category, its inputs, the input name, types and values. Inputs that are connected to other nodes will not display a value. This is where a node's properties such as its name and input values can be adjusted. When an input value is changed the material is automatically updated to reflect that change. The node info button displays the `doc` string for the selected node and its inputs if they exist. This `doc` string is currently read only. -The show All Inputs checkbox displays all possible inputs for a node. With the box unchecked only inputs that have a connection or have had a value set will be shown. Only these inputs will be saved out when the graph is saved. +The show All Inputs checkbox displays all possible inputs for a node. With the box unchecked only inputs that have a connection or have had a value set will be shown. Only these inputs will be saved out when the graph is saved. ## Render View Above the `Node Property Editor`, the `Render View` displays the current material on the Arnold Shader Ball. If inside a subgraph it will display the material associated with that subgraph; otherwise it will display the output of the selected node. It automatically updates when any changes are made to the graph. -To adjust the relative sizes of the Node Property Editor and Render View windows, drag the separator between these windows in the application. The render view window camera can be changed using the left or right mouse buttons to manipulate the shader ball. +To adjust the relative sizes of the Node Property Editor and Render View windows, drag the separator between these windows in the application. The render view window camera can be changed using the left or right mouse buttons to manipulate the shader ball. ## Keyboard Shortcuts diff --git a/documents/DeveloperGuide/ShaderGeneration.md b/documents/DeveloperGuide/ShaderGeneration.md index 594715fb39..75d28a348a 100644 --- a/documents/DeveloperGuide/ShaderGeneration.md +++ b/documents/DeveloperGuide/ShaderGeneration.md @@ -210,7 +210,7 @@ ShaderPtr ShaderGenerator::generate(const string& name, The shader generation process can be divided into initialization and code generation. The initialization consists of a number of steps: 1. Create an optimized version of the graph as a tree with the given input element as root, and with only the used dependencies connected upstream. This involves removing unused paths in the graph, converting constant nodes to constant values, and adding in any default nodes for ports that are unconnected but have default connections specified. Removal of unused paths typically involves constant folding and pruning of conditional branches that will never be taken. Since the resulting shader in the end will be compiled by a shading language compiler, and receive a lot of additional optimizations, we don’t need to do too much work in this optimization step. However, a few graph level optimizations can make the resulting shader a lot smaller and save time and memory during shader compilation. It will also produce more readable source code which is good for debugging purposes. This optimization step is also a good place to do other custom optimizations needed by a particular target. For example simplification of the graph, which could involve substituting expensive nodes with approximate nodes, identification of common subgraphs that can be merged, etc. 2. The nodes are sorted in topological order. Since a node can be referenced by many other nodes in the graph we need an ordering of the nodes so that nodes that have a dependency on other nodes come after all dependent nodes. This step also makes sure there are no cyclic dependencies in the graph. -3. The stages for the shader are created. For a HW shader this is normally a vertex stage and a pixel stage, but other stages can be added as needed. At the minumum a single pixel stage is required, so even shaders that has no concept of multiple stages, like OSL, needs to have a single pixel stage created. +3. The stages for the shader are created. For a HW shader this is normally a vertex stage and a pixel stage, but other stages can be added as needed. At the minimum a single pixel stage is required, so even shaders that has no concept of multiple stages, like OSL, needs to have a single pixel stage created. 4. The shader stages interface of uniforms and varyings are established. This consists of the graph interface ports that are in use, as well as internal ports that have been published to the interface (an example of the latter is for a hardware shader generator where image texture filenames get converted to texture samplers which needs to be published in order to be bound by the target application). Each node in the graph is also called for a chance to create any uniforms or varyings needed by its implementation. 5. Information about scope is tracked for each node. This information is needed to handle branching by conditional nodes. For example, if a node is used only by a particular branch on a varying conditional we want to calculate this node only inside that scope, when that corresponding branch is taken. A node can be used in global scope, in a single conditional scope or by multiple conditional scopes. @@ -230,7 +230,7 @@ Note that if a single monolithic shader for the whole graph is not appropriate f ## 1.5 Shader Stages -Creation of multiple shader stages is supported. This is needed in order to generate separate code for multiple stages on hardware render targets. A `pixel` stage must always be created by all targets, even for shading languages like OSL that natively doensn't have a concept of stages. The stage is where the generated shader code is stored as well as all uniforms, inputs and outputs for the shader. This is handled by the `ShaderStage` class, and the data can be retrieved from it when generation is completed. +Creation of multiple shader stages is supported. This is needed in order to generate separate code for multiple stages on hardware render targets. A `pixel` stage must always be created by all targets, even for shading languages like OSL that natively doesn't have a concept of stages. The stage is where the generated shader code is stored as well as all uniforms, inputs and outputs for the shader. This is handled by the `ShaderStage` class, and the data can be retrieved from it when generation is completed. One or more `ShaderStage` instances are created and stored on the `Shader` class. In addition to the `pixel` stage, hardware generators always specify a `vertex` stage. If additional stages are needed they can be added as well. When creating shader input variables you specify which stage the variable should be used in, see 1.7 for more information on shader variable creation. diff --git a/documents/DeveloperGuide/Viewer.md b/documents/DeveloperGuide/Viewer.md index 388132ff47..17155b15ba 100644 --- a/documents/DeveloperGuide/Viewer.md +++ b/documents/DeveloperGuide/Viewer.md @@ -65,7 +65,7 @@ Shadow maps from the primary directional light may be enabled with the `Shadow M ## Images -By default, the MaterialX viewer loads and saves image files using `stb_image`, which supports commmon 8-bit formats such as JPEG, PNG, TGA, and BMP, as well as the HDR format for high-dynamic-range images. If you need access to additional image formats such as EXR and TIFF, then the MaterialX viewer can be built with support for `OpenImageIO`. To build MaterialX with OpenImageIO, check the `MATERIALX_BUILD_OIIO` option in CMake, and specify the location of your OpenImageIO installation with the `MATERIALX_OIIO_DIR` option. +By default, the MaterialX viewer loads and saves image files using `stb_image`, which supports common 8-bit formats such as JPEG, PNG, TGA, and BMP, as well as the HDR format for high-dynamic-range images. If you need access to additional image formats such as EXR and TIFF, then the MaterialX viewer can be built with support for `OpenImageIO`. To build MaterialX with OpenImageIO, check the `MATERIALX_BUILD_OIIO` option in CMake, and specify the location of your OpenImageIO installation with the `MATERIALX_OIIO_DIR` option. ## Keyboard Shortcuts diff --git a/documents/Specification/MaterialX.GeomExts.md b/documents/Specification/MaterialX.GeomExts.md index 5ff300de01..c7a874767b 100644 --- a/documents/Specification/MaterialX.GeomExts.md +++ b/documents/Specification/MaterialX.GeomExts.md @@ -196,9 +196,9 @@ Either a `geom` or a `collection` may be specified, but not both. ### GeomProp Elements -The core MaterialX Specification defines a Geometric Property, or "geomprop", as an intrinsic or user-defined surface coordinate property of geometries referenced in a specific space and/or index, and provides several nodes to retrive the values of these properties within a shading network nodegraph, as well as a <geompropdef> element used to define the name and output type of custom geometric properties beyond the standard ones: `position`, `normal`, `tangent`, `bitangent`, `texcoord` and `geomcolor`. +The core MaterialX Specification defines a Geometric Property, or "geomprop", as an intrinsic or user-defined surface coordinate property of geometries referenced in a specific space and/or index, and provides several nodes to retrieve the values of these properties within a shading network nodegraph, as well as a <geompropdef> element used to define the name and output type of custom geometric properties beyond the standard ones: `position`, `normal`, `tangent`, `bitangent`, `texcoord` and `geomcolor`. -MaterialX Geometry Extensions expands upons this by allowing the use of <geomprop> elements to define specific uniform values of a geometric property with specific geometries, as opposed to relying on those values being defined externally. This could include application-specific metadata, attributes passed from a lighting package to a renderer, or other geometry-specific data. A geomprop may also specify a `unittype` and `unit` if appropriate to indicate that the geometric property's value is in that unit; see the [**Units** section of the main MaterialX Specification](./MaterialX.Specification.md#units), although typically the <geompropdef> would define the `unittype` and `unit`, and a geomprop would only provide an overriding `unit` if the unit for its value differed from the geompropdef's defined default unit. +MaterialX Geometry Extensions expands upon this by allowing the use of <geomprop> elements to define specific uniform values of a geometric property with specific geometries, as opposed to relying on those values being defined externally. This could include application-specific metadata, attributes passed from a lighting package to a renderer, or other geometry-specific data. A geomprop may also specify a `unittype` and `unit` if appropriate to indicate that the geometric property's value is in that unit; see the [**Units** section of the main MaterialX Specification](./MaterialX.Specification.md#units), although typically the <geompropdef> would define the `unittype` and `unit`, and a geomprop would only provide an overriding `unit` if the unit for its value differed from the geompropdef's defined default unit. ```xml diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md index 67fecd80b3..748856f274 100644 --- a/documents/Specification/MaterialX.PBRSpec.md +++ b/documents/Specification/MaterialX.PBRSpec.md @@ -407,7 +407,7 @@ Note that the standard library includes definitions for [**`displacement`**](./M -* **`chiang_hair_absorption_from_color`** : Coverts the hair scattering color to absorption coefficient using the mapping method described in [^Chiang2016]. Output type `vector3`. +* **`chiang_hair_absorption_from_color`** : Converts the hair scattering color to absorption coefficient using the mapping method described in [^Chiang2016]. Output type `vector3`. * `color` (color3): Scattering color. Defaults to (1.0, 1.0, 1.0). * `azimuthal_roughness` (float): Azimuthal roughness, range [0.0, 1.0]. Defaults to 0.2. diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index d49f9c17a7..9d6fcd7623 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -1544,7 +1544,7 @@ Adjustment nodes have one input named "in", and apply a specified function to va * `gain` (float): Multiplier increases lighter color values, leaving black values unchanged; default is 1. * `contrast` (float): Linearly increase or decrease the color contrast; default is 1. * `contrastpivot` (float): Pivot value around which contrast applies. This value will not change as contrast is adjusted; default is 0.5. - * `exposure` (float): Multplier which increases or decreases color brightness by 2^value; default is 0. + * `exposure` (float): Multiplier which increases or decreases color brightness by 2^value; default is 0. diff --git a/documents/Specification/README.md b/documents/Specification/README.md index e8425c07bd..6b1afb2bb5 100644 --- a/documents/Specification/README.md +++ b/documents/Specification/README.md @@ -25,7 +25,7 @@ The documents in this folder comprise the complete MaterialX Specification, vers The parts of the main MaterialX Specification document dealing with various Geometry-related features has now been split into a separate [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) document, describing Collections, Geometry Name Expressions, geometry-related data types, Geometry Info elements and the GeomProp and Token elements used within them, and Look, Property, Visibility and assignment elements. -With this split, applications can claim to be MaterialX Compatible if they support all the things described in the main Specification, e.g. the elements for nodegraph shading networks and materials as well as the standard set of nodes, while using an application's native mechanisms or something like USD to describe the assignment of these materials to geometry. Applications may additionally support the MaterialX Geometry Extensions and thus use a single unified representation for complete CG objecct looks. +With this split, applications can claim to be MaterialX Compatible if they support all the things described in the main Specification, e.g. the elements for nodegraph shading networks and materials as well as the standard set of nodes, while using an application's native mechanisms or something like USD to describe the assignment of these materials to geometry. Applications may additionally support the MaterialX Geometry Extensions and thus use a single unified representation for complete CG object looks. **New Support for Shader AOVs** @@ -110,7 +110,7 @@ The following new standard physically based shading nodes have been added: * <Token> elements are now explicitly allowed to be children of compound nodegraphs, and token values may now have defined enum/enumvalues. * Inputs in <nodedef>s may now supply "hints" to code generators as to their intended interpretation, e.g. "transparency" or "opacity". * <Attributedef> elements may now define enum/enumvalues to list acceptable values or labels/mapped values for an attribute. -* If a string input specifies an "enum" list, the list is now considered a "strict" list of allowable values; no values are allowed outside that list. To make the input non-strict, one must omit the "enum" atribute from the input. +* If a string input specifies an "enum" list, the list is now considered a "strict" list of allowable values; no values are allowed outside that list. To make the input non-strict, one must omit the "enum" attribute from the input. Suggestions for v1.39: diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index 77437b8c56..02167b8c51 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -1458,7 +1458,7 @@ export class Material Viewer class Keeps track of local scene, and property editor as well as current MaterialX document - and assocaited material, shader and lighting information. + and associated material, shader and lighting information. */ export class Viewer { diff --git a/javascript/README.md b/javascript/README.md index bed7e0bcda..05c4c8a214 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -98,7 +98,7 @@ Note that a sample build script is provided in `javascript/build_javascript_win.bat` with a corresponding script to clean the build area in `javascript/clean_javascript_win.bat`. Modify the Emscripten SDK and MaterialX build locations as needed. -Additionaly the github actions workflow YAML file (`.github/workflows/main.yml`) can be examined as well. +Additionally the github actions workflow YAML file (`.github/workflows/main.yml`) can be examined as well. ## Using the Bindings ### Consuming the Module @@ -221,7 +221,7 @@ Each entry corresponds to a uniform name and the value is an object which contai An example that parses the JSON and feeds the uniform data to a three.js based application can be found in the [Web Viewer Sample App](./MaterialXView/src/index.js). ## Maintaining the Bindings -This section provides some background on binding creation for contributors. In general, we recommed to look at existing bindings for examples. +This section provides some background on binding creation for contributors. In general, we recommend to look at existing bindings for examples. ### What to Bind? In general, we aim for 100% coverage of the MaterialX API, at least for the Core and Format packages. However, there are functions and even classes where creating bindings wouldn't make much sense. The `splitString` utility function is such an example, because the JavaScript string class does already have a `split` method. The `FilePath` and `FileSearchPath` classes of the Format package are simply represented as strings on the JavaScript side, even though they provide complex APIs in C++. This is because most of their APIs do not apply to browsers, since they are specific to file system operations. In NodeJs, they would present a competing implementation of the core `fs` module, and therefore be redundant (even though they might be convenient in some cases). @@ -231,7 +231,7 @@ The examples above illustrate that it does not always make sense to create bindi ### Emscripten's optional_override Emscripten's `optional_override` allows to provide custom binding implementations in-place and enables function overloading by parameter count, which is otherwise not supported in JavaScript. Contributors need to be careful when using it, though, since there is a small pitfall. -If a function binding has multiple overloads defined via `optional_override` to support optional parameters, this binding must only be defined once on the base class (i.e. the class that defines the function initially). Virtual functions that are overriden in deriving classes must not be bound again when creating bindings for these derived classes. Doing so can lead to the wrong function (i.e. base class' vs derived class' implementation) being called at runtime. +If a function binding has multiple overloads defined via `optional_override` to support optional parameters, this binding must only be defined once on the base class (i.e. the class that defines the function initially). Virtual functions that are overridden in deriving classes must not be bound again when creating bindings for these derived classes. Doing so can lead to the wrong function (i.e. base class' vs derived class' implementation) being called at runtime. ### Optional Parameters Many C++ functions have optional parameters. Unfortunately, emscripten does not automatically deal with optional parameters. Binding these functions the 'normal' way will require users to provide all parameters in JavaScript, including optional ones. We provide helper macros to cicumvent this issue. Different flavors of the `BIND_*_FUNC` macros defined in `Helpers.h` can be used to conveniently bind functions with optional parameters. See uses of these macros in the existing bindings for examples. diff --git a/libraries/bxdf/lama/lama_conductor.mtlx b/libraries/bxdf/lama/lama_conductor.mtlx index 4b6b80f64a..d3a8cb765f 100644 --- a/libraries/bxdf/lama/lama_conductor.mtlx +++ b/libraries/bxdf/lama/lama_conductor.mtlx @@ -2,7 +2,7 @@ + doc="Overall color multiplier. It should be used with parsimony, as a non-white value breaks physicality. The preferred way to define the color of a conductor is through the Fresnel attributes right below." /> + doc="Rotates the anisotropy direction (possibly overridden by the previous attribute) around the normal, from 0 to 360 degrees." /> diff --git a/libraries/bxdf/lama/lama_dielectric.mtlx b/libraries/bxdf/lama/lama_dielectric.mtlx index eb5509033c..1aa75e5d5d 100644 --- a/libraries/bxdf/lama/lama_dielectric.mtlx +++ b/libraries/bxdf/lama/lama_dielectric.mtlx @@ -2,9 +2,9 @@ + doc="Color multiplier for external reflection. It should be used with parsimony, as a non-white value breaks physicality." /> + doc="Color multiplier for rays going inside the medium (covers external transmission and internal reflection). It should be used with parcimony, as a non-white value breaks physicality. The preferred way to define the color of a dielectric is through the Interior attributes right below." /> + doc="Rotates the anisotropy direction (possibly overridden by the previous attribute) around the normal, from 0 to 360 degrees." /> + doc="Color multiplier for external reflection. It should be used with parsimony, as a non-white value breaks physicality." /> + doc="Color multiplier for rays going inside the medium (covers external transmission and internal reflection). It should be used sparingly, as a non-white value breaks physicality. The preferred way to define the color of a dielectric is through the Interior attributes right below." /> + doc="Rotates the anisotropy direction (possibly overridden by the previous attribute) around the normal, from 0 to 360 degrees." /> + doc="Rotates the anisotropy direction (possibly overridden by the previous attribute) around the normal, from 0 to 360 degrees." /> - + @@ -174,19 +174,19 @@ - + - + - + diff --git a/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl b/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl index 22b2226ab3..9670c38113 100644 --- a/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl @@ -38,7 +38,7 @@ void mx_chiang_hair_absorption_from_color(vec3 color, float betaN, out vec3 abso void mx_chiang_hair_roughness( float longitudinal, float azimuthal, - float scale_TT, // empirical roughenss scale from Marschner et al. (2003). + float scale_TT, // empirical roughness scale from Marschner et al. (2003). float scale_TRT, // default: scale_TT = 0.5, scale_TRT = 2.0 out vec2 roughness_R, out vec2 roughness_TT, @@ -325,7 +325,7 @@ void mx_chiang_hair_bsdf_indirect( inout BSDF bsdf ) { - // this indirect lighing is *very* rough approximation + // this indirect lighting is *very* rough approximation N = mx_forward_facing_normal(N, V); diff --git a/libraries/stdlib/genglsl/lib/mx_hsv.glsl b/libraries/stdlib/genglsl/lib/mx_hsv.glsl index 923e9eac4e..1fb78b2202 100644 --- a/libraries/stdlib/genglsl/lib/mx_hsv.glsl +++ b/libraries/stdlib/genglsl/lib/mx_hsv.glsl @@ -1,7 +1,7 @@ /* Color transform functions. -These funcions are modified versions of the color operators found in Open Shading Language: +These functions are modified versions of the color operators found in Open Shading Language: github.com/imageworks/OpenShadingLanguage/blob/master/src/liboslexec/opcolor.cpp It contains the subset of color operators needed to implement the MaterialX diff --git a/libraries/stdlib/genglsl/lib/mx_noise.glsl b/libraries/stdlib/genglsl/lib/mx_noise.glsl index b48475bc11..21d2f1beea 100644 --- a/libraries/stdlib/genglsl/lib/mx_noise.glsl +++ b/libraries/stdlib/genglsl/lib/mx_noise.glsl @@ -90,7 +90,7 @@ vec3 mx_trilerp(vec3 v0, vec3 v1, vec3 v2, vec3 v3, vec3 v4, vec3 v5, vec3 v6, v // 2 and 3 dimensional gradient functions - perform a dot product against a // randomly chosen vector. Note that the gradient vector is not normalized, but -// this only affects the overal "scale" of the result, so we simply account for +// this only affects the overall "scale" of the result, so we simply account for // the scale by multiplying in the corresponding "perlin" function. float mx_gradient_float(uint hash, float x, float y) { @@ -468,7 +468,7 @@ float mx_worley_distance(vec2 p, int x, int y, int xoff, int yoff, float jitter, return abs(diff.x) + abs(diff.y); // Manhattan distance if (metric == 3) return max(abs(diff.x), abs(diff.y)); // Chebyshev distance - // Either Euclidian or Distance^2 + // Either Euclidean or Distance^2 return dot(diff, diff); } @@ -480,7 +480,7 @@ float mx_worley_distance(vec3 p, int x, int y, int z, int xoff, int yoff, int zo return abs(diff.x) + abs(diff.y) + abs(diff.z); // Manhattan distance if (metric == 3) return max(max(abs(diff.x), abs(diff.y)), abs(diff.z)); // Chebyshev distance - // Either Euclidian or Distance^2 + // Either Euclidean or Distance^2 return dot(diff, diff); } diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 7fadecf5e5..512f28ef16 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -3226,7 +3226,7 @@ - + @@ -3238,7 +3238,7 @@ - + diff --git a/pyproject.toml b/pyproject.toml index e674339900..6ff95958ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ experimental = true metadata.version.provider = "mtx_skbuild_plugin" metadata.version.provider-path = "./python" -# Uncoment when developing locally to enable inplace builds. +# Uncomment when developing locally to enable in-place builds. # build-dir = "build/" logging.level = "DEBUG" diff --git a/python/MaterialX/_scripts/README.md b/python/MaterialX/_scripts/README.md index f3586c5133..8041cb5f62 100644 --- a/python/MaterialX/_scripts/README.md +++ b/python/MaterialX/_scripts/README.md @@ -1,2 +1,2 @@ -This directory is empty buit it's used when packaging the Python library. +This directory is empty built it's used when packaging the Python library. the files in ../../Scripts will be copied inside. diff --git a/python/MaterialX/main.py b/python/MaterialX/main.py index ebf67f485b..c20899a4e3 100644 --- a/python/MaterialX/main.py +++ b/python/MaterialX/main.py @@ -273,7 +273,7 @@ def _typeToName(t): return getTypeString(t()) def _valueToString(value): - "(Deprecated) Convert a Python value to its correponding MaterialX value string." + "(Deprecated) Convert a Python value to its corresponding MaterialX value string." warnings.warn("This function is deprecated; call MaterialX.getValueString instead.", DeprecationWarning, stacklevel = 2) return getValueString(value) diff --git a/python/Scripts/baketextures.py b/python/Scripts/baketextures.py index 7856dca749..6595044115 100644 --- a/python/Scripts/baketextures.py +++ b/python/Scripts/baketextures.py @@ -20,7 +20,7 @@ def main(): parser.add_argument("--average", dest="average", action="store_true", help="Average baked images to generate constant values.") parser.add_argument("--path", dest="paths", action='append', nargs='+', help="An additional absolute search path location (e.g. '/projects/MaterialX')") parser.add_argument("--library", dest="libraries", action='append', nargs='+', help="An additional relative path to a custom data library folder (e.g. 'libraries/custom')") - parser.add_argument('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to seprate MaterialX documents. Default is True') + parser.add_argument('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to separate MaterialX documents. Default is True') if platform == "darwin": parser.add_argument("--glsl", dest="useGlslBackend", default=False, type=bool, help="Set to True to use GLSL backend (default = Metal).") parser.add_argument(dest="inputFilename", help="Filename of the input document.") diff --git a/python/Scripts/genmdl.py b/python/Scripts/genmdl.py index e7c2c0481f..5d1ef1cb7b 100644 --- a/python/Scripts/genmdl.py +++ b/python/Scripts/genmdl.py @@ -209,10 +209,10 @@ def _writeFourArgumentCombine(file, outputType): outputType = 'color3'; file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2, mxp_in3, mxp_in4);\n') -def _writeIfGreater(file, comparitor): - file.write(INDENT + 'if (mxp_value1 ' + comparitor + ' mxp_value2) { return mxp_in1; } return mxp_in2;\n' ) +def _writeIfGreater(file, comparator): + file.write(INDENT + 'if (mxp_value1 ' + comparator + ' mxp_value2) { return mxp_in1; } return mxp_in2;\n' ) -def _writeTranformSpace(file, outputType, functionName, input, fromspace, tospace): +def _writeTransformSpace(file, outputType, functionName, input, fromspace, tospace): file.write(INDENT + 'state::coordinate_space fromSpace = ::mx_map_space(' + fromspace + ');\n') file.write(INDENT + 'state::coordinate_space toSpace = ::mx_map_space(' + tospace + ');\n') file.write(INDENT + 'return mk_' + outputType + '( state::' + functionName + '(fromSpace, toSpace, ' + input + '));\n') @@ -872,25 +872,25 @@ def main(): file.write(INDENT + 'return math::lerp(mxp_valuet, mxp_valueb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') wroteImplementation = True elif nodeCategory == 'transformvector': - _writeTranformSpace(file, outputType, 'transform_vector', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') + _writeTransformSpace(file, outputType, 'transform_vector', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') wroteImplementation = True elif nodeCategory == 'transformpoint': - _writeTranformSpace(file, outputType, 'transform_point', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') + _writeTransformSpace(file, outputType, 'transform_point', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') wroteImplementation = True elif nodeCategory == 'transformnormal': - _writeTranformSpace(file, outputType, 'transform_normal', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') + _writeTransformSpace(file, outputType, 'transform_normal', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') wroteImplementation = True elif nodeCategory == 'position': - _writeTranformSpace(file, outputType, 'transform_point', 'state::position()', 'mx_coordinatespace_type_model', 'mxp_space') + _writeTransformSpace(file, outputType, 'transform_point', 'state::position()', 'mx_coordinatespace_type_model', 'mxp_space') wroteImplementation = True elif nodeCategory == 'normal': - _writeTranformSpace(file, outputType, 'transform_normal', 'state::normal()', 'mx_coordinatespace_type_model', 'mxp_space') + _writeTransformSpace(file, outputType, 'transform_normal', 'state::normal()', 'mx_coordinatespace_type_model', 'mxp_space') wroteImplementation = True elif nodeCategory == 'tangent': - _writeTranformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_u(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space') + _writeTransformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_u(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space') wroteImplementation = True elif nodeCategory == 'bitangent': - _writeTranformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_v(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space') + _writeTransformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_v(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space') wroteImplementation = True elif nodeCategory == 'texcoord': file.write(INDENT + 'return mk_' + outputType + '(state::texture_coordinate(mxp_index));\n') diff --git a/python/Scripts/translateshader.py b/python/Scripts/translateshader.py index fca1e2ab07..08c94b582f 100644 --- a/python/Scripts/translateshader.py +++ b/python/Scripts/translateshader.py @@ -21,7 +21,7 @@ def main(): parser.add_argument("--hdr", dest="hdr", action="store_true", help="Bake images with high dynamic range (e.g. in HDR or EXR format).") parser.add_argument("--path", dest="paths", action='append', nargs='+', help="An additional absolute search path location (e.g. '/projects/MaterialX')") parser.add_argument("--library", dest="libraries", action='append', nargs='+', help="An additional relative path to a custom data library folder (e.g. 'libraries/custom')") - parser.add_argument('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to seprate MaterialX documents. Default is True') + parser.add_argument('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to separate MaterialX documents. Default is True') if platform == "darwin": parser.add_argument("--glsl", dest="useGlslBackend", default=False, type=bool, help="Set to True to use GLSL backend (default = Metal).") parser.add_argument(dest="inputFilename", help="Filename of the input document.") diff --git a/resources/Materials/TestSuite/_options.mtlx b/resources/Materials/TestSuite/_options.mtlx index 298f16f0c3..d9b2950b43 100644 --- a/resources/Materials/TestSuite/_options.mtlx +++ b/resources/Materials/TestSuite/_options.mtlx @@ -36,7 +36,7 @@ - + diff --git a/resources/Materials/TestSuite/stdlib/texture/ramp.mtlx b/resources/Materials/TestSuite/stdlib/texture/ramp.mtlx index e25f1b9edb..af88901837 100644 --- a/resources/Materials/TestSuite/stdlib/texture/ramp.mtlx +++ b/resources/Materials/TestSuite/stdlib/texture/ramp.mtlx @@ -4,7 +4,7 @@ Basic ramp unit test : - Ramp (left-to-right) - Ramp (top-to-bottom) - - Ramp (four coner) + - Ramp (four corner) --> diff --git a/source/JsMaterialX/JsMaterialXGenShader/JsGenContext.cpp b/source/JsMaterialX/JsMaterialXGenShader/JsGenContext.cpp index 50537151fe..461f84b31d 100644 --- a/source/JsMaterialX/JsMaterialXGenShader/JsGenContext.cpp +++ b/source/JsMaterialX/JsMaterialXGenShader/JsGenContext.cpp @@ -44,7 +44,7 @@ void initContext(mx::GenContext& context, mx::FileSearchPath searchPath, mx::Doc context.getOptions().targetDistanceUnit = "meter"; } -/// Tries to load the standard libaries and initialize the given generation context. The loaded libraries are added to the returned document +/// Tries to load the standard libraries and initialize the given generation context. The loaded libraries are added to the returned document mx::DocumentPtr loadStandardLibraries(mx::GenContext& context) { mx::DocumentPtr stdLib; diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index bec824ecda..b755e46d37 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -773,7 +773,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr } } - // If did not peform a value comparison, perform the default comparison + // If did not perform a value comparison, perform the default comparison if (!performedValueComparison) { return Element::isAttributeEquivalent(rhs, attributeName, options, message); @@ -855,7 +855,7 @@ void StringResolver::addTokenSubstitutions(ConstElementPtr element) const string DELIMITER_PREFIX = "["; const string DELIMITER_POSTFIX = "]"; - // Travese from sibliings up until root is reached. + // Traverse from siblings up until root is reached. // Child tokens override any parent tokens. ConstElementPtr parent = element->getParent(); while (parent) diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 6b145a57b1..c7823fe1d6 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -410,7 +410,7 @@ class MX_CORE_API Element : public std::enable_shared_from_this /// Add a child element of the given category and name. /// @param category The category string of the new child element. - /// If the category string is recognized, then the correponding Element + /// If the category string is recognized, then the corresponding Element /// subclass is generated; otherwise, a GenericElement is generated. /// @param name The name of the new child element. /// If no name is specified, then a unique name will automatically be @@ -678,7 +678,7 @@ class MX_CORE_API Element : public std::enable_shared_from_this /// @return The upstream Edge, if valid, or an empty Edge object. virtual Edge getUpstreamEdge(size_t index = 0) const; - /// Return the number of queriable upstream edges for this element. + /// Return the number of queryable upstream edges for this element. virtual size_t getUpstreamEdgeCount() const { return 0; @@ -1076,7 +1076,7 @@ class MX_CORE_API ValueElement : public TypedElement return getAttribute(UNIT_ATTRIBUTE); } - /// Return the unit defined by the assocaited NodeDef if this element + /// Return the unit defined by the associated NodeDef if this element /// is a child of a Node. const string& getActiveUnit() const; diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index 599f85ed9d..c0bc3922d0 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -279,7 +279,7 @@ class MX_CORE_API Output : public PortElement /// this element in the dataflow graph. Edge getUpstreamEdge(size_t index = 0) const override; - /// Return the number of queriable upstream edges for this element. + /// Return the number of queryable upstream edges for this element. size_t getUpstreamEdgeCount() const override { return 1; diff --git a/source/MaterialXCore/Node.h b/source/MaterialXCore/Node.h index 5a6b7c4144..181acfd6da 100644 --- a/source/MaterialXCore/Node.h +++ b/source/MaterialXCore/Node.h @@ -119,7 +119,7 @@ class MX_CORE_API Node : public InterfaceElement /// this element in the dataflow graph. Edge getUpstreamEdge(size_t index = 0) const override; - /// Return the number of queriable upstream edges for this element. + /// Return the number of queryable upstream edges for this element. size_t getUpstreamEdgeCount() const override { return getInputCount(); diff --git a/source/MaterialXCore/Unit.h b/source/MaterialXCore/Unit.h index dbc63bb68e..2b104f90a4 100644 --- a/source/MaterialXCore/Unit.h +++ b/source/MaterialXCore/Unit.h @@ -196,7 +196,7 @@ class MX_CORE_API UnitConverterRegistry void write(DocumentPtr doc) const; /// Convert input values which have a source unit to a given target unit. - /// Returns if any unit conversion occured. + /// Returns if any unit conversion occurred. bool convertToUnit(DocumentPtr doc, const string& unitType, const string& targetUnit); private: diff --git a/source/MaterialXCore/Version.cpp b/source/MaterialXCore/Version.cpp index 62f83a5660..a1a6e16d5b 100644 --- a/source/MaterialXCore/Version.cpp +++ b/source/MaterialXCore/Version.cpp @@ -500,7 +500,7 @@ void Document::upgradeVersion() } } - // Change nodes with category "tranform[vector|point|normal]", + // Change nodes with category "transform[vector|point|normal]", // which are not fromspace/tospace variants, to "transformmatrix" else if (nodeCategory == "transformpoint" || nodeCategory == "transformvector" || diff --git a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h index 8a08081987..776f288c2b 100644 --- a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h +++ b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h @@ -26,7 +26,7 @@ class MX_GENGLSL_API HeightToNormalNodeGlsl : public ConvolutionNode const string& getTarget() const override; protected: - /// Return if given type is an acceptible input + /// Return if given type is an acceptable input bool acceptsInputType(TypeDesc type) const override; /// Compute offset strings for sampling diff --git a/source/MaterialXGenGlsl/Nodes/LightCompoundNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/LightCompoundNodeGlsl.cpp index 6f005766fd..31b1b6758b 100644 --- a/source/MaterialXGenGlsl/Nodes/LightCompoundNodeGlsl.cpp +++ b/source/MaterialXGenGlsl/Nodes/LightCompoundNodeGlsl.cpp @@ -95,7 +95,7 @@ void LightCompoundNodeGlsl::emitFunctionDefinition(ClosureContext* cct, GenConte if (cct) { // Use the first output for classifying node type for the closure context. - // This is only relevent for closures, and they only have a single output. + // This is only relevant for closures, and they only have a single output. const TypeDesc nodeType = _rootGraph->getOutputSocket()->getType(); shadergen.emitLine("void " + _functionName + cct->getSuffix(nodeType) + "(LightData light, vec3 position, out lightshader result)", stage, false); } diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index a3a4db7835..0f983cf8f2 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -85,7 +85,7 @@ const std::unordered_map MdlShaderGenerator::GEOMPROP_DEFINITION MdlShaderGenerator::MdlShaderGenerator() : ShaderGenerator(MdlSyntax::create()) { - // Register build-in implementations + // Register built-in implementations // registerImplementation("IM_surfacematerial_" + MdlShaderGenerator::TARGET, MaterialNodeMdl::create); @@ -571,7 +571,7 @@ bool checkTransmissionIorDependencies(ShaderGraph* g, std::set& gr return result; } -// Disconnect any incomming connections to transmission IOR +// Disconnect any incoming connections to transmission IOR // inside a graph. void disconnectTransmissionIor(ShaderGraph* g) { @@ -673,7 +673,7 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen // For graphs that has a dependency with transmission IOR on the inside, // we can declare the corresponding inputs as being uniform and preserve - // the internal connection to transmssion IOR. + // the internal connection to transmission IOR. for (ShaderGraph* g : graphsWithIorDependency) { for (ShaderOutput* socket : g->getInputSockets()) diff --git a/source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp index ae10ca3fa8..2d4c89a195 100644 --- a/source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp @@ -41,7 +41,7 @@ void BlurNodeMdl::outputSampleArray(const ShaderGenerator& shadergen, ShaderStag shadergen.emitLineEnd(stage, false); } // We must fill out the whole array to have a valid MDL syntax. - // So padd it with dummy default values. + // So pad it with dummy default values. for (size_t i = sampleCount; i < maxSampleCount; i++) { shadergen.emitLineBegin(stage); diff --git a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp index 59b488c875..ec5f45db12 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp @@ -48,7 +48,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC const bool isMaterialExpr = (upstream->hasClassification(ShaderNode::Classification::CLOSURE) || upstream->hasClassification(ShaderNode::Classification::SHADER)); - // since the emit fuctions are const, the field name to generate a function for is passed via context + // since the emit functions are const, the field name to generate a function for is passed via context const std::string& fieldName = outputSocket->getName(); GenUserDataStringPtr fieldNamePtr = std::make_shared(fieldName); context.pushUserData(CompoundNodeMdl::GEN_USER_DATA_RETURN_STRUCT_FIELD_NAME, fieldNamePtr); @@ -57,7 +57,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC shadergen.emitComment("unrolled structure field: " + _returnStruct + "." + fieldName + " (name=\"" + node.getName() + "\")", stage); emitFunctionSignature(node, context, stage); - // Special case for material expresions. + // Special case for material expressions. if (isMaterialExpr) { shadergen.emitLine(" = let", stage, false); @@ -103,7 +103,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC // Emit function signature. emitFunctionSignature(node, context, stage); - // Special case for material expresions. + // Special case for material expressions. if (isMaterialExpr) { shadergen.emitLine(" = let", stage, false); diff --git a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp index 2dab721e24..517e1ca912 100644 --- a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp @@ -58,7 +58,7 @@ void CompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& // Emit function signature. emitFunctionSignature(node, context, stage); - // Special case for material expresions. + // Special case for material expressions. if (isMaterialExpr) { shadergen.emitLine(" = let", stage, false); diff --git a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h index 1e295e5872..cf4d2b7d06 100644 --- a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h @@ -23,7 +23,7 @@ class MX_GENMDL_API HeightToNormalNodeMdl : public ConvolutionNode const string& getTarget() const override; protected: - /// Return if given type is an acceptible input + /// Return if given type is an acceptable input bool acceptsInputType(TypeDesc type) const override; /// Compute offset strings for sampling diff --git a/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp index 6891fc1778..48ae89c13f 100644 --- a/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp @@ -41,7 +41,7 @@ void MaterialNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& cont shadergen.emitLineBegin(stage); - // Emit the output and funtion name. + // Emit the output and function name. shadergen.emitOutput(node.getOutput(), true, false, context, stage); shadergen.emitString(" = materialx::stdlib_", stage); shadergenMdl.emitMdlVersionFilenameSuffix(context, stage); diff --git a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp index 8904d835f4..53c2914f9e 100644 --- a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp @@ -75,7 +75,7 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex shadergen.emitLineBegin(stage); - // Emit the output and funtion name. + // Emit the output and function name. shadergen.emitOutput(node.getOutput(), true, false, context, stage); shadergen.emitString(" = materialx::pbrlib_", stage); shadergen.emitMdlVersionFilenameSuffix(context, stage); diff --git a/source/MaterialXGenMdl/mdl/materialx/core.mdl b/source/MaterialXGenMdl/mdl/materialx/core.mdl index 4e49ce9448..f4dbb8f3c8 100644 --- a/source/MaterialXGenMdl/mdl/materialx/core.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/core.mdl @@ -53,13 +53,13 @@ export const float FLOAT_EPS = 0.000001; // matrix33 --> float3x3 // matrix44 --> float4x4 // string --> string, or context specific enums (see below) -// filename --> texture_2d, or other repective resource type +// filename --> texture_2d, or other respective resource type // geomname --> (N.A.) // array --> T[] (deferred-size arrays) // // NOTE: The type mapping is not bijective, multiple types in MaterialX // map to the same type in MDL, which can impact the translation -// of overloaded nodes to not generate mutliple identical definitions. +// of overloaded nodes to not generate multiple identical definitions. // Special struct type for color4 export struct color4 { @@ -201,6 +201,6 @@ export enum mx_distribution_type { }; // Custom annotation for MDL function parameters to map between MDL and the original MaterialX graph. -// * When added to a paramater, the "name" will contain the path in the MaterialX graph starting +// * When added to a parameter, the "name" will contain the path in the MaterialX graph starting // from the root up to the input using `/` as separator. export annotation origin(string name); diff --git a/source/MaterialXGenMdl/mdl/materialx/noise.mdl b/source/MaterialXGenMdl/mdl/materialx/noise.mdl index 3051cf19c2..8f7fe1b511 100644 --- a/source/MaterialXGenMdl/mdl/materialx/noise.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/noise.mdl @@ -81,7 +81,7 @@ float3 mx_trilerp_float3(float3 v0, float3 v1, float3 v2, float3 v3, float3 v4, // 2 and 3 dimensional gradient functions - perform a dot product against a // randomly chosen vector. Note that the gradient vector is not normalized, but -// this only affects the overal "scale" of the result, so we simply account for +// this only affects the overall "scale" of the result, so we simply account for // the scale by multiplying in the corresponding "perlin" function. float mx_gradient_float(int mxp_hash, float mxp_x, float mxp_y) { @@ -545,7 +545,7 @@ float mx_worley_distance2(float2 p, int x, int y, int xoff, int yoff, float jitt return math::abs(diff.x) + math::abs(diff.y); // Manhattan distance if (metric == 3) return math::max(math::abs(diff.x), math::abs(diff.y)); // Chebyshev distance - // Either Euclidian or Distance^2 + // Either Euclidean or Distance^2 return math::dot(diff, diff); } @@ -563,7 +563,7 @@ float mx_worley_distance3(float3 p, int x, int y, int z, int xoff, int yoff, int return math::abs(diff.x) + math::abs(diff.y) + math::abs(diff.z); // Manhattan distance if (metric == 3) return math::max(math::max(math::abs(diff.x), math::abs(diff.y)), math::abs(diff.z)); // Chebyshev distance - // Either Euclidian or Distance^2 + // Either Euclidean or Distance^2 return math::dot(diff, diff); } diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index d886d43e96..4c75e5008a 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -219,9 +219,9 @@ void MslShaderGenerator::MetalizeGeneratedShader(ShaderStage& shaderStage) const pos = sourceCode.find(keyword); while (pos != std::string::npos) { - char preceeding = sourceCode[pos - 1], succeeding = sourceCode[pos + keyword.length()]; + char preceding = sourceCode[pos - 1], succeeding = sourceCode[pos + keyword.length()]; bool isOutKeyword = - (preceeding == '(' || preceeding == ',' || std::isspace(preceeding)) && + (preceding == '(' || preceding == ',' || std::isspace(preceding)) && std::isspace(succeeding) && succeeding != '\n'; size_t beg = pos; diff --git a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h index e8dd879949..02ff1f7456 100644 --- a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h +++ b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h @@ -26,7 +26,7 @@ class MX_GENMSL_API HeightToNormalNodeMsl : public ConvolutionNode const string& getTarget() const override; protected: - /// Return if given type is an acceptible input + /// Return if given type is an acceptable input bool acceptsInputType(TypeDesc type) const override; /// Compute offset strings for sampling diff --git a/source/MaterialXGenMsl/Nodes/LightCompoundNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/LightCompoundNodeMsl.cpp index 1e5bd787a8..d7d5d8ceaa 100644 --- a/source/MaterialXGenMsl/Nodes/LightCompoundNodeMsl.cpp +++ b/source/MaterialXGenMsl/Nodes/LightCompoundNodeMsl.cpp @@ -95,7 +95,7 @@ void LightCompoundNodeMsl::emitFunctionDefinition(ClosureContext* cct, GenContex if (cct) { // Use the first output for classifying node type for the closure context. - // This is only relevent for closures, and they only have a single output. + // This is only relevant for closures, and they only have a single output. const TypeDesc nodeType = _rootGraph->getOutputSocket()->getType(); shadergen.emitLine("void " + _functionName + cct->getSuffix(nodeType) + "(LightData light, float3 position, out lightshader result)", stage, false); } diff --git a/source/MaterialXGenOsl/Nodes/MaterialNodeOsl.cpp b/source/MaterialXGenOsl/Nodes/MaterialNodeOsl.cpp index 42518e9c1d..cab5a8d695 100644 --- a/source/MaterialXGenOsl/Nodes/MaterialNodeOsl.cpp +++ b/source/MaterialXGenOsl/Nodes/MaterialNodeOsl.cpp @@ -50,7 +50,7 @@ void MaterialNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& cont shadergen.emitLineBegin(stage); - // Emit the output and funtion name. + // Emit the output and function name. shadergen.emitOutput(node.getOutput(), true, false, context, stage); shadergen.emitString(" = mx_surfacematerial(", stage); diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index ff8cad36f5..22dd6f81d1 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -31,7 +31,7 @@ const string OslShaderGenerator::TARGET = "genosl"; OslShaderGenerator::OslShaderGenerator() : ShaderGenerator(OslSyntax::create()) { - // Register build-in implementations + // Register built-in implementations // registerImplementation("IM_blur_float_" + OslShaderGenerator::TARGET, BlurNodeOsl::create); @@ -214,7 +214,7 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G { // Special case for having 'surfaceshader' as final output type. // This type is a struct internally (BSDF, EDF, opacity) so we must - // comvert this to a single closure color type in order for renderers + // convert this to a single closure color type in order for renderers // to understand this output. const ShaderGraphOutputSocket* socket = graph.getOutputSocket(0); const string result = getUpstreamResult(socket, context); @@ -251,7 +251,7 @@ void OslShaderGenerator::registerShaderMetadata(const DocumentPtr& doc, GenConte ShaderMetadataRegistryPtr registry = context.getUserData(ShaderMetadataRegistry::USER_DATA_NAME); if (!registry) { - throw ExceptionShaderGenError("Registration of metadata faild"); + throw ExceptionShaderGenError("Registration of metadata failed"); } // Rename the standard metadata names to corresponding OSL metadata names. diff --git a/source/MaterialXGenShader/HwShaderGenerator.cpp b/source/MaterialXGenShader/HwShaderGenerator.cpp index 20f91d6985..d9862650e3 100644 --- a/source/MaterialXGenShader/HwShaderGenerator.cpp +++ b/source/MaterialXGenShader/HwShaderGenerator.cpp @@ -330,7 +330,7 @@ ShaderPtr HwShaderGenerator::createShader(const string& name, ElementPtr element ShaderStagePtr ps = createStage(Stage::PIXEL, *shader); VariableBlockPtr psOutputs = ps->createOutputBlock(HW::PIXEL_OUTPUTS, "o_ps"); - // Create required Uniform blocks and any additonal blocks if needed. + // Create required Uniform blocks and any additional blocks if needed. VariableBlockPtr psPrivateUniforms = ps->createUniformBlock(HW::PRIVATE_UNIFORMS, "u_prv"); VariableBlockPtr psPublicUniforms = ps->createUniformBlock(HW::PUBLIC_UNIFORMS, "u_pub"); VariableBlockPtr lightData = ps->createUniformBlock(HW::LIGHT_DATA, HW::T_LIGHT_DATA_INSTANCE); @@ -468,7 +468,7 @@ ShaderPtr HwShaderGenerator::createShader(const string& name, ElementPtr element ShaderPort* filename = psPublicUniforms->add(Type::FILENAME, input->getVariable(), input->getValue()); filename->setPath(input->getPath()); - // Assing the uniform name to the input value + // Assign the uniform name to the input value // so we can reference it during code generation. input->setValue(Value::createValue(input->getVariable())); } diff --git a/source/MaterialXGenShader/HwShaderGenerator.h b/source/MaterialXGenShader/HwShaderGenerator.h index bdd1e33a5c..3712410606 100644 --- a/source/MaterialXGenShader/HwShaderGenerator.h +++ b/source/MaterialXGenShader/HwShaderGenerator.h @@ -23,7 +23,7 @@ a listing of the variables with a description of what data they should be bound However, different renderers can have different requirements on naming conventions for these variables. In order to facilitate this the generators will use token substitution for naming the variables. The -first colum below shows the token names that should be used in source code before the token substitution +first column below shows the token names that should be used in source code before the token substitution is done. The second row shows the real identifier names that will be used by default after substitution. An generator can override these identifier names in order to use a custom naming convention for these. Overriding identifier names is done by changing the entries in the identifiers map given to the function diff --git a/source/MaterialXGenShader/Nodes/BlurNode.h b/source/MaterialXGenShader/Nodes/BlurNode.h index fa41d11678..a53cc7b712 100644 --- a/source/MaterialXGenShader/Nodes/BlurNode.h +++ b/source/MaterialXGenShader/Nodes/BlurNode.h @@ -24,7 +24,7 @@ class MX_GENSHADER_API BlurNode : public ConvolutionNode /// Emit function definitions for sampling functions used by this node. virtual void emitSamplingFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const = 0; - /// Return if given type is an acceptible input + /// Return if given type is an acceptable input bool acceptsInputType(TypeDesc type) const override; /// Compute offset strings for sampling diff --git a/source/MaterialXGenShader/Nodes/ClosureCompoundNode.cpp b/source/MaterialXGenShader/Nodes/ClosureCompoundNode.cpp index 2f9f5a7dec..91677e7f40 100644 --- a/source/MaterialXGenShader/Nodes/ClosureCompoundNode.cpp +++ b/source/MaterialXGenShader/Nodes/ClosureCompoundNode.cpp @@ -60,7 +60,7 @@ void ClosureCompoundNode::emitFunctionDefinition(ClosureContext* cct, GenContext if (cct) { // Use the first output for classifying node type for the closure context. - // This is only relevent for closures, and they only have a single output. + // This is only relevant for closures, and they only have a single output. const TypeDesc closureType = _rootGraph->getOutputSocket()->getType(); shadergen.emitString("void " + _functionName + cct->getSuffix(closureType) + "(", stage); @@ -165,7 +165,7 @@ void ClosureCompoundNode::emitFunctionCall(const ShaderNode& node, GenContext& c if (cct) { // Use the first output for classifying node type for the closure context. - // This is only relevent for closures, and they only have a single output. + // This is only relevant for closures, and they only have a single output. const ShaderGraphOutputSocket* outputSocket = _rootGraph->getOutputSocket(); const TypeDesc closureType = outputSocket->getType(); diff --git a/source/MaterialXGenShader/Nodes/ClosureSourceCodeNode.h b/source/MaterialXGenShader/Nodes/ClosureSourceCodeNode.h index ad56c7ff03..5527dee135 100644 --- a/source/MaterialXGenShader/Nodes/ClosureSourceCodeNode.h +++ b/source/MaterialXGenShader/Nodes/ClosureSourceCodeNode.h @@ -11,7 +11,7 @@ MATERIALX_NAMESPACE_BEGIN /// @class ClosureSourceCodeNode -/// Implemention for a closure node using data-driven static source code. +/// Implementation for a closure node using data-driven static source code. class MX_GENSHADER_API ClosureSourceCodeNode : public SourceCodeNode { public: diff --git a/source/MaterialXGenShader/Nodes/HwImageNode.cpp b/source/MaterialXGenShader/Nodes/HwImageNode.cpp index e8eddd6e1a..260359b50a 100644 --- a/source/MaterialXGenShader/Nodes/HwImageNode.cpp +++ b/source/MaterialXGenShader/Nodes/HwImageNode.cpp @@ -10,7 +10,7 @@ #include MATERIALX_NAMESPACE_BEGIN -// Additional implementaton arguments for image nodes +// Additional implementation arguments for image nodes const string UV_SCALE = "uv_scale"; const string UV_OFFSET = "uv_offset"; diff --git a/source/MaterialXGenShader/Nodes/MaterialNode.cpp b/source/MaterialXGenShader/Nodes/MaterialNode.cpp index 34e7a21a95..fa6dca0f86 100644 --- a/source/MaterialXGenShader/Nodes/MaterialNode.cpp +++ b/source/MaterialXGenShader/Nodes/MaterialNode.cpp @@ -48,7 +48,7 @@ void MaterialNode::emitFunctionCall(const ShaderNode& _node, GenContext& context const ShaderNode* surfaceshaderNode = surfaceshaderInput->getConnection()->getNode(); shadergen.emitFunctionCall(*surfaceshaderNode, context, stage); - // Assing this result to the material output variable. + // Assign this result to the material output variable. const ShaderOutput* output = node.getOutput(); shadergen.emitLine(syntax.getTypeName(output->getType()) + " " + output->getVariable() + " = " + surfaceshaderInput->getConnection()->getVariable(), stage); } diff --git a/source/MaterialXGenShader/Nodes/SourceCodeNode.h b/source/MaterialXGenShader/Nodes/SourceCodeNode.h index 6169dc0f61..593ec846bd 100644 --- a/source/MaterialXGenShader/Nodes/SourceCodeNode.h +++ b/source/MaterialXGenShader/Nodes/SourceCodeNode.h @@ -13,7 +13,7 @@ MATERIALX_NAMESPACE_BEGIN /// @class SourceCodeNode -/// Implemention for a node using data-driven static source code. +/// Implementation for a node using data-driven static source code. /// This is the default implementation used for all nodes that /// do not have a custom ShaderNodeImpl class. class MX_GENSHADER_API SourceCodeNode : public ShaderNodeImpl diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index c60910aaed..0c9f80cf8e 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -1165,7 +1165,7 @@ void ShaderGraph::populateUnitTransformMap(UnitSystemPtr unitSystem, ShaderPort* // return; //} - // Only support convertion for float and vectors. arrays, matrices are not supported. + // Only support conversion for float and vectors. arrays, matrices are not supported. // TODO: This should be provided by the UnitSystem. bool supportedType = (shaderPort->getType() == Type::FLOAT || shaderPort->getType() == Type::VECTOR2 || diff --git a/source/MaterialXGenShader/ShaderGraph.h b/source/MaterialXGenShader/ShaderGraph.h index 77fd090b66..3ad126923b 100644 --- a/source/MaterialXGenShader/ShaderGraph.h +++ b/source/MaterialXGenShader/ShaderGraph.h @@ -46,7 +46,7 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode /// Constructor. ShaderGraph(const ShaderGraph* parent, const string& name, ConstDocumentPtr document, const StringSet& reservedWords); - /// Desctructor. + /// Destructor. virtual ~ShaderGraph() { } /// Create a new shader graph from an element. diff --git a/source/MaterialXGenShader/ShaderNodeImpl.cpp b/source/MaterialXGenShader/ShaderNodeImpl.cpp index 7cd929a8e0..663b85eb2b 100644 --- a/source/MaterialXGenShader/ShaderNodeImpl.cpp +++ b/source/MaterialXGenShader/ShaderNodeImpl.cpp @@ -29,7 +29,7 @@ void ShaderNodeImpl::initialize(const InterfaceElement& element, GenContext&) // By default use the implementation name as hash to make it unique. // Derived classes can override this to create other hashes, - // e.g. to share the same hash beteen nodes that can share + // e.g. to share the same hash between nodes that can share // the same function definition. _hash = std::hash{}(_name); } diff --git a/source/MaterialXGenShader/ShaderNodeImpl.h b/source/MaterialXGenShader/ShaderNodeImpl.h index b9fd2a5148..c1527509dd 100644 --- a/source/MaterialXGenShader/ShaderNodeImpl.h +++ b/source/MaterialXGenShader/ShaderNodeImpl.h @@ -97,7 +97,7 @@ class MX_GENSHADER_API ShaderNodeImpl /// Returns true if a graph input is accessible by users. /// Accessible inputs are allowed to be published as shader uniforms /// and hence must be presentable in a user interface. - /// By default all graph inputs are considered to be acessible. + /// By default all graph inputs are considered to be accessible. virtual bool isEditable(const ShaderGraphInputSocket& /*input*/) const { return true; diff --git a/source/MaterialXGenShader/ShaderStage.cpp b/source/MaterialXGenShader/ShaderStage.cpp index 7ed3e710aa..e5db61e503 100644 --- a/source/MaterialXGenShader/ShaderStage.cpp +++ b/source/MaterialXGenShader/ShaderStage.cpp @@ -315,7 +315,7 @@ void ShaderStage::addBlock(const string& str, const FilePath& sourceFilename, Ge const string& INCLUDE = _syntax->getIncludeStatement(); const string& QUOTE = _syntax->getStringQuote(); - // Add each line in the block seperately to get correct indentation. + // Add each line in the block separately to get correct indentation. StringStream stream(str); for (string line; std::getline(stream, line);) { diff --git a/source/MaterialXGenShader/ShaderStage.h b/source/MaterialXGenShader/ShaderStage.h index 72e0c2cdd5..c6b73d3ae8 100644 --- a/source/MaterialXGenShader/ShaderStage.h +++ b/source/MaterialXGenShader/ShaderStage.h @@ -148,7 +148,7 @@ class MX_GENSHADER_API ShaderStage }; public: - /// Contructor. + /// Constructor. ShaderStage(const string& name, ConstSyntaxPtr syntax); /// Return the stage name. diff --git a/source/MaterialXGenShader/Syntax.h b/source/MaterialXGenShader/Syntax.h index 6f16633b59..5faafd002a 100644 --- a/source/MaterialXGenShader/Syntax.h +++ b/source/MaterialXGenShader/Syntax.h @@ -166,7 +166,7 @@ class MX_GENSHADER_API Syntax virtual string getArrayVariableSuffix(TypeDesc type, const Value& value) const; [[deprecated]] string getArrayVariableSuffix(const TypeDesc* type, const Value& value) const { return getArrayVariableSuffix(*type, value); } - /// Query if given type is suppored in the syntax. + /// Query if given type is supported in the syntax. /// By default all types are assumed to be supported. [[deprecated]] virtual bool typeSupported(const TypeDesc* type) const; diff --git a/source/MaterialXGenShader/UnitSystem.cpp b/source/MaterialXGenShader/UnitSystem.cpp index 232351b526..21d5076177 100644 --- a/source/MaterialXGenShader/UnitSystem.cpp +++ b/source/MaterialXGenShader/UnitSystem.cpp @@ -51,7 +51,7 @@ void ScalarUnitNode::emitFunctionDefinition(const ShaderNode& node, GenContext& { DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { - // Emit the helper funtion mx__unit_ratio that embeds a look up table for unit scale + // Emit the helper function mx__unit_ratio that embeds a look up table for unit scale vector unitScales; unitScales.reserve(_scalarUnitConverter->getUnitScale().size()); auto unitScaleMap = _scalarUnitConverter->getUnitScale(); @@ -116,7 +116,7 @@ UnitTransform::UnitTransform(const string& ss, const string& ts, TypeDesc t, con } } -const string UnitSystem::UNITSYTEM_NAME = "default_unit_system"; +const string UnitSystem::UNITSYSTEM_NAME = "default_unit_system"; UnitSystem::UnitSystem(const string& target) : _target(createValidName(target)) @@ -186,7 +186,7 @@ ShaderNodePtr UnitSystem::createNode(ShaderGraph* parent, const UnitTransform& t UnitTypeDefPtr scalarTypeDef = _document->getUnitTypeDef(transform.unitType); if (!_unitRegistry || !_unitRegistry->getUnitConverter(scalarTypeDef)) { - throw ExceptionTypeError("Unit registry unavaliable or undefined unit converter for: " + transform.unitType); + throw ExceptionTypeError("Unit registry unavailable or undefined unit converter for: " + transform.unitType); } LinearUnitConverterPtr scalarConverter = std::dynamic_pointer_cast(_unitRegistry->getUnitConverter(scalarTypeDef)); diff --git a/source/MaterialXGenShader/UnitSystem.h b/source/MaterialXGenShader/UnitSystem.h index 4108917558..c603bb32e5 100644 --- a/source/MaterialXGenShader/UnitSystem.h +++ b/source/MaterialXGenShader/UnitSystem.h @@ -59,7 +59,7 @@ class MX_GENSHADER_API UnitSystem /// Return the UnitSystem name virtual const string& getName() const { - return UnitSystem::UNITSYTEM_NAME; + return UnitSystem::UNITSYSTEM_NAME; } /// Assign unit converter registry replacing any previous assignment @@ -81,7 +81,7 @@ class MX_GENSHADER_API UnitSystem /// Returns a nodedef for a given transform virtual NodeDefPtr getNodeDef(const UnitTransform& transform) const; - static const string UNITSYTEM_NAME; + static const string UNITSYSTEM_NAME; protected: // Protected constructor diff --git a/source/MaterialXGenShader/Util.h b/source/MaterialXGenShader/Util.h index 23a59e0437..abaf062228 100644 --- a/source/MaterialXGenShader/Util.h +++ b/source/MaterialXGenShader/Util.h @@ -28,7 +28,7 @@ class ShaderGenerator; /// how transparency can be done and target applications might need to do /// additional checks to track transparency correctly. For example, custom /// surface shader nodes implemented in source code will not be tracked by this -/// function and transprency for such nodes must be tracked separately by the +/// function and transparency for such nodes must be tracked separately by the /// target application. /// MX_GENSHADER_API bool isTransparentSurface(ElementPtr element, const string& target = EMPTY_STRING); @@ -60,7 +60,7 @@ MX_GENSHADER_API vector findRenderableElements(ConstDocumentPtr /// The optional target string can be used to guide the selection of nodedef declarations. MX_GENSHADER_API InputPtr getNodeDefInput(InputPtr nodeInput, const string& target); -/// Perform token substitutions on the given source string, using the given substituation map. +/// Perform token substitutions on the given source string, using the given substitution map. /// Tokens are required to start with '$' and can only consist of alphanumeric characters. /// The full token name, including '$' and all following alphanumeric character, will be replaced /// by the corresponding string in the substitution map, if the token exists in the map. diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 25e96c7ea5..92a33939ab 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -307,7 +307,7 @@ ed::PinId Graph::getOutputPin(UiNodePtr node, UiNodePtr upNode, UiPinPtr input) { if (upNode->getNodeGraph() != nullptr) { - // For nodegraph need to get the correct ouput pin according to the names of the output nodes + // For nodegraph need to get the correct output pin according to the names of the output nodes mx::OutputPtr output; if (input->_pinNode->getNode()) { @@ -333,7 +333,7 @@ ed::PinId Graph::getOutputPin(UiNodePtr node, UiNodePtr upNode, UiPinPtr input) } else { - // For node need to get the correct ouput pin based on the output attribute + // For node need to get the correct output pin based on the output attribute if (!upNode->outputPins.empty()) { std::string outputName = mx::EMPTY_STRING; @@ -514,7 +514,7 @@ void Graph::findYSpacing(float startY) int prevLevel = _levelMap[i].front()->_level - 1; float avgY = findAvgY(_levelMap[prevLevel]); float height = totalHeight(_levelMap[i].front()->_level); - // caculate the starting position to be above the previous level's center so that it is evenly spaced on either side of the center + // calculate the starting position to be above the previous level's center so that it is evenly spaced on either side of the center float startingPos = avgY - ((height + (_levelMap[i].size() * 20)) / 2) + startY; setYSpacing(_levelMap[i].front()->_level, startingPos); } @@ -4120,7 +4120,7 @@ void Graph::drawGraph(ImVec2 mousePos) } connectLinks(); - // Set to false after intial layout so that nodes can be moved + // Set to false after initial layout so that nodes can be moved _initial = false; _autoLayout = false; diff --git a/source/MaterialXGraphEditor/Graph.h b/source/MaterialXGraphEditor/Graph.h index f225f5e686..ab2b25aff1 100644 --- a/source/MaterialXGraphEditor/Graph.h +++ b/source/MaterialXGraphEditor/Graph.h @@ -235,7 +235,7 @@ class Graph RenderViewPtr _renderer; - // document and intializing information + // document and initializing information mx::FilePath _materialFilename; mx::DocumentPtr _graphDoc; mx::StringSet _xincludeFiles; @@ -248,7 +248,7 @@ class Graph mx::ImagePtr _image; mx::ImageHandlerPtr _imageHandler; - // containers of node informatin + // containers of node information std::vector _graphNodes; std::vector _currPins; std::vector _currLinks; diff --git a/source/MaterialXRender/Camera.h b/source/MaterialXRender/Camera.h index 3135904b5a..322ea42ad8 100644 --- a/source/MaterialXRender/Camera.h +++ b/source/MaterialXRender/Camera.h @@ -154,7 +154,7 @@ class MX_RENDER_API Camera const Vector3& target, const Vector3& up); - /// Create a perpective projection matrix given a set of clip planes with [-1,1] projected Z. + /// Create a perspective projection matrix given a set of clip planes with [-1,1] projected Z. static Matrix44 createPerspectiveMatrix(float left, float right, float bottom, float top, float nearP, float farP); @@ -164,7 +164,7 @@ class MX_RENDER_API Camera float bottom, float top, float nearP, float farP); - /// Create a perpective projection matrix given a set of clip planes with [0,1] projected Z. + /// Create a perspective projection matrix given a set of clip planes with [0,1] projected Z. static Matrix44 createPerspectiveMatrixZP(float left, float right, float bottom, float top, float nearP, float farP); diff --git a/source/MaterialXRender/Image.h b/source/MaterialXRender/Image.h index 76e1b88eee..31a76ed8a3 100644 --- a/source/MaterialXRender/Image.h +++ b/source/MaterialXRender/Image.h @@ -28,7 +28,7 @@ using ConstImagePtr = shared_ptr; /// A map from strings to images. using ImageMap = std::unordered_map; -/// A vetor of images. +/// A vector of images. using ImageVec = std::vector; /// A pair of images. diff --git a/source/MaterialXRender/ImageHandler.h b/source/MaterialXRender/ImageHandler.h index e5d2082f8d..e290b14366 100644 --- a/source/MaterialXRender/ImageHandler.h +++ b/source/MaterialXRender/ImageHandler.h @@ -158,7 +158,7 @@ class MX_RENDER_API ImageLoader /// @class ImageHandler /// Base image handler class. Keeps track of images which are loaded from /// disk via supplied ImageLoader. Derived classes are responsible for -/// determinining how to perform the logic for "binding" of these resources +/// determining how to perform the logic for "binding" of these resources /// for a given target (such as a given shading language). class MX_RENDER_API ImageHandler { diff --git a/source/MaterialXRender/TextureBaker.h b/source/MaterialXRender/TextureBaker.h index 656bb63c1d..191b7c2ef8 100644 --- a/source/MaterialXRender/TextureBaker.h +++ b/source/MaterialXRender/TextureBaker.h @@ -258,7 +258,7 @@ class TextureBaker : public Renderer // Populate file template variable naming map StringMap initializeFileTemplateMap(InputPtr input, NodePtr shader, const string& udim = EMPTY_STRING); - // Find first occurence of variable in filename from start index onwards + // Find first occurrence of variable in filename from start index onwards size_t findVarInTemplate(const string& filename, const string& var, size_t start = 0); // Generate a texture filename for the given graph output. diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index b63e1faecc..29ee9ecebe 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -924,7 +924,7 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() continue; } - // TODO: Shoud we really create new ones here each update? + // TODO: Should we really create new ones here each update? InputPtr inputPtr = std::make_shared(-1, -1, int(v->getType().getSize()), EMPTY_STRING); _uniformList[v->getVariable()] = inputPtr; inputPtr->isConstant = true; diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.h b/source/MaterialXRenderMsl/MslPipelineStateObject.h index a823662f5f..7193d8470c 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.h +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.h @@ -190,7 +190,7 @@ class MX_RENDERMSL_API MslProgram /// Bind input geometry streams void bindMesh(id renderCmdEncoder, MeshPtr mesh); - /// Queries the index buffer assinged to a mesh partition + /// Queries the index buffer assigned to a mesh partition id getIndexBuffer(MeshPartitionPtr mesh) { if (_indexBufferIds.find(mesh) != _indexBufferIds.end()) diff --git a/source/MaterialXRenderOsl/OslRenderer.h b/source/MaterialXRenderOsl/OslRenderer.h index 40d6eed811..912dc9e0e3 100644 --- a/source/MaterialXRenderOsl/OslRenderer.h +++ b/source/MaterialXRenderOsl/OslRenderer.h @@ -26,7 +26,7 @@ using OslRendererPtr = std::shared_ptr; /// - Source code validation: Use of "oslc" to compile and test output results /// - Introspection check: None at this time. /// - Binding: None at this time. -/// - Render validation: Use of "testrender" to output rendered images. Assumes source compliation was success +/// - Render validation: Use of "testrender" to output rendered images. Assumes source compilation was success /// as it depends on the existence of corresponding .oso files. /// class MX_RENDEROSL_API OslRenderer : public ShaderRenderer diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index 223aae5694..8402f6f525 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -222,7 +222,7 @@ TEST_CASE("Document equivalence", "[document]") bool equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(!equivalent); - // Check attibute values + // Check attribute values options.performValueComparisons = true; equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(equivalent); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 858fc39a97..b206af6ee4 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -213,7 +213,7 @@ void checkImplementations(mx::GenContext& context, mx::ImplementationPtr impl = inter->asA(); if (impl) { - // Test if the generator has an interal implementation first + // Test if the generator has an internal implementation first if (shadergen.implementationRegistered(impl->getName())) { found_str += "Found generator impl for nodedef: " + nodeDefName + ", Node: " diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h index e44df13efd..04870eae18 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h @@ -51,7 +51,7 @@ void checkImplementations(mx::GenContext& context, // Utility test to check unique name generation on a shader generator void testUniqueNames(mx::GenContext& context, const std::string& stage); -// Utility to perfrom simple performance test to load, validate and generate shaders +// Utility to perform simple performance test to load, validate and generate shaders void shaderGenPerformanceTest(mx::GenContext& context); // @@ -91,7 +91,7 @@ class TestSuiteOptions // Render size mx::Vector2 renderSize = { 512, 512 }; - // Set this to be true if it is desired to dump out uniform and attribut information to the logging file. + // Set this to be true if it is desired to dump out uniform and attribute information to the logging file. bool dumpUniformsAndAttributes = true; // Geometry file to be rendered diff --git a/source/MaterialXTest/MaterialXRender/RenderUtil.cpp b/source/MaterialXTest/MaterialXRender/RenderUtil.cpp index e3e5e8033e..ec3d603284 100644 --- a/source/MaterialXTest/MaterialXRender/RenderUtil.cpp +++ b/source/MaterialXTest/MaterialXRender/RenderUtil.cpp @@ -36,7 +36,7 @@ void ShaderRenderTester::getGenerationOptions(const GenShaderUtil::TestSuiteOpti reducedOption.shaderInterfaceType = mx::SHADER_INTERFACE_REDUCED; optionsList.push_back(reducedOption); } - // Alway fallback to complete if no options specified. + // Always fallback to complete if no options specified. if ((testOptions.shaderInterfaces & 2) || optionsList.empty()) { mx::GenOptions completeOption = originalOptions; diff --git a/source/MaterialXTest/MaterialXRender/RenderUtil.h b/source/MaterialXTest/MaterialXRender/RenderUtil.h index af4e221f25..b6b6bf5a9d 100644 --- a/source/MaterialXTest/MaterialXRender/RenderUtil.h +++ b/source/MaterialXTest/MaterialXRender/RenderUtil.h @@ -26,7 +26,7 @@ namespace mx = MaterialX; // Input uniform and stream checking as well as node implementation coverage and profiling // can also be performed depending on the options enabled. // -// See the test suite file "_options.mtlx" which is parsed during validaiton to +// See the test suite file "_options.mtlx" which is parsed during validation to // restrive validation options. // namespace RenderUtil @@ -113,7 +113,7 @@ class ShaderRenderTester void loadDependentLibraries(GenShaderUtil::TestSuiteOptions options, mx::FileSearchPath searchPath, mx::DocumentPtr& dependLib); - // Load any additional libraries requird by the generator + // Load any additional libraries required by the generator virtual void loadAdditionalLibraries(mx::DocumentPtr /*dependLib*/, GenShaderUtil::TestSuiteOptions& /*options*/) {}; diff --git a/source/MaterialXTest/MaterialXRenderGlsl/RenderGlsl.cpp b/source/MaterialXTest/MaterialXRenderGlsl/RenderGlsl.cpp index 9cfd3f4197..e28931803c 100644 --- a/source/MaterialXTest/MaterialXRenderGlsl/RenderGlsl.cpp +++ b/source/MaterialXTest/MaterialXRenderGlsl/RenderGlsl.cpp @@ -58,7 +58,7 @@ class GlslShaderRenderTester : public RenderUtil::ShaderRenderTester }; // In addition to standard texture and shader definition libraries, additional lighting files -// are loaded in. If no files are specifed in the input options, a sample +// are loaded in. If no files are specified in the input options, a sample // compound light type and a set of lights in a "light rig" are loaded in to a given // document. void GlslShaderRenderTester::loadAdditionalLibraries(mx::DocumentPtr document, @@ -103,7 +103,7 @@ void GlslShaderRenderTester::registerLights(mx::DocumentPtr document, } // -// Create a renderer with the apporpraite image, geometry and light handlers. +// Create a renderer with the appropriate image, geometry and light handlers. // The light handler on the renderer is cleared on initialization to indicate no lighting // is required. During code generation, if the element to validate requires lighting then // the handler _lightHandler will be used. diff --git a/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm b/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm index d276d5b1cc..8e58111df2 100644 --- a/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm +++ b/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm @@ -63,7 +63,7 @@ bool runRenderer(const std::string& shaderName, }; // In addition to standard texture and shader definition libraries, additional lighting files -// are loaded in. If no files are specifed in the input options, a sample +// are loaded in. If no files are specified in the input options, a sample // compound light type and a set of lights in a "light rig" are loaded in to a given // document. void MslShaderRenderTester::loadAdditionalLibraries(mx::DocumentPtr document, @@ -108,7 +108,7 @@ bool runRenderer(const std::string& shaderName, } // -// Create a renderer with the apporpraite image, geometry and light handlers. +// Create a renderer with the appropriate image, geometry and light handlers. // The light handler on the renderer is cleared on initialization to indicate no lighting // is required. During code generation, if the element to validate requires lighting then // the handler _lightHandler will be used. diff --git a/source/MaterialXTest/README.md b/source/MaterialXTest/README.md index 91b6da633e..2a1489dd7c 100644 --- a/source/MaterialXTest/README.md +++ b/source/MaterialXTest/README.md @@ -33,7 +33,7 @@ Refer to the [test suite documentation](../../resources/Materials/TestSuite/READ - GenGlsl.cpp : GLSL shader generation tests which are run when the test tag `[genglsl]` is specified. - GenOsl.cpp : OSL shader generation tests which are run when the test tag `[genosl]` is specified. - GenMdl.cpp : MDL shader generation tests which are run when the test tag `[genmdl]` is specified. -- GenMsl.cpp : MSL shader generation tests which are run when the test tage `[genmsl]` is specified. +- GenMsl.cpp : MSL shader generation tests which are run when the test tag `[genmsl]` is specified. Per-language tests will scan MaterialX files in the test suite for input materials. @@ -48,7 +48,7 @@ Depending on which tests are executed log files are produced at the location tha - Render.cpp : Core render tests which are run when the test tag `[rendercore]` is specified. - RenderGlsl.cpp : GLSL render tests which are run when the test tag `[renderglsl]` is specified. - RenderOsl.cpp : OSL render tests which are run when the test tag `[renderosl]` is specified. -- RenderMsl.mm: MSL render tests which are run when the test tage `[rendermsl]` is specified. +- RenderMsl.mm: MSL render tests which are run when the test tag `[rendermsl]` is specified. Per language tests will scan MaterialX files in the test suite for input materials. diff --git a/source/MaterialXView/CMakeLists.txt b/source/MaterialXView/CMakeLists.txt index e33a148bb3..fd6da586e1 100644 --- a/source/MaterialXView/CMakeLists.txt +++ b/source/MaterialXView/CMakeLists.txt @@ -1,4 +1,4 @@ -option(MATERIALX_NANOGUI_EXTERNAL "Build aginst an external install of NanoGUI (NANOGUI_ROOT may also need to be set)" OFF) +option(MATERIALX_NANOGUI_EXTERNAL "Build against an external install of NanoGUI (NANOGUI_ROOT may also need to be set)" OFF) set(MATERIALXVIEW_RENDER_BACKEND_DEFINITIONS "") From baa3595209ded3736a6b984fbefc414b9b1d23a6 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 16 Jan 2025 15:44:31 -0800 Subject: [PATCH 75/76] Update Doxygen comments (#2186) This changelist updates the Doxygen comments for MaterialXGenShader classes, improving the consistency of generated API documentation. --- source/MaterialXGenShader/HwShaderGenerator.h | 2 +- source/MaterialXGenShader/Nodes/HwTransformNode.h | 3 +++ source/MaterialXGenShader/TypeDesc.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/MaterialXGenShader/HwShaderGenerator.h b/source/MaterialXGenShader/HwShaderGenerator.h index 3712410606..d78aaf917a 100644 --- a/source/MaterialXGenShader/HwShaderGenerator.h +++ b/source/MaterialXGenShader/HwShaderGenerator.h @@ -343,7 +343,7 @@ class MX_GENSHADER_API HwShaderGenerator : public ShaderGenerator mutable ClosureContext _defEmission; }; -/// @class HwShaderGenerator +/// @class HwImplementation /// Base class for HW node implementations. class MX_GENSHADER_API HwImplementation : public ShaderNodeImpl { diff --git a/source/MaterialXGenShader/Nodes/HwTransformNode.h b/source/MaterialXGenShader/Nodes/HwTransformNode.h index a97e57405c..2103f3b4c8 100644 --- a/source/MaterialXGenShader/Nodes/HwTransformNode.h +++ b/source/MaterialXGenShader/Nodes/HwTransformNode.h @@ -34,6 +34,7 @@ class MX_GENSHADER_API HwTransformNode : public ShaderNodeImpl static const string WORLD; }; +/// Vector transform implementation for hardware languages class MX_GENSHADER_API HwTransformVectorNode : public HwTransformNode { public: @@ -45,6 +46,7 @@ class MX_GENSHADER_API HwTransformVectorNode : public HwTransformNode string getHomogeneousCoordinate() const override { return "0.0"; } }; +/// Point transform implementation for hardware languages class MX_GENSHADER_API HwTransformPointNode : public HwTransformVectorNode { public: @@ -54,6 +56,7 @@ class MX_GENSHADER_API HwTransformPointNode : public HwTransformVectorNode string getHomogeneousCoordinate() const override { return "1.0"; } }; +/// Normal transform implementation for hardware languages class MX_GENSHADER_API HwTransformNormalNode : public HwTransformNode { public: diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index d19fea604a..b61c598caf 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -275,6 +275,8 @@ class MX_GENSHADER_API StructTypeDesc vector _members; }; +/// @class StructTypeDescRegistry +/// Helper class for struct type registration. class MX_GENSHADER_API StructTypeDescRegistry { public: From c27914b8d0ed042948ee40526458f2673f5284fa Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 20 Jan 2025 14:26:10 -0800 Subject: [PATCH 76/76] Finalize changelog for 1.39.2 (#2188) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bc0c72444..af6462b2ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## [1.39.2] - Release Candidate +## [1.39.2] - 2025-01-20 ### Added - Added support for the [Chiang Hair BSDF](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1968), with initial implementations in hardware shading languages and MDL.