From 1a39d99a41ccfd5c0a12759b185af3946e2ff45f Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 12 Sep 2023 17:03:47 -0700 Subject: [PATCH 01/22] Update documentation - Update links to pre-built binaries in README.md. - Update link to ASWF Open Source Days in README.md. - Update MaterialX Overview in MainPage.md. - Update code and data syntax in ShaderGeneration.md. - Update documentation for the ImageHandler::acquireImage method. --- README.md | 8 +- documents/DeveloperGuide/MainPage.md | 2 +- documents/DeveloperGuide/ShaderGeneration.md | 135 +++++++++---------- source/MaterialXRender/ImageHandler.h | 3 + 4 files changed, 71 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index e6c6e2d0e4..ddccb4a9db 100644 --- a/README.md +++ b/README.md @@ -60,13 +60,13 @@ The Open Chess Set is an open reference asset, consisting of a [MaterialX file]( The following packages contain pre-built binaries for the latest release, including the MaterialX viewer, Python libraries, and example assets: -- [Microsoft Windows (Visual Studio 2022, Python 3.9)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Windows_VS2022_x64_Python39.zip) -- [MacOS (Xcode 13, Python 3.9)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_MacOS_Xcode_13_Python39.zip) -- [Linux (GCC 11, Python 3.9)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Linux_GCC_11_Python39.zip) +- [Microsoft Windows (Visual Studio 2022, Python 3.11)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Windows_VS2022_x64_Python311.zip) +- [MacOS (Xcode 14, Python 3.11)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_MacOS_Xcode_14_Python311.zip) +- [Linux (GCC 12, Python 3.11)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Linux_GCC_12_Python311.zip) ### Additional Resources - The [Developer Guide](http://www.materialx.org/docs/api/index.html) contains a developer-oriented overview of MaterialX with API documentation. - The [Python Scripts](python/Scripts) folder contains standalone examples of MaterialX Python code. - The [JavaScript](javascript) folder contains details on building JavaScript bindings for MaterialX. -- Presentations at [ASWF Open Source Days](http://www.materialx.org/assets/ASWF_OSD2022_MaterialX_OSL_Final.pdf) and the [SIGGRAPH Physically Based Shading Course](https://blog.selfshadow.com/publications/s2020-shading-course/#materialx) provide details on the roadmap for MaterialX development. +- Presentations at [ASWF Open Source Days](https://materialx.org/assets/ASWF_OSD2023_MaterialX_Final.pdf) and the [SIGGRAPH Physically Based Shading Course](https://blog.selfshadow.com/publications/s2020-shading-course/#materialx) provide details on the roadmap for MaterialX development. diff --git a/documents/DeveloperGuide/MainPage.md b/documents/DeveloperGuide/MainPage.md index 79441a3e4d..d6c098a23d 100644 --- a/documents/DeveloperGuide/MainPage.md +++ b/documents/DeveloperGuide/MainPage.md @@ -1,6 +1,6 @@ # MaterialX Overview -MaterialX is an open standard for transfer of rich material and look-development content between applications and renderers. Originated at Lucasfilm in 2012, MaterialX has been used by Industrial Light & Magic (ILM) in feature films such as _Star Wars: The Force Awakens_ and real-time experiences such as _Trials on Tatooine_, and it remains the central material format for new ILM productions. +MaterialX is an open standard for representing rich material and look-development content in computer graphics, enabling its platform-independent description and exchange across applications and renderers. Launched at [Industrial Light & Magic](https://www.ilm.com/) in 2012, MaterialX has been a key technology in their feature films and real-time experiences since _Star Wars: The Force Awakens_ and _Millennium Falcon: Smugglers Run_. The project was released as open source in 2017, with companies including Sony Pictures Imageworks, Pixar, Autodesk, Adobe, and SideFX contributing to its ongoing development. In 2021, MaterialX became the seventh hosted project of the [Academy Software Foundation](https://www.aswf.io/). ### Quick Start for Developers diff --git a/documents/DeveloperGuide/ShaderGeneration.md b/documents/DeveloperGuide/ShaderGeneration.md index 059b34d580..01bd823ec4 100644 --- a/documents/DeveloperGuide/ShaderGeneration.md +++ b/documents/DeveloperGuide/ShaderGeneration.md @@ -33,37 +33,41 @@ Figure 2. The first option is to keep inline code in a file. The file extension ```xml // Nodedef elements for node - - - + + + + - - - + + + + <... more types ...> // Implementation elements for node - - + + <... more types ...> // Nodedef elements for node - - - - + + + + + - - - - + + + + + <... more types ...> // Implementation elements for node - - + + <... more types ...> ``` ```c++ @@ -79,30 +83,29 @@ For nodes that can’t be implemented by inline expressions a function definitio ```xml // Nodedef element - - - - - - - - - - - + + + + + + + + + + + + // Implementation element - + ``` ```c++ // File 'mx_image_color3.osl' contains: void mx_image_color3(string file, string layer, color defaultvalue, - vector2 texcoord, string filtertype, - string uaddressmode, string vaddressmode, - string framerange, int frameoffset, - string frameendaction, output color out) + vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, + string framerange, int frameoffset, string frameendaction, + output color out) { // Sample the texture out = texture(file, texcoord.x, texcoord.y, @@ -120,40 +123,28 @@ As an alternative to defining source code, there is also an option to reference This is useful for creating a compound for a set of nodes performing some common operation. It can then be referenced as a node inside other nodegraphs. It is also useful for creating compatibility graphs for unknown nodes. If a node is created by some third party, and its implementation is unknown or proprietary, a compatibility graph can be created using known nodes and be referenced as a stand-in implementation. Linking a nodegraph to a nodedef is done by simply setting a nodedef attribute on the nodegraph definition. See Figure 4 for an example. ```xml - - + + + + - - - - - + + - - - - - - - - - - + + - - - - - - - - - - + + + + + + + - + ``` **Figure 4**: Checker node implementation using a nodegraph. @@ -161,10 +152,9 @@ This is useful for creating a compound for a set of nodes performing some common ### 1.3.4 Dynamic Code Generation In some situations static source code is not enough to implement a node. The code might need to be customized depending on parameters set on the node. Or for a hardware render target vertex streams or uniform inputs might need to be created in order to supply the data needed for the node implementation. -In this case, a C++ class can be added to handle the implementation of the node. The class should be derived from the base class `ShaderNodeImpl`. It should specify what language and target it is for by overriding `getLanguage()` and `getTarget()`. It can also be specified to support all languages or all targets by setting the identifier to an empty string, as done for the target identifier in the example below. It then needs to be registered for a `ShaderGenerator` by calling `ShaderGenerator::registerImplementation()`. See Figure 5 for an example. +In this case, a C++ class can be added to handle the implementation of the node. The class should be derived from the base class `ShaderNodeImpl`. It should specify what target it is for by overriding `getTarget()`. It then needs to be registered for a `ShaderGenerator` by calling `ShaderGenerator::registerImplementation()`. See Figure 5 for an example. -When a `ShaderNodeImpl` class is used for a nodedef the corresponding `` -element doesn’t need a file attribute, since no static source code is used. The `` element will then act only as a declaration that there exists an implementation for the nodedef for a particular language and target. +When a `ShaderNodeImpl` class is used for a nodedef the corresponding `` element doesn’t need a file attribute, since no static source code is used. The `` element will then act only as a declaration that there exists an implementation for the nodedef for a particular target. Note that by using a `ShaderNodeImpl` class for your node's implementation it is no longer data driven, as in the other three methods above. So it's recommended to use this only when inline expressions or static source code functions are not enough to handle the implementation of a node. @@ -175,8 +165,7 @@ class FooOsl : public ShaderNodeImpl public: static ShaderNodeImplPtr create() { return std::make_shared(); } - const string& getLanguage() const override { return LANGUAGE_OSL; } - const string& getTarget() const override { return EMPTY_STRING; } + const string& getTarget() const override { return OslShaderGenerator::TARGET; } void emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override @@ -291,7 +280,8 @@ class TexCoordGlsl : public ShaderNodeImpl const string index = indexInput ? indexInput->getValue()->getValueString() : "0"; const string variable = "texcoord_" + index; - BEGIN_SHADER_STAGE(stage, Stage::VERTEX) + DEFINE_SHADER_STAGE(stage, Stage::VERTEX) + { VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA); const string prefix = vertexData.getInstance() + "."; ShaderPort* texcoord = vertexData[variable]; @@ -300,9 +290,10 @@ class TexCoordGlsl : public ShaderNodeImpl shadergen.emitLine(prefix + texcoord->getVariable() + " = i_" + variable, stage); texcoord->setEmitted(); } - END_SHADER_STAGE(shader, Stage::VERTEX) + } - BEGIN_SHADER_STAGE(stage, Stage::PIXEL) + DEFINE_SHADER_STAGE(stage, Stage::PIXEL) + { VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA); const string prefix = vertexData.getInstance() + "."; ShaderPort* texcoord = vertexData[variable]; @@ -310,7 +301,7 @@ class TexCoordGlsl : public ShaderNodeImpl shadergen.emitOutput(node.getOutput(), true, false, context, stage); shadergen.emitString(" = " + prefix + texcoord->getVariable(), stage); shadergen.emitLineEnd(stage); - END_SHADER_STAGE(shader, Stage::PIXEL) + } } }; ``` diff --git a/source/MaterialXRender/ImageHandler.h b/source/MaterialXRender/ImageHandler.h index c744eb2f6a..fafc021857 100644 --- a/source/MaterialXRender/ImageHandler.h +++ b/source/MaterialXRender/ImageHandler.h @@ -186,7 +186,10 @@ class MX_RENDER_API ImageHandler /// Acquire an image from the cache or file system. If the image is not /// found in the cache, then each image loader will be applied in turn. + /// If the image cannot be found by any loader, then a uniform image of the + /// given default color will be returned. /// @param filePath File path of the image. + /// @param defaultColor Default color to use as a fallback for missing images. /// @return On success, a shared pointer to the acquired image. ImagePtr acquireImage(const FilePath& filePath, const Color4& defaultColor = Color4(0.0f)); From a5a74feab2eec007ca8e87eeb9c57c667e32ff2c Mon Sep 17 00:00:00 2001 From: Niklas Harrysson Date: Sun, 17 Sep 2023 00:11:53 +0200 Subject: [PATCH 02/22] Fix attenuation of coated emission in Standard Surface (#1534) This change list fixes a math mistake in the handling of how emission is attenuated by the top coat in Standard Surface. Thanks to @portsmouth and @Reedbeta for reporting my mistake and suggesting a workaround. --- libraries/bxdf/standard_surface.mtlx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/bxdf/standard_surface.mtlx b/libraries/bxdf/standard_surface.mtlx index 843885aa50..c7de68929a 100644 --- a/libraries/bxdf/standard_surface.mtlx +++ b/libraries/bxdf/standard_surface.mtlx @@ -386,6 +386,10 @@ + + + + @@ -398,8 +402,8 @@ - - + + From 6c486837e682abd61fdd566fc28ef9980cdcda93 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 22 Sep 2023 10:26:46 -0700 Subject: [PATCH 03/22] Align default precision across shading languages (#1538) This changelist removes explicit overrides of floating-point precision in shader generation, making the default precision 6 decimal places across shading languages, and allowing the client to adjust the precision of generated shaders via Value::setFloatPrecision. This addresses a slight visual regression in generated OSL (with a maximum visual error on the order of 1e-3), caused by a hard-coding of floating-point precision to 3 decimal places in OslSyntax. --- source/MaterialXCore/Value.cpp | 5 ++++- source/MaterialXCore/Value.h | 2 +- source/MaterialXGenGlsl/GlslShaderGenerator.cpp | 4 +--- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 3 +++ source/MaterialXGenMsl/MslShaderGenerator.cpp | 4 +--- source/MaterialXGenOsl/OslShaderGenerator.cpp | 3 +++ source/MaterialXGenOsl/OslSyntax.cpp | 1 - 7 files changed, 13 insertions(+), 9 deletions(-) diff --git a/source/MaterialXCore/Value.cpp b/source/MaterialXCore/Value.cpp index 238473d5ad..3e8c1f4462 100644 --- a/source/MaterialXCore/Value.cpp +++ b/source/MaterialXCore/Value.cpp @@ -242,7 +242,10 @@ ScopedFloatFormatting::ScopedFloatFormatting(Value::FloatFormat format, int prec _precision(Value::getFloatPrecision()) { Value::setFloatFormat(format); - Value::setFloatPrecision(precision); + if (precision >= 0) + { + Value::setFloatPrecision(precision); + } } ScopedFloatFormatting::~ScopedFloatFormatting() diff --git a/source/MaterialXCore/Value.h b/source/MaterialXCore/Value.h index 8e55a97acf..1bd29b1d2b 100644 --- a/source/MaterialXCore/Value.h +++ b/source/MaterialXCore/Value.h @@ -198,7 +198,7 @@ template class MX_CORE_API TypedValue : public Value class MX_CORE_API ScopedFloatFormatting { public: - explicit ScopedFloatFormatting(Value::FloatFormat format, int precision = 6); + explicit ScopedFloatFormatting(Value::FloatFormat format, int precision = -1); ~ScopedFloatFormatting(); private: diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp index 766b61ec05..839f591aa5 100644 --- a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp +++ b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp @@ -279,9 +279,7 @@ ShaderPtr GlslShaderGenerator::generate(const string& name, ElementPtr element, { ShaderPtr shader = createShader(name, element, context); - // Turn on fixed float formatting to make sure float values are - // emitted with a decimal point and not as integers, and to avoid - // any scientific notation which isn't supported by all OpenGL targets. + // Request fixed floating-point notation for consistency across targets. ScopedFloatFormatting fmt(Value::FloatFormatFixed); // Make sure we initialize/reset the binding context before generation. diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index dddf1f2f13..f64b555c20 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -198,6 +198,9 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G ShaderPtr shader = createShader(name, element, context); + // Request fixed floating-point notation for consistency across targets. + ScopedFloatFormatting fmt(Value::FloatFormatFixed); + ShaderGraph& graph = shader->getGraph(); ShaderStage& stage = shader->getStage(Stage::PIXEL); diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index dcb0a3ed69..0d97e8408f 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -283,9 +283,7 @@ ShaderPtr MslShaderGenerator::generate(const string& name, ElementPtr element, G { ShaderPtr shader = createShader(name, element, context); - // Turn on fixed float formatting to make sure float values are - // emitted with a decimal point and not as integers, and to avoid - // any scientific notation which isn't supported by all OpenGL targets. + // Request fixed floating-point notation for consistency across targets. ScopedFloatFormatting fmt(Value::FloatFormatFixed); // Make sure we initialize/reset the binding context before generation. diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index b4edbee44b..b37a84c579 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -170,6 +170,9 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G { ShaderPtr shader = createShader(name, element, context); + // Request fixed floating-point notation for consistency across targets. + ScopedFloatFormatting fmt(Value::FloatFormatFixed); + ShaderGraph& graph = shader->getGraph(); ShaderStage& stage = shader->getStage(Stage::PIXEL); diff --git a/source/MaterialXGenOsl/OslSyntax.cpp b/source/MaterialXGenOsl/OslSyntax.cpp index d421c5e3d9..5a6b45dd61 100644 --- a/source/MaterialXGenOsl/OslSyntax.cpp +++ b/source/MaterialXGenOsl/OslSyntax.cpp @@ -220,7 +220,6 @@ class OSLMatrix3TypeSyntax : public AggregateTypeSyntax string getValue(const Value& value, bool uniform) const override { - ScopedFloatFormatting fmt(Value::FloatFormatFixed, 3); StringVec values = splitString(value.getValueString(), ","); return getValue(values, uniform); } From 7009c6daf7459716350593e318e4243d6e808f19 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 28 Sep 2023 17:57:00 -0700 Subject: [PATCH 04/22] Initial coverage test in GitHub CI This changelist adds an initial coverage test to GitHub Actions builds, uploading the generated HTML document as a new build artifact. --- .github/workflows/main.yml | 61 +++++++++++++++++++++++++++----------- CMakeLists.txt | 6 ++++ 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d5ac9d3f79..4fdcefb7fb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,6 +39,14 @@ jobs: python: 3.11 upload_shaders: ON + - name: Linux_GCC_CoverageAnalysis + os: ubuntu-22.04 + compiler: gcc + compiler_version: "None" + python: None + coverage_analysis: ON + cmake_config: -DMATERIALX_COVERAGE_ANALYSIS=ON -DMATERIALX_BUILD_RENDER=OFF -DMATERIALX_BUILD_PYTHON=OFF + - name: Linux_Clang_10_Python37 os: ubuntu-20.04 compiler: clang @@ -120,28 +128,32 @@ jobs: run: | sudo apt-get update sudo apt-get install xorg-dev mesa-utils - if [ "${{ matrix.compiler }}" = "gcc" ]; then - sudo apt-get install -y g++-${{ matrix.compiler_version }} g++-${{ matrix.compiler_version }}-multilib - echo "CC=gcc-${{ matrix.compiler_version }}" >> $GITHUB_ENV - echo "CXX=g++-${{ matrix.compiler_version }}" >> $GITHUB_ENV - else - sudo apt-get install -y clang-${{ matrix.compiler_version }} libc++-${{ matrix.compiler_version }}-dev libc++abi-${{ matrix.compiler_version }}-dev - echo "CC=clang-${{ matrix.compiler_version }}" >> $GITHUB_ENV - echo "CXX=clang++-${{ matrix.compiler_version }}" >> $GITHUB_ENV + if [ "${{ matrix.compiler_version }}" != 'None' ]; then + if [ "${{ matrix.compiler }}" = "gcc" ]; then + sudo apt-get install -y g++-${{ matrix.compiler_version }} g++-${{ matrix.compiler_version }}-multilib + echo "CC=gcc-${{ matrix.compiler_version }}" >> $GITHUB_ENV + echo "CXX=g++-${{ matrix.compiler_version }}" >> $GITHUB_ENV + else + sudo apt-get install -y clang-${{ matrix.compiler_version }} libc++-${{ matrix.compiler_version }}-dev libc++abi-${{ matrix.compiler_version }}-dev + echo "CC=clang-${{ matrix.compiler_version }}" >> $GITHUB_ENV + echo "CXX=clang++-${{ matrix.compiler_version }}" >> $GITHUB_ENV + fi fi - name: Install Dependencies (MacOS) if: runner.os == 'macOS' run: | - if [ "${{ matrix.compiler }}" = "gcc" ]; then - brew install gcc@${{ matrix.compiler_version }} - echo "CC=gcc-${{ matrix.compiler_version }}" >> $GITHUB_ENV - echo "CXX=g++-${{ matrix.compiler_version }}" >> $GITHUB_ENV - else - ls -ls /Applications/ - sudo xcode-select -switch /Applications/Xcode_${{ matrix.compiler_version }}.app - echo "CC=clang" >> $GITHUB_ENV - echo "CXX=clang++" >> $GITHUB_ENV + if [ "${{ matrix.compiler_version }}" != 'None' ]; then + if [ "${{ matrix.compiler }}" = "gcc" ]; then + brew install gcc@${{ matrix.compiler_version }} + echo "CC=gcc-${{ matrix.compiler_version }}" >> $GITHUB_ENV + echo "CXX=g++-${{ matrix.compiler_version }}" >> $GITHUB_ENV + else + ls -ls /Applications/ + sudo xcode-select -switch /Applications/Xcode_${{ matrix.compiler_version }}.app + echo "CC=clang" >> $GITHUB_ENV + echo "CXX=clang++" >> $GITHUB_ENV + fi fi - name: Install Dependencies (Windows) @@ -222,6 +234,14 @@ jobs: run: | python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --target msl --validator "xcrun metal --language=metal" --validatorArgs="-w" + - name: Coverage Analysis Tests + if: matrix.coverage_analysis == 'ON' + run: | + sudo apt-get install gcovr + mkdir coverage + gcovr --html --html-details --output coverage/index.html --exclude .*\/External\/.* --root .. . + working-directory: build + - name: Static Analysis Tests if: matrix.static_analysis == 'ON' && runner.os == 'Linux' run: | @@ -279,6 +299,13 @@ jobs: name: Renders_${{ matrix.name }} path: build/render/*.png + - name: Upload Coverage Report + uses: actions/upload-artifact@v3 + if: matrix.coverage_analysis == 'ON' + with: + name: MaterialX_Coverage + path: build/coverage + - name: JavaScript CMake Generate if: matrix.build_javascript == 'ON' run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index c255924fa4..de6aa7442f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ option(MATERIALX_INSTALL_PYTHON "Install the MaterialX Python package as a third option(MATERIALX_INSTALL_RESOURCES "Install the resources folder when building render modules." ON) option(MATERIALX_TEST_RENDER "Run rendering tests for MaterialX Render module. GPU required for graphics validation." ON) option(MATERIALX_WARNINGS_AS_ERRORS "Interpret all compiler warnings as errors." OFF) +option(MATERIALX_COVERAGE_ANALYSIS "Build MaterialX libraries with coverage analysis on supporting platforms." OFF) option(MATERIALX_DYNAMIC_ANALYSIS "Build MaterialX libraries with dynamic analysis on supporting platforms." OFF) option(MATERIALX_OSL_LEGACY_CLOSURES "Build OSL shader generation supporting the legacy OSL closures." ON) @@ -138,6 +139,7 @@ mark_as_advanced(MATERIALX_INSTALL_PYTHON) mark_as_advanced(MATERIALX_INSTALL_RESOURCES) mark_as_advanced(MATERIALX_TEST_RENDER) mark_as_advanced(MATERIALX_WARNINGS_AS_ERRORS) +mark_as_advanced(MATERIALX_COVERAGE_ANALYSIS) mark_as_advanced(MATERIALX_DYNAMIC_ANALYSIS) mark_as_advanced(MATERIALX_PYTHON_VERSION) mark_as_advanced(MATERIALX_PYTHON_EXECUTABLE) @@ -228,6 +230,10 @@ else() if(MATERIALX_WARNINGS_AS_ERRORS) add_compile_options(-Werror) endif() + if(MATERIALX_COVERAGE_ANALYSIS) + add_compile_options(--coverage -O0) + add_link_options(--coverage) + endif() if(MATERIALX_DYNAMIC_ANALYSIS) set(DYNAMIC_ANALYSIS_OPTIONS -fsanitize=address -fsanitize=leak -fsanitize=undefined -fno-sanitize-recover=all) add_compile_options(${DYNAMIC_ANALYSIS_OPTIONS}) From 0bd09787e869619ea4ca0f78fe89711539d9f2cf Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 3 Oct 2023 09:08:10 -0700 Subject: [PATCH 05/22] Improvements to shader generation tests - Include all example documents by default in shader generation tests, rather than excluding a subset of the examples in all generators. - Remove an unused input from the render test suite options, eliminating a source of syntax errors in shader generation tests. --- resources/Materials/TestSuite/_options.mtlx | 3 --- .../MaterialXGenShader/GenShaderUtil.cpp | 21 ------------------- .../MaterialXGenShader/GenShaderUtil.h | 8 +++---- 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/resources/Materials/TestSuite/_options.mtlx b/resources/Materials/TestSuite/_options.mtlx index 8716cba5f0..bb29fbd7c1 100644 --- a/resources/Materials/TestSuite/_options.mtlx +++ b/resources/Materials/TestSuite/_options.mtlx @@ -87,9 +87,6 @@ - - - diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 863cd1af05..261aacdefe 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -480,27 +480,6 @@ void ShaderGeneratorTester::setupDependentLibraries() loadLibraries({ "libraries" }, _searchPath, _dependLib, _skipLibraryFiles); } -void ShaderGeneratorTester::addSkipFiles() -{ - _skipFiles.insert("_options.mtlx"); - _skipFiles.insert("light_rig_test_1.mtlx"); - _skipFiles.insert("light_rig_test_2.mtlx"); - _skipFiles.insert("light_compound_test.mtlx"); - _skipFiles.insert("xinclude_search_path.mtlx"); - _skipFiles.insert("1_38_parameter_to_input.mtlx"); - _skipFiles.insert("1_36_to_1_37.mtlx"); - _skipFiles.insert("1_37_to_1_38.mtlx"); - _skipFiles.insert("material_element_to_surface_material.mtlx"); -} - -void ShaderGeneratorTester::addSkipNodeDefs() -{ -} - -void ShaderGeneratorTester::addSkipLibraryFiles() -{ -} - LightIdMap ShaderGeneratorTester::computeLightIdMap(const std::vector& nodes) { std::unordered_map idMap; diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h index 7be195e9de..ea34170d71 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h @@ -180,13 +180,13 @@ class ShaderGeneratorTester virtual void setTestStages() = 0; // Add files in to not examine - virtual void addSkipFiles(); + virtual void addSkipFiles() { }; // Add nodedefs to not examine - virtual void addSkipNodeDefs(); + virtual void addSkipNodeDefs() { }; // Add files to be skipped while loading libraries - virtual void addSkipLibraryFiles(); + virtual void addSkipLibraryFiles() { }; // Add color management virtual void addColorManagement(); @@ -268,8 +268,6 @@ class ShaderGeneratorTester mx::StringSet _usedImplementations; }; - - } // namespace GenShaderUtil #endif From a79ddfb25589955bdb6060f4ce379dce56029275 Mon Sep 17 00:00:00 2001 From: Niklas Harrysson Date: Wed, 4 Oct 2023 17:16:32 +0200 Subject: [PATCH 06/22] Use explicit colorspace parameters in OSL texture calls (#1546) This change list adds the parameter "colorspace" to the texture call in OSL, for sampling color3/color4 textures. Previously this was supported under the covers, by token replacement that a custom OSL generator had to setup, and only done for the Arnold OSL generator. --- libraries/stdlib/genosl/mx_image_color3.osl | 3 +-- libraries/stdlib/genosl/mx_image_color4.osl | 2 +- source/MaterialXGenOsl/OslShaderGenerator.cpp | 4 ---- source/MaterialXGenOsl/OslShaderGenerator.h | 3 --- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/libraries/stdlib/genosl/mx_image_color3.osl b/libraries/stdlib/genosl/mx_image_color3.osl index 15b594e885..89ba94f376 100644 --- a/libraries/stdlib/genosl/mx_image_color3.osl +++ b/libraries/stdlib/genosl/mx_image_color3.osl @@ -12,6 +12,5 @@ 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 $extraTextureLookupArguments); + out = texture(file.filename, st.x, st.y, "subimage", layer, "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 3bde1a5047..261108b5b4 100644 --- a/libraries/stdlib/genosl/mx_image_color4.osl +++ b/libraries/stdlib/genosl/mx_image_color4.osl @@ -15,7 +15,7 @@ void mx_image_color4(textureresource file, string layer, color4 default_value, v 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 $extraTextureLookupArguments ); + "missingcolor", missingColor, "missingalpha", missingAlpha, "swrap", uaddressmode, "twrap", vaddressmode, "colorspace", file.colorspace); out = color4(rgb, alpha); } diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index b37a84c579..28ada48626 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -26,7 +26,6 @@ MATERIALX_NAMESPACE_BEGIN const string OslShaderGenerator::TARGET = "genosl"; -const string OslShaderGenerator::T_FILE_EXTRA_ARGUMENTS = "$extraTextureLookupArguments"; // // OslShaderGenerator methods @@ -161,9 +160,6 @@ OslShaderGenerator::OslShaderGenerator() : // registerImplementation("IM_surfacematerial_" + OslShaderGenerator::TARGET, MaterialNodeOsl::create); - - // Extra arguments for texture lookups. - _tokenSubstitutions[T_FILE_EXTRA_ARGUMENTS] = EMPTY_STRING; } ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, GenContext& context) const diff --git a/source/MaterialXGenOsl/OslShaderGenerator.h b/source/MaterialXGenOsl/OslShaderGenerator.h index 91690adc1d..0c7ca426d7 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.h +++ b/source/MaterialXGenOsl/OslShaderGenerator.h @@ -48,9 +48,6 @@ class MX_GENOSL_API OslShaderGenerator : public ShaderGenerator void registerShaderMetadata(const DocumentPtr& doc, GenContext& context) const override; protected: - // Extra file arguments for texture lookup call - static const string T_FILE_EXTRA_ARGUMENTS; - /// Create and initialize a new OSL shader for shader generation. virtual ShaderPtr createShader(const string& name, ElementPtr element, GenContext& context) const; From ab4c211ac3bc033afa8c9a0dbcfafa48eff2147e Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Wed, 4 Oct 2023 11:26:15 -0400 Subject: [PATCH 07/22] Add XML tags to MaterialX blocks in specification (#1544) - Add xml formatting tag for spec markdown docs. - Existing docs like shader gen already use the appropriate formatting tags. - Tested this with converters such as pandoc, and VScode markdown converter and should make no difference as they will just end up as preformatted text `
`.
---
 documents/Specification/MaterialX.GeomExts.md |  42 +++---
 .../Specification/MaterialX.Specification.md  | 130 +++++++++---------
 .../Specification/MaterialX.Supplement.md     |   2 +-
 3 files changed, 87 insertions(+), 87 deletions(-)

diff --git a/documents/Specification/MaterialX.GeomExts.md b/documents/Specification/MaterialX.GeomExts.md
index fb0d581ed8..5ff300de01 100644
--- a/documents/Specification/MaterialX.GeomExts.md
+++ b/documents/Specification/MaterialX.GeomExts.md
@@ -113,7 +113,7 @@ Collections are recipes for building a list of geometries (which can be any path
 
 A **<collection>** element contains lists of geometry expressions and/or collections to be included, and an optional list of geometry expressions to be excluded:
 
-```
+```xml
   
@@ -132,7 +132,7 @@ As a shorthand convenience, MaterialX allows the specification of a `geomprefix`
 So the following MTLX file snippets are equivalent:
 
 
-```
+```xml
   
     
   
@@ -176,7 +176,7 @@ The most common use for geominfo elements is to define the filenames (or portion
 
 A **<geominfo>** element contains one or more geometry property and/or token definitions, and associates them and their values with all geometries listed in the `geom` or `collection` attribute of the <geominfo>:
 
-```
+```xml
   
     ...geometry property and token value definitions...
   
@@ -200,7 +200,7 @@ The core MaterialX Specification defines a Geometric Property, or "geomprop", as
 
 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.
 
-```
+```xml
     
 ```
 
@@ -216,7 +216,7 @@ Only float and vectorN geometric properties may specify a `unittype` an
 
 For example, one could specify a unique surface ID value associated with a geometry:
 
-```
+```xml
   
   
     
@@ -225,13 +225,13 @@ For example, one could specify a unique surface ID value associated with a geome
 
 GeomProp values can be accessed from a nodegraph using a `` node:
 
-```
+```xml
   
 ```
 
 A <geomprop> can also be used to define a default value for an intrinsic varying geometric property such as "geomcolor" for the geometry specified by the enclosing <geominfo>, which would be returned by the corresponding Geometric node (e.g. <geomcolor>) if the current geometry did not itself define values for that property.
 
-```
+```xml
   
     
   
@@ -243,7 +243,7 @@ A <geomprop> can also be used to define a default value for an intrinsic vary
 
 Token elements may be used within <geominfo> elements to define constant (typically string or integer) named values associated with specific geometries.  These geometry token values can be substituted into filenames within image nodes; see the [**Additional Filename Substitutions**](#additional-filename-substitutions) section above for details:
 
-```
+```xml
   
 ```
 
@@ -257,7 +257,7 @@ Token elements have the following attributes:
 
 For example, one could specify a texture identifier value associated with a geometry:
 
-```
+```xml
   
     
   
@@ -265,7 +265,7 @@ For example, one could specify a texture identifier value associated with a geom
 
 and then reference that token's value in a filename:
 
-```
+```xml
   
     
@@ -279,7 +279,7 @@ The <txtid> in the file name would be replaced by whatever value the txtid to
 
 TokenDefault elements define the default value for a specified geometry token name; this default value will be used in a filename string substitution if an explicit token value is not defined for the current geometry.  Since TokenDefault does not apply to any geometry in particular, it must be used outside of a <geominfo> element.
 
-```
+```xml
   
 ```
 
@@ -288,7 +288,7 @@ TokenDefault elements define the default value for a specified geometry token na
 
 Workflows involving textures with implicitly-computed filenames based on u,v coordinates (such as <UDIM> and <UVTILE>) can be made more efficient by explicitly listing the set of values that they resolve to for any given geometry.  The MaterialX specification reserves two geomprop names for this purpose, `udimset` and `uvtileset`, each of which is a stringarray containing a comma-separated list of UDIM or UVTILE values:
 
-```
+```xml
   
     
   
@@ -313,7 +313,7 @@ A MaterialX document can contain multiple property and/or look elements.
 
 A **<property>** element defines the name, type and value of a look-specific non-material property of geometry; <**propertyset**> elements are used to group a number of <property>s into a single named object.  The connection between properties or propertysets and specific geometries or collections is done in a <look> element, so that these properties can be reused across different geometries, and enabled in some looks but not others.  <Property> elements may only be used within <propertyset>s; they may not be used independently, although a dedicated <propertyassign> element may be used within a <look> to declare a property name, type, value and assignment all at once.
 
-```
+```xml
   
     
     
@@ -338,7 +338,7 @@ In the example above, the "trace_maxdiffusedepth" property is target-specific, h
 
 A **<look>** element contains one or more material, variant, visibility and/or propertyset assignment declarations:
 
-```
+```xml
   
     ...materialassign, variantassign, visibilityassign, property/propertysetassign declarations...
   
@@ -348,7 +348,7 @@ Looks can inherit the assignments from another look by including an `inherit` at
 
 A number of looks can be grouped together into a **LookGroup**, e.g. to indicate which looks are defined for a particular asset:
 
-```
+```xml
   
 ```
 
@@ -368,7 +368,7 @@ For elements which make assignments to geometries, the pathed names within `geom
 
 MaterialAssign elements are used within a <look> to connect a specified material to one or more geometries or collections (either a `geom` or a `collection` may be specified, but not both).
 
-```
+```xml
   
@@ -383,7 +383,7 @@ Material assignments are generally assumed to be mutually-exclusive, that is, an
 
 VariantAssign elements are used within a <materialassign> or a <look> to apply the values defined in one variant of a variantset to one assigned material, or to all applicable materials in a look.
 
-```
+```xml
   
     
     
@@ -407,7 +407,7 @@ In the above example, the input/token values defined within variant "var1" will
 
 Visibility elements are used within a <look> to define various types of generalized visibility between a "viewer" object and other geometries.  A "viewer object" is simply a geometry that has the ability to "see" other geometries in some rendering context and thus may need to have the list of geometries that it "sees" in different contexts be specified; the most common examples are light sources and a primary rendering camera.
 
-```
+```xml
   
@@ -442,7 +442,7 @@ If the <visibility> `geom` or `collection` refers to light geometry, then ass
 
 For the "secondary" vistype, `viewergeom` should be renderable geometry rather than a light, to declare that certain other geometry is or is not visible to indirect bounce illumination or raytraced reflections in that `viewergeom`.  In this example, "/b" would not be seen in reflections nor contribute indirect bounce illumination to "/a", while geometry "/c" would not be visible to _any_ secondary rays:
 
-```
+```xml
   
   
 ```
@@ -452,7 +452,7 @@ For the "secondary" vistype, `viewergeom` should be renderable geometry rather t
 
 PropertyAssign and PropertySetAssign elements are used within a <look> to connect a specified property value or propertyset to one or more geometries or collections.
 
-```
+```xml
   
@@ -467,7 +467,7 @@ Either a `geom` or a `collection` may be specified, but not both.  Multiple prop
 
 This example defines four collections, a light shader and material, and a propertyset, which are then used by two looks:
 
-```
+```xml
 
 
   
diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md
index 7e876bdb57..4b99956fb4 100644
--- a/documents/Specification/MaterialX.Specification.md
+++ b/documents/Specification/MaterialX.Specification.md
@@ -267,7 +267,7 @@ Types not defined with a specific semantic are assumed to have semantic="default
 
 Custom types are defined using the <typedef> element:
 
-```
+```xml
   
   
 ```
@@ -292,7 +292,7 @@ The standard MaterialX distribution includes definitions for four "shader"-seman
 
 An MTLX file (with file extension ".mtlx") has the following general form:
 
-```
+```xml
   
   
     
@@ -303,7 +303,7 @@ That is, a standard XML declaration line followed by a root <materialx> eleme
 
 Standard XML XIncludes are supported ([http://en/wikipedia.org/wiki/XInclude](http://en/wikipedia.org/wiki/Xinclude)), as well as standard XML comments and the XML character entities `"`, `&`, `'`, `<` and `>`:
 
-```
+```xml
   
   
   
@@ -345,7 +345,7 @@ The working color space of a MaterialX document is defined by the `colorspace` a
 
 The color space of individual color image files and values may be defined via a `colorspace` attribute in an input which defines a filename or value.  Color images and values in spaces other than the working color space are expected to be transformed by the application into the working space before computations are performed.  In the example below, an image file has been defined in the “srgb_texture” color space, while its default value has been defined in “lin_rec709”; both should be transformed to the application’s working color space before being applied to any computations.
 
-```
+```xml
   
     
@@ -364,7 +364,7 @@ MaterialX allows floating-point and vector values to be defined in terms of a sp
 
 Unit types are defined using a <unittypedef> element, and a set of units of that type is defined using a <unitdef> element with one or more child <unit> elements:
 
-```
+```xml
   
   
     
@@ -397,7 +397,7 @@ References to elements in a different namespace are qualified using the syntax "
 
 Mtllib.mtlx contains the following (assuming that "..." contains any necessary material input connections and other element definitions):
 
-```
+```xml
   
   
     ...
@@ -412,7 +412,7 @@ Mtllib.mtlx contains the following (assuming that "..." contains any necessary m
 
 Then another MaterialX file could reference these materials like this:
 
-```
+```xml
     
     ...
     
@@ -423,7 +423,7 @@ Then another MaterialX file could reference these materials like this:
 
 Similarly, if a .mtlx file defining the "site_ops" namespace defined a custom color3-typed node "mynoise" with a single float input "f", it could be used in a node graph like this:
 
-```
+```xml
     
       
     
@@ -431,7 +431,7 @@ Similarly, if a .mtlx file defining the "site_ops" namespace defined a custom co
 
 A `namespace` attribute may also be added to individual <nodedef>s or <nodegraph>s, in which case the `name` and `node` of a <nodedef>, or just the `name` of a <nodegraph> will be assigned to the specified `namespace`.  In a <nodegraph>, the `nodedef` must include a namespace reference if the <nodedef> to which it refers is defined in a specific namespace, even if it's the same namespace as the <nodegraph>: this is because the `namespace` only applies to the content that is created by or contained within an element, not to anything external referenced by that element.
 
-```
+```xml
   
     
   
@@ -453,14 +453,14 @@ Geometric Properties, or "geomprops", are intrinsic or user-defined surface coor
 
 One may also define custom geometric properties using a <geompropdef> element:
 
-```
+```xml
   
 ```
 
 e.g.
 
-```
+```xml
   
   
 ```
@@ -469,13 +469,13 @@ The `type` of the geomprop may be any non-array MaterialX type, although `string
 
 Once defined, a custom geomprop name may be used any place that a standard geomprop can:
 
-```
+```xml
   
 ```
 
 A geompropdef may also specify a `unittype` and a `unit` to indicate that the geometric property is defined in terms of a specific unit.  If a geomprop with a defined unit is accessed in a nodegraph using <geompropvalue>, the geometric property value will be converted from the unit specified by the geompropdef to the application-specified scene unit.
 
-```
+```xml
   
 ```
 
@@ -487,7 +487,7 @@ As a shorthand convenience, MaterialX allows the specification of a `fileprefix`
 
 So the following snippets are equivalent:
 
-```
+```xml
   
     
       
@@ -538,7 +538,7 @@ Nodes are individual data generation or processing "blocks".  Node functionality
 
 Individual node elements have the form:
 
-```
+```xml
   
     
@@ -560,7 +560,7 @@ Node elements contain zero or more <input> elements defining the name, type,
 
 A float/vectorN input of a node, or a "filename"-type input referring to an image file containing float or vectorN values, may specify a unit for its value by providing a `unit` attribute, and that unit must be one associated with the `unittype` for that input in the nodedef, if specified; please see the [Units](#units) section above for details on declaring units and unittypes.  If the nodedef for a node (see the [Custom Nodes](#custom-nodes) section below) does not declare a `unittype` for an input, the node may do so; it is not permissible to provide a `unit` for a node input without a compatible `unittype` being defined on either the node or applicable nodedef.
 
-```
+```xml
   
     
   
@@ -570,7 +570,7 @@ Unless specified otherwise, all inputs default to a value of 0 in all channels f
 
 A node input must generally be connected to outputs of the same type, but float inputs may also be connected to any single channel within a multi-channel data types by adding an integer "channel" attribute, indicating the channel number (0-3) to extract from the input:
 
-```
+```xml
   
     
   
@@ -593,7 +593,7 @@ Standard MaterialX nodes have exactly one output, while custom nodes may have an
 
 A graph containing any number of nodes and output declarations forms a Node Graph, which may be enclosed within a <nodegraph> element to group them together into a single functional unit.  Please see the [Custom Node Definition Using Node Graphs](#custom-node-definition-using-node-graphs) section below for details on how nodegraphs can be used to describe the functionality of new nodes.
 
-```
+```xml
   
     ...node element(s)...
     ...output element(s)...
@@ -606,7 +606,7 @@ A graph containing any number of nodes and output declarations forms a Node Grap
 
 Output data streams are defined using **<output>** elements, and may be used to declare which output streams are connectable to other MaterialX elements.  Within a node graph, an <output> element declares an output stream that may be connected to a shader input or to the input of a referencing node in another graph when the nodegraph is the implementation of a custom node.  See the [Custom Node Definition Using Node Graphs](#custom-node-definition-using-node-graphs) section for details on the use of node graphs as node implementations.
 
-```
+```xml
   
   
@@ -640,7 +640,7 @@ This section defines the Source Nodes that all MaterialX implementations are exp
 
 Texture nodes are used to read filtered image data from image or texture map files for processing within a node graph.
 
-```
+```xml
   
     
     
@@ -721,7 +721,7 @@ Arbitrary frame number expressions and speed changes are not supported.
 
 Procedural nodes are used to generate value data programmatically.
 
-```
+```xml
   
     
   
@@ -900,7 +900,7 @@ To scale or offset the noise pattern generated by `noise3d`, `fractal3d` or `cel
 
 Geometric nodes are used to reference local geometric properties from within a node graph:
 
-```
+```xml
   
   
     
@@ -982,7 +982,7 @@ Applications may also reference other renderer-specific named spaces, at the exp
 
 Global nodes generate color data using non-local geometric context, requiring access to geometric features beyond the surface point being processed.  This non-local context can be provided by tracing rays into the scene, rasterizing scene geometry, or any other appropriate method.
 
-```
+```xml
   
     
   
@@ -1002,7 +1002,7 @@ Standard Global nodes:
 
 Application nodes are used to reference application-defined properties within a node graph, and have no inputs:
 
-```
+```xml
   
   
 ```
@@ -1028,7 +1028,7 @@ Standard Application nodes:
 
 Operator nodes process one or more required input streams to form an output.  Like other nodes, each operator must define its output type, which in most cases also determines the type(s) of the required input streams.
 
-```
+```xml
   
     
     
@@ -1786,7 +1786,7 @@ A simple merge of two single-layer images with a separate mask image, followed b
 
 ![Nodegraph Example 1](media/nodegraph1.png "Nodegraph Example 1")
 
-```
+```xml
 
 
   
@@ -1818,7 +1818,7 @@ A more complex nodegraph using geometry properties to define two diffuse albedo
 
 ![Nodegraph Example 2](media/nodegraph2.png "Nodegraph Example 2")
 
-```
+```xml
 
 
   
@@ -1885,7 +1885,7 @@ MaterialX supports the definition of nodes, attributes and inputs that are speci
 
 Targets are declared using a <targetdef> element:
 
-```
+```xml
   
   
   
@@ -1893,7 +1893,7 @@ Targets are declared using a <targetdef> element:
 
 A target may inherit from another target, so that any reference to a parent target will automatically include any definitions specific to the inherited child target that do not have a definition for the parent target itself:
 
-```
+```xml
   
   
   
@@ -1913,14 +1913,14 @@ While the MaterialX specification describes the attributes and elements that are
 If an application requires additional information related to any MaterialX element, it may define and utilize additional attributes with non-standard names.  Custom attributes are defined using <attributedef> elements:
 
 
-```
+```xml
   
 ```
 
 where _name_ is a unique name for the attributedef, _attrname_ is the name of the custom attribute to define, _type_ is the type of the attribute (typically string, stringarray, integer or boolean, although any MaterialX type is allowed), _defaultvalue_ is the default value for the attribute, _target_ is an optional list of targets to which this attribute applies, and _elements_ is an optional list of element names or elementname/inputname in which the attribute may be used.  It is also permissible to provide enum and enumvalues attributes for an attributedef, to define specific labels and values that the custom attribute is allowed to take, using the same syntax and limitations as enum/enumvalues on nodedef inputs and tokens (see below).  By default, a custom attribute is not emitted as metadata in generated shaders, but can be exported if the `exportable` attribute is set to "true".  Examples:
 
-```
+```xml
   
   
     
   
@@ -1948,7 +1948,7 @@ Once defined, custom attributes may be used in exactly the same manner as standa
 
 If an application requires additional custom inputs within a standard MaterialX node, it may define a target application-specific <nodedef> for that node inheriting the base input definitions from the standard node's <nodedef>, then add inputs specific to that target application.  
 
-```
+```xml
   
     
   
@@ -1958,7 +1958,7 @@ In the above example, a Maya-specific version of the color4-type <image> node
 
 When using a node, the definition appropriate for the current target will automatically be used, and other targets will ignore any inputs that are not part of the nodedef for that target.  However, one may specify a documentational  `target` attribute on an input to hint what target it is intended for if desired.  In this example, the "preFilter" input has indicated that it is specific to the "maya" target.
 
-```
+```xml
   
     
     
@@ -1998,7 +1998,7 @@ NodeDefs must define one or more child <output> elements within the <noded
 
 The parameter interface of a custom node is specified via a set of child <input> and <token> elements of the <nodedef>, while documentation of the folder structure of a node may be defined using a number of <uifolder> elements, each of which may provide a doc attribute to provide documentation for that folder layer.  A <uifolder> element may not contain any other elements; in particular, the <input>s and <token>s of the nodedef interface must be direct children of the <nodedef>.  Nested folders may be indicated using a full path for the folder, with a "/" separator between folder levels.
 
-```
+```xml
   
     
     
@@ -2012,7 +2012,7 @@ The parameter interface of a custom node is specified via a set of child <inp
 
 **Input** elements are used within a <nodedef> to declare the spatially-varying and uniform inputs for a node:
 
-```
+```xml
   
 ```
 
@@ -2047,7 +2047,7 @@ It is permissible to define a `value` or a `defaultgeomprop` for an input but no
 
 **Token** elements are used within a <nodedef> to declare uniform "interface token" string-substitution values to be referenced and substituted within filenames used in a node's nodegraph implementation:
 
-```
+```xml
   
 ```
 
@@ -2068,7 +2068,7 @@ Please see the [Example Pre-Shader Compositing Material](#example-pre-shader-com
 
 **Output** elements are used within a <nodedef> to declare an output for node definitions, including the output's name, type, and default value or "defaultinput" connection:
 
-```
+```xml
   
 ```
 
@@ -2103,7 +2103,7 @@ An <implementation> may define a `file` or `sourcecode` attribute, or neither
 
 Because the names used for node inputs (such as "normal" or "default") may conflict with the reserved words in various shading languages, or may simply be different for specific targets, <implementation> elements may contain a number of <input> elements to remap the `name`s of <input>s as specified in the <nodedef> to different `implname`s to indicate what the input name is actually called in the implementation's code.  Only the inputs that need to be remapped to new `implname`s need to be listed; for each, it is recommended that the `type` of that input be listed for clarity, but if specified, it must match the type specified in the <nodedef>: <implementation>s are not allowed to change the type or any other attribute defined in the <nodedef>.  In this example, the <implementation> declares that the "default" input defined in the "ND_image_color3" nodedef is actually called "default_value" in the "mx_image_color" function:
 
-```
+```xml
   
     
@@ -2112,7 +2112,7 @@ Because the names used for node inputs (such as "normal" or "default") may confl
 
 For uniform inputs and tokens whose nodedef description includes an enum list of allowable values, individual implementations may associate different target-specific resolved values for them potentially of a different type; these may be described by providing an `enumvalues` attribute on the uniform input or token within an <implementation> and if appropriate, an `impltype` to declare the target-specific type of these enumvalues.  Note that if the type of an enum input in the nodedef is an array type, then the `impltype` (if specified) must also be an array type, while `enumvalues` is a list of values of the base (non-array) type.  The following <implementation> states that for the "mystudio" target, the uaddressmode and vaddressmode inputs of the "image" node are actually called "extrapolate_u" and "extrapolate_v", are integers rather than strings, and take different values (e.g. "clamp" is 2):
 
-```
+```xml
   
   
      element with a file attribute defining an external compiled implementation of a surface shader may contain one or more <aov> elements to declare the names and types of arbitrary output variables ("AOVs") which the shader can output to the renderer.  AOVs must be of type float, color3, vector3, BSDF or EDF.  Note that in MaterialX, AOVs for pre-shading "pattern" colors are normally of type color3, while post-shaded color-like values are normally of type BSDF and emissive color-like values are normally of type EDF.  An <implementation> with a `nodegraph` attribute may not contain <aov> elements; instead, <aovoutput> elements within the nodegraph should be used.
 
-```
+```xml
   
@@ -2139,7 +2139,7 @@ An <implementation> element with a file attribute defining an external compil
 
 #### Example Custom Nodes Defined by External File Implementations
 
-```
+```xml
   
     
     
@@ -2179,7 +2179,7 @@ This example defines two templates for a custom operator node called "mariBlend"
 
 Here is an example of a two-output node definition and external implementation declaration.
 
-```
+```xml
   
     
     
@@ -2203,7 +2203,7 @@ A **<nodegraph>** element consists of at least one node element and at least
 
 A **functional nodegraph** is a nodegraph-based implementation for a specified <nodedef>, with the <nodedef> declaring the set of inputs that the nodegraph accepts: a functional nodegraph may not itself specify any direct child input elements.
 
-```
+```xml
   
     ...node element(s)...
     ...output element(s)...
@@ -2212,7 +2212,7 @@ A **functional nodegraph** is a nodegraph-based implementation for a specified &
 
 or
 
-```
+```xml
   
     ...node element(s)...
     ...output element(s)...
@@ -2223,7 +2223,7 @@ or
 
 The type(s) of the <output>(s) of the <nodedef> and the type(s) of the nodegraph <output>(s) must agree, and if there are multiple outputs, then the `name`s of the <output>s in the <nodegraph> and <nodedef> must also agree.  The inputs and tokens of the <nodedef> can be referenced within <input> and <token> elements of nodes within the nodegraph implementation using `interfacename` attributes in place of `value` or `nodename` attributes, e.g. a nodedef input "i2" and interface token "diffmap" could be referenced as follows:
 
-```
+```xml
     
     
 ```
@@ -2235,7 +2235,7 @@ Note that a uniform <input> of a node within the nodegraph may use `interface
 
 A **compound <nodegraph>** element may specify one or more child <input> and/or <token> elements.  In this case, the <nodegraph> functions as a collapsible "wrapper" for the contained nodes.
 
-```
+```xml
   
     [...input and/or token element(s)...]
     ...node and/or (compound) nodegraph element(s)...
@@ -2250,7 +2250,7 @@ It is permissible to define multiple nodegraph- and/or file-based implementation
 
 #### Example Custom Node Defined by a Nodegraph
 
-```
+```xml
   
     
     
@@ -2277,7 +2277,7 @@ The inputs of the nodegraph are declared by the <nodedef>, and the nodes with
 
 Once defined with a <nodedef>, using a custom node within a node graph follows the same syntax as any other standard node: the name of the element is the name of the custom node, and the MaterialX type of the node's output is required; the custom node's child elements define connections of inputs to other node outputs as well as any input values for the custom node.
 
-```
+```xml
   
     
     
@@ -2292,7 +2292,7 @@ Once defined with a <nodedef>, using a custom node within a node graph follow
 
 When invoking nodes with multiple outputs, the `type` of the node should be declared as "multioutput", and other node inputs connecting to an output of the node must include an `output` attribute to specify which output of the node to connect to:
 
-```
+```xml
   
     
     
@@ -2313,7 +2313,7 @@ When invoking nodes with multiple outputs, the `type` of the node should be decl
 
 Custom nodes that output data types with a "shader" semantic are referred to in MaterialX as "Shader Nodes".  Shaders, along with their inputs, are declared using the same <nodedef>, <implementation> and <nodegraph> elements described above:
 
-```
+```xml
   
     ...input declarations...
     
@@ -2331,7 +2331,7 @@ NodeDef elements defining shader nodes do not typically include `default` or `de
 
 As mentioned in the [Custom Data Types](#custom-data-types) section earlier, the standard MaterialX distribution includes the following standard data types for shaders:
 
-```
+```xml
   
   
   
@@ -2342,7 +2342,7 @@ These types all declare that they have "shader" semantic, but define different c
 
 Instantiation of shader nodes to give them specific values is done the same way as instantiating any other node type:
 
-```
+```xml
   
     
     
@@ -2352,7 +2352,7 @@ Instantiation of shader nodes to give them specific values is done the same way
 
 Instantiated shader nodes can also inherit from other shader nodes of the same class:
 
-```
+```xml
   
     
   
@@ -2398,7 +2398,7 @@ The Standard MaterialX Library defines the following nodes and node variants ope
 
 A functional nodegraph with either a "shader" or "material"-semantic output type may contain a number of <aovoutput> elements to declare arbitrary output variables ("AOVs") which the renderer can see and output as additional streams of information.  AOVoutputs must be of type float, color3 or vector3 for pre-shading "pattern" values, or BSDF or EDF for shader-node output values; the renderer is expected to extract the appropriate color-like information from BSDF and EDF types.  AOVs defined within a shader-semantic node instantiated within this functional nodegraph may be "passed along" and potentially renamed (but may not be modified or operated on in any way) by providing a sourceaov attribute in the <aovoutput>.
 
-```
+```xml
   
 ```
@@ -2413,7 +2413,7 @@ The attributes for <aovoutput> elements are:
 
 Examples:
 
-```
+```xml
   
   
@@ -2424,7 +2424,7 @@ Examples:
 
 Example of using <aovoutput> with sourceaov to forward AOVs from within an instantiation of a shader-semantic node; this assumes that <standard_surface> has itself defined <aovoutput>s for "diffuse" and "specular" AOVs:
 
-```
+```xml
   
     
       s for geometric
 
 Custom nodes that output data types with a "material" semantic are referred to in MaterialX as "Material Nodes".  Material nodes typically have one or more "shader" semantic inputs which establish what shaders the material references; previous versions of MaterialX used <shaderref> elements to establish these shader-to-material connections.  Material Nodes are declared using the same <nodedef> elements as described above:
 
-```
+```xml
   
     
     ...additional shader or input declarations...
@@ -2476,7 +2476,7 @@ The attributes for <nodedef> elements as they pertain to the declaration of m
 
 The standard MaterialX distribution includes a single material type definition used as the output type for all material nodes:
 
-```
+```xml
   
 ```
 
@@ -2501,7 +2501,7 @@ as well as definitions for three standard material nodes, all outputting type "m
 
 Material nodes supporting multiple shaders of the same type for different rendering targets can be defined:
 
-```
+```xml
   
     
     
@@ -2514,7 +2514,7 @@ Material nodes supporting multiple shaders of the same type for different render
 
 Creating materials with specific values bound to shader inputs involves instantiating a Shader Node for each desired shader type and setting values on those shader nodes, and connecting the shader node(s) to the inputs of a Material Node:
 
-```
+```xml
   
     
     
@@ -2535,7 +2535,7 @@ Alternatively, and perhaps more usefully, a complete network of multiple shader
 
 Materials can inherit from other materials, to add or change shaders connected to different inputs; in this example, a displacement shader is added to the above "Mgold" material to create a new "Mgolddsp" material:
 
-```
+```xml
   
     
     
@@ -2555,7 +2555,7 @@ Inheritance of material-type custom nodes is also allowed, so that new or change
 
 A material to blend between three different surface layers using mask textures.  This example also demonstrates the use of the "target" attribute of a shader implementation element to define multiple renderer-specific shaders of the same type referenced within a single material, and the use of interface tokens to define texture filenames.
 
-```
+```xml
 
 
   
+
+  
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+    
+      
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+  
+
diff --git a/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_25.mtlx b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_25.mtlx
new file mode 100644
index 0000000000..df723e7054
--- /dev/null
+++ b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_25.mtlx
@@ -0,0 +1,28 @@
+
+
+  
+
+  
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  
+
diff --git a/resources/Materials/TestSuite/stdlib/upgrade/1_36_to_1_37.mtlx b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_36.mtlx
similarity index 99%
rename from resources/Materials/TestSuite/stdlib/upgrade/1_36_to_1_37.mtlx
rename to resources/Materials/TestSuite/stdlib/upgrade/syntax_1_36.mtlx
index 84db1c6101..08a049435f 100644
--- a/resources/Materials/TestSuite/stdlib/upgrade/1_36_to_1_37.mtlx
+++ b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_36.mtlx
@@ -1,9 +1,7 @@
 
 
   
 
   
diff --git a/resources/Materials/TestSuite/stdlib/upgrade/1_37_to_1_38.mtlx b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx
similarity index 62%
rename from resources/Materials/TestSuite/stdlib/upgrade/1_37_to_1_38.mtlx
rename to resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx
index 28b9ae8ad2..3cb8eb6237 100644
--- a/resources/Materials/TestSuite/stdlib/upgrade/1_37_to_1_38.mtlx
+++ b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx
@@ -1,5 +1,9 @@
 
-
+
+  
+
   
     
       
@@ -37,4 +41,24 @@
       
     
+ + + + + + + + + + + + + + + + + + + + diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 4ba48cc84b..0449189873 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -492,12 +492,10 @@ void Document::upgradeVersion() if (nodeDef->hasAttribute("shadertype")) { nodeDef->setType(SURFACE_SHADER_TYPE_STRING); - nodeDef->removeAttribute("shadertype"); } if (nodeDef->hasAttribute("shaderprogram")) { nodeDef->setNodeString(nodeDef->getAttribute("shaderprogram")); - nodeDef->removeAttribute("shaderprogram"); } } else if (child->getCategory() == "shaderref") @@ -751,8 +749,18 @@ void Document::upgradeVersion() // Remove legacy shader nodedefs. for (NodeDefPtr nodeDef : getNodeDefs()) { - if (nodeDef->getType() == "surface") + if (nodeDef->hasAttribute("shadertype")) { + for (ElementPtr mat : getChildrenOfType("material")) + { + for (ElementPtr shaderRef : mat->getChildrenOfType("shaderref")) + { + if (shaderRef->getAttribute(InterfaceElement::NODE_DEF_ATTRIBUTE) == nodeDef->getName()) + { + shaderRef->removeAttribute(InterfaceElement::NODE_DEF_ATTRIBUTE); + } + } + } removeNodeDef(nodeDef->getName()); } } diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index 176014ba65..d2967e6b85 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -82,26 +82,6 @@ void applyModifiers(mx::DocumentPtr doc, const DocumentModifiers& modifiers) } } - // Remap references to unimplemented shader nodedefs. - for (mx::NodePtr materialNode : doc->getMaterialNodes()) - { - for (mx::NodePtr shader : getShaderNodes(materialNode)) - { - mx::NodeDefPtr nodeDef = shader->getNodeDef(); - if (nodeDef && !nodeDef->getImplementation()) - { - std::vector altNodeDefs = doc->getMatchingNodeDefs(nodeDef->getNodeString()); - for (mx::NodeDefPtr altNodeDef : altNodeDefs) - { - if (altNodeDef->getImplementation()) - { - shader->setNodeDefString(altNodeDef->getName()); - } - } - } - } - } - // Remap unsupported texture coordinate indices. for (mx::ElementPtr elem : doc->traverseTree()) { diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index 29092071cf..af39035dbe 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -108,108 +108,3 @@ TEST_CASE("Document", "[document]") // Validate the combined document. REQUIRE(doc->validate()); } - -TEST_CASE("Version", "[document]") -{ - mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); - mx::DocumentPtr stdlib = mx::createDocument(); - mx::loadLibraries({ "libraries" }, searchPath, stdlib); - searchPath.append(searchPath.find("resources/Materials/TestSuite/stdlib/upgrade")); - - // 1.36 to 1.37 - { - mx::DocumentPtr doc = mx::createDocument(); - mx::readFromXmlFile(doc, "1_36_to_1_37.mtlx", searchPath); - doc->importLibrary(stdlib); - REQUIRE(doc->validate()); - - mx::XmlWriteOptions writeOptions; - writeOptions.writeXIncludeEnable = true; - std::string xmlString = mx::writeToXmlString(doc, &writeOptions); - - mx::DocumentPtr doc2 = mx::createDocument(); - mx::readFromXmlString(doc2, xmlString); - REQUIRE(doc2->validate()); - - // Check conversion to desired types occurred - std::unordered_map convertSet = - { - { "invertmatrix", 2}, - { "rotate2d", 1}, - { "rotate3d", 1}, - { "transformmatrix", 7}, - { "ifgreatereq", 7}, - { "separate2", 1}, - { "separate3", 1}, - { "separate4", 1}, - { "combine2", 1}, - { "combine3", 1}, - { "combine4", 1} - }; - for (mx::NodePtr node : doc2->getNodes()) - { - auto convertItem = convertSet.find(node->getCategory()); - if (convertItem != convertSet.end()) - { - convertItem->second--; - } - } - for (auto convertItem : convertSet) - { - REQUIRE((convertItem.second == 0)); - } - } - - // 1.37 to 1.38 - { - mx::DocumentPtr doc = mx::createDocument(); - mx::readFromXmlFile(doc, "1_37_to_1_38.mtlx", searchPath); - doc->importLibrary(stdlib); - REQUIRE(doc->validate()); - - mx::XmlWriteOptions writeOptions; - writeOptions.writeXIncludeEnable = false; - std::string xmlString = mx::writeToXmlString(doc, &writeOptions); - - mx::DocumentPtr doc2 = mx::createDocument(); - mx::readFromXmlString(doc2, xmlString); - REQUIRE(doc2->validate()); - - // atan2 test - const std::string ATAN2 = "atan2"; - mx::StringMap ATAN2_MAP; - ATAN2_MAP["in1"] = "in2"; - ATAN2_MAP["in2"] = "in1"; - - for (mx::ElementPtr elem : doc->traverseTree()) - { - mx::NodePtr node = elem->asA(); - if (!node) - { - continue; - } - const std::string& nodeCategory = node->getCategory(); - if (nodeCategory == ATAN2) - { - const std::string &nodePath = node->getNamePath(); - for (auto in : ATAN2_MAP) - { - mx::ElementPtr input = node->getChild(in.first); - if (input) - { - mx::ElementPtr newNode = doc2->getDescendant(nodePath); - REQUIRE((newNode && newNode->getChild(in.second))); - } - } - } - } - - mx::NodeGraphPtr testNodeGraph = doc2->getNodeGraph("NG_Test"); - REQUIRE(!testNodeGraph->getNode("add")); - REQUIRE(testNodeGraph->getNode("add1")); - REQUIRE(testNodeGraph->getNode("add2")); - REQUIRE(testNodeGraph->getNode("add2")->getInput("in1")->getInterfaceName() == "add"); - REQUIRE(testNodeGraph->getNode("add1")->getInput("in1")->getNodeName() == "add2"); - } -} - diff --git a/source/MaterialXTest/MaterialXRender/RenderUtil.cpp b/source/MaterialXTest/MaterialXRender/RenderUtil.cpp index af392a9a05..0460f9282a 100644 --- a/source/MaterialXTest/MaterialXRender/RenderUtil.cpp +++ b/source/MaterialXTest/MaterialXRender/RenderUtil.cpp @@ -76,19 +76,6 @@ void ShaderRenderTester::loadDependentLibraries(GenShaderUtil::TestSuiteOptions loadAdditionalLibraries(dependLib, options); } -void ShaderRenderTester::addSkipFiles() -{ - _skipFiles.insert("_options.mtlx"); - _skipFiles.insert("light_rig_test_1.mtlx"); - _skipFiles.insert("light_rig_test_2.mtlx"); - _skipFiles.insert("light_compound_test.mtlx"); - _skipFiles.insert("xinclude_search_path.mtlx"); - _skipFiles.insert("1_38_parameter_to_input.mtlx"); - _skipFiles.insert("1_36_to_1_37.mtlx"); - _skipFiles.insert("1_37_to_1_38.mtlx"); - _skipFiles.insert("material_element_to_surface_material.mtlx"); -} - bool ShaderRenderTester::validate(const mx::FilePath optionsFilePath) { #ifdef LOG_TO_FILE @@ -144,9 +131,6 @@ bool ShaderRenderTester::validate(const mx::FilePath optionsFilePath) } ioTimer.endTimer(); - // Add files to skip - addSkipFiles(); - // Load in the library dependencies once // This will be imported in each test document below ioTimer.startTimer(); @@ -215,11 +199,6 @@ bool ShaderRenderTester::validate(const mx::FilePath optionsFilePath) for (const mx::FilePath& file : files) { - if (_skipFiles.count(file)) - { - continue; - } - ioTimer.startTimer(); // Check if a file override set is used and ignore all files // not part of the override set diff --git a/source/MaterialXTest/MaterialXRender/RenderUtil.h b/source/MaterialXTest/MaterialXRender/RenderUtil.h index 9f892569de..b29145dcb1 100644 --- a/source/MaterialXTest/MaterialXRender/RenderUtil.h +++ b/source/MaterialXTest/MaterialXRender/RenderUtil.h @@ -114,9 +114,6 @@ class ShaderRenderTester } #endif - // Add files to skip - void addSkipFiles(); - // Load dependencies void loadDependentLibraries(GenShaderUtil::TestSuiteOptions options, mx::FileSearchPath searchPath, mx::DocumentPtr& dependLib); @@ -181,9 +178,6 @@ class ShaderRenderTester bool _resolveImageFilenames; mx::StringResolverPtr _customFilenameResolver; - // Files to skip - mx::StringSet _skipFiles; - // Color management information mx::ColorManagementSystemPtr _colorManagementSystem; mx::FilePath _colorManagementConfigFile; diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 6346658d07..560a19e778 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -121,26 +121,6 @@ void applyModifiers(mx::DocumentPtr doc, const DocumentModifiers& modifiers) } } - // Remap references to unimplemented shader nodedefs. - for (mx::NodePtr materialNode : doc->getMaterialNodes()) - { - for (mx::NodePtr shader : getShaderNodes(materialNode)) - { - mx::NodeDefPtr nodeDef = shader->getNodeDef(); - if (nodeDef && !nodeDef->getImplementation()) - { - std::vector altNodeDefs = doc->getMatchingNodeDefs(nodeDef->getNodeString()); - for (mx::NodeDefPtr altNodeDef : altNodeDefs) - { - if (altNodeDef->getImplementation()) - { - shader->setNodeDefString(altNodeDef->getName()); - } - } - } - } - } - // Remap unsupported texture coordinate indices. for (mx::ElementPtr elem : doc->traverseTree()) { From 85dc5e1ea3239de507af07143224fd1c7852ee75 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 7 Oct 2023 09:59:34 -0700 Subject: [PATCH 10/22] Improvements to 1.37 upgrade (#1555) - Add an example shading model graph using MaterialX 1.37 syntax, allowing improved coverage of version upgrade logic in unit tests. - Simplify the logic for 1.37 upgrades in Document::upgradeVersion, removing legacy code that was dedicated to upgrading the MaterialX standard libraries. --- .../TestSuite/stdlib/upgrade/syntax_1_37.mtlx | 151 ++++++++++------ source/MaterialXCore/Document.cpp | 166 +++++------------- 2 files changed, 144 insertions(+), 173 deletions(-) diff --git a/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx index 3cb8eb6237..66dc69f668 100644 --- a/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx +++ b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx @@ -4,61 +4,110 @@ Examples of MaterialX 1.37 syntax --> - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 0449189873..80143bb9c8 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -1040,39 +1040,7 @@ void Document::upgradeVersion() } } - // Update atan2 interface and rotate3d interface - const string ATAN2 = "atan2"; - const string IN1 = "in1"; - const string IN2 = "in2"; - const string ROTATE3D = "rotate3d"; - const string AXIS = "axis"; - const string INPUT_ONE = "1.0"; - - // Update nodedefs - bool upgradeAtan2Instances = false; - for (auto nodedef : getMatchingNodeDefs(ATAN2)) - { - InputPtr input = nodedef->getInput(IN1); - InputPtr input2 = nodedef->getInput(IN2); - string inputValue = input->getValueString(); - // Only flip value if nodedef value is the previous versions. - if (inputValue == INPUT_ONE) - { - input->setValueString(input2->getValueString()); - input2->setValueString(inputValue); - upgradeAtan2Instances = true; - } - } - for (auto nodedef : getMatchingNodeDefs(ROTATE3D)) - { - ElementPtr axis = nodedef->getChild(AXIS); - if (axis) - { - nodedef->changeChildCategory(axis, "input"); - } - } - - // Update BSDF interfaces + // Define BSDF node pairs. using StringPair = std::pair; const StringPair DIELECTRIC_BRDF = { "dielectric_brdf", "dielectric_bsdf" }; const StringPair DIELECTRIC_BTDF = { "dielectric_btdf", "dielectric_bsdf" }; @@ -1085,57 +1053,11 @@ void Document::upgradeVersion() const StringPair SUBSURFACE_BRDF = { "subsurface_brdf", "subsurface_bsdf" }; const StringPair THIN_FILM_BRDF = { "thin_film_brdf", "thin_film_bsdf" }; - const string SCATTER_MODE = "scatter_mode"; - const string BSDF = "BSDF"; - const string LAYER = "layer"; - const string TOP = "top"; - const string BASE = "base"; - const string INTERIOR = "interior"; - const string ARTISTIC_IOR = "artistic_ior"; - const string COMPLEX_IOR = "complex_ior"; - const string REFLECTIVITY = "reflectivity"; - const string EDGE_COLOR = "edge_color"; - const string IOR = "ior"; - const string EXTINCTION = "extinction"; - const string COLOR3 = "color3"; - const string VECTOR3 = "vector3"; - const string CONVERT = "convert"; - const string IN = "in"; - - // Function for upgrading BSDF nodedef. - auto upgradeBsdfNodeDef = [SCATTER_MODE](NodeDefPtr nodedef, const string& newCategory, bool addScatterMode = false) - { - if (nodedef) - { - nodedef->setName(newCategory); - if (addScatterMode) - { - InputPtr mode = nodedef->addInput(SCATTER_MODE, STRING_TYPE_STRING); - mode->setIsUniform(true); - mode->setValueString("R"); - mode->setAttribute("enum", "R,T,RT"); - } - } - }; - - // Update nodedefs. - upgradeBsdfNodeDef(getNodeDef(DIELECTRIC_BRDF.first), DIELECTRIC_BRDF.second, true); - upgradeBsdfNodeDef(getNodeDef(GENERALIZED_SCHLICK_BRDF.first), GENERALIZED_SCHLICK_BRDF.second, true); - upgradeBsdfNodeDef(getNodeDef(CONDUCTOR_BRDF.first), CONDUCTOR_BRDF.second); - upgradeBsdfNodeDef(getNodeDef(SHEEN_BRDF.first), SHEEN_BRDF.second); - upgradeBsdfNodeDef(getNodeDef(DIFFUSE_BRDF.first), DIFFUSE_BRDF.second); - upgradeBsdfNodeDef(getNodeDef(BURLEY_DIFFUSE_BRDF.first), BURLEY_DIFFUSE_BRDF.second); - upgradeBsdfNodeDef(getNodeDef(DIFFUSE_BTDF.first), DIFFUSE_BTDF.second); - upgradeBsdfNodeDef(getNodeDef(SUBSURFACE_BRDF.first), SUBSURFACE_BRDF.second); - upgradeBsdfNodeDef(getNodeDef(THIN_FILM_BRDF.first), THIN_FILM_BRDF.second); - removeNodeDef(DIELECTRIC_BTDF.first); - removeNodeDef(COMPLEX_IOR); - // Function for upgrading old nested layering setup // to new setup with layer operators. - auto upgradeBsdfLayering = [TOP, BASE, LAYER, BSDF](NodePtr node) + auto upgradeBsdfLayering = [](NodePtr node) { - InputPtr base = node->getInput(BASE); + InputPtr base = node->getInput("base"); if (base) { NodePtr baseNode = base->getConnectedNode(); @@ -1146,13 +1068,13 @@ void Document::upgradeVersion() // so we don't need to update any connection references. const string oldName = node->getName(); node->setName(oldName + "__layer_top"); - NodePtr layer = parent->addNode(LAYER, oldName, BSDF); - InputPtr layerTop = layer->addInput(TOP, BSDF); - InputPtr layerBase = layer->addInput(BASE, BSDF); + NodePtr layer = parent->addNode("layer", oldName, "BSDF"); + InputPtr layerTop = layer->addInput("top", "BSDF"); + InputPtr layerBase = layer->addInput("base", "BSDF"); layerTop->setConnectedNode(node); layerBase->setConnectedNode(baseNode); } - node->removeInput(BASE); + node->removeInput("base"); } }; @@ -1177,31 +1099,31 @@ void Document::upgradeVersion() continue; } const string& nodeCategory = node->getCategory(); - if (upgradeAtan2Instances && nodeCategory == ATAN2) + if (nodeCategory == "atan2") { - InputPtr input = node->getInput(IN1); - InputPtr input2 = node->getInput(IN2); + InputPtr input = node->getInput("in1"); + InputPtr input2 = node->getInput("in2"); if (input && input2) { input->setName(EMPTY_STRING); - input2->setName(IN1); - input->setName(IN2); + input2->setName("in1"); + input->setName("in2"); } else { if (input) { - input->setName(IN2); + input->setName("in2"); } if (input2) { - input2->setName(IN1); + input2->setName("in1"); } } } - else if (nodeCategory == ROTATE3D) + else if (nodeCategory == "rotate3d") { - ElementPtr axis = node->getChild(AXIS); + ElementPtr axis = node->getChild("axis"); if (axis) { node->changeChildCategory(axis, "input"); @@ -1215,8 +1137,8 @@ void Document::upgradeVersion() else if (nodeCategory == DIELECTRIC_BTDF.first) { node->setCategory(DIELECTRIC_BTDF.second); - node->removeInput(INTERIOR); - InputPtr mode = node->addInput(SCATTER_MODE, STRING_TYPE_STRING); + node->removeInput("interior"); + InputPtr mode = node->addInput("scatter_mode", STRING_TYPE_STRING); mode->setValueString("T"); } else if (nodeCategory == GENERALIZED_SCHLICK_BRDF.first) @@ -1240,32 +1162,32 @@ void Document::upgradeVersion() // Create an artistic_ior node to convert from artistic to physical parameterization. GraphElementPtr parent = node->getParent()->asA(); - NodePtr artisticIor = parent->addNode(ARTISTIC_IOR, node->getName() + "__artistic_ior", "multioutput"); - OutputPtr artisticIor_ior = artisticIor->addOutput(IOR, COLOR3); - OutputPtr artisticIor_extinction = artisticIor->addOutput(EXTINCTION, COLOR3); + NodePtr artisticIor = parent->addNode("artistic_ior", node->getName() + "__artistic_ior", "multioutput"); + OutputPtr artisticIor_ior = artisticIor->addOutput("ior", "color3"); + OutputPtr artisticIor_extinction = artisticIor->addOutput("extinction", "color3"); // Copy values and connections from conductor node to artistic_ior node. - InputPtr reflectivity = node->getInput(REFLECTIVITY); + InputPtr reflectivity = node->getInput("reflectivity"); if (reflectivity) { - InputPtr artisticIor_reflectivity = artisticIor->addInput(REFLECTIVITY, COLOR3); + InputPtr artisticIor_reflectivity = artisticIor->addInput("reflectivity", "color3"); copyAttributes(reflectivity, artisticIor_reflectivity); } - InputPtr edge_color = node->getInput(EDGE_COLOR); + InputPtr edge_color = node->getInput("edge_color"); if (edge_color) { - InputPtr artisticIor_edge_color = artisticIor->addInput(EDGE_COLOR, COLOR3); + InputPtr artisticIor_edge_color = artisticIor->addInput("edge_color", "color3"); copyAttributes(edge_color, artisticIor_edge_color); } // Update the parameterization on the conductor node // and connect it to the artistic_ior node. - node->removeInput(REFLECTIVITY); - node->removeInput(EDGE_COLOR); - InputPtr ior = node->addInput(IOR, COLOR3); + node->removeInput("reflectivity"); + node->removeInput("edge_color"); + InputPtr ior = node->addInput("ior", "color3"); ior->setNodeName(artisticIor->getName()); ior->setOutputString(artisticIor_ior->getName()); - InputPtr extinction = node->addInput(EXTINCTION, COLOR3); + InputPtr extinction = node->addInput("extinction", "color3"); extinction->setNodeName(artisticIor->getName()); extinction->setOutputString(artisticIor_extinction->getName()); } @@ -1285,17 +1207,17 @@ void Document::upgradeVersion() { node->setCategory(SUBSURFACE_BRDF.second); } - else if (nodeCategory == ARTISTIC_IOR) + else if (nodeCategory == "artistic_ior") { - OutputPtr ior = node->getOutput(IOR); + OutputPtr ior = node->getOutput("ior"); if (ior) { - ior->setType(COLOR3); + ior->setType("color3"); } - OutputPtr extinction = node->getOutput(EXTINCTION); + OutputPtr extinction = node->getOutput("extinction"); if (extinction) { - extinction->setType(COLOR3); + extinction->setType("color3"); } } @@ -1306,18 +1228,18 @@ void Document::upgradeVersion() // since we can't modify the graph while traversing it. for (InputPtr input : node->getInputs()) { - if (input->getOutputString() == IOR && input->getType() == VECTOR3) + if (input->getOutputString() == "ior" && input->getType() == "vector3") { NodePtr connectedNode = input->getConnectedNode(); - if (connectedNode && connectedNode->getCategory() == ARTISTIC_IOR) + if (connectedNode && connectedNode->getCategory() == "artistic_ior") { artisticIorConnections.push_back(input); } } - else if (input->getOutputString() == EXTINCTION && input->getType() == VECTOR3) + else if (input->getOutputString() == "extinction" && input->getType() == "vector3") { NodePtr connectedNode = input->getConnectedNode(); - if (connectedNode && connectedNode->getCategory() == ARTISTIC_IOR) + if (connectedNode && connectedNode->getCategory() == "artistic_ior") { artisticExtConnections.push_back(input); } @@ -1331,10 +1253,10 @@ void Document::upgradeVersion() NodePtr artisticIorNode = input->getConnectedNode(); ElementPtr node = input->getParent(); GraphElementPtr parent = node->getParent()->asA(); - NodePtr convert = parent->addNode(CONVERT, node->getName() + "__convert_ior", VECTOR3); - InputPtr convertInput = convert->addInput(IN, COLOR3); + NodePtr convert = parent->addNode("convert", node->getName() + "__convert_ior", "vector3"); + InputPtr convertInput = convert->addInput("in", "color3"); convertInput->setNodeName(artisticIorNode->getName()); - convertInput->setOutputString(IOR); + convertInput->setOutputString("ior"); input->setNodeName(convert->getName()); input->removeAttribute(PortElement::OUTPUT_ATTRIBUTE); } @@ -1343,10 +1265,10 @@ void Document::upgradeVersion() NodePtr artisticIorNode = input->getConnectedNode(); ElementPtr node = input->getParent(); GraphElementPtr parent = node->getParent()->asA(); - NodePtr convert = parent->addNode(CONVERT, node->getName() + "__convert_extinction", VECTOR3); - InputPtr convertInput = convert->addInput(IN, COLOR3); + NodePtr convert = parent->addNode("convert", node->getName() + "__convert_extinction", "vector3"); + InputPtr convertInput = convert->addInput("in", "color3"); convertInput->setNodeName(artisticIorNode->getName()); - convertInput->setOutputString(EXTINCTION); + convertInput->setOutputString("extinction"); input->setNodeName(convert->getName()); input->removeAttribute(PortElement::OUTPUT_ATTRIBUTE); } From f583ea1aaa4d1e97488fd7528695d7590a566db5 Mon Sep 17 00:00:00 2001 From: Igor Elovikov Date: Sat, 7 Oct 2023 20:13:03 +0300 Subject: [PATCH 11/22] Fix Ninja builds of both Viewer and Editor (#1533) Related to: #1208 --- source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt b/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt index eaae85a825..2ec553856f 100644 --- a/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt +++ b/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt @@ -41,7 +41,7 @@ if (BUILD_SHARED_LIBS AND UNIX) # On Unix-like systems, shared libraries can use the soname system. set(GLFW_LIB_NAME glfw) else() - set(GLFW_LIB_NAME glfw3) + set(GLFW_LIB_NAME glfw3_minimal) endif() if (GLFW_VULKAN_STATIC) From 695901492ef791d09a0ecf23c0ef7680aa27a563 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 7 Oct 2023 15:39:32 -0700 Subject: [PATCH 12/22] Improvements to look inheritance - Add support for look inheritance in the MaterialX viewer. - Improve coverage of look inheritance in MaterialX unit tests. - Raises statement coverage for MaterialX unit tests to 88.6%. --- source/MaterialXTest/MaterialXCore/Look.cpp | 2 ++ source/MaterialXView/Viewer.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/source/MaterialXTest/MaterialXCore/Look.cpp b/source/MaterialXTest/MaterialXCore/Look.cpp index 4106bf2eb3..006538891c 100644 --- a/source/MaterialXTest/MaterialXCore/Look.cpp +++ b/source/MaterialXTest/MaterialXCore/Look.cpp @@ -75,6 +75,7 @@ TEST_CASE("Look", "[look]") // Create an inherited look. mx::LookPtr look2 = doc->addLook(); look2->setInheritsFrom(look); + REQUIRE(look2->getActiveMaterialAssigns().size() == 2); REQUIRE(look2->getActivePropertySetAssigns().size() == 1); REQUIRE(look2->getActiveVisibilities().size() == 1); @@ -86,6 +87,7 @@ TEST_CASE("Look", "[look]") // Disconnect the inherited look. look2->setInheritsFrom(nullptr); + REQUIRE(look2->getActiveMaterialAssigns().empty()); REQUIRE(look2->getActivePropertySetAssigns().empty()); REQUIRE(look2->getActiveVisibilities().empty()); } diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 560a19e778..c06846f2ce 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -1375,7 +1375,7 @@ void Viewer::loadDocument(const mx::FilePath& filename, mx::DocumentPtr librarie // with later assignments superseding earlier ones. for (mx::LookPtr look : doc->getLooks()) { - for (mx::MaterialAssignPtr matAssign : look->getMaterialAssigns()) + for (mx::MaterialAssignPtr matAssign : look->getActiveMaterialAssigns()) { const std::string& activeGeom = matAssign->getActiveGeom(); for (mx::MeshPartitionPtr part : _geometryList) From c7f01d89e402ff58364cbdcf52cbd2d6f2213e0e Mon Sep 17 00:00:00 2001 From: Niklas Harrysson Date: Mon, 9 Oct 2023 19:54:24 +0200 Subject: [PATCH 13/22] Improve OSL generation of filename inputs (#1547) This change list modifies the generation of public filename parameters from being a textureresource struct, to being two separate string parameters for filename and colorspace. --- source/MaterialXGenOsl/OslShaderGenerator.cpp | 212 +++++++++++------- source/MaterialXGenOsl/OslShaderGenerator.h | 3 + 2 files changed, 130 insertions(+), 85 deletions(-) diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index 28ada48626..fbb2bb29be 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -294,6 +294,25 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G emitLineBreak(stage); } + // Inputs of type 'filename' has been generated into two shader inputs. + // So here we construct a single 'textureresource' from these inputs, + // to be used further downstream. See emitShaderInputs() for details. + VariableBlock& inputs = stage.getUniformBlock(OSL::UNIFORMS); + for (size_t i = 0; i < inputs.size(); ++i) + { + ShaderPort* input = inputs[i]; + if (input->getType() == Type::FILENAME) + { + // Construct the textureresource variable. + const string newVariableName = input->getVariable() + "_"; + const string& type = _syntax->getTypeName(input->getType()); + emitLine(type + newVariableName + " = {" + input->getVariable() + ", " + input->getVariable() + "_colorspace}", stage); + + // Update the variable name to be used downstream. + input->setVariable(newVariableName); + } + } + // 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); @@ -489,111 +508,75 @@ void OslShaderGenerator::emitLibraryIncludes(ShaderStage& stage, GenContext& con emitLineBreak(stage); } -namespace -{ - -std::unordered_map GEOMPROP_DEFINITIONS = -{ - { "Pobject", "transform(\"object\", P)" }, - { "Pworld", "P" }, - { "Nobject", "transform(\"object\", N)" }, - { "Nworld", "N" }, - { "Tobject", "transform(\"object\", dPdu)" }, - { "Tworld", "dPdu" }, - { "Bobject", "transform(\"object\", dPdv)" }, - { "Bworld", "dPdv" }, - { "UV0", "{u,v}" }, - { "Vworld", "I" } -}; - -} // anonymous namespace - void OslShaderGenerator::emitShaderInputs(const VariableBlock& inputs, ShaderStage& stage) const { - 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())) } - }; - - const std::set METADATA_TYPE_BLACKLIST = + static const std::unordered_map GEOMPROP_DEFINITIONS = { - Type::VECTOR2, // Custom struct types doesn't support metadata declarations. - Type::VECTOR4, // - Type::COLOR4, // - Type::FILENAME, // - Type::BSDF // + { "Pobject", "transform(\"object\", P)" }, + { "Pworld", "P" }, + { "Nobject", "transform(\"object\", N)" }, + { "Nworld", "N" }, + { "Tobject", "transform(\"object\", dPdu)" }, + { "Tworld", "dPdu" }, + { "Bobject", "transform(\"object\", dPdv)" }, + { "Bworld", "dPdv" }, + { "UV0", "{u,v}" }, + { "Vworld", "I" } }; for (size_t i = 0; i < inputs.size(); ++i) { const ShaderPort* input = inputs[i]; - const string& type = _syntax->getTypeName(input->getType()); - string value = _syntax->getValue(input, true); - - emitLineBegin(stage); - emitString(type + " " + input->getVariable(), stage); - const string& geomprop = input->getGeomProp(); - if (!geomprop.empty()) + if (input->getType() == Type::FILENAME) { - auto it = GEOMPROP_DEFINITIONS.find(geomprop); - if (it != GEOMPROP_DEFINITIONS.end()) - { - value = it->second; - } + // Shader inputs of type 'filename' (textures) need special handling. + // In OSL codegen a 'filename' is translated to the custom type 'textureresource', + // which is a struct containing a file string and a colorspace string. + // For the published shader interface we here split this into two separate inputs, + // which gives a nicer shader interface with widget metadata on each input. + + ValuePtr value = input->getValue(); + const string valueStr = value ? value->getValueString() : EMPTY_STRING; + + // Add the file string input + emitLineBegin(stage); + emitString("string " + input->getVariable() + " = \"" + valueStr + "\"", stage); + emitMetadata(input, stage); + emitString(",", stage); + emitLineEnd(stage, false); + + // Add the colorspace string input + emitLineBegin(stage); + emitString("string " + input->getVariable() + "_colorspace = \"" + input->getColorSpace() + "\"", stage); + emitLineEnd(stage, false); + emitScopeBegin(stage, Syntax::DOUBLE_SQUARE_BRACKETS); + emitLine("string widget = \"colorspace\"", stage, false); + emitScopeEnd(stage, false, false); } - - if (value.empty()) + else { - value = _syntax->getDefaultValue(input->getType()); - } - emitString(" = " + value, stage); - - // - // Add shader input metadata. - // - - auto widgetMetadataIt = UI_WIDGET_METADATA.find(input->getType()); - const ShaderMetadata* widgetMetadata = widgetMetadataIt != UI_WIDGET_METADATA.end() ? &widgetMetadataIt->second : nullptr; - const ShaderMetadataVecPtr& metadata = input->getMetadata(); + emitLineBegin(stage); + emitString(type + " " + input->getVariable(), stage); - if (widgetMetadata || (metadata && metadata->size())) - { - StringVec metadataLines; - if (metadata) + string value = _syntax->getValue(input, true); + const string& geomprop = input->getGeomProp(); + if (!geomprop.empty()) { - for (size_t j = 0; j < metadata->size(); ++j) + auto it = GEOMPROP_DEFINITIONS.find(geomprop); + if (it != GEOMPROP_DEFINITIONS.end()) { - const ShaderMetadata& data = metadata->at(j); - if (METADATA_TYPE_BLACKLIST.count(data.type) == 0) - { - const string& delim = (widgetMetadata || j < metadata->size() - 1) ? Syntax::COMMA : EMPTY_STRING; - const string& dataType = _syntax->getTypeName(data.type); - const string dataValue = _syntax->getValue(data.type, *data.value, true); - metadataLines.push_back(dataType + " " + data.name + " = " + dataValue + delim); - } + value = it->second; } } - if (widgetMetadata) + if (value.empty()) { - const string& dataType = _syntax->getTypeName(widgetMetadata->type); - const string dataValue = _syntax->getValue(widgetMetadata->type, *widgetMetadata->value, true); - metadataLines.push_back(dataType + " " + widgetMetadata->name + " = " + dataValue); - } - if (metadataLines.size()) - { - emitLineEnd(stage, false); - emitScopeBegin(stage, Syntax::DOUBLE_SQUARE_BRACKETS); - for (auto line : metadataLines) - { - emitLine(line, stage, false); - } - emitScopeEnd(stage, false, false); + value = _syntax->getDefaultValue(input->getType()); } + + emitString(" = " + value, stage); + emitMetadata(input, stage); } if (i < inputs.size()) @@ -618,6 +601,65 @@ void OslShaderGenerator::emitShaderOutputs(const VariableBlock& outputs, ShaderS } } +void OslShaderGenerator::emitMetadata(const ShaderPort* port, ShaderStage& stage) const +{ + 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())) } + }; + + static const std::set METADATA_TYPE_BLACKLIST = + { + Type::VECTOR2, // Custom struct types doesn't support metadata declarations. + Type::VECTOR4, // + Type::COLOR4, // + Type::FILENAME, // + Type::BSDF // + }; + + auto widgetMetadataIt = UI_WIDGET_METADATA.find(port->getType()); + const ShaderMetadata* widgetMetadata = widgetMetadataIt != UI_WIDGET_METADATA.end() ? &widgetMetadataIt->second : nullptr; + const ShaderMetadataVecPtr& metadata = port->getMetadata(); + + if (widgetMetadata || (metadata && metadata->size())) + { + StringVec metadataLines; + if (metadata) + { + for (size_t j = 0; j < metadata->size(); ++j) + { + const ShaderMetadata& data = metadata->at(j); + if (METADATA_TYPE_BLACKLIST.count(data.type) == 0) + { + const string& delim = (widgetMetadata || j < metadata->size() - 1) ? Syntax::COMMA : EMPTY_STRING; + const string& dataType = _syntax->getTypeName(data.type); + const string dataValue = _syntax->getValue(data.type, *data.value, true); + metadataLines.push_back(dataType + " " + data.name + " = " + dataValue + delim); + } + } + } + if (widgetMetadata) + { + const string& dataType = _syntax->getTypeName(widgetMetadata->type); + const string dataValue = _syntax->getValue(widgetMetadata->type, *widgetMetadata->value, true); + metadataLines.push_back(dataType + " " + widgetMetadata->name + " = " + dataValue); + } + if (metadataLines.size()) + { + emitLineEnd(stage, false); + emitScopeBegin(stage, Syntax::DOUBLE_SQUARE_BRACKETS); + for (auto line : metadataLines) + { + emitLine(line, stage, false); + } + emitScopeEnd(stage, false, false); + } + } +} + namespace OSL { diff --git a/source/MaterialXGenOsl/OslShaderGenerator.h b/source/MaterialXGenOsl/OslShaderGenerator.h index 0c7ca426d7..e5cf13977e 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.h +++ b/source/MaterialXGenOsl/OslShaderGenerator.h @@ -59,6 +59,9 @@ class MX_GENOSL_API OslShaderGenerator : public ShaderGenerator /// Emit a block of shader outputs. virtual void emitShaderOutputs(const VariableBlock& inputs, ShaderStage& stage) const; + + /// Emit metadata for a shader parameter. + virtual void emitMetadata(const ShaderPort* port, ShaderStage& stage) const; }; namespace OSL From 54adaeefcb2864632e2e7a38e842e8cd6658ea54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ars=C3=A8ne=20P=C3=A9rard-Gayot?= Date: Fri, 13 Oct 2023 21:47:47 +0200 Subject: [PATCH 14/22] Fix edge case in HW shader generation for texcoords (#1559) This merges both TexCoordNodeMsl and TexCoordNodeGlsl into a single HwTexCoordNode. The parts of the node that are configurable (e.g. the input index) can be changed via re-implementation of the virtual member function getIndexInput(). The new mechanism works regardless of syntax, and uses the smallest texcoord width, depending on what is used in the shader graph. --- .../TestSuite/stdlib/texture/texcoord.mtlx | 25 ++++++ .../MaterialXGenGlsl/GlslShaderGenerator.cpp | 6 +- source/MaterialXGenGlsl/GlslShaderGenerator.h | 2 +- .../Nodes/TexCoordNodeGlsl.cpp | 62 -------------- source/MaterialXGenMsl/MslShaderGenerator.cpp | 6 +- source/MaterialXGenMsl/MslShaderGenerator.h | 2 +- .../MaterialXGenMsl/Nodes/TexCoordNodeMsl.cpp | 62 -------------- .../MaterialXGenMsl/Nodes/TexCoordNodeMsl.h | 26 ------ source/MaterialXGenShader/HwShaderGenerator.h | 3 + .../Nodes/HwTexCoordNode.cpp | 83 +++++++++++++++++++ .../Nodes/HwTexCoordNode.h} | 15 ++-- source/MaterialXGenShader/ShaderStage.cpp | 17 +++- source/MaterialXGenShader/ShaderStage.h | 26 ++++-- 13 files changed, 163 insertions(+), 172 deletions(-) create mode 100644 resources/Materials/TestSuite/stdlib/texture/texcoord.mtlx delete mode 100644 source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.cpp delete mode 100644 source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.cpp delete mode 100644 source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.h create mode 100644 source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp rename source/{MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.h => MaterialXGenShader/Nodes/HwTexCoordNode.h} (55%) diff --git a/resources/Materials/TestSuite/stdlib/texture/texcoord.mtlx b/resources/Materials/TestSuite/stdlib/texture/texcoord.mtlx new file mode 100644 index 0000000000..4fbf6d12d9 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/texture/texcoord.mtlx @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp index 839f591aa5..87582c8f50 100644 --- a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp +++ b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -34,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -174,8 +174,8 @@ GlslShaderGenerator::GlslShaderGenerator() : // registerImplementation("IM_bitangent_vector3_" + GlslShaderGenerator::TARGET, BitangentNodeGlsl::create); // - registerImplementation("IM_texcoord_vector2_" + GlslShaderGenerator::TARGET, TexCoordNodeGlsl::create); - registerImplementation("IM_texcoord_vector3_" + GlslShaderGenerator::TARGET, TexCoordNodeGlsl::create); + registerImplementation("IM_texcoord_vector2_" + GlslShaderGenerator::TARGET, HwTexCoordNode::create); + registerImplementation("IM_texcoord_vector3_" + GlslShaderGenerator::TARGET, HwTexCoordNode::create); // registerImplementation("IM_geomcolor_float_" + GlslShaderGenerator::TARGET, GeomColorNodeGlsl::create); registerImplementation("IM_geomcolor_color3_" + GlslShaderGenerator::TARGET, GeomColorNodeGlsl::create); diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.h b/source/MaterialXGenGlsl/GlslShaderGenerator.h index 1df2ace543..4464f5d47c 100644 --- a/source/MaterialXGenGlsl/GlslShaderGenerator.h +++ b/source/MaterialXGenGlsl/GlslShaderGenerator.h @@ -45,7 +45,7 @@ class MX_GENGLSL_API GlslShaderGenerator : public HwShaderGenerator ShaderNodeImplPtr getImplementation(const NodeDef& nodedef, GenContext& context) const override; /// Determine the prefix of vertex data variables. - virtual string getVertexDataPrefix(const VariableBlock& vertexData) const; + string getVertexDataPrefix(const VariableBlock& vertexData) const override; public: /// Unique identifier for this generator target diff --git a/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.cpp deleted file mode 100644 index 846c77f5b7..0000000000 --- a/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#include - -#include - -MATERIALX_NAMESPACE_BEGIN - -ShaderNodeImplPtr TexCoordNodeGlsl::create() -{ - return std::make_shared(); -} - -void TexCoordNodeGlsl::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const -{ - const ShaderOutput* output = node.getOutput(); - const ShaderInput* indexInput = node.getInput(INDEX); - const string index = indexInput ? indexInput->getValue()->getValueString() : "0"; - - ShaderStage& vs = shader.getStage(Stage::VERTEX); - ShaderStage& ps = shader.getStage(Stage::PIXEL); - - addStageInput(HW::VERTEX_INPUTS, output->getType(), HW::T_IN_TEXCOORD + "_" + index, vs); - addStageConnector(HW::VERTEX_DATA, output->getType(), HW::T_TEXCOORD + "_" + index, vs, ps); -} - -void TexCoordNodeGlsl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const -{ - const GlslShaderGenerator& shadergen = static_cast(context.getShaderGenerator()); - - const ShaderInput* indexInput = node.getInput(INDEX); - const string index = indexInput ? indexInput->getValue()->getValueString() : "0"; - const string variable = HW::T_TEXCOORD + "_" + index; - - DEFINE_SHADER_STAGE(stage, Stage::VERTEX) - { - VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA); - const string prefix = shadergen.getVertexDataPrefix(vertexData); - ShaderPort* texcoord = vertexData[variable]; - if (!texcoord->isEmitted()) - { - shadergen.emitLine(prefix + texcoord->getVariable() + " = " + HW::T_IN_TEXCOORD + "_" + index, stage); - texcoord->setEmitted(); - } - } - - DEFINE_SHADER_STAGE(stage, Stage::PIXEL) - { - VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA); - const string prefix = shadergen.getVertexDataPrefix(vertexData); - ShaderPort* texcoord = vertexData[variable]; - shadergen.emitLineBegin(stage); - shadergen.emitOutput(node.getOutput(), true, false, context, stage); - shadergen.emitString(" = " + prefix + texcoord->getVariable(), stage); - shadergen.emitLineEnd(stage); - } -} - -MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index 0d97e8408f..1d93104ce8 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -34,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -178,8 +178,8 @@ MslShaderGenerator::MslShaderGenerator() : // registerImplementation("IM_bitangent_vector3_" + MslShaderGenerator::TARGET, BitangentNodeMsl::create); // - registerImplementation("IM_texcoord_vector2_" + MslShaderGenerator::TARGET, TexCoordNodeMsl::create); - registerImplementation("IM_texcoord_vector3_" + MslShaderGenerator::TARGET, TexCoordNodeMsl::create); + registerImplementation("IM_texcoord_vector2_" + MslShaderGenerator::TARGET, HwTexCoordNode::create); + registerImplementation("IM_texcoord_vector3_" + MslShaderGenerator::TARGET, HwTexCoordNode::create); // registerImplementation("IM_geomcolor_float_" + MslShaderGenerator::TARGET, GeomColorNodeMsl::create); registerImplementation("IM_geomcolor_color3_" + MslShaderGenerator::TARGET, GeomColorNodeMsl::create); diff --git a/source/MaterialXGenMsl/MslShaderGenerator.h b/source/MaterialXGenMsl/MslShaderGenerator.h index ecbf37d7a6..631c38f33d 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.h +++ b/source/MaterialXGenMsl/MslShaderGenerator.h @@ -48,7 +48,7 @@ class MX_GENMSL_API MslShaderGenerator : public HwShaderGenerator ShaderNodeImplPtr getImplementation(const NodeDef& nodedef, GenContext& context) const override; /// Determine the prefix of vertex data variables. - virtual string getVertexDataPrefix(const VariableBlock& vertexData) const; + string getVertexDataPrefix(const VariableBlock& vertexData) const override; public: /// Unique identifier for this generator target diff --git a/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.cpp deleted file mode 100644 index a88152eb82..0000000000 --- a/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#include - -#include - -MATERIALX_NAMESPACE_BEGIN - -ShaderNodeImplPtr TexCoordNodeMsl::create() -{ - return std::make_shared(); -} - -void TexCoordNodeMsl::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const -{ - const ShaderOutput* output = node.getOutput(); - const ShaderInput* indexInput = node.getInput(INDEX); - const string index = indexInput ? indexInput->getValue()->getValueString() : "0"; - - ShaderStage& vs = shader.getStage(Stage::VERTEX); - ShaderStage& ps = shader.getStage(Stage::PIXEL); - - addStageInput(HW::VERTEX_INPUTS, output->getType(), HW::T_IN_TEXCOORD + "_" + index, vs); - addStageConnector(HW::VERTEX_DATA, output->getType(), HW::T_TEXCOORD + "_" + index, vs, ps); -} - -void TexCoordNodeMsl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const -{ - const MslShaderGenerator& shadergen = static_cast(context.getShaderGenerator()); - - const ShaderInput* indexInput = node.getInput(INDEX); - const string index = indexInput ? indexInput->getValue()->getValueString() : "0"; - const string variable = HW::T_TEXCOORD + "_" + index; - - DEFINE_SHADER_STAGE(stage, Stage::VERTEX) - { - VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA); - const string prefix = shadergen.getVertexDataPrefix(vertexData); - ShaderPort* texcoord = vertexData[variable]; - if (!texcoord->isEmitted()) - { - shadergen.emitLine(prefix + texcoord->getVariable() + " = " + HW::T_IN_TEXCOORD + "_" + index, stage); - texcoord->setEmitted(); - } - } - - DEFINE_SHADER_STAGE(stage, Stage::PIXEL) - { - VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA); - const string prefix = shadergen.getVertexDataPrefix(vertexData); - ShaderPort* texcoord = vertexData[variable]; - shadergen.emitLineBegin(stage); - shadergen.emitOutput(node.getOutput(), true, false, context, stage); - shadergen.emitString(" = " + prefix + texcoord->getVariable(), stage); - shadergen.emitLineEnd(stage); - } -} - -MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.h b/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.h deleted file mode 100644 index 6c227cc63b..0000000000 --- a/source/MaterialXGenMsl/Nodes/TexCoordNodeMsl.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef MATERIALX_TEXCOORDNODEMSL_H -#define MATERIALX_TEXCOORDNODEMSL_H - -#include - -MATERIALX_NAMESPACE_BEGIN - -/// TexCoord node implementation for MSL -class MX_GENMSL_API TexCoordNodeMsl : public MslImplementation -{ - public: - static ShaderNodeImplPtr create(); - - void createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const override; - - void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; -}; - -MATERIALX_NAMESPACE_END - -#endif diff --git a/source/MaterialXGenShader/HwShaderGenerator.h b/source/MaterialXGenShader/HwShaderGenerator.h index 66d60dc68a..bba572c631 100644 --- a/source/MaterialXGenShader/HwShaderGenerator.h +++ b/source/MaterialXGenShader/HwShaderGenerator.h @@ -306,6 +306,9 @@ class MX_GENSHADER_API HwShaderGenerator : public ShaderGenerator /// Unbind all light shaders previously bound. static void unbindLightShaders(GenContext& context); + /// Determine the prefix of vertex data variables. + virtual string getVertexDataPrefix(const VariableBlock& vertexData) const = 0; + /// Types of closure contexts for HW. enum ClosureContextType { diff --git a/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp b/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp new file mode 100644 index 0000000000..3aa84400df --- /dev/null +++ b/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp @@ -0,0 +1,83 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include + +MATERIALX_NAMESPACE_BEGIN + +string HwTexCoordNode::INDEX = "index"; + +ShaderNodeImplPtr HwTexCoordNode::create() +{ + return std::make_shared(); +} + +void HwTexCoordNode::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const +{ + const ShaderOutput* output = node.getOutput(); + const string index = getIndex(node); + + ShaderStage& vs = shader.getStage(Stage::VERTEX); + ShaderStage& ps = shader.getStage(Stage::PIXEL); + + addStageInput(HW::VERTEX_INPUTS, output->getType(), HW::T_IN_TEXCOORD + "_" + index, vs, true); + addStageConnector(HW::VERTEX_DATA, output->getType(), HW::T_TEXCOORD + "_" + index, vs, ps, true); +} + +void HwTexCoordNode::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const +{ + const HwShaderGenerator& shadergen = static_cast(context.getShaderGenerator()); + + const string index = getIndex(node); + const string variable = HW::T_TEXCOORD + "_" + index; + const ShaderOutput* output = node.getOutput(); + + DEFINE_SHADER_STAGE(stage, Stage::VERTEX) + { + VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA); + const string prefix = shadergen.getVertexDataPrefix(vertexData); + ShaderPort* texcoord = vertexData[variable]; + if (!texcoord->isEmitted()) + { + shadergen.emitLine(prefix + texcoord->getVariable() + " = " + HW::T_IN_TEXCOORD + "_" + index, stage); + texcoord->setEmitted(); + } + } + + DEFINE_SHADER_STAGE(stage, Stage::PIXEL) + { + VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA); + const string prefix = shadergen.getVertexDataPrefix(vertexData); + ShaderPort* texcoord = vertexData[variable]; + shadergen.emitLineBegin(stage); + shadergen.emitOutput(output, true, false, context, stage); + + // Extract the requested number of components from the texture coordinates (which may be a + // larger datatype than the requested number of texture coordinates, if several texture + // coordinate nodes with different width coexist). + string suffix = EMPTY_STRING; + if (output->getType() == Type::VECTOR2) + { + suffix = ".xy"; + } + else if (output->getType() == Type::VECTOR3) + { + suffix = ".xyz"; + } + + shadergen.emitString(" = " + prefix + texcoord->getVariable() + suffix, stage); + shadergen.emitLineEnd(stage); + } +} + +string HwTexCoordNode::getIndex(const ShaderNode& node) const +{ + const ShaderInput* input = node.getInput(INDEX); + return input ? input->getValue()->getValueString() : "0"; +} + +MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.h b/source/MaterialXGenShader/Nodes/HwTexCoordNode.h similarity index 55% rename from source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.h rename to source/MaterialXGenShader/Nodes/HwTexCoordNode.h index c15a86fd9c..9aae3d18ce 100644 --- a/source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.h +++ b/source/MaterialXGenShader/Nodes/HwTexCoordNode.h @@ -3,15 +3,15 @@ // SPDX-License-Identifier: Apache-2.0 // -#ifndef MATERIALX_TEXCOORDNODEGLSL_H -#define MATERIALX_TEXCOORDNODEGLSL_H +#ifndef MATERIALX_HWTEXCOORDNODE_H +#define MATERIALX_HWTEXCOORDNODE_H -#include +#include MATERIALX_NAMESPACE_BEGIN -/// TexCoord node implementation for GLSL -class MX_GENGLSL_API TexCoordNodeGlsl : public GlslImplementation +/// Generic texture coordinate node for hardware languages +class MX_GENSHADER_API HwTexCoordNode : public ShaderNodeImpl { public: static ShaderNodeImplPtr create(); @@ -19,6 +19,11 @@ class MX_GENGLSL_API TexCoordNodeGlsl : public GlslImplementation void createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const override; void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; + + protected: + virtual string getIndex(const ShaderNode& node) const; + + static string INDEX; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/ShaderStage.cpp b/source/MaterialXGenShader/ShaderStage.cpp index 822f3c9664..b5387bcb94 100644 --- a/source/MaterialXGenShader/ShaderStage.cpp +++ b/source/MaterialXGenShader/ShaderStage.cpp @@ -65,11 +65,26 @@ ShaderPort* VariableBlock::find(const ShaderPortPredicate& predicate) return nullptr; } -ShaderPort* VariableBlock::add(const TypeDesc* type, const string& name, ValuePtr value) +ShaderPort* VariableBlock::add(const TypeDesc* type, const string& name, ValuePtr value, bool shouldWiden) { auto it = _variableMap.find(name); if (it != _variableMap.end()) { + if (shouldWiden) + { + // Automatically try to widen the type of the shader port if the requested type differs from + // the existing port's type. + if (it->second->getType()->getSize() < type->getSize()) + { + it->second->setType(type); + } + } + else if (type != it->second->getType()) + { + throw ExceptionShaderGenError("Trying to add shader port '" + name + "' with type '" + + type->getName() + "', but existing shader port with type '" + + it->second->getType()->getName() + "' was found"); + } return it->second.get(); } diff --git a/source/MaterialXGenShader/ShaderStage.h b/source/MaterialXGenShader/ShaderStage.h index 71004f8e52..a6a5cec0b8 100644 --- a/source/MaterialXGenShader/ShaderStage.h +++ b/source/MaterialXGenShader/ShaderStage.h @@ -113,7 +113,14 @@ class MX_GENSHADER_API VariableBlock ShaderPort* find(const ShaderPortPredicate& predicate); /// Add a new shader port to this block. - ShaderPort* add(const TypeDesc* type, const string& name, ValuePtr value = nullptr); + /// @param type The desired shader port type + /// @param name The shader port name + /// @param value The value to attach to the shader port + /// @param shouldWiden When false, an exception is thrown if the type of the existing port with + /// the same name does not match the requested type. When true, the types can mismatch, and the + /// type of any existing port is widened to match the requested type when necessary. + /// @return A new shader port, or a pre-existing shader port with the same name. + ShaderPort* add(const TypeDesc* type, const string& name, ValuePtr value = nullptr, bool shouldWiden = false); /// Add an existing shader port to this block. void add(ShaderPortPtr port); @@ -339,20 +346,22 @@ inline ShaderPort* addStageUniform(const string& block, inline ShaderPort* addStageInput(const string& block, const TypeDesc* type, const string& name, - ShaderStage& stage) + ShaderStage& stage, + bool shouldWiden = false) { VariableBlock& inputs = stage.getInputBlock(block); - return inputs.add(type, name); + return inputs.add(type, name, {}, shouldWiden); } /// Utility function for adding a new shader port to an output block. inline ShaderPort* addStageOutput(const string& block, const TypeDesc* type, const string& name, - ShaderStage& stage) + ShaderStage& stage, + bool shouldWiden = false) { VariableBlock& outputs = stage.getOutputBlock(block); - return outputs.add(type, name); + return outputs.add(type, name, {}, shouldWiden); } /// Utility function for adding a connector block between stages. @@ -370,10 +379,11 @@ inline void addStageConnector(const string& block, const TypeDesc* type, const string& name, ShaderStage& from, - ShaderStage& to) + ShaderStage& to, + bool shouldWiden = false) { - addStageOutput(block, type, name, from); - addStageInput(block, type, name, to); + addStageOutput(block, type, name, from, shouldWiden); + addStageInput(block, type, name, to, shouldWiden); } MATERIALX_NAMESPACE_END From eb52ec28e09fc86e00b6e7120f5676d37db6e8b8 Mon Sep 17 00:00:00 2001 From: Erika Harrison Date: Fri, 13 Oct 2023 17:26:19 -0600 Subject: [PATCH 15/22] Update link connections by dragging between ports (#1569) Currently, one must explicitly delete an existing link before adding a new link for a given node. This change enables dragging to update a link connection, and automatically deletes the existing link on the input pin if one exists. Note: An output pin on a node may have many outgoing links, but an input pin may only have one incoming link. This behaviour is unchanged. Also: - Renames a few variables for consistency on start/end and input/output pins - Ensures you can't add a link from an input to an input, or from an output to an output - Can also drag from an output to an input and have it correctly delete existing link --- source/MaterialXGraphEditor/Graph.cpp | 307 ++++++++++++++------------ source/MaterialXGraphEditor/Graph.h | 4 +- 2 files changed, 171 insertions(+), 140 deletions(-) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 2b28317ee2..522280cb08 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -846,7 +846,7 @@ void Graph::setRenderMaterial(UiNodePtr node) } } -void Graph::updateMaterials(mx::InputPtr input, mx::ValuePtr value) +void Graph::updateMaterials(mx::InputPtr input /* = nullptr */, mx::ValuePtr value /* = nullptr */) { std::string renderablePath; if (_currRenderNode) @@ -2483,12 +2483,22 @@ void Graph::setDefaults(mx::InputPtr input) } } -void Graph::addLink(ed::PinId inputPinId, ed::PinId outputPinId) +void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) { - int end_attr = int(outputPinId.Get()); - int start_attr = int(inputPinId.Get()); - UiPinPtr inputPin = getPin(outputPinId); - UiPinPtr outputPin = getPin(inputPinId); + // prefer to assume left to right - start is an output, end is an input; swap if inaccurate + if (UiPinPtr inputPin = getPin(endPinId); inputPin && inputPin->_kind != ed::PinKind::Input) + { + auto tmp = startPinId; + startPinId = endPinId; + endPinId = tmp; + } + + int end_attr = int(endPinId.Get()); + int start_attr = int(startPinId.Get()); + ed::PinId outputPinId = startPinId; + ed::PinId inputPinId = endPinId; + UiPinPtr outputPin = getPin(outputPinId); + UiPinPtr inputPin = getPin(inputPinId); if (!inputPin || !outputPin) { @@ -2505,187 +2515,206 @@ void Graph::addLink(ed::PinId inputPinId, ed::PinId outputPinId) return; } - if (inputPin->_connected == false) + // Perform kind check + bool kindsMatch = (outputPin->_kind == inputPin->_kind); + if (kindsMatch) { - int upNode = getNodeId(inputPinId); - int downNode = getNodeId(outputPinId); - UiNodePtr uiDownNode = _graphNodes[downNode]; - UiNodePtr uiUpNode = _graphNodes[upNode]; - if (!uiDownNode || !uiUpNode) - { - ed::RejectNewItem(); - return; - } + ed::RejectNewItem(); + showLabel("Invalid connection due to same input/output kind", ImColor(50, 50, 50, 255)); + return; + } - // make sure there is an implementation for node - const mx::ShaderGenerator& shadergen = _renderer->getGenContext().getShaderGenerator(); + int upNode = getNodeId(outputPinId); + int downNode = getNodeId(inputPinId); + UiNodePtr uiDownNode = _graphNodes[downNode]; + UiNodePtr uiUpNode = _graphNodes[upNode]; + if (!uiDownNode || !uiUpNode) + { + ed::RejectNewItem(); + return; + } - // Prevent direct connecting from input to output - if (uiDownNode->getInput() && uiUpNode->getOutput()) - { - ed::RejectNewItem(); - showLabel("Direct connections between inputs and outputs is invalid", ImColor(50, 50, 50, 255)); - return; - } + // make sure there is an implementation for node + const mx::ShaderGenerator& shadergen = _renderer->getGenContext().getShaderGenerator(); - // Find the implementation for this nodedef if not an input or output uinode - if (uiDownNode->getInput() && _isNodeGraph) + // Prevent direct connecting from input to output + if (uiDownNode->getInput() && uiUpNode->getOutput()) + { + ed::RejectNewItem(); + showLabel("Direct connections between inputs and outputs is invalid", ImColor(50, 50, 50, 255)); + return; + } + + // Find the implementation for this nodedef if not an input or output uinode + if (uiDownNode->getInput() && _isNodeGraph) + { + ed::RejectNewItem(); + showLabel("Cannot connect to inputs inside of graph", ImColor(50, 50, 50, 255)); + return; + } + else if (uiUpNode->getNode()) + { + mx::ShaderNodeImplPtr impl = shadergen.getImplementation(*_graphNodes[upNode]->getNode()->getNodeDef(), _renderer->getGenContext()); + if (!impl) { ed::RejectNewItem(); - showLabel("Cannot connect to inputs inside of graph", ImColor(50, 50, 50, 255)); + showLabel("Invalid Connection: Node does not have an implementation", ImColor(50, 50, 50, 255)); return; } - else if (uiUpNode->getNode()) + } + + if (ed::AcceptNewItem()) + { + // If the accepting node already has a link, remove it + if (inputPin->_connected) { - mx::ShaderNodeImplPtr impl = shadergen.getImplementation(*_graphNodes[upNode]->getNode()->getNodeDef(), _renderer->getGenContext()); - if (!impl) + for (auto linksItr = _currLinks.begin(); linksItr != _currLinks.end(); linksItr++) { - ed::RejectNewItem(); - showLabel("Invalid Connection: Node does not have an implementation", ImColor(50, 50, 50, 255)); - return; + if (linksItr->_endAttr == end_attr) + { + // found existing link - remove it; adapted from deleteLink + // note: ed::BreakLinks doesn't work as the order ends up inaccurate + deleteLinkInfo(linksItr->_startAttr, linksItr->_endAttr); + _currLinks.erase(linksItr); + break; + } } + } - if (ed::AcceptNewItem()) - { - // Since we accepted new link, lets add one to our list of links. - Link link; - link._startAttr = start_attr; - link._endAttr = end_attr; - _currLinks.push_back(link); - _frameCount = ImGui::GetFrameCount(); - _renderer->setMaterialCompilation(true); + // Since we accepted new link, lets add one to our list of links. + Link link; + link._startAttr = start_attr; + link._endAttr = end_attr; + _currLinks.push_back(link); + _frameCount = ImGui::GetFrameCount(); + _renderer->setMaterialCompilation(true); - if (uiDownNode->getNode() || uiDownNode->getNodeGraph()) + if (uiDownNode->getNode() || uiDownNode->getNodeGraph()) + { + mx::InputPtr connectingInput = nullptr; + for (UiPinPtr pin : uiDownNode->inputPins) { - mx::InputPtr connectingInput = nullptr; - for (UiPinPtr pin : uiDownNode->inputPins) + if (pin->_pinId == inputPinId) { - if (pin->_pinId == outputPinId) + addNodeInput(uiDownNode, pin->_input); + // update value to be empty + if (uiDownNode->getNode() && uiDownNode->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING) { - addNodeInput(uiDownNode, pin->_input); - // update value to be empty - if (uiDownNode->getNode() && uiDownNode->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING) + if (uiUpNode->getOutput() != nullptr) { - if (uiUpNode->getOutput() != nullptr) - { - pin->_input->setConnectedOutput(uiUpNode->getOutput()); - } - else if (uiUpNode->getInput() != nullptr) - { - pin->_input->setInterfaceName(uiUpNode->getName()); - } - else + pin->_input->setConnectedOutput(uiUpNode->getOutput()); + } + else if (uiUpNode->getInput() != nullptr) + { + pin->_input->setInterfaceName(uiUpNode->getName()); + } + else + { + // node graph + if (uiUpNode->getNodeGraph() != nullptr) { - // node graph - if (uiUpNode->getNodeGraph() != nullptr) + for (UiPinPtr outPin : uiUpNode->outputPins) { - for (UiPinPtr outPin : uiUpNode->outputPins) + // set pin connection to correct output + if (outPin->_pinId == outputPinId) { - // set pin connection to correct output - if (outPin->_pinId == inputPinId) - { - mx::OutputPtr outputs = uiUpNode->getNodeGraph()->getOutput(outPin->_name); - pin->_input->setConnectedOutput(outputs); - } + mx::OutputPtr outputs = uiUpNode->getNodeGraph()->getOutput(outPin->_name); + pin->_input->setConnectedOutput(outputs); } } - else - { - pin->_input->setConnectedNode(uiUpNode->getNode()); - } } + else + { + pin->_input->setConnectedNode(uiUpNode->getNode()); + } + } + } + else + { + if (uiUpNode->getInput()) + { + pin->_input->setInterfaceName(uiUpNode->getName()); } else { - if (uiUpNode->getInput()) - { - pin->_input->setInterfaceName(uiUpNode->getName()); - } - else + if (uiUpNode->getNode()) { - if (uiUpNode->getNode()) + mx::NodePtr upstreamNode = _graphNodes[upNode]->getNode(); + mx::NodeDefPtr upstreamNodeDef = upstreamNode->getNodeDef(); + bool isMultiOutput = upstreamNodeDef ? upstreamNodeDef->getOutputs().size() > 1 : false; + + // This is purely to avoid adding a reference to an update node only 1 output, + // as currently validation consides adding this an error. Otherwise + // it will add an "output" attribute all the time. + if (!isMultiOutput) { - mx::NodePtr upstreamNode = _graphNodes[upNode]->getNode(); - mx::NodeDefPtr upstreamNodeDef = upstreamNode->getNodeDef(); - bool isMultiOutput = upstreamNodeDef ? upstreamNodeDef->getOutputs().size() > 1 : false; - - // This is purely to avoid adding a reference to an update node only 1 output, - // as currently validation consides adding this an error. Otherwise - // it will add an "output" attribute all the time. - if (!isMultiOutput) - { - pin->_input->setConnectedNode(uiUpNode->getNode()); - } - else + pin->_input->setConnectedNode(uiUpNode->getNode()); + } + else + { + for (UiPinPtr outPin : _graphNodes[upNode]->outputPins) { - for (UiPinPtr outPin : _graphNodes[upNode]->outputPins) + // set pin connection to correct output + if (outPin->_pinId == outputPinId) { - // set pin connection to correct output - if (outPin->_pinId == inputPinId) + mx::OutputPtr outputs = uiUpNode->getNode()->getOutput(outPin->_name); + if (!outputs) { - mx::OutputPtr outputs = uiUpNode->getNode()->getOutput(outPin->_name); - if (!outputs) - { - outputs = uiUpNode->getNode()->addOutput(outPin->_name, pin->_input->getType()); - } - pin->_input->setConnectedOutput(outputs); + outputs = uiUpNode->getNode()->addOutput(outPin->_name, pin->_input->getType()); } + pin->_input->setConnectedOutput(outputs); } } } - else if (uiUpNode->getNodeGraph()) + } + else if (uiUpNode->getNodeGraph()) + { + for (UiPinPtr outPin : uiUpNode->outputPins) { - for (UiPinPtr outPin : uiUpNode->outputPins) + // set pin connection to correct output + if (outPin->_pinId == outputPinId) { - // set pin connection to correct output - if (outPin->_pinId == inputPinId) - { - mx::OutputPtr outputs = uiUpNode->getNodeGraph()->getOutput(outPin->_name); - pin->_input->setConnectedOutput(outputs); - } + mx::OutputPtr outputs = uiUpNode->getNodeGraph()->getOutput(outPin->_name); + pin->_input->setConnectedOutput(outputs); } } } } - - pin->setConnected(true); - pin->_input->removeAttribute(mx::ValueElement::VALUE_ATTRIBUTE); - connectingInput = pin->_input; - break; } + + pin->setConnected(true); + pin->_input->removeAttribute(mx::ValueElement::VALUE_ATTRIBUTE); + connectingInput = pin->_input; + break; } - // create new edge and set edge information - createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); } - else if (_graphNodes[downNode]->getOutput() != nullptr) - { - mx::InputPtr connectingInput = nullptr; - _graphNodes[downNode]->getOutput()->setConnectedNode(_graphNodes[upNode]->getNode()); + // create new edge and set edge information + createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); + } + else if (_graphNodes[downNode]->getOutput() != nullptr) + { + mx::InputPtr connectingInput = nullptr; + _graphNodes[downNode]->getOutput()->setConnectedNode(_graphNodes[upNode]->getNode()); - // create new edge and set edge information - createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); - } - else + // create new edge and set edge information + createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); + } + else + { + // create new edge and set edge info + UiEdge newEdge = UiEdge(_graphNodes[upNode], _graphNodes[downNode], nullptr); + if (!edgeExists(newEdge)) { - // create new edge and set edge info - UiEdge newEdge = UiEdge(_graphNodes[upNode], _graphNodes[downNode], nullptr); - if (!edgeExists(newEdge)) - { - _graphNodes[downNode]->edges.push_back(newEdge); - _currEdge.push_back(newEdge); + _graphNodes[downNode]->edges.push_back(newEdge); + _currEdge.push_back(newEdge); - // update input node num and output connections - _graphNodes[downNode]->setInputNodeNum(1); - _graphNodes[upNode]->setOutputConnection(_graphNodes[downNode]); - } + // update input node num and output connections + _graphNodes[downNode]->setInputNodeNum(1); + _graphNodes[upNode]->setOutputConnection(_graphNodes[downNode]); } } } - else - { - ed::RejectNewItem(); - } } void Graph::removeEdge(int downNode, int upNode, UiPinPtr pin) @@ -4045,12 +4074,12 @@ void Graph::drawGraph(ImVec2 mousePos) // Add new link if (ed::BeginCreate()) { - ed::PinId inputPinId, outputPinId, filterPinId; - if (ed::QueryNewLink(&inputPinId, &outputPinId)) + ed::PinId startPinId, endPinId, filterPinId; + if (ed::QueryNewLink(&startPinId, &endPinId)) { if (!readOnly()) { - addLink(inputPinId, outputPinId); + addLink(startPinId, endPinId); } else { diff --git a/source/MaterialXGraphEditor/Graph.h b/source/MaterialXGraphEditor/Graph.h index 8c76f0f68d..9b9857c69a 100644 --- a/source/MaterialXGraphEditor/Graph.h +++ b/source/MaterialXGraphEditor/Graph.h @@ -90,7 +90,9 @@ class Graph // Add link to nodegraph and set up connections between UiNodes and // MaterialX Nodes to update shader - void addLink(ed::PinId inputPinId, ed::PinId outputPinId); + // startPinId - where the link was initiated + // endPinId - where the link was ended + void addLink(ed::PinId startPinId, ed::PinId endPinId); // Delete link from current link vector and remove any connections in // UiNode or MaterialX Nodes to update shader From 044645345bd491250ff6041489b83b28640e54bb Mon Sep 17 00:00:00 2001 From: Andy <94316446+beersandrew@users.noreply.github.com> Date: Sat, 14 Oct 2023 22:56:53 +0300 Subject: [PATCH 16/22] Restructure Add Node List (#1562) Added a list of nodes to the best of my ability to be the order they should be displayed --- source/MaterialXGraphEditor/Graph.cpp | 166 ++++++++++++++------------ source/MaterialXGraphEditor/Graph.h | 27 ++++- 2 files changed, 112 insertions(+), 81 deletions(-) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 522280cb08..849b8607b4 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -236,9 +236,6 @@ void Graph::addExtraNodes() return; } - // Clear any old nodes, if we previously used tab with another graph doc - _extraNodes.clear(); - // Get all types from the doc std::vector types; std::vector typeDefs = _graphDoc->getTypeDefs(); @@ -252,18 +249,16 @@ void Graph::addExtraNodes() for (const std::string& type : types) { std::string nodeName = "ND_input_" + type; - _extraNodes["Input Nodes"].push_back({ nodeName, type, "input" }); + _nodesToAdd.emplace_back(nodeName, type, "input", "Input Nodes"); nodeName = "ND_output_" + type; - _extraNodes["Output Nodes"].push_back({ nodeName, type, "output" }); + _nodesToAdd.emplace_back(nodeName, type, "output", "Output Nodes"); } // Add group node - std::vector groupNode{ "ND_group", "", "group" }; - _extraNodes["Group Nodes"].push_back(groupNode); + _nodesToAdd.emplace_back("ND_group", "", "group", "Group Nodes"); // Add nodegraph node - std::vector nodeGraph{ "ND_nodegraph", "", "nodegraph" }; - _extraNodes["Node Graph"].push_back(nodeGraph); + _nodesToAdd.emplace_back("ND_nodegraph", "", "nodegraph", "Node Graph"); } ed::PinId Graph::getOutputPin(UiNodePtr node, UiNodePtr upNode, UiPinPtr input) @@ -1224,20 +1219,63 @@ void Graph::setUiNodeInfo(UiNodePtr node, const std::string& type, const std::st void Graph::createNodeUIList(mx::DocumentPtr doc) { _nodesToAdd.clear(); - const std::string EXTRA_GROUP_NAME = "extra"; - for (mx::NodeDefPtr nodeDef : doc->getNodeDefs()) + + std::vector ordered_groups = { + "texture2d", + "texture3d", + "procedural", + "procedural2d", + "procedural3d", + "geometric", + "translation", + "convolution2d", + "math", + "adjustment", + "compositing", + "conditional", + "channel", + "organization", + "global", + "application", + "material", + "shader", + "pbr", + "light", + "colortransform", + "no_group" + }; + + auto nodeDefs = doc->getNodeDefs(); + std::unordered_map> groupToNodeDef; + + for (const auto& nodeDef : nodeDefs) { - // NodeDef is the key for the map std::string group = nodeDef->getNodeGroup(); + if (group.empty()) { - group = EXTRA_GROUP_NAME; + group = "no_group"; } - if (_nodesToAdd.find(group) == _nodesToAdd.end()) + + if (groupToNodeDef.find(group) == groupToNodeDef.end()) { - _nodesToAdd[group] = std::vector(); + groupToNodeDef[group] = std::vector(); + } + groupToNodeDef[group].push_back(nodeDef); + } + + for (const auto& group : ordered_groups) + { + auto it = groupToNodeDef.find(group); + if (it != groupToNodeDef.end()) + { + const auto& groupNodeDefs = it->second; + + for (const auto& nodeDef : groupNodeDefs) + { + _nodesToAdd.emplace_back(nodeDef->getName(), nodeDef->getType(), nodeDef->getNodeString(), group); + } } - _nodesToAdd[group].push_back(nodeDef); } addExtraNodes(); @@ -3595,96 +3633,66 @@ void Graph::addNodePopup(bool cursor) // Input string length // Filter extra nodes - includes inputs, outputs, groups, and node graphs const std::string NODEGRAPH_ENTRY = "Node Graph"; - for (std::unordered_map>>::iterator it = _extraNodes.begin(); it != _extraNodes.end(); ++it) + + // Filter nodedefs and add to menu if matches filter + for (auto node : _nodesToAdd) { // Filter out list of nodes if (subs.size() > 0) { ImGui::SetNextWindowSizeConstraints(ImVec2(250.0f, 300.0f), ImVec2(-1.0f, 500.0f)); - for (size_t i = 0; i < it->second.size(); i++) - { - std::string str(it->second[i][0]); - std::string nodeName = it->second[i][0]; + std::string str(node.getName()); + std::string nodeName = node.getName(); - // Disallow creating nested nodegraphs - if (_isNodeGraph && it->first == NODEGRAPH_ENTRY) - { - continue; - } + // Disallow creating nested nodegraphs + if (_isNodeGraph && node.getGroup() == NODEGRAPH_ENTRY) + { + continue; + } - // Allow spaces to be used to search for node names - std::replace(subs.begin(), subs.end(), ' ', '_'); + // Allow spaces to be used to search for node names + std::replace(subs.begin(), subs.end(), ' ', '_'); - if (str.find(subs) != std::string::npos) + if (str.find(subs) != std::string::npos) + { + if (ImGui::MenuItem(getUserNodeDefName(nodeName).c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) { - if (ImGui::MenuItem(getUserNodeDefName(nodeName).c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) - { - addNode(it->second[i][2], getUserNodeDefName(nodeName), it->second[i][1]); - _addNewNode = true; - memset(input, '\0', sizeof(input)); - } + addNode(node.getCategory(), getUserNodeDefName(nodeName), node.getType()); + _addNewNode = true; + memset(input, '\0', sizeof(input)); } } } else { ImGui::SetNextWindowSizeConstraints(ImVec2(100, 10), ImVec2(-1, 300)); - if (ImGui::BeginMenu(it->first.c_str())) + if (ImGui::BeginMenu(node.getGroup().c_str())) { ImGui::SetWindowFontScale(_fontScale); - for (size_t j = 0; j < it->second.size(); j++) + std::string name = node.getName(); + std::string prefix = "ND_"; + if (name.compare(0, prefix.size(), prefix) == 0 && name.compare(prefix.size(), std::string::npos, node.getCategory()) == 0) { - std::string name = it->second[j][0]; if (ImGui::MenuItem(getUserNodeDefName(name).c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) { - addNode(it->second[j][2], getUserNodeDefName(name), it->second[j][1]); - _addNewNode = true; - } - } - ImGui::EndMenu(); - } - } - } - - // Filter nodedefs and add to menu if matches filter - for (std::unordered_map>::iterator it = _nodesToAdd.begin(); it != _nodesToAdd.end(); ++it) - { - // Filter out list of nodes - if (subs.size() > 0) - { - ImGui::SetNextWindowSizeConstraints(ImVec2(250.0f, 300.0f), ImVec2(-1.0f, 500.0f)); - for (size_t i = 0; i < it->second.size(); i++) - { - std::string str(it->second[i]->getName()); - std::string nodeName = it->second[i]->getName(); - if (str.find(subs) != std::string::npos) - { - std::string val = getUserNodeDefName(nodeName); - if (ImGui::MenuItem(val.c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) - { - addNode(it->second[i]->getNodeString(), val, it->second[i]->getType()); + addNode(node.getCategory(), getUserNodeDefName(name), node.getType()); _addNewNode = true; - memset(input, '\0', sizeof(input)); } } - } - } - else - { - ImGui::SetNextWindowSizeConstraints(ImVec2(100, 10), ImVec2(-1, 300)); - if (ImGui::BeginMenu(it->first.c_str())) - { - ImGui::SetWindowFontScale(_fontScale); - for (size_t i = 0; i < it->second.size(); i++) + else { - std::string name = it->second[i]->getName(); - std::string val = getUserNodeDefName(name); - if (ImGui::MenuItem(val.c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) + if (ImGui::BeginMenu(node.getCategory().c_str())) { - addNode(it->second[i]->getNodeString(), val, it->second[i]->getType()); - _addNewNode = true; + if (ImGui::MenuItem(getUserNodeDefName(name).c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) + { + addNode(node.getCategory(), getUserNodeDefName(name), node.getType()); + _addNewNode = true; + } + ImGui::EndMenu(); } } + + ImGui::EndMenu(); } } diff --git a/source/MaterialXGraphEditor/Graph.h b/source/MaterialXGraphEditor/Graph.h index 9b9857c69a..87d4119c2a 100644 --- a/source/MaterialXGraphEditor/Graph.h +++ b/source/MaterialXGraphEditor/Graph.h @@ -14,6 +14,30 @@ #include +class MenuItem +{ + public: + MenuItem(const std::string& name, const std::string& type, const std::string& category, const std::string& group) : + name(name), type(type), category(category), group(group) { } + + // getters + std::string getName() const { return name; } + std::string getType() const { return type; } + std::string getCategory() const { return category; } + std::string getGroup() const { return group; } + + // setters + void setName(const std::string& newName) { this->name = newName; } + void setType(const std::string& newType) { this->type = newType; } + void setCategory(const std::string& newCategory) { this->category = newCategory; } + void setGroup(const std::string& newGroup) { this->group = newGroup; } + + private: + std::string name; + std::string type; + std::string category; + std::string group; +}; namespace ed = ax::NodeEditor; namespace mx = MaterialX; @@ -248,8 +272,7 @@ class Graph std::vector _currGraphName; // for adding new nodes - std::unordered_map> _nodesToAdd; - std::unordered_map>> _extraNodes; + std::vector _nodesToAdd; // stacks to dive into and out of node graphs std::stack> _graphStack; From 74462510a32948341131b93d1695514cfc283927 Mon Sep 17 00:00:00 2001 From: iukpo-lucasfilm <145880411+iukpo-lucasfilm@users.noreply.github.com> Date: Sat, 14 Oct 2023 15:26:23 -0700 Subject: [PATCH 17/22] Stop Graph Editor from creating imgui.ini file (#1570) Added code to stop creation of imgui.ini after saving material after saving then closing Graph Editor --- source/MaterialXGraphEditor/Main.cpp | 51 ++++------------------------ 1 file changed, 7 insertions(+), 44 deletions(-) diff --git a/source/MaterialXGraphEditor/Main.cpp b/source/MaterialXGraphEditor/Main.cpp index 754d766798..5bbcbdad66 100644 --- a/source/MaterialXGraphEditor/Main.cpp +++ b/source/MaterialXGraphEditor/Main.cpp @@ -23,44 +23,6 @@ static void errorCallback(int error, const char* description) fprintf(stderr, "Glfw Error %d: %s\n", error, description); } -mx::FilePath getConfigPath() -{ - mx::FilePath configPath; - auto xdgConfigHome = mx::getEnviron("XDG_CONFIG_HOME"); - auto homeDirectory = mx::getEnviron("HOME"); - if (!xdgConfigHome.empty()) - { - configPath = mx::FilePath(xdgConfigHome); - } - else if (!homeDirectory.empty()) - { -#if defined(__APPLE__) - configPath = mx::FilePath(homeDirectory) / "Library" / "Preferences"; -#else - configPath = mx::FilePath(homeDirectory) / ".config"; - if (!configPath.exists()) - { - configPath.createDirectory(); - } -#endif - } - else - { - return {}; - } - - configPath = configPath / "MaterialX"; - configPath.createDirectory(); - - if (!configPath.exists()) - { - std::cerr << "Failed to create MaterialX config directory at " << configPath.asString() << std::endl; - return {}; - } - - return configPath / "GraphEditor.imgui.ini"; -} - const std::string options = " Options: \n" " --material [FILENAME] Specify the filename of the MTLX document to be displayed in the graph editor\n" @@ -197,13 +159,14 @@ int main(int argc, char* const argv[]) IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); - io.Fonts->AddFontDefault(); - mx::FilePath configPath = getConfigPath(); - if (!configPath.isEmpty()) - { - io.IniFilename = configPath.asString().c_str(); - } + // Set ini and log filename to NULL. This will prevent the automatic creation of imgui.ini + // in the same folder as the saved material. + // TODO: Consider setting the ini and log file paths to an application directory. + io.IniFilename = NULL; + io.LogFilename = NULL; + + io.Fonts->AddFontDefault(); // Setup Dear ImGui style ImGui::StyleColorsDark(); From a62a468ed80f4a6830950cc7a9ff7e544567d669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ars=C3=A8ne=20P=C3=A9rard-Gayot?= Date: Sun, 15 Oct 2023 20:18:43 +0200 Subject: [PATCH 18/22] Fix edge case in HW shader generation for transform nodes (#1560) This merges the TransformXXXNodeGlsl and TransformXXXNodeMsl classes into a HwTransformNode which has 3 subclasses, HwTransformVectorNode, HwTransformPointNode, and HwTransformNormalNode, all of which can be configured by overriding the virtual methods of HwTransformNode. --- .../MaterialXGenGlsl/GlslShaderGenerator.cpp | 15 +-- source/MaterialXGenGlsl/GlslShaderGenerator.h | 5 - .../Nodes/TransformNormalNodeGlsl.cpp | 43 ------- .../Nodes/TransformNormalNodeGlsl.h | 27 ----- .../Nodes/TransformPointNodeGlsl.cpp | 23 ---- .../Nodes/TransformPointNodeGlsl.h | 25 ---- .../Nodes/TransformVectorNodeGlsl.cpp | 84 ------------- .../Nodes/TransformVectorNodeGlsl.h | 30 ----- source/MaterialXGenMsl/MslShaderGenerator.cpp | 15 +-- source/MaterialXGenMsl/MslShaderGenerator.h | 5 - .../Nodes/TransformNormalNodeMsl.cpp | 43 ------- .../Nodes/TransformNormalNodeMsl.h | 27 ----- .../Nodes/TransformPointNodeMsl.cpp | 23 ---- .../Nodes/TransformPointNodeMsl.h | 25 ---- .../Nodes/TransformVectorNodeMsl.cpp | 84 ------------- .../Nodes/TransformVectorNodeMsl.h | 30 ----- .../Nodes/HwTransformNode.cpp | 110 ++++++++++++++++++ .../Nodes/HwTransformNode.h | 71 +++++++++++ source/MaterialXGenShader/ShaderNode.cpp | 5 + source/MaterialXGenShader/ShaderNode.h | 3 + .../PyMaterialXGenShader/PyShaderPort.cpp | 1 + 21 files changed, 198 insertions(+), 496 deletions(-) delete mode 100644 source/MaterialXGenGlsl/Nodes/TransformNormalNodeGlsl.cpp delete mode 100644 source/MaterialXGenGlsl/Nodes/TransformNormalNodeGlsl.h delete mode 100644 source/MaterialXGenGlsl/Nodes/TransformPointNodeGlsl.cpp delete mode 100644 source/MaterialXGenGlsl/Nodes/TransformPointNodeGlsl.h delete mode 100644 source/MaterialXGenGlsl/Nodes/TransformVectorNodeGlsl.cpp delete mode 100644 source/MaterialXGenGlsl/Nodes/TransformVectorNodeGlsl.h delete mode 100644 source/MaterialXGenMsl/Nodes/TransformNormalNodeMsl.cpp delete mode 100644 source/MaterialXGenMsl/Nodes/TransformNormalNodeMsl.h delete mode 100644 source/MaterialXGenMsl/Nodes/TransformPointNodeMsl.cpp delete mode 100644 source/MaterialXGenMsl/Nodes/TransformPointNodeMsl.h delete mode 100644 source/MaterialXGenMsl/Nodes/TransformVectorNodeMsl.cpp delete mode 100644 source/MaterialXGenMsl/Nodes/TransformVectorNodeMsl.h create mode 100644 source/MaterialXGenShader/Nodes/HwTransformNode.cpp create mode 100644 source/MaterialXGenShader/Nodes/HwTransformNode.h diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp index 87582c8f50..ec5e48d4ec 100644 --- a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp +++ b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp @@ -22,9 +22,6 @@ #include #include #include -#include -#include -#include #include #include @@ -34,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -228,13 +226,13 @@ GlslShaderGenerator::GlslShaderGenerator() : registerImplementation(elementNames, BlurNodeGlsl::create); // elementNames = { @@ -902,11 +900,6 @@ ShaderNodeImplPtr GlslShaderGenerator::getImplementation(const NodeDef& nodedef, } const string GlslImplementation::SPACE = "space"; -const string GlslImplementation::TO_SPACE = "tospace"; -const string GlslImplementation::FROM_SPACE = "fromspace"; -const string GlslImplementation::WORLD = "world"; -const string GlslImplementation::OBJECT = "object"; -const string GlslImplementation::MODEL = "model"; const string GlslImplementation::INDEX = "index"; const string GlslImplementation::GEOMPROP = "geomprop"; diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.h b/source/MaterialXGenGlsl/GlslShaderGenerator.h index 4464f5d47c..acc8b0d6ee 100644 --- a/source/MaterialXGenGlsl/GlslShaderGenerator.h +++ b/source/MaterialXGenGlsl/GlslShaderGenerator.h @@ -110,11 +110,6 @@ class MX_GENGLSL_API GlslImplementation : public ShaderNodeImpl /// Internal string constants static const string SPACE; - static const string TO_SPACE; - static const string FROM_SPACE; - static const string WORLD; - static const string OBJECT; - static const string MODEL; static const string INDEX; static const string GEOMPROP; }; diff --git a/source/MaterialXGenGlsl/Nodes/TransformNormalNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/TransformNormalNodeGlsl.cpp deleted file mode 100644 index 0800fb4bf3..0000000000 --- a/source/MaterialXGenGlsl/Nodes/TransformNormalNodeGlsl.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#include - -MATERIALX_NAMESPACE_BEGIN - -ShaderNodeImplPtr TransformNormalNodeGlsl::create() -{ - return std::make_shared(); -} - -void TransformNormalNodeGlsl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const -{ - TransformVectorNodeGlsl::emitFunctionCall(node, context, stage); - - DEFINE_SHADER_STAGE(stage, Stage::PIXEL) - { - const ShaderGenerator& shadergen = context.getShaderGenerator(); - const ShaderOutput* output = node.getOutput(); - shadergen.emitLineBegin(stage); - shadergen.emitOutput(output, false, false, context, stage); - shadergen.emitString(" = normalize(" + output->getVariable() + ")", stage); - shadergen.emitLineEnd(stage); - } -} - -const string& TransformNormalNodeGlsl::getMatrix(const string& fromSpace, const string& toSpace) const -{ - if ((fromSpace == MODEL || fromSpace == OBJECT) && toSpace == WORLD) - { - return HW::T_WORLD_INVERSE_TRANSPOSE_MATRIX; - } - else if (fromSpace == WORLD && (toSpace == MODEL || toSpace == OBJECT)) - { - return HW::T_WORLD_TRANSPOSE_MATRIX; - } - return EMPTY_STRING; -} - -MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/Nodes/TransformNormalNodeGlsl.h b/source/MaterialXGenGlsl/Nodes/TransformNormalNodeGlsl.h deleted file mode 100644 index f08ec564d9..0000000000 --- a/source/MaterialXGenGlsl/Nodes/TransformNormalNodeGlsl.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef MATERIALX_TRANSFORMNORMALNODEGLSL_H -#define MATERIALX_TRANSFORMNORMALNODEGLSL_H - -#include - -MATERIALX_NAMESPACE_BEGIN - -/// TransformNormal node implementation for GLSL -class MX_GENGLSL_API TransformNormalNodeGlsl : public TransformVectorNodeGlsl -{ - public: - static ShaderNodeImplPtr create(); - - protected: - void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; - - const string& getMatrix(const string& fromSpace, const string& toSpace) const override; -}; - -MATERIALX_NAMESPACE_END - -#endif diff --git a/source/MaterialXGenGlsl/Nodes/TransformPointNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/TransformPointNodeGlsl.cpp deleted file mode 100644 index 1570939bfe..0000000000 --- a/source/MaterialXGenGlsl/Nodes/TransformPointNodeGlsl.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#include - -#include - -MATERIALX_NAMESPACE_BEGIN - -ShaderNodeImplPtr TransformPointNodeGlsl::create() -{ - return std::make_shared(); -} - -string TransformPointNodeGlsl::getHomogeneousCoordinate(const ShaderInput* in, GenContext& context) const -{ - const ShaderGenerator& shadergen = context.getShaderGenerator(); - return "vec4(" + shadergen.getUpstreamResult(in, context) + ", 1.0)"; -} - -MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/Nodes/TransformPointNodeGlsl.h b/source/MaterialXGenGlsl/Nodes/TransformPointNodeGlsl.h deleted file mode 100644 index eb366d8190..0000000000 --- a/source/MaterialXGenGlsl/Nodes/TransformPointNodeGlsl.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef MATERIALX_TRANSFORMPOINTNODEGLSL_H -#define MATERIALX_TRANSFORMPOINTNODEGLSL_H - -#include - -MATERIALX_NAMESPACE_BEGIN - -/// TransformPoint node implementation for GLSL -class MX_GENGLSL_API TransformPointNodeGlsl : public TransformVectorNodeGlsl -{ - public: - static ShaderNodeImplPtr create(); - - protected: - virtual string getHomogeneousCoordinate(const ShaderInput* in, GenContext& context) const override; -}; - -MATERIALX_NAMESPACE_END - -#endif diff --git a/source/MaterialXGenGlsl/Nodes/TransformVectorNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/TransformVectorNodeGlsl.cpp deleted file mode 100644 index df1e921497..0000000000 --- a/source/MaterialXGenGlsl/Nodes/TransformVectorNodeGlsl.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#include - -#include - -MATERIALX_NAMESPACE_BEGIN - -ShaderNodeImplPtr TransformVectorNodeGlsl::create() -{ - return std::make_shared(); -} - -void TransformVectorNodeGlsl::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const -{ - const ShaderInput* toSpaceInput = node.getInput(TO_SPACE); - string toSpace = toSpaceInput ? toSpaceInput->getValue()->getValueString() : EMPTY_STRING; - - const ShaderInput* fromSpaceInput = node.getInput(FROM_SPACE); - string fromSpace = fromSpaceInput ? fromSpaceInput->getValue()->getValueString() : EMPTY_STRING; - - const string& matrix = getMatrix(fromSpace, toSpace); - if (!matrix.empty()) - { - ShaderStage& ps = shader.getStage(Stage::PIXEL); - addStageUniform(HW::PRIVATE_UNIFORMS, Type::MATRIX44, matrix, ps); - } -} - -void TransformVectorNodeGlsl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const -{ - DEFINE_SHADER_STAGE(stage, Stage::PIXEL) - { - const ShaderGenerator& shadergen = context.getShaderGenerator(); - - const ShaderInput* inInput = node.getInput("in"); - if (inInput->getType() != Type::VECTOR3 && inInput->getType() != Type::VECTOR4) - { - throw ExceptionShaderGenError("Transform node must have 'in' type of vector3 or vector4."); - } - - const ShaderInput* toSpaceInput = node.getInput(TO_SPACE); - string toSpace = toSpaceInput ? toSpaceInput->getValue()->getValueString() : EMPTY_STRING; - - const ShaderInput* fromSpaceInput = node.getInput(FROM_SPACE); - string fromSpace = fromSpaceInput ? fromSpaceInput->getValue()->getValueString() : EMPTY_STRING; - - shadergen.emitLineBegin(stage); - shadergen.emitOutput(node.getOutput(), true, false, context, stage); - shadergen.emitString(" = (", stage); - const string& matrix = getMatrix(fromSpace, toSpace); - if (!matrix.empty()) - { - shadergen.emitString(matrix + " * ", stage); - } - shadergen.emitString(getHomogeneousCoordinate(inInput, context), stage); - shadergen.emitString(").xyz", stage); - shadergen.emitLineEnd(stage); - } -} - -const string& TransformVectorNodeGlsl::getMatrix(const string& fromSpace, const string& toSpace) const -{ - if ((fromSpace == MODEL || fromSpace == OBJECT) && toSpace == WORLD) - { - return HW::T_WORLD_MATRIX; - } - else if (fromSpace == WORLD && (toSpace == MODEL || toSpace == OBJECT)) - { - return HW::T_WORLD_INVERSE_MATRIX; - } - return EMPTY_STRING; -} - -string TransformVectorNodeGlsl::getHomogeneousCoordinate(const ShaderInput* in, GenContext& context) const -{ - const ShaderGenerator& shadergen = context.getShaderGenerator(); - return "vec4(" + shadergen.getUpstreamResult(in, context) + ", 0.0)"; -} - -MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/Nodes/TransformVectorNodeGlsl.h b/source/MaterialXGenGlsl/Nodes/TransformVectorNodeGlsl.h deleted file mode 100644 index e9861650b3..0000000000 --- a/source/MaterialXGenGlsl/Nodes/TransformVectorNodeGlsl.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef MATERIALX_TRANSFORMVECTORNODEGLSL_H -#define MATERIALX_TRANSFORMVECTORNODEGLSL_H - -#include - -MATERIALX_NAMESPACE_BEGIN - -/// TransformVector node implementation for GLSL -class MX_GENGLSL_API TransformVectorNodeGlsl : public GlslImplementation -{ - public: - static ShaderNodeImplPtr create(); - - void createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const override; - - void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; - - protected: - virtual const string& getMatrix(const string& fromSpace, const string& toSpace) const; - virtual string getHomogeneousCoordinate(const ShaderInput* in, GenContext& context) const; -}; - -MATERIALX_NAMESPACE_END - -#endif diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index 1d93104ce8..ea3fb7112d 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -22,9 +22,6 @@ #include #include #include -#include -#include -#include #include #include @@ -34,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -232,13 +230,13 @@ MslShaderGenerator::MslShaderGenerator() : registerImplementation(elementNames, BlurNodeMsl::create); // elementNames = { @@ -1404,11 +1402,6 @@ ShaderNodeImplPtr MslShaderGenerator::getImplementation(const NodeDef& nodedef, } const string MslImplementation::SPACE = "space"; -const string MslImplementation::TO_SPACE = "tospace"; -const string MslImplementation::FROM_SPACE = "fromspace"; -const string MslImplementation::WORLD = "world"; -const string MslImplementation::OBJECT = "object"; -const string MslImplementation::MODEL = "model"; const string MslImplementation::INDEX = "index"; const string MslImplementation::GEOMPROP = "geomprop"; diff --git a/source/MaterialXGenMsl/MslShaderGenerator.h b/source/MaterialXGenMsl/MslShaderGenerator.h index 631c38f33d..21817db735 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.h +++ b/source/MaterialXGenMsl/MslShaderGenerator.h @@ -137,11 +137,6 @@ class MX_GENMSL_API MslImplementation : public ShaderNodeImpl /// Internal string constants static const string SPACE; - static const string TO_SPACE; - static const string FROM_SPACE; - static const string WORLD; - static const string OBJECT; - static const string MODEL; static const string INDEX; static const string GEOMPROP; }; diff --git a/source/MaterialXGenMsl/Nodes/TransformNormalNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/TransformNormalNodeMsl.cpp deleted file mode 100644 index 98810c025b..0000000000 --- a/source/MaterialXGenMsl/Nodes/TransformNormalNodeMsl.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#include - -MATERIALX_NAMESPACE_BEGIN - -ShaderNodeImplPtr TransformNormalNodeMsl::create() -{ - return std::make_shared(); -} - -void TransformNormalNodeMsl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const -{ - TransformVectorNodeMsl::emitFunctionCall(node, context, stage); - - DEFINE_SHADER_STAGE(stage, Stage::PIXEL) - { - const ShaderGenerator& shadergen = context.getShaderGenerator(); - const ShaderOutput* output = node.getOutput(); - shadergen.emitLineBegin(stage); - shadergen.emitOutput(output, false, false, context, stage); - shadergen.emitString(" = normalize(" + output->getVariable() + ")", stage); - shadergen.emitLineEnd(stage); - } -} - -const string& TransformNormalNodeMsl::getMatrix(const string& fromSpace, const string& toSpace) const -{ - if ((fromSpace == MODEL || fromSpace == OBJECT) && toSpace == WORLD) - { - return HW::T_WORLD_INVERSE_TRANSPOSE_MATRIX; - } - else if (fromSpace == WORLD && (toSpace == MODEL || toSpace == OBJECT)) - { - return HW::T_WORLD_TRANSPOSE_MATRIX; - } - return EMPTY_STRING; -} - -MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMsl/Nodes/TransformNormalNodeMsl.h b/source/MaterialXGenMsl/Nodes/TransformNormalNodeMsl.h deleted file mode 100644 index 603ba3771c..0000000000 --- a/source/MaterialXGenMsl/Nodes/TransformNormalNodeMsl.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef MATERIALX_TRANSFORMNORMALNODEMSL_H -#define MATERIALX_TRANSFORMNORMALNODEMSL_H - -#include - -MATERIALX_NAMESPACE_BEGIN - -/// TransformNormal node implementation for MSL -class MX_GENMSL_API TransformNormalNodeMsl : public TransformVectorNodeMsl -{ - public: - static ShaderNodeImplPtr create(); - - protected: - void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; - - const string& getMatrix(const string& fromSpace, const string& toSpace) const override; -}; - -MATERIALX_NAMESPACE_END - -#endif diff --git a/source/MaterialXGenMsl/Nodes/TransformPointNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/TransformPointNodeMsl.cpp deleted file mode 100644 index 38db776855..0000000000 --- a/source/MaterialXGenMsl/Nodes/TransformPointNodeMsl.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#include - -#include - -MATERIALX_NAMESPACE_BEGIN - -ShaderNodeImplPtr TransformPointNodeMsl::create() -{ - return std::make_shared(); -} - -string TransformPointNodeMsl::getHomogeneousCoordinate(const ShaderInput* in, GenContext& context) const -{ - const ShaderGenerator& shadergen = context.getShaderGenerator(); - return "float4(" + shadergen.getUpstreamResult(in, context) + ", 1.0)"; -} - -MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMsl/Nodes/TransformPointNodeMsl.h b/source/MaterialXGenMsl/Nodes/TransformPointNodeMsl.h deleted file mode 100644 index 9fc2361d7d..0000000000 --- a/source/MaterialXGenMsl/Nodes/TransformPointNodeMsl.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef MATERIALX_TRANSFORMPOINTNODEMSL_H -#define MATERIALX_TRANSFORMPOINTNODEMSL_H - -#include - -MATERIALX_NAMESPACE_BEGIN - -/// TransformPoint node implementation for MSL -class MX_GENMSL_API TransformPointNodeMsl : public TransformVectorNodeMsl -{ - public: - static ShaderNodeImplPtr create(); - - protected: - virtual string getHomogeneousCoordinate(const ShaderInput* in, GenContext& context) const override; -}; - -MATERIALX_NAMESPACE_END - -#endif diff --git a/source/MaterialXGenMsl/Nodes/TransformVectorNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/TransformVectorNodeMsl.cpp deleted file mode 100644 index c5d6ce242a..0000000000 --- a/source/MaterialXGenMsl/Nodes/TransformVectorNodeMsl.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#include - -#include - -MATERIALX_NAMESPACE_BEGIN - -ShaderNodeImplPtr TransformVectorNodeMsl::create() -{ - return std::make_shared(); -} - -void TransformVectorNodeMsl::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const -{ - const ShaderInput* toSpaceInput = node.getInput(TO_SPACE); - string toSpace = toSpaceInput ? toSpaceInput->getValue()->getValueString() : EMPTY_STRING; - - const ShaderInput* fromSpaceInput = node.getInput(FROM_SPACE); - string fromSpace = fromSpaceInput ? fromSpaceInput->getValue()->getValueString() : EMPTY_STRING; - - const string& matrix = getMatrix(fromSpace, toSpace); - if (!matrix.empty()) - { - ShaderStage& ps = shader.getStage(Stage::PIXEL); - addStageUniform(HW::PRIVATE_UNIFORMS, Type::MATRIX44, matrix, ps); - } -} - -void TransformVectorNodeMsl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const -{ - DEFINE_SHADER_STAGE(stage, Stage::PIXEL) - { - const ShaderGenerator& shadergen = context.getShaderGenerator(); - - const ShaderInput* inInput = node.getInput("in"); - if (inInput->getType() != Type::VECTOR3 && inInput->getType() != Type::VECTOR4) - { - throw ExceptionShaderGenError("Transform node must have 'in' type of vector3 or vector4."); - } - - const ShaderInput* toSpaceInput = node.getInput(TO_SPACE); - string toSpace = toSpaceInput ? toSpaceInput->getValue()->getValueString() : EMPTY_STRING; - - const ShaderInput* fromSpaceInput = node.getInput(FROM_SPACE); - string fromSpace = fromSpaceInput ? fromSpaceInput->getValue()->getValueString() : EMPTY_STRING; - - shadergen.emitLineBegin(stage); - shadergen.emitOutput(node.getOutput(), true, false, context, stage); - shadergen.emitString(" = (", stage); - const string& matrix = getMatrix(fromSpace, toSpace); - if (!matrix.empty()) - { - shadergen.emitString(matrix + " * ", stage); - } - shadergen.emitString(getHomogeneousCoordinate(inInput, context), stage); - shadergen.emitString(").xyz", stage); - shadergen.emitLineEnd(stage); - } -} - -const string& TransformVectorNodeMsl::getMatrix(const string& fromSpace, const string& toSpace) const -{ - if ((fromSpace == MODEL || fromSpace == OBJECT) && toSpace == WORLD) - { - return HW::T_WORLD_MATRIX; - } - else if (fromSpace == WORLD && (toSpace == MODEL || toSpace == OBJECT)) - { - return HW::T_WORLD_INVERSE_MATRIX; - } - return EMPTY_STRING; -} - -string TransformVectorNodeMsl::getHomogeneousCoordinate(const ShaderInput* in, GenContext& context) const -{ - const ShaderGenerator& shadergen = context.getShaderGenerator(); - return "float4(" + shadergen.getUpstreamResult(in, context) + ", 0.0)"; -} - -MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMsl/Nodes/TransformVectorNodeMsl.h b/source/MaterialXGenMsl/Nodes/TransformVectorNodeMsl.h deleted file mode 100644 index 013a3db29a..0000000000 --- a/source/MaterialXGenMsl/Nodes/TransformVectorNodeMsl.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef MATERIALX_TRANSFORMVECTORNODEMSL_H -#define MATERIALX_TRANSFORMVECTORNODEMSL_H - -#include - -MATERIALX_NAMESPACE_BEGIN - -/// TransformVector node implementation for MSL -class MX_GENMSL_API TransformVectorNodeMsl : public MslImplementation -{ - public: - static ShaderNodeImplPtr create(); - - void createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const override; - - void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; - - protected: - virtual const string& getMatrix(const string& fromSpace, const string& toSpace) const; - virtual string getHomogeneousCoordinate(const ShaderInput* in, GenContext& context) const; -}; - -MATERIALX_NAMESPACE_END - -#endif diff --git a/source/MaterialXGenShader/Nodes/HwTransformNode.cpp b/source/MaterialXGenShader/Nodes/HwTransformNode.cpp new file mode 100644 index 0000000000..018924855d --- /dev/null +++ b/source/MaterialXGenShader/Nodes/HwTransformNode.cpp @@ -0,0 +1,110 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include + +MATERIALX_NAMESPACE_BEGIN + +const string HwTransformNode::FROM_SPACE = "fromspace"; +const string HwTransformNode::TO_SPACE = "tospace"; +const string HwTransformNode::MODEL = "model"; +const string HwTransformNode::OBJECT = "object"; +const string HwTransformNode::WORLD = "world"; + +void HwTransformNode::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const +{ + const string toSpace = getToSpace(node); + const string fromSpace = getFromSpace(node); + const string& matrix = getMatrix(fromSpace, toSpace); + if (!matrix.empty()) + { + ShaderStage& ps = shader.getStage(Stage::PIXEL); + addStageUniform(HW::PRIVATE_UNIFORMS, Type::MATRIX44, matrix, ps); + } +} + +void HwTransformNode::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const +{ + DEFINE_SHADER_STAGE(stage, Stage::PIXEL) + { + const ShaderGenerator& shadergen = context.getShaderGenerator(); + + const ShaderOutput* output = node.getOutput(); + const ShaderInput* inInput = node.getInput("in"); + if (inInput->getType() != Type::VECTOR3 && inInput->getType() != Type::VECTOR4) + { + throw ExceptionShaderGenError("Transform node must have 'in' type of vector3 or vector4."); + } + + shadergen.emitLineBegin(stage); + shadergen.emitOutput(output, true, false, context, stage); + shadergen.emitString(" = (", stage); + + const string toSpace = getToSpace(node); + const string fromSpace = getFromSpace(node); + const string& matrix = getMatrix(fromSpace, toSpace); + if (!matrix.empty()) + { + shadergen.emitString(matrix + " * ", stage); + } + + const string type = shadergen.getSyntax().getTypeName(Type::VECTOR4); + const string input = shadergen.getUpstreamResult(inInput, context); + shadergen.emitString(type + "(" + input + ", " + getHomogeneousCoordinate() + ")).xyz", stage); + shadergen.emitLineEnd(stage); + + if (shouldNormalize()) + { + shadergen.emitLineBegin(stage); + shadergen.emitOutput(output, false, false, context, stage); + shadergen.emitString(" = normalize(" + output->getVariable() + ")", stage); + shadergen.emitLineEnd(stage); + } + } +} + +string HwTransformNode::getFromSpace(const ShaderNode& node) const +{ + const ShaderInput* input = node.getInput(FROM_SPACE); + return input ? input->getValueString() : EMPTY_STRING; +} + +string HwTransformNode::getToSpace(const ShaderNode& node) const +{ + const ShaderInput* input = node.getInput(TO_SPACE); + return input ? input->getValueString() : EMPTY_STRING; +} + +const string& HwTransformNode::getMatrix(const string& fromSpace, const string& toSpace) const +{ + if ((fromSpace == MODEL || fromSpace == OBJECT) && toSpace == WORLD) + { + return getModelToWorldMatrix(); + } + else if (fromSpace == WORLD && (toSpace == MODEL || toSpace == OBJECT)) + { + return getWorldToModelMatrix(); + } + return EMPTY_STRING; +} + +ShaderNodeImplPtr HwTransformVectorNode::create() +{ + return std::make_shared(); +} + +ShaderNodeImplPtr HwTransformPointNode::create() +{ + return std::make_shared(); +} + +ShaderNodeImplPtr HwTransformNormalNode::create() +{ + return std::make_shared(); +} + +MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/Nodes/HwTransformNode.h b/source/MaterialXGenShader/Nodes/HwTransformNode.h new file mode 100644 index 0000000000..a97e57405c --- /dev/null +++ b/source/MaterialXGenShader/Nodes/HwTransformNode.h @@ -0,0 +1,71 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef MATERIALX_HWTRANSFORMNODE_H +#define MATERIALX_HWTRANSFORMNODE_H + +#include + +MATERIALX_NAMESPACE_BEGIN + +/// Generic transformation node for hardware languages +class MX_GENSHADER_API HwTransformNode : public ShaderNodeImpl +{ + public: + void createVariables(const ShaderNode& node, GenContext& context, Shader& shader) const override; + void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; + + protected: + virtual const string& getMatrix(const string& fromSpace, const string& toSpace) const; + virtual const string& getModelToWorldMatrix() const = 0; + virtual const string& getWorldToModelMatrix() const = 0; + virtual string getHomogeneousCoordinate() const = 0; + virtual bool shouldNormalize() const { return false; } + + virtual string getFromSpace(const ShaderNode&) const; + virtual string getToSpace(const ShaderNode&) const; + + static const string FROM_SPACE; + static const string TO_SPACE; + static const string MODEL; + static const string OBJECT; + static const string WORLD; +}; + +class MX_GENSHADER_API HwTransformVectorNode : public HwTransformNode +{ + public: + static ShaderNodeImplPtr create(); + + protected: + const string& getModelToWorldMatrix() const override { return HW::T_WORLD_MATRIX; } + const string& getWorldToModelMatrix() const override { return HW::T_WORLD_INVERSE_MATRIX; } + string getHomogeneousCoordinate() const override { return "0.0"; } +}; + +class MX_GENSHADER_API HwTransformPointNode : public HwTransformVectorNode +{ + public: + static ShaderNodeImplPtr create(); + + protected: + string getHomogeneousCoordinate() const override { return "1.0"; } +}; + +class MX_GENSHADER_API HwTransformNormalNode : public HwTransformNode +{ + public: + static ShaderNodeImplPtr create(); + + protected: + const string& getModelToWorldMatrix() const override { return HW::T_WORLD_INVERSE_TRANSPOSE_MATRIX; } + const string& getWorldToModelMatrix() const override { return HW::T_WORLD_TRANSPOSE_MATRIX; } + string getHomogeneousCoordinate() const override { return "0.0"; } + bool shouldNormalize() const override { return true; } +}; + +MATERIALX_NAMESPACE_END + +#endif diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index 04551cb6d2..3e393178f1 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -32,6 +32,11 @@ string ShaderPort::getFullName() const return (_node->getName() + "_" + _name); } +string ShaderPort::getValueString() const +{ + return getValue() ? getValue()->getValueString() : EMPTY_STRING; +} + // // ShaderInput methods // diff --git a/source/MaterialXGenShader/ShaderNode.h b/source/MaterialXGenShader/ShaderNode.h index 536e0adc1e..dd74269764 100644 --- a/source/MaterialXGenShader/ShaderNode.h +++ b/source/MaterialXGenShader/ShaderNode.h @@ -170,6 +170,9 @@ class MX_GENSHADER_API ShaderPort : public std::enable_shared_from_this Date: Mon, 16 Oct 2023 13:54:34 -0700 Subject: [PATCH 19/22] Add floating popup to pins when hovered (#1565) Added a tooltip/popup showing the name, type, value and connection of a pin! --- source/MaterialXGraphEditor/Graph.cpp | 64 ++++++++++++++++++++++++++- source/MaterialXGraphEditor/Graph.h | 2 + source/MaterialXGraphEditor/UiNode.h | 23 ++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 849b8607b4..439f720e2e 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -2257,6 +2257,7 @@ std::vector Graph::createNodes(bool nodegraph) } upUiNode->outputPins[pinIndex]->addConnection(pin); + pin->addConnection(upUiNode->outputPins[pinIndex]); } pin->setConnected(true); } @@ -2322,6 +2323,7 @@ std::vector Graph::createNodes(bool nodegraph) } } upUiNode->outputPins[pinIndex]->addConnection(pin); + pin->addConnection(upUiNode->outputPins[pinIndex]); } pin->setConnected(true); } @@ -2392,6 +2394,7 @@ std::vector Graph::createNodes(bool nodegraph) } } upUiNode->outputPins[pinIndex]->addConnection(pin); + pin->addConnection(upUiNode->outputPins[pinIndex]); } } @@ -2628,6 +2631,11 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) _frameCount = ImGui::GetFrameCount(); _renderer->setMaterialCompilation(true); + inputPin->addConnection(outputPin); + outputPin->addConnection(inputPin); + outputPin->setConnected(true); + inputPin->setConnected(true); + if (uiDownNode->getNode() || uiDownNode->getNodeGraph()) { mx::InputPtr connectingInput = nullptr; @@ -2721,6 +2729,7 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) } } + pin->setConnected(true); pin->_input->removeAttribute(mx::ValueElement::VALUE_ATTRIBUTE); connectingInput = pin->_input; @@ -2806,9 +2815,13 @@ void Graph::deleteLinkInfo(int startAttr, int endAttr) setDefaults(_graphNodes[upNode]->getInput()); } + for (UiPinPtr connect : pin->_connections) + { + pin->deleteConnection(connect); + } + // Remove any output reference pin->_input->removeAttribute(mx::PortElement::OUTPUT_ATTRIBUTE); - pin->setConnected(false); // If a value exists update the input with it @@ -2833,6 +2846,10 @@ void Graph::deleteLinkInfo(int startAttr, int endAttr) _graphNodes[downNode]->getNodeGraph()->getInput(pin->_name)->removeAttribute(mx::ValueElement::INTERFACE_NAME_ATTRIBUTE); setDefaults(_graphNodes[upNode]->getInput()); } + for (UiPinPtr connect : pin->_connections) + { + pin->deleteConnection(connect); + } pin->_input->setConnectedNode(nullptr); pin->setConnected(false); setDefaults(pin->_input); @@ -2847,6 +2864,10 @@ void Graph::deleteLinkInfo(int startAttr, int endAttr) { removeEdge(downNode, upNode, pin); _graphNodes[downNode]->getOutput()->removeAttribute("nodename"); + for (UiPinPtr connect : pin->_connections) + { + pin->deleteConnection(connect); + } pin->setConnected(false); } } @@ -3744,6 +3765,46 @@ void Graph::searchNodePopup(bool cursor) } } +bool Graph::isPinHovered() +{ + ed::PinId currentPin = ed::GetHoveredPin(); + ed::PinId nullPin = 0; + return currentPin != nullPin; +} + +void Graph::addPinPopup() +{ + // Add a floating popup to pin when hovered + if (isPinHovered()) + { + ed::Suspend(); + UiPinPtr pin = getPin(ed::GetHoveredPin()); + std::string connected = ""; + std::string value = ""; + if (pin->_connected) + { + connected = "\nConnected to"; + int size = static_cast(pin->getConnections().size()); + for (int i = 0; i < size; i++) + { + UiPinPtr connectedPin = pin->getConnections()[i]; + connected = connected + " " + connectedPin->_name; + if (i != size - 1) + { + connected = connected + ","; + } + } + } + else if (pin->_input != nullptr) + { + value = "\nValue: " + pin->_input->getValueString(); + } + const std::string message("Name: " + pin->_name + "\nType: " + pin->_type + value + connected); + ImGui::SetTooltip("%s", message.c_str()); + ed::Resume(); + } +} + void Graph::readOnlyPopup() { if (_popup) @@ -3860,6 +3921,7 @@ void Graph::drawGraph(ImVec2 mousePos) ImGui::SetNextWindowSizeConstraints(ImVec2(250.0f, 300.0f), ImVec2(-1.0f, 500.0f)); addNodePopup(TextCursor); searchNodePopup(TextCursor); + addPinPopup(); readOnlyPopup(); ImGui::PopStyleVar(); diff --git a/source/MaterialXGraphEditor/Graph.h b/source/MaterialXGraphEditor/Graph.h index 87d4119c2a..fcdf93723e 100644 --- a/source/MaterialXGraphEditor/Graph.h +++ b/source/MaterialXGraphEditor/Graph.h @@ -213,6 +213,8 @@ class Graph void addNodePopup(bool cursor); void searchNodePopup(bool cursor); + bool isPinHovered(); + void addPinPopup(); bool readOnly(); void readOnlyPopup(); diff --git a/source/MaterialXGraphEditor/UiNode.h b/source/MaterialXGraphEditor/UiNode.h index c03ae43219..cf7aa41e28 100644 --- a/source/MaterialXGraphEditor/UiNode.h +++ b/source/MaterialXGraphEditor/UiNode.h @@ -95,6 +95,29 @@ class UiPin _connections.push_back(pin); } + void deleteConnection(UiPinPtr pin) + { + for (size_t i = 0; i < _connections.size(); i++) + { + if (_connections[i]->_pinId == pin->_pinId) + { + _connections.erase(_connections.begin()+i); + } + } + for (size_t i = 0; i < pin->_connections.size(); i++) + { + if (pin->_connections[i]->_pinId == _pinId) + { + pin->_connections.erase(pin->_connections.begin() + i); + } + } + if (pin->_connections.size() == 0) + { + pin->setConnected(false); + } + return; + } + const std::vector& getConnections() { return _connections; From d5634c83335766952026f6120dcea7b902894c44 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 17 Oct 2023 10:18:51 -0700 Subject: [PATCH 20/22] Refinements to Graph class - Move the ordered group vector in Graph::createNodeUIList to a constant at module scope. - Use the joinStrings helper function in Graph::addPinPopup to simplify its implementation. - Update comments to align with coding conventions. --- source/MaterialXGraphEditor/Graph.cpp | 105 ++++++++++++-------------- 1 file changed, 48 insertions(+), 57 deletions(-) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 439f720e2e..889789706b 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -23,6 +23,32 @@ const ImVec2 DEFAULT_NODE_SIZE = ImVec2(138, 116); const int DEFAULT_ALPHA = 255; const int FILTER_ALPHA = 50; +const std::array NODE_GROUP_ORDER = +{ + "texture2d", + "texture3d", + "procedural", + "procedural2d", + "procedural3d", + "geometric", + "translation", + "convolution2d", + "math", + "adjustment", + "compositing", + "conditional", + "channel", + "organization", + "global", + "application", + "material", + "shader", + "pbr", + "light", + "colortransform", + "none" +}; + // Based on ImRect_Expanded function in ImGui Node Editor blueprints-example.cpp ImRect expandImRect(const ImRect& rect, float x, float y) { @@ -1220,41 +1246,15 @@ void Graph::createNodeUIList(mx::DocumentPtr doc) { _nodesToAdd.clear(); - std::vector ordered_groups = { - "texture2d", - "texture3d", - "procedural", - "procedural2d", - "procedural3d", - "geometric", - "translation", - "convolution2d", - "math", - "adjustment", - "compositing", - "conditional", - "channel", - "organization", - "global", - "application", - "material", - "shader", - "pbr", - "light", - "colortransform", - "no_group" - }; - auto nodeDefs = doc->getNodeDefs(); std::unordered_map> groupToNodeDef; for (const auto& nodeDef : nodeDefs) { std::string group = nodeDef->getNodeGroup(); - if (group.empty()) { - group = "no_group"; + group = NODE_GROUP_ORDER.back(); } if (groupToNodeDef.find(group) == groupToNodeDef.end()) @@ -1264,7 +1264,7 @@ void Graph::createNodeUIList(mx::DocumentPtr doc) groupToNodeDef[group].push_back(nodeDef); } - for (const auto& group : ordered_groups) + for (const auto& group : NODE_GROUP_ORDER) { auto it = groupToNodeDef.find(group); if (it != groupToNodeDef.end()) @@ -2526,7 +2526,7 @@ void Graph::setDefaults(mx::InputPtr input) void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) { - // prefer to assume left to right - start is an output, end is an input; swap if inaccurate + // Prefer to assume left to right - start is an output, end is an input; swap if inaccurate if (UiPinPtr inputPin = getPin(endPinId); inputPin && inputPin->_kind != ed::PinKind::Input) { auto tmp = startPinId; @@ -2575,7 +2575,7 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) return; } - // make sure there is an implementation for node + // Make sure there is an implementation for node const mx::ShaderGenerator& shadergen = _renderer->getGenContext().getShaderGenerator(); // Prevent direct connecting from input to output @@ -2613,7 +2613,7 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) { if (linksItr->_endAttr == end_attr) { - // found existing link - remove it; adapted from deleteLink + // Found existing link - remove it; adapted from deleteLink // note: ed::BreakLinks doesn't work as the order ends up inaccurate deleteLinkInfo(linksItr->_startAttr, linksItr->_endAttr); _currLinks.erase(linksItr); @@ -2644,7 +2644,8 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) if (pin->_pinId == inputPinId) { addNodeInput(uiDownNode, pin->_input); - // update value to be empty + + // Update value to be empty if (uiDownNode->getNode() && uiDownNode->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING) { if (uiUpNode->getOutput() != nullptr) @@ -2657,12 +2658,11 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) } else { - // node graph if (uiUpNode->getNodeGraph() != nullptr) { for (UiPinPtr outPin : uiUpNode->outputPins) { - // set pin connection to correct output + // Set pin connection to correct output if (outPin->_pinId == outputPinId) { mx::OutputPtr outputs = uiUpNode->getNodeGraph()->getOutput(outPin->_name); @@ -2689,10 +2689,6 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) mx::NodePtr upstreamNode = _graphNodes[upNode]->getNode(); mx::NodeDefPtr upstreamNodeDef = upstreamNode->getNodeDef(); bool isMultiOutput = upstreamNodeDef ? upstreamNodeDef->getOutputs().size() > 1 : false; - - // This is purely to avoid adding a reference to an update node only 1 output, - // as currently validation consides adding this an error. Otherwise - // it will add an "output" attribute all the time. if (!isMultiOutput) { pin->_input->setConnectedNode(uiUpNode->getNode()); @@ -2701,7 +2697,7 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) { for (UiPinPtr outPin : _graphNodes[upNode]->outputPins) { - // set pin connection to correct output + // Set pin connection to correct output if (outPin->_pinId == outputPinId) { mx::OutputPtr outputs = uiUpNode->getNode()->getOutput(outPin->_name); @@ -2718,7 +2714,7 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) { for (UiPinPtr outPin : uiUpNode->outputPins) { - // set pin connection to correct output + // Set pin connection to correct output if (outPin->_pinId == outputPinId) { mx::OutputPtr outputs = uiUpNode->getNodeGraph()->getOutput(outPin->_name); @@ -2729,14 +2725,14 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) } } - pin->setConnected(true); pin->_input->removeAttribute(mx::ValueElement::VALUE_ATTRIBUTE); connectingInput = pin->_input; break; } } - // create new edge and set edge information + + // Create new edge and set edge information createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); } else if (_graphNodes[downNode]->getOutput() != nullptr) @@ -2744,19 +2740,19 @@ void Graph::addLink(ed::PinId startPinId, ed::PinId endPinId) mx::InputPtr connectingInput = nullptr; _graphNodes[downNode]->getOutput()->setConnectedNode(_graphNodes[upNode]->getNode()); - // create new edge and set edge information + // Create new edge and set edge information createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); } else { - // create new edge and set edge info + // Create new edge and set edge info UiEdge newEdge = UiEdge(_graphNodes[upNode], _graphNodes[downNode], nullptr); if (!edgeExists(newEdge)) { _graphNodes[downNode]->edges.push_back(newEdge); _currEdge.push_back(newEdge); - // update input node num and output connections + // Update input node num and output connections _graphNodes[downNode]->setInputNodeNum(1); _graphNodes[upNode]->setOutputConnection(_graphNodes[downNode]); } @@ -3779,23 +3775,18 @@ void Graph::addPinPopup() { ed::Suspend(); UiPinPtr pin = getPin(ed::GetHoveredPin()); - std::string connected = ""; - std::string value = ""; + std::string connected; + std::string value; if (pin->_connected) { - connected = "\nConnected to"; - int size = static_cast(pin->getConnections().size()); - for (int i = 0; i < size; i++) + mx::StringVec connectedNames; + for (UiPinPtr connectedPin : pin->getConnections()) { - UiPinPtr connectedPin = pin->getConnections()[i]; - connected = connected + " " + connectedPin->_name; - if (i != size - 1) - { - connected = connected + ","; - } + connectedNames.push_back(connectedPin->_name); } + connected = "\nConnected to " + mx::joinStrings(connectedNames, ", "); } - else if (pin->_input != nullptr) + else if (pin->_input) { value = "\nValue: " + pin->_input->getValueString(); } From 1c78f460e582a83d0b79117428996b74b6b7b60c Mon Sep 17 00:00:00 2001 From: nicolassavva-autodesk <61437351+nicolassavva-autodesk@users.noreply.github.com> Date: Wed, 18 Oct 2023 16:16:03 -0700 Subject: [PATCH 21/22] Remove unused uniforms in HW generation for heighttonormal (#1576) This PR addresses the undesirable shaderGen for Metal and GLSL targets when using the HeightToNormalNode. The parent ConvolutionNode class emits a couple of filter kernel arrays, for box and gaussian weights, that may cause shader compiler issues when they remain unused. --- source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.cpp | 5 +++++ source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h | 2 ++ source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.cpp | 5 +++++ source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h | 2 ++ 4 files changed, 14 insertions(+) diff --git a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.cpp index 157cd5be04..e98a4ab75c 100644 --- a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.cpp +++ b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.cpp @@ -33,6 +33,11 @@ ShaderNodeImplPtr HeightToNormalNodeGlsl::create() return std::make_shared(); } +void HeightToNormalNodeGlsl::createVariables(const ShaderNode&, GenContext&, Shader&) const +{ + // Default filter kernels from ConvolutionNode are not used by this derived class. +} + void HeightToNormalNodeGlsl::computeSampleOffsetStrings(const string& sampleSizeName, const string& offsetTypeString, unsigned int, StringVec& offsetStrings) const { diff --git a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h index 638623ea43..fc6e6b421f 100644 --- a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h +++ b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h @@ -18,6 +18,8 @@ class MX_GENGLSL_API HeightToNormalNodeGlsl : public ConvolutionNode public: static ShaderNodeImplPtr create(); + void createVariables(const ShaderNode&, GenContext&, Shader& shader) const override; + void emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; diff --git a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.cpp index 12b1a9675c..7282e5e9df 100644 --- a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.cpp +++ b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.cpp @@ -33,6 +33,11 @@ ShaderNodeImplPtr HeightToNormalNodeMsl::create() return std::make_shared(); } +void HeightToNormalNodeMsl::createVariables(const ShaderNode&, GenContext&, Shader&) const +{ + // Default filter kernels from ConvolutionNode are not used by this derived class. +} + void HeightToNormalNodeMsl::computeSampleOffsetStrings(const string& sampleSizeName, const string& offsetTypeString, unsigned int, StringVec& offsetStrings) const { diff --git a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h index 752c411ed5..035ad300b4 100644 --- a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h +++ b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h @@ -18,6 +18,8 @@ class MX_GENMSL_API HeightToNormalNodeMsl : public ConvolutionNode public: static ShaderNodeImplPtr create(); + void createVariables(const ShaderNode&, GenContext&, Shader& shader) const override; + void emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; From 78d27622a0edc00f4936d7d7c613b29f5d181fe0 Mon Sep 17 00:00:00 2001 From: Rasmus Bonnedal Date: Thu, 19 Oct 2023 02:57:37 +0200 Subject: [PATCH 22/22] Update overlay node logic to match reference (#1539) This commit changes the overlay node to match the overlay operation in the Adobe PDF spec. It also changes the implementation to graph based instead of code snippets. --- .../Specification/MaterialX.Specification.md | 2 +- libraries/stdlib/genglsl/mx_overlay.glsl | 25 ---- .../stdlib/genglsl/mx_overlay_color3.glsl | 6 - .../stdlib/genglsl/mx_overlay_color4.glsl | 6 - .../stdlib/genglsl/stdlib_genglsl_impl.mtlx | 5 - .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 5 - .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 5 - libraries/stdlib/genosl/mx_overlay_color3.osl | 16 --- libraries/stdlib/genosl/mx_overlay_color4.osl | 22 ---- .../stdlib/genosl/stdlib_genosl_impl.mtlx | 5 - libraries/stdlib/stdlib_defs.mtlx | 4 +- libraries/stdlib/stdlib_ng.mtlx | 112 ++++++++++++++++++ .../stdlib/compositing/compositing.mtlx | 12 +- .../MaterialXGenMdl/mdl/materialx/stdlib.mdl | 60 ---------- 14 files changed, 121 insertions(+), 164 deletions(-) delete mode 100644 libraries/stdlib/genglsl/mx_overlay.glsl delete mode 100644 libraries/stdlib/genglsl/mx_overlay_color3.glsl delete mode 100644 libraries/stdlib/genglsl/mx_overlay_color4.glsl delete mode 100644 libraries/stdlib/genosl/mx_overlay_color3.osl delete mode 100644 libraries/stdlib/genosl/mx_overlay_color4.osl diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 4b99956fb4..895b4756c5 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -1496,7 +1496,7 @@ Blend nodes take two 1-4 channel inputs and apply the same operator to all chann | **`burn`** | 1-(1-B)/F | float, colorN | | **`dodge`** | B/(1-F) | float, colorN | | **`screen`** | 1-(1-F)(1-B) | float, colorN | -| **`overlay`** | 2FB if F<0.5;
1-(1-F)(1-B) if F>=0.5 | float, colorN | +| **`overlay`** | 2FB if B<0.5;
1-2(1-F)(1-B) if B>=0.5 | float, colorN | #### Merge Nodes diff --git a/libraries/stdlib/genglsl/mx_overlay.glsl b/libraries/stdlib/genglsl/mx_overlay.glsl deleted file mode 100644 index e1bec8ac44..0000000000 --- a/libraries/stdlib/genglsl/mx_overlay.glsl +++ /dev/null @@ -1,25 +0,0 @@ -float mx_overlay(float fg, float bg) -{ - return (fg < 0.5) ? (2.0 * fg * bg) : (1.0 - (1.0 - fg) * (1.0 - bg)); -} - -vec2 mx_overlay(vec2 fg, vec2 bg) -{ - return vec2(mx_overlay(fg.r, bg.r), - mx_overlay(fg.g, bg.g)); -} - -vec3 mx_overlay(vec3 fg, vec3 bg) -{ - return vec3(mx_overlay(fg.r, bg.r), - mx_overlay(fg.g, bg.g), - mx_overlay(fg.b, bg.b)); -} - -vec4 mx_overlay(vec4 fg, vec4 bg) -{ - return vec4(mx_overlay(fg.r, bg.r), - mx_overlay(fg.g, bg.g), - mx_overlay(fg.b, bg.b), - mx_overlay(fg.a, bg.a)); -} diff --git a/libraries/stdlib/genglsl/mx_overlay_color3.glsl b/libraries/stdlib/genglsl/mx_overlay_color3.glsl deleted file mode 100644 index 3b6ae67804..0000000000 --- a/libraries/stdlib/genglsl/mx_overlay_color3.glsl +++ /dev/null @@ -1,6 +0,0 @@ -#include "mx_overlay.glsl" - -void mx_overlay_color3(vec3 fg, vec3 bg, float mix, out vec3 result) -{ - result = mix * mx_overlay(fg, bg) + (1.0-mix) * bg; -} diff --git a/libraries/stdlib/genglsl/mx_overlay_color4.glsl b/libraries/stdlib/genglsl/mx_overlay_color4.glsl deleted file mode 100644 index 411e0da372..0000000000 --- a/libraries/stdlib/genglsl/mx_overlay_color4.glsl +++ /dev/null @@ -1,6 +0,0 @@ -#include "mx_overlay.glsl" - -void mx_overlay_color4(vec4 fg, vec4 bg, float mix, out vec4 result) -{ - result = mix * mx_overlay(fg, bg) + (1.0-mix) * bg; -} diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index 90d3120bd7..07aae6ce66 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -560,11 +560,6 @@ - - - - - diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index ab0d776936..0081dec924 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -568,11 +568,6 @@ - - - - - diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index fcab8fd69d..dea1c49636 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -560,11 +560,6 @@ - - - - - diff --git a/libraries/stdlib/genosl/mx_overlay_color3.osl b/libraries/stdlib/genosl/mx_overlay_color3.osl deleted file mode 100644 index 387653fe05..0000000000 --- a/libraries/stdlib/genosl/mx_overlay_color3.osl +++ /dev/null @@ -1,16 +0,0 @@ -float overlay(float fg, float bg) -{ - return (fg < 0.5) ? (2 * fg * bg) : (1 - (1 - fg) * (1 - bg)); -} - -color overlay(color fg, color bg) -{ - return color(overlay(fg[0], bg[0]), - overlay(fg[1], bg[1]), - overlay(fg[2], bg[2])); -} - -void mx_overlay_color3(color fg, color bg, float mix, output color out) -{ - out = mix * overlay(fg, bg) + (1-mix) * bg; -} diff --git a/libraries/stdlib/genosl/mx_overlay_color4.osl b/libraries/stdlib/genosl/mx_overlay_color4.osl deleted file mode 100644 index 1ae6a72c15..0000000000 --- a/libraries/stdlib/genosl/mx_overlay_color4.osl +++ /dev/null @@ -1,22 +0,0 @@ -float overlay(float fg, float bg) -{ - return (fg < 0.5) ? (2 * fg * bg) : (1 - (1 - fg) * (1 - bg)); -} - -color overlay(color fg, color bg) -{ - return color(overlay(fg[0], bg[0]), - overlay(fg[1], bg[1]), - overlay(fg[2], bg[2])); -} - -color4 overlay(color4 fg, color4 bg) -{ - return color4(overlay(fg.rgb, bg.rgb), - overlay(fg.a, bg.a)); -} - -void mx_overlay_color4(color4 fg, color4 bg, float mix, output color4 out) -{ - out = mix * overlay(fg, bg) + (1-mix) * bg; -} diff --git a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx index 1ba22ef6a3..42828ce641 100644 --- a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -561,11 +561,6 @@ - - - - - diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index bb5e8edd1f..3f187e2be1 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -3343,8 +3343,8 @@ diff --git a/libraries/stdlib/stdlib_ng.mtlx b/libraries/stdlib/stdlib_ng.mtlx index e031e72412..4983aaa477 100644 --- a/libraries/stdlib/stdlib_ng.mtlx +++ b/libraries/stdlib/stdlib_ng.mtlx @@ -3391,6 +3391,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx b/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx index e7a742c581..b125e70dca 100644 --- a/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx +++ b/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx @@ -183,24 +183,24 @@
- - + + - - + + - - + + diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl index bce4a44ea5..8089feb7f0 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl @@ -2777,66 +2777,6 @@ export color4 mx_screen_color4( return color4(rgb,a); } -float mx_overlay(float mxp_fg, float mxp_bg) -{ - return (mxp_fg < 0.5) ? (2 * mxp_fg * mxp_bg) : (1 - (1 - mxp_fg) * (1 - mxp_bg)); -} -float2 mx_overlay(float2 mxp_fg, float2 mxp_bg) [[ anno::unused() ]] -{ - return float2( - mx_overlay(mxp_fg.x, mxp_bg.x), - mx_overlay(mxp_fg.y, mxp_bg.y) - ); -} -color mx_overlay(color mxp_fg, color mxp_bg) -{ - float3 fg(mxp_fg); - float3 bg(mxp_bg); - return color( - mx_overlay(fg.x, bg.x), - mx_overlay(fg.y, bg.y), - mx_overlay(fg.z, bg.z) - ); -} - -export float mx_overlay_float( - float mxp_fg = 0.0, - float mxp_bg = 0.0, - float mxp_mix = 1.0 -) - [[ - anno::description("Node Group: compositing") - ]] -{ - return mxp_mix * mx_overlay(mxp_fg, mxp_bg) + (1-mxp_mix) * mxp_bg; -} - -export color mx_overlay_color3( - color mxp_fg = color(0.0), - color mxp_bg = color(0.0), - float mxp_mix = 1.0 -) - [[ - anno::description("Node Group: compositing") - ]] -{ - return mxp_mix * mx_overlay(mxp_fg, mxp_bg) + (1-mxp_mix) * mxp_bg; -} - -export color4 mx_overlay_color4( - color4 mxp_fg = mk_color4(0.0, 0.0, 0.0, 0.0), - color4 mxp_bg = mk_color4(0.0, 0.0, 0.0, 0.0), - float mxp_mix = float(1.0) -) - [[ - anno::description("Node Group: compositing") - ]] -{ - color rgb = mxp_mix * mx_overlay(mxp_fg.rgb, mxp_bg.rgb) + (1-mxp_mix) * mxp_bg.rgb; - float a = mxp_mix * mx_overlay(mxp_fg.a , mxp_bg.a ) + (1-mxp_mix) * mxp_bg.a; - return color4(rgb,a); -} - export color4 mx_disjointover_color4( color4 mxp_fg = mk_color4(0.0, 0.0, 0.0, 0.0), color4 mxp_bg = mk_color4(0.0, 0.0, 0.0, 0.0),