diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d5ac9d3f79..1af8012ef0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,19 +25,28 @@ jobs: python: 3.7 cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON - - name: Linux_GCC_11_Python39 - os: ubuntu-20.04 - compiler: gcc - compiler_version: "11" - python: 3.9 - build_javascript: ON - - name: Linux_GCC_12_Python311 os: ubuntu-22.04 compiler: gcc compiler_version: "12" python: 3.11 - upload_shaders: ON + build_javascript: ON + + - name: Linux_GCC_13_Python312 + os: ubuntu-22.04 + compiler: gcc + compiler_version: "13" + python: 3.12 + static_analysis: ON + cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=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 @@ -45,20 +54,19 @@ jobs: compiler_version: "10" python: 3.7 cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON - static_analysis: ON - - name: Linux_Clang_14_Python311 + - name: Linux_Clang_15_Python312 os: ubuntu-22.04 compiler: clang - compiler_version: "14" - python: 3.11 + compiler_version: "15" + python: 3.12 test_render: ON clang_format: ON - - name: Linux_Clang_14_DynamicAnalysis + - name: Linux_Clang_DynamicAnalysis os: ubuntu-22.04 compiler: clang - compiler_version: "14" + compiler_version: "15" python: None cmake_config: -DMATERIALX_DYNAMIC_ANALYSIS=ON dynamic_analysis: ON @@ -70,17 +78,17 @@ jobs: cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON python: 3.7 - - name: MacOS_Xcode_13_Python39 - os: macos-12 - compiler: xcode - compiler_version: "13.4" - python: 3.9 - - name: MacOS_Xcode_14_Python311 os: macos-13 compiler: xcode compiler_version: "14.3" python: 3.11 + + - name: MacOS_Xcode_15_Python312 + os: macos-13 + compiler: xcode + compiler_version: "15.0" + python: 3.12 test_shaders: ON - name: iOS_Xcode_15 @@ -96,18 +104,19 @@ jobs: python: 3.7 cmake_config: -G "Visual Studio 16 2019" -A "Win32" -DMATERIALX_BUILD_SHARED_LIBS=ON - - name: Windows_VS2022_x64_Python39 + - name: Windows_VS2022_x64_Python311 os: windows-2022 architecture: x64 - python: 3.9 + python: 3.11 cmake_config: -G "Visual Studio 17 2022" -A "x64" + test_shaders: ON - - name: Windows_VS2022_x64_Python311 + - name: Windows_VS2022_x64_Python312 os: windows-2022 architecture: x64 - python: 3.11 + python: 3.12 cmake_config: -G "Visual Studio 17 2022" -A "x64" - test_shaders: ON + upload_shaders: ON steps: - name: Sync Repository @@ -120,28 +129,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) @@ -160,6 +173,10 @@ jobs: python-version: ${{ matrix.python }} architecture: ${{ matrix.architecture }} + - name: Install Python Dependencies + if: matrix.python != 'None' + run: pip install setuptools + - name: Install Emscripten if: matrix.build_javascript == 'ON' run: | @@ -178,17 +195,13 @@ jobs: - name: Run Clang Format if: matrix.clang_format == 'ON' - run: find source \( -name *.h -o -name *.cpp -o -name *.mm \) ! -path "*/External/*" ! -path "*/NanoGUI/*" | xargs clang-format -i --verbose + run: find source \( -name *.h -o -name *.cpp -o -name *.mm -o -name *.inl \) ! -path "*/External/*" ! -path "*/NanoGUI/*" | xargs clang-format -i --verbose - name: CMake Generate - run: | - mkdir build - cd build - cmake -DMATERIALX_BUILD_PYTHON=ON -DMATERIALX_BUILD_VIEWER=ON -DMATERIALX_BUILD_GRAPH_EDITOR=ON -DMATERIALX_TEST_RENDER=OFF -DMATERIALX_WARNINGS_AS_ERRORS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ${{matrix.cmake_config}} .. + run: cmake -S . -B build -DMATERIALX_BUILD_PYTHON=ON -DMATERIALX_BUILD_VIEWER=ON -DMATERIALX_BUILD_GRAPH_EDITOR=ON -DMATERIALX_TEST_RENDER=OFF -DMATERIALX_WARNINGS_AS_ERRORS=ON ${{matrix.cmake_config}} - name: CMake Build - run: cmake --build . --target install --config Release --parallel 2 - working-directory: build + run: cmake --build build --target install --config Release --parallel 2 - name: CMake Unit Tests run: ctest -VV --output-on-failure --build-config Release @@ -222,6 +235,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,17 +300,20 @@ 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: | - mkdir javascript/build - cd javascript/build - cmake -DMATERIALX_BUILD_JS=ON -DMATERIALX_EMSDK_PATH=${{ env.EMSDK }} -DMATERIALX_BUILD_RENDER=OFF -DMATERIALX_BUILD_TESTS=OFF -DMATERIALX_BUILD_GEN_OSL=OFF -DMATERIALX_BUILD_GEN_MDL=OFF ../.. + run: cmake -S . -B javascript/build -DMATERIALX_BUILD_JS=ON -DMATERIALX_EMSDK_PATH=${{ env.EMSDK }} - name: JavaScript CMake Build if: matrix.build_javascript == 'ON' - run: cmake --build . --target install --config Release --parallel 2 - working-directory: javascript/build + run: cmake --build javascript/build --target install --config Release --parallel 2 - name: JavaScript Unit Tests if: matrix.build_javascript == 'ON' diff --git a/CMakeLists.txt b/CMakeLists.txt index c255924fa4..c29565a7ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(MATERIALX_BUILD_VERSION 9) set(MATERIALX_LIBRARY_VERSION ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}) # Cmake setup -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.16) set(CMAKE_CXX_STANDARD 14) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) set(CMAKE_MACOSX_RPATH ON) @@ -45,6 +45,7 @@ option(MATERIALX_BUILD_GEN_MSL "Build the MSL shader generator back-end." ON) option(MATERIALX_BUILD_RENDER "Build the MaterialX Render modules." ON) option(MATERIALX_BUILD_OIIO "Build OpenImageIO support for MaterialXRender." OFF) option(MATERIALX_BUILD_TESTS "Build unit tests." ON) +option(MATERIALX_BUILD_BENCHMARK_TESTS "Build benchmark tests." OFF) option(MATERIALX_BUILD_SHARED_LIBS "Build MaterialX libraries as shared rather than static." OFF) option(MATERIALX_PYTHON_LTO "Enable link-time optimizations for MaterialX Python." ON) @@ -52,6 +53,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) @@ -59,13 +61,21 @@ option(MATERIALX_BUILD_IOS "Build MaterialX for iOS." OFF) if (MATERIALX_BUILD_IOS) set(CMAKE_SYSTEM_NAME iOS) add_definitions(-DTARGET_OS_IOS=1) - set(MATERIALX_BUILD_PYTHON OFF) - set(MATERIALX_BUILD_VIEWER OFF) - set(MATERIALX_BUILD_GRAPH_EDITOR OFF) - set(MATERIALX_BUILD_GEN_GLSL OFF) - set(MATERIALX_BUILD_GEN_OSL OFF) - set(MATERIALX_BUILD_GEN_MDL OFF) - set(MATERIALX_BUILD_TESTS OFF) + set(MATERIALX_BUILD_PYTHON OFF) + set(MATERIALX_BUILD_VIEWER OFF) + set(MATERIALX_BUILD_GRAPH_EDITOR OFF) + set(MATERIALX_BUILD_GEN_GLSL OFF) + set(MATERIALX_BUILD_GEN_OSL OFF) + set(MATERIALX_BUILD_GEN_MDL OFF) + set(MATERIALX_BUILD_TESTS OFF) +endif() + +if (MATERIALX_BUILD_JS) + set(MATERIALX_BUILD_GEN_OSL OFF) + set(MATERIALX_BUILD_GEN_MSL OFF) + set(MATERIALX_BUILD_GEN_MDL OFF) + set(MATERIALX_BUILD_RENDER OFF) + set(MATERIALX_BUILD_TESTS OFF) endif() set(MATERIALX_PYTHON_VERSION "" CACHE STRING @@ -79,10 +89,6 @@ set(MATERIALX_PYTHON_PYBIND11_DIR "" CACHE PATH set(MATERIALX_OIIO_DIR "" CACHE PATH "Path to the root folder of the OpenImageIO installation.") -if (MATERIALX_BUILD_JS) - set(MATERIALX_BUILD_GEN_GLSL ON) -endif() - # Settings to define installation layout set(MATERIALX_INSTALL_INCLUDE_PATH "include" CACHE STRING "Install header include path (e.g. 'inc', 'include').") set(MATERIALX_INSTALL_LIB_PATH "lib" CACHE STRING "Install lib path (e.g. 'libs', 'lib').") @@ -130,6 +136,7 @@ mark_as_advanced(MATERIALX_BUILD_GEN_MSL) mark_as_advanced(MATERIALX_BUILD_RENDER) mark_as_advanced(MATERIALX_BUILD_OIIO) mark_as_advanced(MATERIALX_BUILD_TESTS) +mark_as_advanced(MATERIALX_BUILD_BENCHMARK_TESTS) mark_as_advanced(MATERIALX_BUILD_SHARED_LIBS) mark_as_advanced(MATERIALX_NAMESPACE_SUFFIX) mark_as_advanced(MATERIALX_LIBNAME_SUFFIX) @@ -138,6 +145,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) @@ -175,6 +183,9 @@ endif() if(MATERIALX_TEST_RENDER) add_definitions(-DMATERIALX_TEST_RENDER) endif() +if (MATERIALX_BUILD_BENCHMARK_TESTS) + add_definitions(-DMATERIALX_BUILD_BENCHMARK_TESTS) +endif() if (MATERIALX_BUILD_GEN_MDL) add_definitions(-DMATERIALX_MDLC_EXECUTABLE=\"${MATERIALX_MDLC_EXECUTABLE}\") @@ -228,6 +239,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}) @@ -328,14 +343,12 @@ if(MATERIALX_BUILD_JS) add_subdirectory(source/JsMaterialX) endif() -if(${CMAKE_VERSION} VERSION_GREATER "3.6.2") - if(MATERIALX_BUILD_VIEWER) - set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MaterialXView) - elseif(MATERIALX_BUILD_GRAPH_EDITOR) - set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MaterialXGraphEditor) - elseif(MATERIALX_BUILD_TESTS) - set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MaterialXTest) - endif() +if(MATERIALX_BUILD_VIEWER) + set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MaterialXView) +elseif(MATERIALX_BUILD_GRAPH_EDITOR) + set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MaterialXGraphEditor) +elseif(MATERIALX_BUILD_TESTS) + set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MaterialXTest) endif() # Install root-level documents 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..895b4756c5 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 @@ -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 @@ -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/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index ab0d776936..022f0896f1 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -22,22 +22,22 @@ - + - + - + - + - + - + @@ -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_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/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/python/Scripts/baketextures.py b/python/Scripts/baketextures.py index caf2aaed3e..ce132036a6 100644 --- a/python/Scripts/baketextures.py +++ b/python/Scripts/baketextures.py @@ -5,9 +5,8 @@ import sys, os, argparse from sys import platform + import MaterialX as mx -from MaterialX import PyMaterialXGenShader -from MaterialX import PyMaterialXGenGlsl from MaterialX import PyMaterialXRender as mx_render from MaterialX import PyMaterialXRenderGlsl as mx_render_glsl if platform == "darwin": diff --git a/python/Scripts/generateshader.py b/python/Scripts/generateshader.py index 8329f7231e..f6158d270a 100644 --- a/python/Scripts/generateshader.py +++ b/python/Scripts/generateshader.py @@ -5,12 +5,13 @@ ''' import sys, os, argparse, subprocess + import MaterialX as mx -import MaterialX.PyMaterialXGenShader as mx_gen_shader import MaterialX.PyMaterialXGenGlsl as mx_gen_glsl -import MaterialX.PyMaterialXGenOsl as mx_gen_osl import MaterialX.PyMaterialXGenMdl as mx_gen_mdl import MaterialX.PyMaterialXGenMsl as mx_gen_msl +import MaterialX.PyMaterialXGenOsl as mx_gen_osl +import MaterialX.PyMaterialXGenShader as mx_gen_shader def validateCode(sourceCodeFile, codevalidator, codevalidatorArgs): if codevalidator: @@ -24,7 +25,7 @@ def validateCode(sourceCodeFile, codevalidator, codevalidatorArgs): print(cmd_flatten) try: output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - result = output.decode(encoding='utf-8') + return output.decode(encoding='utf-8') except subprocess.CalledProcessError as out: return (out.output.decode(encoding='utf-8')) return "" @@ -82,7 +83,7 @@ def main(): try: mx.loadLibraries(libraryFolders, searchPath, stdlib) doc.importLibrary(stdlib) - except err: + except Exception as err: print('Generation failed: "', err, '"') sys.exit(-1) diff --git a/python/Scripts/genmdl.py b/python/Scripts/genmdl.py index f42add0425..ded1021554 100644 --- a/python/Scripts/genmdl.py +++ b/python/Scripts/genmdl.py @@ -3,9 +3,11 @@ Generate MDL implementation directory based on MaterialX nodedefs ''' -import sys import os -import string; os.environ['PYTHONIOENCODING'] = 'utf-8' +import sys + +os.environ['PYTHONIOENCODING'] = 'utf-8' + import MaterialX as mx def usage(): @@ -345,7 +347,7 @@ def main(): doc = mx.createDocument() searchPath = os.path.join(_startPath, 'libraries') - libraryPath = os.path.join(searchPath, 'stdlib') + libraryPath = os.path.join(searchPath, LIBRARY) _loadLibraries(doc, searchPath, libraryPath) DEFINITION_PREFIX = 'ND_' @@ -522,7 +524,7 @@ def main(): if isinstance(elem, mx.Output): outputValue = elem.getAttribute('default') if outputValue == '[]': - outputvalue = '' + outputValue = '' if not outputValue: outputValue = elem.getAttribute('defaultinput') if outputValue: diff --git a/python/Scripts/mxdoc.py b/python/Scripts/mxdoc.py index 7ee21eb8e5..7c9ba09a07 100644 --- a/python/Scripts/mxdoc.py +++ b/python/Scripts/mxdoc.py @@ -3,7 +3,9 @@ Print markdown documentation for each nodedef in the given document. ''' -import sys, os, argparse +import argparse +import sys + import MaterialX as mx HEADERS = ('Name', 'Type', 'Default Value', diff --git a/python/Scripts/mxformat.py b/python/Scripts/mxformat.py index 8f6ad731e1..0b327883bd 100644 --- a/python/Scripts/mxformat.py +++ b/python/Scripts/mxformat.py @@ -4,7 +4,9 @@ the documents to the latest version of the standard. ''' -import sys, os, argparse +import argparse +import os + import MaterialX as mx def main(): diff --git a/python/Scripts/mxvalidate.py b/python/Scripts/mxvalidate.py index e251b4599b..8b5271e9ed 100755 --- a/python/Scripts/mxvalidate.py +++ b/python/Scripts/mxvalidate.py @@ -3,7 +3,9 @@ Verify that the given file is a valid MaterialX document. ''' -import sys, os, argparse +import argparse +import sys + import MaterialX as mx def main(): @@ -25,7 +27,7 @@ def main(): stdlib = mx.createDocument() try: mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), stdlib) - except err: + except Exception as err: print(err) sys.exit(0) doc.importLibrary(stdlib) diff --git a/python/Scripts/translateshader.py b/python/Scripts/translateshader.py index 71d7a480b5..f7c5686211 100644 --- a/python/Scripts/translateshader.py +++ b/python/Scripts/translateshader.py @@ -5,15 +5,13 @@ ''' import sys, os, argparse -import MaterialX as mx - from sys import platform + +import MaterialX as mx from MaterialX import PyMaterialXGenShader as mx_gen_shader -from MaterialX import PyMaterialXGenGlsl as ms_gen_glsl from MaterialX import PyMaterialXRender as mx_render from MaterialX import PyMaterialXRenderGlsl as mx_render_glsl if platform == "darwin": - from MaterialX import PyMaterialXGenMsl as ms_gen_msl from MaterialX import PyMaterialXRenderMsl as mx_render_msl def main(): 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/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/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/resources/Materials/TestSuite/stdlib/upgrade/1_37_to_1_38.mtlx b/resources/Materials/TestSuite/stdlib/upgrade/1_37_to_1_38.mtlx deleted file mode 100644 index 28b9ae8ad2..0000000000 --- a/resources/Materials/TestSuite/stdlib/upgrade/1_37_to_1_38.mtlx +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/upgrade/1_38_parameter_to_input.mtlx b/resources/Materials/TestSuite/stdlib/upgrade/1_38_parameter_to_input.mtlx deleted file mode 100644 index 220836d354..0000000000 --- a/resources/Materials/TestSuite/stdlib/upgrade/1_38_parameter_to_input.mtlx +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/upgrade/material_element_to_surface_material.mtlx b/resources/Materials/TestSuite/stdlib/upgrade/material_element_to_surface_material.mtlx deleted file mode 100644 index 4979f7a6da..0000000000 --- a/resources/Materials/TestSuite/stdlib/upgrade/material_element_to_surface_material.mtlx +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_22.mtlx b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_22.mtlx new file mode 100644 index 0000000000..a9eff392d3 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_22.mtlx @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/syntax_1_37.mtlx b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx new file mode 100644 index 0000000000..66dc69f668 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index cf9587ecda..c3150e2a87 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -84,7 +84,7 @@ InterfaceElementPtr NodeDef::getImplementation(const string& target) const } } } - + // Then search for a generic match. for (InterfaceElementPtr interface : interfaces) { diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 4ba48cc84b..80143bb9c8 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()); } } @@ -1032,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" }; @@ -1077,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(); @@ -1138,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"); } }; @@ -1169,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"); @@ -1207,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) @@ -1232,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()); } @@ -1277,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"); } } @@ -1298,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); } @@ -1323,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); } @@ -1335,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); } diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 18d028efd3..5131dc8070 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -168,7 +168,7 @@ void Element::setChildIndex(const string& name, int index) return; } - if (index < 0 || index > (int) _childOrder.size()) + if (index < 0 || index >= (int) _childOrder.size()) { throw Exception("Invalid child index"); } diff --git a/source/MaterialXCore/Geom.h b/source/MaterialXCore/Geom.h index c4d7f78060..f008a26419 100644 --- a/source/MaterialXCore/Geom.h +++ b/source/MaterialXCore/Geom.h @@ -90,16 +90,7 @@ class MX_CORE_API GeomPath { return _empty ? EMPTY_STRING : UNIVERSAL_GEOM_NAME; } - string geom; - for (size_t i = 0; i < _vec.size(); i++) - { - geom += _vec[i]; - if (i + 1 < _vec.size()) - { - geom += GEOM_PATH_SEPARATOR; - } - } - return geom; + return GEOM_PATH_SEPARATOR + joinStrings(_vec, GEOM_PATH_SEPARATOR); } /// Return true if there is any geometry in common between the two paths. diff --git a/source/MaterialXCore/Util.cpp b/source/MaterialXCore/Util.cpp index d6001053c5..639b8f343c 100644 --- a/source/MaterialXCore/Util.cpp +++ b/source/MaterialXCore/Util.cpp @@ -24,7 +24,7 @@ const std::tuple LIBRARY_VERSION_TUPLE(MATERIALX_MAJOR_VERSION, bool invalidNameChar(char c) { - return !isalnum(c) && c != '_' && c != ':'; + return !isalnum((unsigned char) c) && c != '_' && c != ':'; } } // anonymous namespace @@ -93,10 +93,10 @@ StringVec splitString(const string& str, const string& sep) string joinStrings(const StringVec& stringVec, const string& sep) { - string res; - for (const string& name : stringVec) + string res = stringVec.empty() ? EMPTY_STRING : stringVec[0]; + for (size_t i = 1; i < stringVec.size(); i++) { - res = res.empty() ? name : res + sep + name; + res += sep + stringVec[i]; } return res; } 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/MaterialXFormat/File.cpp b/source/MaterialXFormat/File.cpp index bb40ba54d1..62b7ec39a8 100644 --- a/source/MaterialXFormat/File.cpp +++ b/source/MaterialXFormat/File.cpp @@ -51,7 +51,7 @@ const string MATERIALX_SEARCH_PATH_ENV_VAR = "MATERIALX_SEARCH_PATH"; inline bool hasWindowsDriveSpecifier(const string& val) { - return (val.length() > 1 && std::isalpha(val[0]) && (val[1] == ':')); + return (val.length() > 1 && std::isalpha((unsigned char) val[0]) && (val[1] == ':')); } // diff --git a/source/MaterialXFormat/Util.cpp b/source/MaterialXFormat/Util.cpp index 32feda4d0d..48ded1d6b1 100644 --- a/source/MaterialXFormat/Util.cpp +++ b/source/MaterialXFormat/Util.cpp @@ -234,7 +234,7 @@ FileSearchPath getDefaultDataSearchPath() } currentPath = currentPath.getParentPath(); } - return FileSearchPath(); + return FileSearchPath(); } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXFormat/Util.h b/source/MaterialXFormat/Util.h index 46f55c41ee..c7ef0c6d38 100644 --- a/source/MaterialXFormat/Util.h +++ b/source/MaterialXFormat/Util.h @@ -62,7 +62,7 @@ MX_FORMAT_API FileSearchPath getSourceSearchPath(ConstDocumentPtr doc); /// Return a file search path to the default data library folder. /// The module path and all parent paths are examined to until either there is -/// no parent or the library folder is found. +/// no parent or the library folder is found. MX_FORMAT_API FileSearchPath getDefaultDataSearchPath(); MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp index 8396a259e6..1af30fd3fd 100644 --- a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp +++ b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -23,9 +22,6 @@ #include #include #include -#include -#include -#include #include #include @@ -34,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -58,17 +56,17 @@ GlslShaderGenerator::GlslShaderGenerator() : // StringVec elementNames; - + // elementNames = { // - "IM_switch_float_" + GlslShaderGenerator::TARGET, - "IM_switch_color3_" + GlslShaderGenerator::TARGET, - "IM_switch_color4_" + GlslShaderGenerator::TARGET, + "IM_switch_float_" + GlslShaderGenerator::TARGET, + "IM_switch_color3_" + GlslShaderGenerator::TARGET, + "IM_switch_color4_" + GlslShaderGenerator::TARGET, "IM_switch_vector2_" + GlslShaderGenerator::TARGET, "IM_switch_vector3_" + GlslShaderGenerator::TARGET, "IM_switch_vector4_" + GlslShaderGenerator::TARGET, - + // "IM_switch_floatI_" + GlslShaderGenerator::TARGET, "IM_switch_color3I_" + GlslShaderGenerator::TARGET, @@ -87,7 +85,7 @@ GlslShaderGenerator::GlslShaderGenerator() : "IM_swizzle_float_vector2_" + GlslShaderGenerator::TARGET, "IM_swizzle_float_vector3_" + GlslShaderGenerator::TARGET, "IM_swizzle_float_vector4_" + GlslShaderGenerator::TARGET, - + // "IM_swizzle_color3_float_" + GlslShaderGenerator::TARGET, "IM_swizzle_color3_color3_" + GlslShaderGenerator::TARGET, @@ -95,7 +93,7 @@ GlslShaderGenerator::GlslShaderGenerator() : "IM_swizzle_color3_vector2_" + GlslShaderGenerator::TARGET, "IM_swizzle_color3_vector3_" + GlslShaderGenerator::TARGET, "IM_swizzle_color3_vector4_" + GlslShaderGenerator::TARGET, - + // "IM_swizzle_color4_float_" + GlslShaderGenerator::TARGET, "IM_swizzle_color4_color3_" + GlslShaderGenerator::TARGET, @@ -103,7 +101,7 @@ GlslShaderGenerator::GlslShaderGenerator() : "IM_swizzle_color4_vector2_" + GlslShaderGenerator::TARGET, "IM_swizzle_color4_vector3_" + GlslShaderGenerator::TARGET, "IM_swizzle_color4_vector4_" + GlslShaderGenerator::TARGET, - + // "IM_swizzle_vector2_float_" + GlslShaderGenerator::TARGET, "IM_swizzle_vector2_color3_" + GlslShaderGenerator::TARGET, @@ -111,7 +109,7 @@ GlslShaderGenerator::GlslShaderGenerator() : "IM_swizzle_vector2_vector2_" + GlslShaderGenerator::TARGET, "IM_swizzle_vector2_vector3_" + GlslShaderGenerator::TARGET, "IM_swizzle_vector2_vector4_" + GlslShaderGenerator::TARGET, - + // "IM_swizzle_vector3_float_" + GlslShaderGenerator::TARGET, "IM_swizzle_vector3_color3_" + GlslShaderGenerator::TARGET, @@ -119,7 +117,7 @@ GlslShaderGenerator::GlslShaderGenerator() : "IM_swizzle_vector3_vector2_" + GlslShaderGenerator::TARGET, "IM_swizzle_vector3_vector3_" + GlslShaderGenerator::TARGET, "IM_swizzle_vector3_vector4_" + GlslShaderGenerator::TARGET, - + // "IM_swizzle_vector4_float_" + GlslShaderGenerator::TARGET, "IM_swizzle_vector4_color3_" + GlslShaderGenerator::TARGET, @@ -174,8 +172,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); @@ -228,13 +226,13 @@ GlslShaderGenerator::GlslShaderGenerator() : registerImplementation(elementNames, BlurNodeGlsl::create); // elementNames = { @@ -279,9 +277,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. @@ -915,11 +911,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 1df2ace543..acc8b0d6ee 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 @@ -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/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/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/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/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index dddf1f2f13..af75a2cef4 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -187,6 +188,14 @@ MdlShaderGenerator::MdlShaderGenerator() : // registerImplementation("IM_sheen_bsdf_" + MdlShaderGenerator::TARGET, LayerableNodeMdl::create); + + // + registerImplementation("IM_image_float_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create); + registerImplementation("IM_image_color3_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create); + registerImplementation("IM_image_color4_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create); + registerImplementation("IM_image_vector2_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create); + registerImplementation("IM_image_vector3_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create); + registerImplementation("IM_image_vector4_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create); } ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, GenContext& context) const @@ -198,6 +207,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); @@ -279,9 +291,9 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G { emitLine("float3 displacement__ = " + result + ".geometry.displacement", stage); emitLine("color finalOutput__ = mk_color3(" - "r: math::dot(displacement__, state::texture_tangent_u(0))," - "g: math::dot(displacement__, state::texture_tangent_v(0))," - "b: math::dot(displacement__, state::normal()))", stage); + "r: math::dot(displacement__, state::texture_tangent_u(0))," + "g: math::dot(displacement__, state::texture_tangent_v(0))," + "b: math::dot(displacement__, state::normal()))", stage); } else { diff --git a/source/MaterialXGenMdl/MdlSyntax.cpp b/source/MaterialXGenMdl/MdlSyntax.cpp index 9d5483bcca..7560297ce4 100644 --- a/source/MaterialXGenMdl/MdlSyntax.cpp +++ b/source/MaterialXGenMdl/MdlSyntax.cpp @@ -48,7 +48,7 @@ class MdlFilenameTypeSyntax : public ScalarTypeSyntax // assuming it ends with a slash ... if (outputValue.back() == '/') { - return getDefaultValue(true); + return getDefaultValue(true); } // ... or the last segment does not have an extension suffix size_t idx_s = outputValue.find_last_of('/'); diff --git a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp index e175696d55..0a2004cd71 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp @@ -41,7 +41,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC { if (!outputSocket->getConnection()) continue; - + const ShaderNode* upstream = outputSocket->getConnection()->getNode(); const bool isMaterialExpr = (upstream->hasClassification(ShaderNode::Classification::CLOSURE) || upstream->hasClassification(ShaderNode::Classification::SHADER)); diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index fd27d5e547..bff1351142 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -368,12 +368,12 @@ const string& MixBsdfNodeMdl::getOperatorName(size_t index) const { switch (index) { - case 0: - return StringConstantsMdl::FG; - case 1: - return StringConstantsMdl::BG; - default: - return StringConstantsMdl::EMPTY; + case 0: + return StringConstantsMdl::FG; + case 1: + return StringConstantsMdl::BG; + default: + return StringConstantsMdl::EMPTY; } } @@ -386,12 +386,12 @@ const string& AddOrMultiplyBsdfNodeMdl::getOperatorName(size_t index) const { switch (index) { - case 0: - return StringConstantsMdl::IN1; - case 1: - return StringConstantsMdl::IN2; - default: - return StringConstantsMdl::EMPTY; + case 0: + return StringConstantsMdl::IN1; + case 1: + return StringConstantsMdl::IN2; + default: + return StringConstantsMdl::EMPTY; } } diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h index 75ea46046c..95c51198f8 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h @@ -21,18 +21,18 @@ class MX_GENMDL_API StringConstantsMdl public: /// String constants - static const string TOP; ///< layer parameter name of the top component + static const string TOP; ///< layer parameter name of the top component static const string BASE; ///< layer parameter name of the base component - static const string FG; ///< parameter of the mix node - static const string BG; ///< parameter of the mix node - static const string IN1; ///< parameter of the add and multiply nodes - static const string IN2; ///< parameter of the add and multiply nodes + static const string FG; ///< parameter of the mix node + static const string BG; ///< parameter of the mix node + static const string IN1; ///< parameter of the add and multiply nodes + static const string IN2; ///< parameter of the add and multiply nodes static const string THICKNESS; ///< thickness parameter name of the thin_film_bsdf - static const string IOR; ///< ior parameter name of the thin_film_bsdf + static const string IOR; ///< ior parameter name of the thin_film_bsdf static const string THIN_FILM_THICKNESS; ///< helper parameter name for transporting thickness - static const string THIN_FILM_IOR; ///< helper parameter name for transporting ior + static const string THIN_FILM_IOR; ///< helper parameter name for transporting ior static const string EMPTY; ///< the empty string "" }; @@ -41,7 +41,7 @@ class MX_GENMDL_API StringConstantsMdl /// thin_film_bsdf through layers and mixers, etc., to the elemental bsdfs that support thin film. /// Because thin-film can not be layered on any BSDF in MDL, we try to push down the parameters to /// the nodes that support thin-film. -template class CarryThinFilmParameters : public TBase +template class CarryThinFilmParameters : public TBase { public: /// Add the thin film inputs for transporting the parameter. diff --git a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp new file mode 100644 index 0000000000..502711fe01 --- /dev/null +++ b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp @@ -0,0 +1,50 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include +#include + +MATERIALX_NAMESPACE_BEGIN + +const string ImageNodeMdl::FLIP_V = "flip_v"; + +ShaderNodeImplPtr ImageNodeMdl::create() +{ + return std::make_shared(); +} + +void ImageNodeMdl::addInputs(ShaderNode& node, GenContext& context) const +{ + BASE::addInputs(node, context); + node.addInput(ImageNodeMdl::FLIP_V, Type::BOOLEAN)->setUniform(); +} + +bool ImageNodeMdl::isEditable(const ShaderInput& input) const +{ + if (input.getName() == ImageNodeMdl::FLIP_V) + { + return false; + } + return BASE::isEditable(input); +} + +void ImageNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& context, ShaderStage& stage) const +{ + DEFINE_SHADER_STAGE(stage, Stage::PIXEL) + { + ShaderNode& node = const_cast(_node); + ShaderInput* flipUInput = node.getInput(ImageNodeMdl::FLIP_V); + ValuePtr value = TypedValue::createValue(context.getOptions().fileTextureVerticalFlip); + if (flipUInput) + { + flipUInput->setValue(value); + } + BASE::emitFunctionCall(_node, context, stage); + } +} + +MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h new file mode 100644 index 0000000000..fe88b2ce09 --- /dev/null +++ b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h @@ -0,0 +1,34 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef MATERIALX_IMAGENODEMDL_H +#define MATERIALX_IMAGENODEMDL_H + +#include + +#include "SourceCodeNodeMdl.h" + +MATERIALX_NAMESPACE_BEGIN + +/// Image node implementation for MDL +class MX_GENMDL_API ImageNodeMdl : public SourceCodeNodeMdl +{ + using BASE = SourceCodeNodeMdl; + + public: + static const string FLIP_V; ///< the empty string "" + + static ShaderNodeImplPtr create(); + + void addInputs(ShaderNode& node, GenContext& context) const override; + + bool isEditable(const ShaderInput& input) const override; + + void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; +}; + +MATERIALX_NAMESPACE_END + +#endif diff --git a/source/MaterialXGenMdl/mdl/materialx/hsv.mdl b/source/MaterialXGenMdl/mdl/materialx/hsv.mdl index 888d4ada86..9adb1505cb 100644 --- a/source/MaterialXGenMdl/mdl/materialx/hsv.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/hsv.mdl @@ -25,16 +25,16 @@ import ::limits::*; export float3 mx_hsvtorgb(float3 hsv) { // from "Color Imaging, Fundamentals and Applications", Reinhard et al., p. 442 - // A hue of 1.0 is questionably valid, and needs to be interpreted as 0.0f - float h_prime = (hsv.x < 1.0f) ? hsv.x * 6.0f : 0.0f; // H * 360.0/60.0 - float h_floor = math::floor(h_prime); - float f = h_prime - h_floor; + float h = 6.0 * (hsv.x - math::floor(hsv.x)); + int hi = int(h); // truncate + float f = h - float(hi); + float zy = hsv.z*hsv.y; float a = hsv.z - zy; float b = hsv.z - zy*f; float c = a + zy*f; - switch(int(h_floor)) { + switch(hi) { default: // hue out of [0,1] range... // fall through... diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl index bce4a44ea5..4ba4f0875a 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl @@ -139,6 +139,11 @@ export float mx_image_float( anno::description("Enumeration {constant,clamp,periodic,mirror}."), anno::display_name("Frame End Action"), anno::unused() + ]], + uniform bool mxp_flip_v = false + [[ + anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."), + anno::hidden() ]] ) [[ @@ -153,7 +158,9 @@ export float mx_image_float( return mxp_default; float returnValue = ::tex::lookup_float(tex: mxp_file, - coord: mxp_texcoord, + coord: mxp_flip_v + ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) + : mxp_texcoord, wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -207,6 +214,11 @@ export color mx_image_color3( anno::description("Enumeration {constant,clamp,periodic,mirror}."), anno::display_name("Frame End Action"), anno::unused() + ]], + uniform bool mxp_flip_v = false + [[ + anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."), + anno::hidden() ]] ) [[ @@ -221,7 +233,9 @@ export color mx_image_color3( return mxp_default; color returnValue = ::tex::lookup_color(tex: mxp_file, - coord: mxp_texcoord, + coord: mxp_flip_v + ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) + : mxp_texcoord, wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -275,6 +289,11 @@ export color4 mx_image_color4( anno::description("Enumeration {constant,clamp,periodic,mirror}."), anno::display_name("Frame End Action"), anno::unused() + ]], + uniform bool mxp_flip_v = false + [[ + anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."), + anno::hidden() ]] ) [[ @@ -289,7 +308,9 @@ export color4 mx_image_color4( return mxp_default; color4 returnValue = mk_color4( ::tex::lookup_float4(tex: mxp_file, - coord: mxp_texcoord, + coord: mxp_flip_v + ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) + : mxp_texcoord, wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode))); return returnValue; @@ -343,6 +364,11 @@ export float2 mx_image_vector2( anno::description("Enumeration {constant,clamp,periodic,mirror}."), anno::display_name("Frame End Action"), anno::unused() + ]], + uniform bool mxp_flip_v = false + [[ + anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."), + anno::hidden() ]] ) [[ @@ -357,7 +383,9 @@ export float2 mx_image_vector2( return mxp_default; float2 returnValue = ::tex::lookup_float2(tex: mxp_file, - coord: mxp_texcoord, + coord: mxp_flip_v + ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) + : mxp_texcoord, wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -411,6 +439,11 @@ export float3 mx_image_vector3( anno::description("Enumeration {constant,clamp,periodic,mirror}."), anno::display_name("Frame End Action"), anno::unused() + ]], + uniform bool mxp_flip_v = false + [[ + anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."), + anno::hidden() ]] ) [[ @@ -425,7 +458,9 @@ export float3 mx_image_vector3( return mxp_default; float3 returnValue = ::tex::lookup_float3(tex: mxp_file, - coord: mxp_texcoord, + coord: mxp_flip_v + ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) + : mxp_texcoord, wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -479,6 +514,11 @@ export float4 mx_image_vector4( anno::description("Enumeration {constant,clamp,periodic,mirror}."), anno::display_name("Frame End Action"), anno::unused() + ]], + uniform bool mxp_flip_v = false + [[ + anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."), + anno::hidden() ]] ) [[ @@ -493,7 +533,9 @@ export float4 mx_image_vector4( return mxp_default; float4 returnValue = ::tex::lookup_float4(tex: mxp_file, - coord: mxp_texcoord, + coord: mxp_flip_v + ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) + : mxp_texcoord, wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -2777,66 +2819,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), diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index 29eac785eb..1939e2a6da 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -23,9 +22,6 @@ #include #include #include -#include -#include -#include #include #include @@ -34,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -178,8 +176,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); @@ -232,13 +230,13 @@ MslShaderGenerator::MslShaderGenerator() : registerImplementation(elementNames, BlurNodeMsl::create); // elementNames = { @@ -283,9 +281,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. @@ -1022,7 +1018,7 @@ void MslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& co emitLightData(context, stage); } } - + bool needsLightBuffer = lighting && context.getOptions().hwMaxActiveLightSources > 0; emitMathMatrixScalarMathOperators(context, stage); @@ -1417,11 +1413,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 ecbf37d7a6..21817db735 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 @@ -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/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; 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/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/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index b4edbee44b..f16770174b 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,15 +160,15 @@ 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 { 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); @@ -295,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); @@ -490,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 = + static const std::unordered_map GEOMPROP_DEFINITIONS = { - { 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 = - { - 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. - // + emitLineBegin(stage); + emitString(type + " " + input->getVariable(), stage); - auto widgetMetadataIt = UI_WIDGET_METADATA.find(input->getType()); - const ShaderMetadata* widgetMetadata = widgetMetadataIt != UI_WIDGET_METADATA.end() ? &widgetMetadataIt->second : nullptr; - const ShaderMetadataVecPtr& metadata = input->getMetadata(); - - 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()) @@ -619,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 91690adc1d..e5cf13977e 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; @@ -62,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 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); } diff --git a/source/MaterialXGenShader/HwShaderGenerator.cpp b/source/MaterialXGenShader/HwShaderGenerator.cpp index bb87cdff46..229c528ce4 100644 --- a/source/MaterialXGenShader/HwShaderGenerator.cpp +++ b/source/MaterialXGenShader/HwShaderGenerator.cpp @@ -263,9 +263,9 @@ ShaderPtr HwShaderGenerator::createShader(const string& name, ElementPtr element if (geomprop) { // A default geomprop was assigned to this graph input. - // For all internal connections to this input, break the connection + // For all internal connections to this input, break the connection // and assign a geomprop node that generates this data. - // Note: If a geomprop node exists already it is reused, + // Note: If a geomprop node exists already it is reused, // so only a single node per geometry type is created. ShaderInputVec connections = socket->getConnections(); for (auto connection : connections) diff --git a/source/MaterialXGenShader/HwShaderGenerator.h b/source/MaterialXGenShader/HwShaderGenerator.h index 5ac05ad542..efe3781952 100644 --- a/source/MaterialXGenShader/HwShaderGenerator.h +++ b/source/MaterialXGenShader/HwShaderGenerator.h @@ -308,6 +308,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/Nodes/HwTransformNode.cpp b/source/MaterialXGenShader/Nodes/HwTransformNode.cpp new file mode 100644 index 0000000000..76394309af --- /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/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index 177201a9e3..d5f51aed1c 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -270,7 +270,7 @@ void ShaderGenerator::registerImplementation(const string& name, CreatorFunction void ShaderGenerator::registerImplementation(const StringVec& nameVec, CreatorFunction creator) { - for(const string& name : nameVec) + for (const string& name : nameVec) { _implFactory.registerClass(name, creator); } diff --git a/source/MaterialXGenShader/ShaderGenerator.h b/source/MaterialXGenShader/ShaderGenerator.h index 8e7f9855de..fa60a4d63e 100644 --- a/source/MaterialXGenShader/ShaderGenerator.h +++ b/source/MaterialXGenShader/ShaderGenerator.h @@ -151,7 +151,7 @@ class MX_GENSHADER_API ShaderGenerator /// Register a shader node implementation for a given implementation element name void registerImplementation(const string& name, CreatorFunction creator); - + /// Register a shader node implementation for a given set of implementation element names void registerImplementation(const StringVec& nameVec, CreatorFunction creator); diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index 04551cb6d2..9ef5b0789a 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 // @@ -285,7 +290,7 @@ ShaderNodePtr ShaderNode::create(const ShaderGraph* parent, const string& name, else if (nodeDef.getNodeString() == CONSTANT) { newNode->_classification = Classification::TEXTURE | Classification::CONSTANT; - } + } else if (nodeDef.getNodeString() == DOT) { newNode->_classification = Classification::TEXTURE | Classification::DOT; 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_thissecond->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 diff --git a/source/MaterialXGraphEditor/CMakeLists.txt b/source/MaterialXGraphEditor/CMakeLists.txt index 1785540bd8..f5f22be2c5 100644 --- a/source/MaterialXGraphEditor/CMakeLists.txt +++ b/source/MaterialXGraphEditor/CMakeLists.txt @@ -9,7 +9,7 @@ if (NOT IS_DIRECTORY "${DEAR_IMGUI_PREFIX}/backends") endif() if(MSVC) - add_compile_options(-wd4100) + add_compile_options(-wd4100 -wd4152 -wd4201 -wd4244 -wd4456) elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wno-unused -Wno-deprecated -Wno-comment -Wno-unused-variable) elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 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) diff --git a/source/MaterialXGraphEditor/FileDialog.h b/source/MaterialXGraphEditor/FileDialog.h index 49b905f28c..4b6c042ef8 100644 --- a/source/MaterialXGraphEditor/FileDialog.h +++ b/source/MaterialXGraphEditor/FileDialog.h @@ -16,9 +16,9 @@ class FileDialog public: enum Flags { - SelectDirectory = 1 << 0, // select directory instead of regular file - EnterNewFilename = 1 << 1, // allow user to enter new filename when selecting regular file - NoTitleBar = 1 << 2, // hide window title bar + SelectDirectory = 1 << 0, // select directory instead of regular file + EnterNewFilename = 1 << 1, // allow user to enter new filename when selecting regular file + NoTitleBar = 1 << 2, // hide window title bar }; public: diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 2b28317ee2..fc682e8f05 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) { @@ -214,7 +240,7 @@ mx::DocumentPtr Graph::loadDocument(mx::FilePath filename) std::cerr << "*** Validation warnings for " << filename.asString() << " ***" << std::endl; std::cerr << message << std::endl; } - + // Cache the currently loaded file _materialFilename = filename; } @@ -236,9 +262,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 +275,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) @@ -846,7 +867,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) @@ -1224,20 +1245,37 @@ 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()) + + 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 = NODE_GROUP_ORDER.back(); } - 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 : NODE_GROUP_ORDER) + { + 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(); @@ -2064,11 +2102,11 @@ mx::InputPtr Graph::findInput(mx::InputPtr nodeInput, const std::string& name) { if (_isNodeGraph) { - for (UiNodePtr node : _graphNodes) + for (UiNodePtr uiNode : _graphNodes) { - if (node->getNode()) + if (uiNode->getNode()) { - for (mx::InputPtr input : node->getNode()->getActiveInputs()) + for (mx::InputPtr input : uiNode->getNode()->getActiveInputs()) { if (input->getInterfaceInput()) { @@ -2219,6 +2257,7 @@ std::vector Graph::createNodes(bool nodegraph) } upUiNode->outputPins[pinIndex]->addConnection(pin); + pin->addConnection(upUiNode->outputPins[pinIndex]); } pin->setConnected(true); } @@ -2284,6 +2323,7 @@ std::vector Graph::createNodes(bool nodegraph) } } upUiNode->outputPins[pinIndex]->addConnection(pin); + pin->addConnection(upUiNode->outputPins[pinIndex]); } pin->setConnected(true); } @@ -2354,6 +2394,7 @@ std::vector Graph::createNodes(bool nodegraph) } } upUiNode->outputPins[pinIndex]->addConnection(pin); + pin->addConnection(upUiNode->outputPins[pinIndex]); } } @@ -2483,12 +2524,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) { @@ -2496,7 +2547,7 @@ void Graph::addLink(ed::PinId inputPinId, ed::PinId outputPinId) return; } - // Perform type check + // Perform type check bool typesMatch = (outputPin->_type == inputPin->_type); if (!typesMatch) { @@ -2505,187 +2556,207 @@ 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); + + inputPin->addConnection(outputPin); + outputPin->addConnection(inputPin); + outputPin->setConnected(true); + inputPin->setConnected(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 + { + 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; + 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 + // 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 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) @@ -2739,9 +2810,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 @@ -2766,6 +2841,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); @@ -2780,6 +2859,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); } } @@ -3009,7 +3092,7 @@ void Graph::loadGraphFromFile(bool prompt) _fileDialog.open(); } else - { + { _graphDoc = loadDocument(_materialFilename); // Rebuild the UI @@ -3020,7 +3103,7 @@ void Graph::loadGraphFromFile(bool prompt) _renderer->setDocument(_graphDoc); _renderer->updateMaterials(nullptr); - } + } } void Graph::saveGraphToFile() @@ -3157,13 +3240,27 @@ void Graph::graphButtons() // Create two windows using splitter float paneWidth = (leftPaneWidth - 2.0f); - ImGui::BeginChild("Selection", ImVec2(paneWidth, 0)); + + float aspectRatio = _renderer->getPixelRatio(); + ImVec2 screenSize = ImVec2(paneWidth, paneWidth / aspectRatio); + + ImVec2 mousePos = ImGui::GetMousePos(); + ImVec2 tempWindowPos = ImGui::GetCursorPos(); + bool cursorInRenderView = mousePos.x > tempWindowPos.x && mousePos.x < (tempWindowPos.x + screenSize.x) && + mousePos.y > tempWindowPos.y && mousePos.y < (tempWindowPos.y + screenSize.y); + + ImGuiWindowFlags windowFlags = 0; + + if (cursorInRenderView) + { + windowFlags |= ImGuiWindowFlags_NoScrollWithMouse; + } + + ImGui::BeginChild("Selection", ImVec2(paneWidth, 0), false, windowFlags); ImVec2 windowPos = ImGui::GetWindowPos(); // RenderView window ImVec2 wsize = ImVec2((float) _renderer->getViewWidth(), (float) _renderer->getViewHeight()); - float aspectRatio = _renderer->getPixelRatio(); - ImVec2 screenSize = ImVec2(paneWidth, paneWidth / aspectRatio); _renderer->setViewWidth((int) screenSize[0]); _renderer->setViewHeight((int) screenSize[1]); @@ -3183,7 +3280,10 @@ void Graph::graphButtons() ImGui::EndChild(); ImGui::SameLine(0.0f, 12.0f); - handleRenderViewInputs(windowPos, screenSize[0], screenSize[1]); + if (cursorInRenderView) + { + handleRenderViewInputs(); + } } void Graph::propertyEditor() @@ -3205,16 +3305,16 @@ void Graph::propertyEditor() std::string name = _currUiNode->getNode()->getParent()->createValidChildName(temp); std::vector downstreamNodes = _currUiNode->getOutputConnections(); - for (UiNodePtr nodes : downstreamNodes) + for (UiNodePtr uiNode : downstreamNodes) { - if (nodes->getInput() == nullptr) + if (!uiNode->getInput() && uiNode->getNode()) { - for (mx::InputPtr input : nodes->getNode()->getActiveInputs()) + for (mx::InputPtr input : uiNode->getNode()->getActiveInputs()) { if (input->getConnectedNode() == _currUiNode->getNode()) { _currUiNode->getNode()->setName(name); - nodes->getNode()->setConnectedNode(input->getName(), _currUiNode->getNode()); + uiNode->getNode()->setConnectedNode(input->getName(), _currUiNode->getNode()); } } } @@ -3229,13 +3329,13 @@ void Graph::propertyEditor() { std::string name = _currUiNode->getInput()->getParent()->createValidChildName(temp); std::vector downstreamNodes = _currUiNode->getOutputConnections(); - for (UiNodePtr nodes : downstreamNodes) + for (UiNodePtr uiNode : downstreamNodes) { - if (nodes->getInput() == nullptr) + if (uiNode->getInput() == nullptr) { - if (nodes->getNode()) + if (uiNode->getNode()) { - for (mx::InputPtr input : nodes->getNode()->getActiveInputs()) + for (mx::InputPtr input : uiNode->getNode()->getActiveInputs()) { if (input->getInterfaceInput() == _currUiNode->getInput()) { @@ -3248,7 +3348,7 @@ void Graph::propertyEditor() } else { - nodes->getOutput()->setConnectedNode(_currUiNode->getNode()); + uiNode->getOutput()->setConnectedNode(_currUiNode->getNode()); } } } @@ -3566,96 +3666,65 @@ 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(); } } @@ -3707,6 +3776,41 @@ 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) + { + mx::StringVec connectedNames; + for (UiPinPtr connectedPin : pin->getConnections()) + { + connectedNames.push_back(connectedPin->_name); + } + connected = "\nConnected to " + mx::joinStrings(connectedNames, ", "); + } + else if (pin->_input) + { + 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) @@ -3741,55 +3845,52 @@ void Graph::shaderPopup() } } -void Graph::handleRenderViewInputs(ImVec2 minValue, float width, float height) +void Graph::handleRenderViewInputs() { ImVec2 mousePos = ImGui::GetMousePos(); - if (mousePos.x > minValue.x && mousePos.x < (minValue.x + width) && mousePos.y > minValue.y && mousePos.y < (minValue.y + height)) + mx::Vector2 mxMousePos = mx::Vector2(mousePos.x, mousePos.y); + float scrollAmt = ImGui::GetIO().MouseWheel; + int button = -1; + bool down = false; + if (ImGui::IsMouseDragging(0) || ImGui::IsMouseDragging(1)) { - mx::Vector2 mxMousePos = mx::Vector2(mousePos.x, mousePos.y); - float scrollAmt = ImGui::GetIO().MouseWheel; - int button = -1; - bool down = false; - if (ImGui::IsMouseDragging(0) || ImGui::IsMouseDragging(1)) - { - _renderer->setMouseMotionEvent(mxMousePos); - } - if (ImGui::IsMouseClicked(0)) - { - button = 0; - down = true; - _renderer->setMouseButtonEvent(button, down, mxMousePos); - } - else if (ImGui::IsMouseClicked(1)) - { - button = 1; - down = true; - _renderer->setMouseButtonEvent(button, down, mxMousePos); - } - else if (ImGui::IsMouseReleased(0)) - { - button = 0; - _renderer->setMouseButtonEvent(button, down, mxMousePos); - } - else if (ImGui::IsMouseReleased(1)) - { - button = 1; - _renderer->setMouseButtonEvent(button, down, mxMousePos); - } - else if (ImGui::IsKeyPressed(ImGuiKey_KeypadAdd)) - { - _renderer->setKeyEvent(ImGuiKey_KeypadAdd); - } - else if (ImGui::IsKeyPressed(ImGuiKey_KeypadSubtract)) - { - _renderer->setKeyEvent(ImGuiKey_KeypadSubtract); - } + _renderer->setMouseMotionEvent(mxMousePos); + } + if (ImGui::IsMouseClicked(0)) + { + button = 0; + down = true; + _renderer->setMouseButtonEvent(button, down, mxMousePos); + } + else if (ImGui::IsMouseClicked(1)) + { + button = 1; + down = true; + _renderer->setMouseButtonEvent(button, down, mxMousePos); + } + else if (ImGui::IsMouseReleased(0)) + { + button = 0; + _renderer->setMouseButtonEvent(button, down, mxMousePos); + } + else if (ImGui::IsMouseReleased(1)) + { + button = 1; + _renderer->setMouseButtonEvent(button, down, mxMousePos); + } + else if (ImGui::IsKeyPressed(ImGuiKey_KeypadAdd)) + { + _renderer->setKeyEvent(ImGuiKey_KeypadAdd); + } + else if (ImGui::IsKeyPressed(ImGuiKey_KeypadSubtract)) + { + _renderer->setKeyEvent(ImGuiKey_KeypadSubtract); + } - // Scrolling not possible if open or save file dialog is open - if (scrollAmt != 0 && !_fileDialogSave.isOpened() && !_fileDialog.isOpened() && !_fileDialogGeom.isOpened()) - { - _renderer->setScrollEvent(scrollAmt); - } + // Scrolling not possible if open or save file dialog is open + if (scrollAmt != 0 && !_fileDialogSave.isOpened() && !_fileDialog.isOpened() && !_fileDialogGeom.isOpened()) + { + _renderer->setScrollEvent(scrollAmt); } } @@ -3823,6 +3924,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(); @@ -4045,12 +4147,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..821ecf71fd 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; @@ -90,7 +114,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 @@ -187,6 +213,8 @@ class Graph void addNodePopup(bool cursor); void searchNodePopup(bool cursor); + bool isPinHovered(); + void addPinPopup(); bool readOnly(); void readOnlyPopup(); @@ -197,7 +225,7 @@ class Graph void selectMaterial(UiNodePtr node); // Allow for camera manipulation of render view window - void handleRenderViewInputs(ImVec2 minValue, float width, float height); + void handleRenderViewInputs(); // Set the node to display in render view based on selected node or nodegraph void setRenderMaterial(UiNodePtr node); @@ -246,8 +274,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; 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(); diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index 176014ba65..3c2e01dff9 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()) { @@ -319,7 +299,7 @@ void RenderView::loadMesh(const mx::FilePath& filename) _cameraTarget = mx::Vector3(); initCamera(); - + if (_shadowMap) { _imageHandler->releaseRenderResources(_shadowMap); @@ -868,7 +848,7 @@ void RenderView::initCamera() { _viewCamera->setViewportSize(mx::Vector2((float) _viewWidth, (float) _viewHeight)); - if ( _geometryHandler->getMeshes().empty()) + if (_geometryHandler->getMeshes().empty()) { return; } diff --git a/source/MaterialXGraphEditor/UiNode.h b/source/MaterialXGraphEditor/UiNode.h index c03ae43219..06d0281676 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; diff --git a/source/MaterialXRender/Camera.cpp b/source/MaterialXRender/Camera.cpp index 6464246e3a..7b9579376c 100644 --- a/source/MaterialXRender/Camera.cpp +++ b/source/MaterialXRender/Camera.cpp @@ -23,8 +23,8 @@ Matrix44 Camera::createViewMatrix(const Vector3& eye, } Matrix44 Camera::createPerspectiveMatrixZP(float left, float right, - float bottom, float top, - float nearP, float farP) + float bottom, float top, + float nearP, float farP) { return Matrix44( (2.0f * nearP) / (right - left), 0.0f, (right + left) / (right - left), 0.0f, @@ -34,8 +34,8 @@ Matrix44 Camera::createPerspectiveMatrixZP(float left, float right, } Matrix44 Camera::createOrthographicMatrixZP(float left, float right, - float bottom, float top, - float nearP, float farP) + float bottom, float top, + float nearP, float farP) { return Matrix44( 2.0f / (right - left), 0.0f, 0.0f, 0.0f, diff --git a/source/MaterialXRender/Camera.h b/source/MaterialXRender/Camera.h index a20c0f0e70..3135904b5a 100644 --- a/source/MaterialXRender/Camera.h +++ b/source/MaterialXRender/Camera.h @@ -163,17 +163,17 @@ class MX_RENDER_API Camera static Matrix44 createOrthographicMatrix(float left, float right, float bottom, float top, float nearP, float farP); - + /// Create a perpective projection matrix given a set of clip planes with [0,1] projected Z. static Matrix44 createPerspectiveMatrixZP(float left, float right, - float bottom, float top, - float nearP, float farP); + float bottom, float top, + float nearP, float farP); /// Create an orthographic projection matrix given a set of clip planes with [0,1] projected Z. static Matrix44 createOrthographicMatrixZP(float left, float right, - float bottom, float top, - float nearP, float farP); - + float bottom, float top, + float nearP, float farP); + /// Apply a perspective transform to the given 3D point, performing a /// homogeneous divide on the transformed result. static Vector3 transformPointPerspective(const Matrix44& m, const Vector3& v) @@ -185,7 +185,7 @@ class MX_RENDER_API Camera /// @} protected: - // Transform matrices + // Transform matrices Matrix44 _worldMatrix; Matrix44 _viewMatrix; Matrix44 _projectionMatrix; diff --git a/source/MaterialXRender/CgltfLoader.cpp b/source/MaterialXRender/CgltfLoader.cpp index 1c8ec598a6..fcc8831732 100644 --- a/source/MaterialXRender/CgltfLoader.cpp +++ b/source/MaterialXRender/CgltfLoader.cpp @@ -59,7 +59,7 @@ void computeMeshMatrices(GLTFMeshMatrixList& meshMatrices, cgltf_node* cnode) } // Iterate over all children. Note that the existence of a mesh - // does not imply that this is a leaf node so traversal should + // does not imply that this is a leaf node so traversal should // continue even when a mesh is encountered. for (cgltf_size i = 0; i < cnode->children_count; i++) { @@ -76,7 +76,7 @@ using GLTFMeshPathList = std::unordered_map; void computeMeshPaths(GLTFMeshPathList& meshPaths, cgltf_node* cnode, FilePath path, size_t nodeCount, size_t meshCount) { string cnodeName = cnode->name ? string(cnode->name) : DEFAULT_NODE_PREFIX + std::to_string(nodeCount++); - path = path / ( createValidName(cnodeName) + "/" ); + path = path / (createValidName(cnodeName) + "/"); cgltf_mesh* cmesh = cnode->mesh; if (cmesh) @@ -92,7 +92,7 @@ void computeMeshPaths(GLTFMeshPathList& meshPaths, cgltf_node* cnode, FilePath p } // Iterate over all children. Note that the existence of a mesh - // does not imply that this is a leaf node so traversal should + // does not imply that this is a leaf node so traversal should // continue even when a mesh is encountered. for (cgltf_size i = 0; i < cnode->children_count; i++) { @@ -220,11 +220,11 @@ bool CgltfLoader::load(const FilePath& filePath, MeshList& meshList, bool texcoo } // Iterate through all parent transform - for (size_t mtx=0; mtx < positionMatrices.size(); mtx++) + for (size_t mtx = 0; mtx < positionMatrices.size(); mtx++) { const Matrix44& positionMatrix = positionMatrices[mtx]; const Matrix44 normalMatrix = positionMatrix.getInverse().getTranspose(); - + for (cgltf_size primitiveIndex = 0; primitiveIndex < cmesh->primitives_count; ++primitiveIndex) { cgltf_primitive* primitive = &cmesh->primitives[primitiveIndex]; @@ -347,8 +347,7 @@ bool CgltfLoader::load(const FilePath& filePath, MeshList& meshList, bool texcoo else { if (_debugLevel > 0) - std::cout << "Unknown stream type: " << std::to_string(attribute->type) - << std::endl; + std::cout << "Unknown stream type: " << std::to_string(attribute->type) << std::endl; } // Fill in stream diff --git a/source/MaterialXRender/CgltfLoader.h b/source/MaterialXRender/CgltfLoader.h index 4f4a7145ba..fb63cb6102 100644 --- a/source/MaterialXRender/CgltfLoader.h +++ b/source/MaterialXRender/CgltfLoader.h @@ -6,7 +6,7 @@ #ifndef MATERIALX_CGLTFLOADER_H #define MATERIALX_CGLTFLOADER_H -/// @file +/// @file /// GLTF format loader using the Cgltf library #include @@ -32,7 +32,7 @@ class MX_RENDER_API CgltfLoader : public GeometryLoader static CgltfLoaderPtr create() { return std::make_shared(); } /// Load geometry from file path - bool load(const FilePath& filePath, MeshList& meshList, bool texcoordVerticalFlip=false) override; + bool load(const FilePath& filePath, MeshList& meshList, bool texcoordVerticalFlip = false) override; private: unsigned int _debugLevel; diff --git a/source/MaterialXRender/GeometryHandler.cpp b/source/MaterialXRender/GeometryHandler.cpp index e2c974a767..dfea0b2ceb 100644 --- a/source/MaterialXRender/GeometryHandler.cpp +++ b/source/MaterialXRender/GeometryHandler.cpp @@ -89,7 +89,7 @@ bool GeometryHandler::loadGeometry(const FilePath& filePath, bool texcoordVertic bool loaded = false; - std::pair range; + std::pair range; string extension = filePath.getExtension(); range = _geometryLoaders.equal_range(extension); GeometryLoaderMap::iterator first = --range.second; @@ -140,19 +140,17 @@ MeshPtr GeometryHandler::createQuadMesh(const Vector2& uvMin, const Vector2& uvM quadTexCoords->setStride(MeshStream::STRIDE_2D); if (!flipTexCoordsHorizontally) { - quadTexCoords->getData().assign({ - uvMax[0], uvMax[1], - uvMax[0], uvMin[1], - uvMin[0], uvMin[1], - uvMin[0], uvMax[1] }); + quadTexCoords->getData().assign({ uvMax[0], uvMax[1], + uvMax[0], uvMin[1], + uvMin[0], uvMin[1], + uvMin[0], uvMax[1] }); } else { - quadTexCoords->getData().assign({ - uvMax[0], uvMin[1], - uvMax[0], uvMax[1], - uvMin[0], uvMax[1], - uvMin[0], uvMin[1] }); + quadTexCoords->getData().assign({ uvMax[0], uvMin[1], + uvMax[0], uvMax[1], + uvMin[0], uvMax[1], + uvMin[0], uvMin[1] }); } MeshPartitionPtr quadIndices = MeshPartition::create(); quadIndices->getIndices().assign({ 0, 1, 3, 1, 2, 3 }); @@ -161,7 +159,7 @@ MeshPtr GeometryHandler::createQuadMesh(const Vector2& uvMin, const Vector2& uvM quadMesh->addStream(quadPositions); quadMesh->addStream(quadTexCoords); quadMesh->addPartition(quadIndices); - + return quadMesh; } diff --git a/source/MaterialXRender/GeometryHandler.h b/source/MaterialXRender/GeometryHandler.h index 0022487602..5dfc561e0e 100644 --- a/source/MaterialXRender/GeometryHandler.h +++ b/source/MaterialXRender/GeometryHandler.h @@ -121,7 +121,7 @@ class MX_RENDER_API GeometryHandler static MeshPtr createQuadMesh(const Vector2& uvMin = Vector2(0.0f, 0.0f), const Vector2& uvMax = Vector2(1.0f, 1.0f), bool flipTexCoordsHorizontally = false); - + protected: // Recompute bounds for all stored geometry void computeBounds(); diff --git a/source/MaterialXRender/Harmonics.cpp b/source/MaterialXRender/Harmonics.cpp index daf6a59d10..3d5c9d0a1d 100644 --- a/source/MaterialXRender/Harmonics.cpp +++ b/source/MaterialXRender/Harmonics.cpp @@ -9,7 +9,8 @@ MATERIALX_NAMESPACE_BEGIN -namespace { +namespace +{ const double PI = std::acos(-1.0); diff --git a/source/MaterialXRender/Harmonics.h b/source/MaterialXRender/Harmonics.h index 10d5f81e49..f51991361a 100644 --- a/source/MaterialXRender/Harmonics.h +++ b/source/MaterialXRender/Harmonics.h @@ -27,7 +27,8 @@ template class ShCoeffs public: ShCoeffs() = default; - explicit ShCoeffs(const std::array& arr) : _arr(arr) { } + explicit ShCoeffs(const std::array& arr) : + _arr(arr) { } /// @name Comparison Operators /// @{ diff --git a/source/MaterialXRender/ImageHandler.cpp b/source/MaterialXRender/ImageHandler.cpp index 870e28b009..b148bf63d9 100644 --- a/source/MaterialXRender/ImageHandler.cpp +++ b/source/MaterialXRender/ImageHandler.cpp @@ -306,12 +306,11 @@ void ImageSamplingProperties::setProperties(const string& fileNameUniform, bool ImageSamplingProperties::operator==(const ImageSamplingProperties& r) const { - return - (enableMipmaps == r.enableMipmaps && - uaddressMode == r.uaddressMode && - vaddressMode == r.vaddressMode && - filterType == r.filterType && - defaultColor == r.defaultColor) ; + return (enableMipmaps == r.enableMipmaps && + uaddressMode == r.uaddressMode && + vaddressMode == r.vaddressMode && + filterType == r.filterType && + defaultColor == r.defaultColor); } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXRender/ImageHandler.h b/source/MaterialXRender/ImageHandler.h index f74ce20e2c..ede28a39b8 100644 --- a/source/MaterialXRender/ImageHandler.h +++ b/source/MaterialXRender/ImageHandler.h @@ -35,7 +35,7 @@ using ImageHandlerPtr = std::shared_ptr; using ImageLoaderPtr = std::shared_ptr; /// Map from strings to vectors of image loaders -using ImageLoaderMap = std::unordered_map< string, std::vector >; +using ImageLoaderMap = std::unordered_map>; /// @class ImageSamplingProperties /// Interface to describe sampling properties for images. @@ -48,16 +48,16 @@ class MX_RENDER_API ImageSamplingProperties /// @param uniformBlock Block containing sampler uniforms void setProperties(const string& fileNameUniform, const VariableBlock& uniformBlock); - + bool operator==(const ImageSamplingProperties& r) const; /// Address mode options. Matches enumerations allowed for image address /// modes, except UNSPECIFIED which indicates no explicit mode was defined. enum class AddressMode : int - { + { UNSPECIFIED = -1, CONSTANT = 0, - CLAMP = 1, + CLAMP = 1, PERIODIC = 2, MIRROR = 3 }; diff --git a/source/MaterialXRender/LightHandler.cpp b/source/MaterialXRender/LightHandler.cpp index cc96d979c7..c7d9311005 100644 --- a/source/MaterialXRender/LightHandler.cpp +++ b/source/MaterialXRender/LightHandler.cpp @@ -51,7 +51,7 @@ void LightHandler::findLights(DocumentPtr doc, vector& lights) void LightHandler::registerLights(DocumentPtr doc, const vector& lights, GenContext& context) { - // Clear context light user data which is set when bindLightShader() + // Clear context light user data which is set when bindLightShader() // is called. This is necessary in case the light types have already been // registered. HwShaderGenerator::unbindLightShaders(context); @@ -71,7 +71,7 @@ void LightHandler::registerLights(DocumentPtr doc, const vector& lights } // Make sure max light count is large enough - const unsigned int lightCount = (unsigned int)lights.size(); + const unsigned int lightCount = (unsigned int) lights.size(); if (lightCount > context.getOptions().hwMaxActiveLightSources) { context.getOptions().hwMaxActiveLightSources = lightCount; diff --git a/source/MaterialXRender/LightHandler.h b/source/MaterialXRender/LightHandler.h index 6564ca22c3..ede56af2a5 100644 --- a/source/MaterialXRender/LightHandler.h +++ b/source/MaterialXRender/LightHandler.h @@ -49,7 +49,7 @@ class MX_RENDER_API LightHandler /// @name Global State /// @{ - + /// Set the light transform. void setLightTransform(const Matrix44& mat) { diff --git a/source/MaterialXRender/Mesh.cpp b/source/MaterialXRender/Mesh.cpp index 110829cd21..bfa7dedd13 100644 --- a/source/MaterialXRender/Mesh.cpp +++ b/source/MaterialXRender/Mesh.cpp @@ -18,7 +18,8 @@ const string MeshStream::BITANGENT_ATTRIBUTE("bitangent"); const string MeshStream::COLOR_ATTRIBUTE("color"); const string MeshStream::GEOMETRY_PROPERTY_ATTRIBUTE("geomprop"); -namespace { +namespace +{ const float MAX_FLOAT = std::numeric_limits::max(); const size_t FACE_VERTEX_COUNT = 3; @@ -266,7 +267,7 @@ void Mesh::splitByUdims() // MeshStream methods // -void MeshStream::transform(const Matrix44 &matrix) +void MeshStream::transform(const Matrix44& matrix) { unsigned int stride = getStride(); size_t numElements = _data.size() / getStride(); @@ -274,17 +275,17 @@ void MeshStream::transform(const Matrix44 &matrix) getType() == MeshStream::TEXCOORD_ATTRIBUTE || getType() == MeshStream::GEOMETRY_PROPERTY_ATTRIBUTE) { - for (size_t i=0; i diff --git a/source/MaterialXRender/OiioImageLoader.h b/source/MaterialXRender/OiioImageLoader.h index 6619c85bb2..38781dad9e 100644 --- a/source/MaterialXRender/OiioImageLoader.h +++ b/source/MaterialXRender/OiioImageLoader.h @@ -7,7 +7,7 @@ #define MATERIALX_OIIOIMAGELOADER_H /// @file -/// Image loader wrapper using OpenImageIO +/// Image loader wrapper using OpenImageIO #include @@ -21,7 +21,7 @@ using OiioImageLoaderPtr = std::shared_ptr; class MX_RENDER_API OiioImageLoader : public ImageLoader { public: - OiioImageLoader() + OiioImageLoader() { // Set all extensions supported by OpenImageIO _extensions.insert(BMP_EXTENSION); @@ -40,7 +40,7 @@ class MX_RENDER_API OiioImageLoader : public ImageLoader _extensions.insert(TXT_EXTENSION); _extensions.insert(TXR_EXTENSION); } - virtual ~OiioImageLoader() { } + virtual ~OiioImageLoader() { } /// Create a new OpenImageIO image loader static OiioImageLoaderPtr create() { return std::make_shared(); } diff --git a/source/MaterialXRender/ShaderMaterial.cpp b/source/MaterialXRender/ShaderMaterial.cpp index d51efa54af..4e8ccc491f 100644 --- a/source/MaterialXRender/ShaderMaterial.cpp +++ b/source/MaterialXRender/ShaderMaterial.cpp @@ -8,8 +8,8 @@ MATERIALX_NAMESPACE_BEGIN -ShaderMaterial::ShaderMaterial() : _hasTransparency(false) {} -ShaderMaterial::~ShaderMaterial() {} +ShaderMaterial::ShaderMaterial() : _hasTransparency(false) { } +ShaderMaterial::~ShaderMaterial() { } void ShaderMaterial::setDocument(DocumentPtr doc) { @@ -62,9 +62,9 @@ bool ShaderMaterial::hasTransparency() const } bool ShaderMaterial::generateEnvironmentShader(GenContext& context, - const FilePath& filename, - DocumentPtr stdLib, - const FilePath& imagePath) + const FilePath& filename, + DocumentPtr stdLib, + const FilePath& imagePath) { // Read in the environment nodegraph. DocumentPtr doc = createDocument(); diff --git a/source/MaterialXRender/ShaderMaterial.h b/source/MaterialXRender/ShaderMaterial.h index cf500463e4..f29b6f763c 100644 --- a/source/MaterialXRender/ShaderMaterial.h +++ b/source/MaterialXRender/ShaderMaterial.h @@ -74,7 +74,7 @@ class MX_RENDER_API ShaderMaterial /// Generate a shader from our currently stored element and /// the given generator context. virtual bool generateShader(GenContext& context) = 0; - + /// Copies shader and API specific generated program from ShaderMaterial to this one. virtual void copyShader(MaterialPtr ShaderMaterial) = 0; @@ -86,7 +86,7 @@ class MX_RENDER_API ShaderMaterial const FilePath& filename, DocumentPtr stdLib, const FilePath& imagePath); - + /// Return the underlying hardware shader. ShaderPtr getShader() const; diff --git a/source/MaterialXRender/ShaderRenderer.h b/source/MaterialXRender/ShaderRenderer.h index c1cfbecfa0..829a0252c1 100644 --- a/source/MaterialXRender/ShaderRenderer.h +++ b/source/MaterialXRender/ShaderRenderer.h @@ -34,7 +34,7 @@ class MX_RENDER_API ShaderRenderer enum class MatrixConvention { OpenGL = 0, - Metal = 1 + Metal = 1 }; /// A map with name and source code for each shader stage. using StageMap = StringMap; @@ -133,7 +133,7 @@ class MX_RENDER_API ShaderRenderer protected: ShaderRenderer(unsigned int width, unsigned int height, Image::BaseType baseType, - MatrixConvention matrixConvention = MatrixConvention::OpenGL); + MatrixConvention matrixConvention = MatrixConvention::OpenGL); protected: unsigned int _width; @@ -167,7 +167,7 @@ class MX_RENDER_API ExceptionRenderError : public Exception { } - ExceptionRenderError& operator=(const ExceptionRenderError& e) + ExceptionRenderError& operator=(const ExceptionRenderError& e) { Exception::operator=(e); _errorLog = e._errorLog; diff --git a/source/MaterialXRender/StbImageLoader.cpp b/source/MaterialXRender/StbImageLoader.cpp index d8747b75ad..b367bf741c 100644 --- a/source/MaterialXRender/StbImageLoader.cpp +++ b/source/MaterialXRender/StbImageLoader.cpp @@ -7,9 +7,9 @@ #if defined(_MSC_VER) #pragma warning(push) - #pragma warning(disable: 4100) - #pragma warning(disable: 4505) - #pragma warning(disable: 4996) + #pragma warning(disable : 4100) + #pragma warning(disable : 4505) + #pragma warning(disable : 4996) #endif #define STB_IMAGE_IMPLEMENTATION @@ -96,7 +96,7 @@ ImagePtr StbImageLoader::loadImage(const FilePath& filePath) int height = 0; int channelCount = 0; Image::BaseType baseType = Image::BaseType::UINT8; - void *buffer = nullptr; + void* buffer = nullptr; // Select standard or float reader based on file extension. string extension = filePath.getExtension(); diff --git a/source/MaterialXRender/StbImageLoader.h b/source/MaterialXRender/StbImageLoader.h index dabbb8ca9e..f9d91fbcc7 100644 --- a/source/MaterialXRender/StbImageLoader.h +++ b/source/MaterialXRender/StbImageLoader.h @@ -34,7 +34,7 @@ class MX_RENDER_API StbImageLoader : public ImageLoader _extensions.insert(PSD_EXTENSION); _extensions.insert(TGA_EXTENSION); } - virtual ~StbImageLoader() { } + virtual ~StbImageLoader() { } /// Create a new stb image loader static StbImageLoaderPtr create() { return std::make_shared(); } diff --git a/source/MaterialXRender/TextureBaker.h b/source/MaterialXRender/TextureBaker.h index 54b1016451..656bb63c1d 100644 --- a/source/MaterialXRender/TextureBaker.h +++ b/source/MaterialXRender/TextureBaker.h @@ -27,7 +27,7 @@ using BakedDocumentVec = std::vector>; /// A helper class for baking procedural material content to textures. /// TODO: Add support for graphs containing geometric nodes such as position /// and normal. -template +template class TextureBaker : public Renderer { public: @@ -112,7 +112,7 @@ class TextureBaker : public Renderer /// Set the name of the baked graph element. void setBakedGraphName(const string& name) { - _bakedGraphName= name; + _bakedGraphName = name; } /// Return the name of the baked graph element. @@ -218,13 +218,13 @@ class TextureBaker : public Renderer void optimizeBakedTextures(NodePtr shader); /// Bake material to document in memory and write baked textures to disk. - DocumentPtr bakeMaterialToDoc(DocumentPtr doc, const FileSearchPath& searchPath, const string& materialPath, + DocumentPtr bakeMaterialToDoc(DocumentPtr doc, const FileSearchPath& searchPath, const string& materialPath, const StringVec& udimSet, std::string& documentName); /// Bake materials in the given document and write them to disk. If multiple documents are written, /// then the given output filename will be used as a template. void bakeAllMaterials(DocumentPtr doc, const FileSearchPath& searchPath, const FilePath& outputFileName); - + /// Set whether to write a separate document per material when calling bakeAllMaterials. /// By default separate documents are written. void writeDocumentPerMaterial(bool value) @@ -295,7 +295,7 @@ class TextureBaker : public Renderer StringMap _bakedInputMap; std::unordered_map _worldSpaceNodes; - + bool _flipSavedImage; bool _writeDocumentPerMaterial; diff --git a/source/MaterialXRender/TextureBaker.inl b/source/MaterialXRender/TextureBaker.inl index bcc9401210..65759ed998 100644 --- a/source/MaterialXRender/TextureBaker.inl +++ b/source/MaterialXRender/TextureBaker.inl @@ -13,7 +13,8 @@ MATERIALX_NAMESPACE_BEGIN -namespace { +namespace +{ const string SRGB_TEXTURE = "srgb_texture"; const string LIN_REC709 = "lin_rec709"; @@ -23,7 +24,7 @@ const string DEFAULT_UDIM_PREFIX = "_"; } // anonymous namespace -template +template string TextureBaker::getValueStringFromColor(const Color4& color, const string& type) { if (type == "color4" || type == "vector4") @@ -45,7 +46,7 @@ string TextureBaker::getValueStringFromColor(const Color4& return EMPTY_STRING; } -template +template TextureBaker::TextureBaker(unsigned int width, unsigned int height, Image::BaseType baseType, bool flipSavedImage) : Renderer(width, height, baseType), _distanceUnit("meter"), @@ -97,7 +98,7 @@ TextureBaker::TextureBaker(unsigned int width, unsigned int _frameCaptureImage->createResourceBuffer(); } -template +template size_t TextureBaker::findVarInTemplate(const string& filename, const string& var, size_t start) { size_t i = filename.find(var, start); @@ -112,17 +113,15 @@ size_t TextureBaker::findVarInTemplate(const string& filena return i; } -template +template FilePath TextureBaker::generateTextureFilename(const StringMap& filenameTemplateMap) { string bakedImageName = _textureFilenameTemplate; for (auto& pair : filenameTemplateMap) { - string replacement = (_texTemplateOverrides.count(pair.first)) ? - _texTemplateOverrides[pair.first] : pair.second; - replacement = (filenameTemplateMap.at("$UDIM").empty() && pair.first == "$UDIMPREFIX") ? - EMPTY_STRING : replacement; + string replacement = (_texTemplateOverrides.count(pair.first)) ? _texTemplateOverrides[pair.first] : pair.second; + replacement = (filenameTemplateMap.at("$UDIM").empty() && pair.first == "$UDIMPREFIX") ? EMPTY_STRING : replacement; for (size_t i = 0; (i = findVarInTemplate(bakedImageName, pair.first, i)) != string::npos; i++) { @@ -140,7 +139,7 @@ FilePath TextureBaker::generateTextureFilename(const String return _outputImagePath / bakedImageName; } -template +template StringMap TextureBaker::initializeFileTemplateMap(InputPtr input, NodePtr shader, const string& udim) { FilePath assetPath = FilePath(shader->getActiveSourceUri()); @@ -156,7 +155,7 @@ StringMap TextureBaker::initializeFileTemplateMap(InputPtr return filenameTemplateMap; } -template +template bool TextureBaker::writeBakedImage(const BakedImage& baked, ImagePtr image) { if (!Renderer::_imageHandler->saveImage(baked.filename, image, _flipSavedImage)) @@ -176,11 +175,11 @@ bool TextureBaker::writeBakedImage(const BakedImage& baked, return true; } -template +template void TextureBaker::bakeShaderInputs(NodePtr material, NodePtr shader, GenContext& context, const string& udim) { _material = material; - + if (!shader) { return; @@ -216,16 +215,16 @@ void TextureBaker::bakeShaderInputs(NodePtr material, NodeP Renderer::_imageHandler->clearImageCache(); } -template +template void TextureBaker::bakeGraphOutput(OutputPtr output, GenContext& context, const StringMap& filenameTemplateMap) { if (!output) { return; } - + bool encodeSrgb = _colorSpace == SRGB_TEXTURE && - (output->getType() == "color3" || output->getType() == "color4"); + (output->getType() == "color3" || output->getType() == "color4"); Renderer::getFramebuffer()->setEncodeSrgb(encodeSrgb); ShaderPtr shader = _generator->generate("BakingShader", output, context); @@ -258,7 +257,7 @@ void TextureBaker::bakeGraphOutput(OutputPtr output, GenCon } } -template +template void TextureBaker::optimizeBakedTextures(NodePtr shader) { if (!shader) @@ -320,7 +319,7 @@ void TextureBaker::optimizeBakedTextures(NodePtr shader) } } -template +template DocumentPtr TextureBaker::generateNewDocumentFromShader(NodePtr shader, const StringVec& udimSet) { if (!shader) @@ -359,7 +358,7 @@ DocumentPtr TextureBaker::generateNewDocumentFromShader(Nod // Optionally create a material node, connecting it to the new shader node. if (_material) { - string materialName = (_texTemplateOverrides.count("$MATERIAL"))? _texTemplateOverrides["$MATERIAL"] : _material->getName(); + string materialName = (_texTemplateOverrides.count("$MATERIAL")) ? _texTemplateOverrides["$MATERIAL"] : _material->getName(); NodePtr bakedMaterial = _bakedTextureDoc->addNode(_material->getCategory(), materialName + BAKED_POSTFIX, _material->getType()); for (auto sourceMaterialInput : _material->getInputs()) { @@ -483,9 +482,9 @@ DocumentPtr TextureBaker::generateNewDocumentFromShader(Nod return _bakedTextureDoc; } -template +template DocumentPtr TextureBaker::bakeMaterialToDoc(DocumentPtr doc, const FileSearchPath& searchPath, const string& materialPath, - const StringVec& udimSet, string& documentName) + const StringVec& udimSet, string& documentName) { if (_outputStream) { @@ -551,7 +550,7 @@ DocumentPtr TextureBaker::bakeMaterialToDoc(DocumentPtr doc return generateNewDocumentFromShader(shaderNode, udimSet); } -template +template void TextureBaker::bakeAllMaterials(DocumentPtr doc, const FileSearchPath& searchPath, const FilePath& outputFilename) { if (_outputImagePath.isEmpty()) @@ -593,31 +592,31 @@ void TextureBaker::bakeAllMaterials(DocumentPtr doc, const if (_writeDocumentPerMaterial) { - // Write documents in memory to disk. - size_t bakeCount = bakedDocuments.size(); - for (size_t i = 0; i < bakeCount; i++) - { - if (bakedDocuments[i].second) + // Write documents in memory to disk. + size_t bakeCount = bakedDocuments.size(); + for (size_t i = 0; i < bakeCount; i++) { - FilePath writeFilename = outputFilename; - - // Add additional filename decorations if there are multiple documents. - if (bakedDocuments.size() > 1) + if (bakedDocuments[i].second) { - const string extension = writeFilename.getExtension(); - writeFilename.removeExtension(); - string filenameSeparator = writeFilename.isDirectory()? EMPTY_STRING : "_"; - writeFilename = FilePath(writeFilename.asString() + filenameSeparator + bakedDocuments[i].first + "." + extension); - } + FilePath writeFilename = outputFilename; - writeToXmlFile(bakedDocuments[i].second, writeFilename); - if (_outputStream) - { - *_outputStream << "Wrote baked document: " << writeFilename.asString() << std::endl; + // Add additional filename decorations if there are multiple documents. + if (bakedDocuments.size() > 1) + { + const string extension = writeFilename.getExtension(); + writeFilename.removeExtension(); + string filenameSeparator = writeFilename.isDirectory() ? EMPTY_STRING : "_"; + writeFilename = FilePath(writeFilename.asString() + filenameSeparator + bakedDocuments[i].first + "." + extension); + } + + writeToXmlFile(bakedDocuments[i].second, writeFilename); + if (_outputStream) + { + *_outputStream << "Wrote baked document: " << writeFilename.asString() << std::endl; + } } } } -} else if (_bakedTextureDoc) { writeToXmlFile(_bakedTextureDoc, outputFilename); @@ -628,7 +627,7 @@ void TextureBaker::bakeAllMaterials(DocumentPtr doc, const } } -template +template void TextureBaker::setupUnitSystem(DocumentPtr unitDefinitions) { UnitTypeDefPtr distanceTypeDef = unitDefinitions ? unitDefinitions->getUnitTypeDef("distance") : nullptr; diff --git a/source/MaterialXRender/TinyObjLoader.cpp b/source/MaterialXRender/TinyObjLoader.cpp index 324a1df3e7..b01af1ebf9 100644 --- a/source/MaterialXRender/TinyObjLoader.cpp +++ b/source/MaterialXRender/TinyObjLoader.cpp @@ -23,7 +23,8 @@ MATERIALX_NAMESPACE_BEGIN -namespace { +namespace +{ const float MAX_FLOAT = std::numeric_limits::max(); const size_t FACE_VERTEX_COUNT = 3; @@ -32,9 +33,10 @@ class VertexVector : public VectorN { public: using VectorN::VectorN; - VertexVector(const Vector3& p, const Vector3& n, const Vector2& t) : VectorN(Uninit{}) + VertexVector(const Vector3& p, const Vector3& n, const Vector2& t) : + VectorN(Uninit{}) { - _arr = {p[0], p[1], p[2], n[0], n[1], n[2], t[0], t[1]}; + _arr = { p[0], p[1], p[2], n[0], n[1], n[2], t[0], t[1] }; } }; diff --git a/source/MaterialXRender/TinyObjLoader.h b/source/MaterialXRender/TinyObjLoader.h index 8cfb80762b..e3934f9e41 100644 --- a/source/MaterialXRender/TinyObjLoader.h +++ b/source/MaterialXRender/TinyObjLoader.h @@ -6,7 +6,7 @@ #ifndef MATERIALX_TINYOBJLOADER_H #define MATERIALX_TINYOBJLOADER_H -/// @file +/// @file /// OBJ geometry format loader using the TinyObj library #include diff --git a/source/MaterialXRender/Types.h b/source/MaterialXRender/Types.h index 6af59b9122..b3c15c9f8b 100644 --- a/source/MaterialXRender/Types.h +++ b/source/MaterialXRender/Types.h @@ -65,7 +65,7 @@ class MX_RENDER_API Vector3d : public VectorN Vector3d() = default; Vector3d(double x, double y, double z) : VectorN(Uninit{}) { - _arr = {x, y, z}; + _arr = { x, y, z }; } }; @@ -78,7 +78,7 @@ class MX_RENDER_API Vector4d : public VectorN Vector4d() = default; Vector4d(double x, double y, double z, double w) : VectorN(Uninit{}) { - _arr = {x, y, z, w}; + _arr = { x, y, z, w }; } }; @@ -91,7 +91,7 @@ class MX_RENDER_API Color3d : public VectorN Color3d() = default; Color3d(double r, double g, double b) : VectorN(Uninit{}) { - _arr = {r, g, b}; + _arr = { r, g, b }; } }; diff --git a/source/MaterialXRender/Util.h b/source/MaterialXRender/Util.h index 9f4a4f97c9..fd1effdceb 100644 --- a/source/MaterialXRender/Util.h +++ b/source/MaterialXRender/Util.h @@ -31,21 +31,21 @@ MX_RENDER_API ShaderPtr createShader(const string& shaderName, GenContext& conte /// Create a shader with a constant color output, using the given standard libraries /// for code generation. MX_RENDER_API ShaderPtr createConstantShader(GenContext& context, - DocumentPtr stdLib, - const string& shaderName, - const Color3& color); + DocumentPtr stdLib, + const string& shaderName, + const Color3& color); /// Create a shader with depth value output, using the given standard libraries /// for code generation. MX_RENDER_API ShaderPtr createDepthShader(GenContext& context, - DocumentPtr stdLib, - const string& shaderName); + DocumentPtr stdLib, + const string& shaderName); /// Create a shader that generates a look-up table for directional albedo, using /// the given standard libraries for code generation. MX_RENDER_API ShaderPtr createAlbedoTableShader(GenContext& context, - DocumentPtr stdLib, - const string& shaderName); + DocumentPtr stdLib, + const string& shaderName); /// Create a shader that generates a pre-convolution map for environment lighting. MX_RENDER_API ShaderPtr createEnvPreConvolutionShader(GenContext& context, @@ -54,10 +54,10 @@ MX_RENDER_API ShaderPtr createEnvPreConvolutionShader(GenContext& context, /// Create a blur shader, using the given standard libraries for code generation. MX_RENDER_API ShaderPtr createBlurShader(GenContext& context, - DocumentPtr stdLib, - const string& shaderName, - const string& filterType, - float filterSize); + DocumentPtr stdLib, + const string& shaderName, + const string& filterType, + float filterSize); /// @} /// @name User Interface Utilities diff --git a/source/MaterialXRenderGlsl/CMakeLists.txt b/source/MaterialXRenderGlsl/CMakeLists.txt index cb2f3c27c2..067cc5d016 100644 --- a/source/MaterialXRenderGlsl/CMakeLists.txt +++ b/source/MaterialXRenderGlsl/CMakeLists.txt @@ -50,7 +50,8 @@ if(MATERIALX_BUILD_SHARED_LIBS) target_compile_definitions(${MATERIALX_MODULE_NAME} PUBLIC GLAD_GLAPI_EXPORT PRIVATE GLAD_GLAPI_EXPORT_BUILD) endif() -set(COMMON_LIBRARIES +target_link_libraries( + ${MATERIALX_MODULE_NAME} MaterialXRenderHw MaterialXGenGlsl ${CMAKE_DL_LIBS}) @@ -59,30 +60,26 @@ if(WIN32) if(MSVC) target_link_libraries( ${MATERIALX_MODULE_NAME} - ${COMMON_LIBRARIES} Opengl32) elseif(MINGW) target_link_libraries( ${MATERIALX_MODULE_NAME} - ${COMMON_LIBRARIES} Opengl32 gdi32) endif() elseif(APPLE) target_link_libraries( ${MATERIALX_MODULE_NAME} - ${COMMON_LIBRARIES} - ${OPENGL_LIBRARIES} + OpenGL::GL "-framework Foundation" "-framework Cocoa" "-framework Metal") elseif(UNIX) target_link_libraries( ${MATERIALX_MODULE_NAME} - ${COMMON_LIBRARIES} - ${OPENGL_LIBRARIES} - ${X11_LIBRARIES} - ${X11_Xt_LIB}) + OpenGL::GL + X11::X11 + X11::Xt) endif() set_target_properties( diff --git a/source/MaterialXRenderGlsl/GLFramebuffer.cpp b/source/MaterialXRenderGlsl/GLFramebuffer.cpp index bb8e567c58..9516e9ad43 100644 --- a/source/MaterialXRenderGlsl/GLFramebuffer.cpp +++ b/source/MaterialXRenderGlsl/GLFramebuffer.cpp @@ -75,33 +75,33 @@ GLFramebuffer::GLFramebuffer(unsigned int width, unsigned int height, unsigned i string errorMessage; switch (status) { - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; - break; - case GL_FRAMEBUFFER_UNSUPPORTED: - errorMessage = "GL_FRAMEBUFFER_UNSUPPORTED"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; - break; - case GL_FRAMEBUFFER_UNDEFINED: - errorMessage = "GL_FRAMEBUFFER_UNDEFINED"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: - errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; - break; - default: - errorMessage = std::to_string(status); - break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + errorMessage = "GL_FRAMEBUFFER_UNSUPPORTED"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; + break; + case GL_FRAMEBUFFER_UNDEFINED: + errorMessage = "GL_FRAMEBUFFER_UNDEFINED"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: + errorMessage = "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; + break; + default: + errorMessage = std::to_string(status); + break; } throw ExceptionRenderError("Frame buffer object setup failed: " + errorMessage); diff --git a/source/MaterialXRenderGlsl/GLTextureHandler.h b/source/MaterialXRenderGlsl/GLTextureHandler.h index 93c7c029d1..5d2e21f53c 100644 --- a/source/MaterialXRenderGlsl/GLTextureHandler.h +++ b/source/MaterialXRenderGlsl/GLTextureHandler.h @@ -33,7 +33,7 @@ class MX_RENDERGLSL_API GLTextureHandler : public ImageHandler /// will fail if there are not enough available image units to bind to. bool bindImage(ImagePtr image, const ImageSamplingProperties& samplingProperties) override; - /// Unbind an image. + /// Unbind an image. bool unbindImage(ImagePtr image) override; /// Create rendering resources for the given image. diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index ce4582d44f..84668d2d0a 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -38,7 +38,7 @@ bool GlslMaterial::loadSource(const FilePath& vertexShaderFile, const FilePath& } // TODO: - // Here we set new source code on the _glProgram without rebuilding + // Here we set new source code on the _glProgram without rebuilding // the _hwShader instance. So the _hwShader is not in sync with the // _glProgram after this operation. _glProgram = GlslProgram::create(); diff --git a/source/MaterialXRenderGlsl/GlslMaterial.h b/source/MaterialXRenderGlsl/GlslMaterial.h index 1e3d0f7f3b..1ae945867a 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.h +++ b/source/MaterialXRenderGlsl/GlslMaterial.h @@ -24,7 +24,8 @@ using GlslMaterialPtr = std::shared_ptr; class MX_RENDERGLSL_API GlslMaterial : public ShaderMaterial { public: - GlslMaterial() : ShaderMaterial() + GlslMaterial() : + ShaderMaterial() { } ~GlslMaterial() { } @@ -45,7 +46,7 @@ class MX_RENDERGLSL_API GlslMaterial : public ShaderMaterial /// Generate a shader from the given hardware shader. bool generateShader(ShaderPtr hwShader) override; - + /// Copy shader from one material to this one void copyShader(MaterialPtr material) override { diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index cad011bb28..dcc76ddda5 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -59,7 +59,7 @@ void GlslProgram::setStages(ShaderPtr shader) // Extract out the shader code per stage _shader = shader; - for (size_t i =0; inumStages(); ++i) + for (size_t i = 0; i < shader->numStages(); ++i) { const ShaderStage& stage = shader->getStage(i); addStage(stage.getName(), stage.getSourceCode()); @@ -101,7 +101,7 @@ void GlslProgram::build() // Compile vertex shader, if any GLuint vertexShaderId = UNDEFINED_OPENGL_RESOURCE_ID; - const string &vertexShaderSource = _stages[Stage::VERTEX]; + const string& vertexShaderSource = _stages[Stage::VERTEX]; if (!vertexShaderSource.empty()) { vertexShaderId = glCreateShader(GL_VERTEX_SHADER); @@ -138,7 +138,7 @@ void GlslProgram::build() fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER); // Compile fragment shader - const char *fragmentChar = fragmentShaderSource.c_str(); + const char* fragmentChar = fragmentShaderSource.c_str(); glShaderSource(fragmentShaderId, 1, &fragmentChar, nullptr); glCompileShader(fragmentShaderId); @@ -324,7 +324,7 @@ void GlslProgram::bindPartition(MeshPartitionPtr part) void GlslProgram::bindMesh(MeshPtr mesh) { - _enabledStreamLocations.clear(); + _enabledStreamLocations.clear(); if (_programId == UNDEFINED_OPENGL_RESOURCE_ID) { @@ -547,7 +547,7 @@ void GlslProgram::bindTextures(ImageHandlerPtr imageHandler) // Always bind a texture unless it is a lighting texture. // Lighting textures are handled in the bindLighting() call. - // If no texture can be loaded then the default color defined in + // If no texture can be loaded then the default color defined in // "samplingProperties" will be used to create a fallback texture. if (fileName != HW::ENV_RADIANCE && fileName != HW::ENV_IRRADIANCE) @@ -914,7 +914,7 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() // Process constants const VariableBlock& constants = ps.getConstantBlock(); - for (size_t i=0; i< constants.size(); ++i) + for (size_t i = 0; i < constants.size(); ++i) { const ShaderPort* v = constants[i]; // There is no way to match with an unnamed variable @@ -1208,9 +1208,9 @@ void GlslProgram::printUniforms(std::ostream& outputStream) string colorspace = input.second->colorspace; bool isConstant = input.second->isConstant; outputStream << "Program Uniform: \"" << input.first - << "\". Location:" << location - << ". GLtype: " << std::hex << gltype - << ". Size: " << std::dec << size; + << "\". Location:" << location + << ". GLtype: " << std::hex << gltype + << ". Size: " << std::dec << size; if (!type.empty()) outputStream << ". TypeString: \"" << type << "\""; if (!value.empty()) @@ -1228,7 +1228,6 @@ void GlslProgram::printUniforms(std::ostream& outputStream) } } - void GlslProgram::printAttributes(std::ostream& outputStream) { updateAttributesList(); @@ -1240,9 +1239,9 @@ void GlslProgram::printAttributes(std::ostream& outputStream) string type = input.second->typeString; string value = input.second->value ? input.second->value->getValueString() : EMPTY_STRING; outputStream << "Program Attribute: \"" << input.first - << "\". Location:" << location - << ". GLtype: " << std::hex << gltype - << ". Size: " << std::dec << size; + << "\". Location:" << location + << ". GLtype: " << std::hex << gltype + << ". Size: " << std::dec << size; if (!type.empty()) outputStream << ". TypeString: \"" << type << "\""; if (!value.empty()) diff --git a/source/MaterialXRenderGlsl/GlslProgram.h b/source/MaterialXRenderGlsl/GlslProgram.h index 2538c63fcb..e90853eedb 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.h +++ b/source/MaterialXRenderGlsl/GlslProgram.h @@ -109,7 +109,7 @@ class MX_RENDERGLSL_API GlslProgram string path; /// Unit string unit; - /// Colorspace + /// Colorspace string colorspace; /// Program input constructor diff --git a/source/MaterialXRenderGlsl/GlslRenderer.h b/source/MaterialXRenderGlsl/GlslRenderer.h index 9ea121aec9..bdf16b44b3 100644 --- a/source/MaterialXRenderGlsl/GlslRenderer.h +++ b/source/MaterialXRenderGlsl/GlslRenderer.h @@ -50,7 +50,7 @@ class MX_RENDERGLSL_API GlslRenderer : public ShaderRenderer { return GLTextureHandler::create(imageLoader); } - + /// Destructor virtual ~GlslRenderer() { } diff --git a/source/MaterialXRenderGlsl/TextureBaker.h b/source/MaterialXRenderGlsl/TextureBaker.h index be1f713cd6..c084b00a1a 100644 --- a/source/MaterialXRenderGlsl/TextureBaker.h +++ b/source/MaterialXRenderGlsl/TextureBaker.h @@ -37,7 +37,7 @@ class MX_RENDERGLSL_API TextureBakerGlsl : public TextureBaker; /// @class SimpleWindow /// A platform-independent window class. -/// +/// /// Plaform-specific resources are encapsulated by a WindowWrapper instance. class MX_RENDERHW_API SimpleWindow { @@ -30,7 +30,7 @@ class MX_RENDERHW_API SimpleWindow virtual ~SimpleWindow(); /// Window initialization - bool initialize(const char* title, unsigned int width, unsigned int height, void *applicationShell); + bool initialize(const char* title, unsigned int width, unsigned int height, void* applicationShell); /// Return our platform-specific resource wrapper WindowWrapperPtr getWindowWrapper() diff --git a/source/MaterialXRenderHw/SimpleWindowLinux.cpp b/source/MaterialXRenderHw/SimpleWindowLinux.cpp index 23779bd92b..5a14a51aba 100644 --- a/source/MaterialXRenderHw/SimpleWindowLinux.cpp +++ b/source/MaterialXRenderHw/SimpleWindowLinux.cpp @@ -26,7 +26,7 @@ SimpleWindow::SimpleWindow() : bool SimpleWindow::initialize(const char* title, unsigned int width, unsigned int height, - void *applicationShell) + void* applicationShell) { int n = 0; @@ -49,13 +49,13 @@ bool SimpleWindow::initialize(const char* title, else { // Reuse existing application shell; - shell = (Widget)applicationShell; + shell = (Widget) applicationShell; } if (!shell) { _id = 0; - return false;; + return false; } Arg args[6]; diff --git a/source/MaterialXRenderHw/SimpleWindowWindows.cpp b/source/MaterialXRenderHw/SimpleWindowWindows.cpp index de5cf48fc1..070950e682 100644 --- a/source/MaterialXRenderHw/SimpleWindowWindows.cpp +++ b/source/MaterialXRenderHw/SimpleWindowWindows.cpp @@ -30,19 +30,19 @@ LRESULT CALLBACK NoOpProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { - case WM_CLOSE: - case WM_DESTROY: - break; - default: - return DefWindowProc(hWnd, msg, wParam, lParam); - break; + case WM_CLOSE: + case WM_DESTROY: + break; + default: + return DefWindowProc(hWnd, msg, wParam, lParam); + break; } return 0; } bool SimpleWindow::initialize(const char* title, unsigned int width, unsigned int height, - void * /*applicationShell*/) + void* /*applicationShell*/) { HINSTANCE hInstance = GetModuleHandle(NULL); @@ -50,14 +50,14 @@ bool SimpleWindow::initialize(const char* title, // WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wc.lpfnWndProc = (WNDPROC)NoOpProc; + wc.lpfnWndProc = (WNDPROC) NoOpProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; // Set the instance to this application wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; // No background required - wc.lpszMenuName = NULL; // No menu required + wc.lpszMenuName = NULL; // No menu required wc.lpszClassName = _windowClassName; if (!RegisterClass(&wc)) @@ -73,10 +73,10 @@ bool SimpleWindow::initialize(const char* title, // Set the rectangle of the client area. RECT WindowRect; - WindowRect.left = (long)0; - WindowRect.top = (long)0; - WindowRect.right = (long)width; - WindowRect.bottom = (long)height; + WindowRect.left = (long) 0; + WindowRect.top = (long) 0; + WindowRect.right = (long) width; + WindowRect.bottom = (long) height; // Calculate the exact window size (including border) so that the // client area has the desired dimensions. @@ -86,13 +86,13 @@ bool SimpleWindow::initialize(const char* title, // Attempt to create the window. HWND hWnd = CreateWindowEx(dwExStyle, _windowClassName, title, dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, - 0, 0, // Window position - WindowRect.right - WindowRect.left, // Window width (including borders) - WindowRect.bottom - WindowRect.top, // Window height (including borders/title bar) - NULL, // No parent window - NULL, // No menu - hInstance, // Instance - NULL); // Don't pass anything To WM_CREATE + 0, 0, // Window position + WindowRect.right - WindowRect.left, // Window width (including borders) + WindowRect.bottom - WindowRect.top, // Window height (including borders/title bar) + NULL, // No parent window + NULL, // No menu + hInstance, // Instance + NULL); // Don't pass anything To WM_CREATE if (!hWnd) { diff --git a/source/MaterialXRenderMsl/CMakeLists.txt b/source/MaterialXRenderMsl/CMakeLists.txt index 4d5e286463..41e00d4b9f 100644 --- a/source/MaterialXRenderMsl/CMakeLists.txt +++ b/source/MaterialXRenderMsl/CMakeLists.txt @@ -42,36 +42,33 @@ add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_RENDERMSL_EXPORTS) -set(COMMON_LIBRARIES +target_link_libraries( + ${MATERIALX_MODULE_NAME} MaterialXRenderHw MaterialXGenMsl ${CMAKE_DL_LIBS}) - -if(APPLE AND NOT MATERIALX_BUILD_IOS) -set(COMMON_LIBRARIES - ${COMMON_LIBRARIES} - "-framework Cocoa") -endif() if(MSVC) target_link_libraries( ${MATERIALX_MODULE_NAME} - ${COMMON_LIBRARIES} Opengl32) elseif(APPLE) + if(NOT MATERIALX_BUILD_IOS) + target_link_libraries( + ${MATERIALX_MODULE_NAME} + "-framework Cocoa" + OpenGL::GL) + endif() target_link_libraries( ${MATERIALX_MODULE_NAME} - ${COMMON_LIBRARIES} - ${OPENGL_LIBRARIES} "-framework Foundation" "-framework Metal") elseif(UNIX) target_link_libraries( ${MATERIALX_MODULE_NAME} - ${COMMON_LIBRARIES} - ${OPENGL_LIBRARIES} - ${X11_LIBRARIES} - ${X11_Xt_LIB}) + OpenGL::GL + X11::X11 + X11::Xt) endif() set_target_properties( diff --git a/source/MaterialXTest/CMakeLists.txt b/source/MaterialXTest/CMakeLists.txt index e66db4bd2e..862a176b50 100644 --- a/source/MaterialXTest/CMakeLists.txt +++ b/source/MaterialXTest/CMakeLists.txt @@ -121,6 +121,10 @@ set_target_properties( VERSION "${MATERIALX_LIBRARY_VERSION}" SOVERSION "${MATERIALX_MAJOR_VERSION}") +if(MATERIALX_BUILD_BENCHMARK_TESTS) + target_compile_definitions(MaterialXTest PRIVATE -DCATCH_CONFIG_ENABLE_BENCHMARKING) +endif() + target_link_libraries( MaterialXTest ${CMAKE_DL_LIBS}) diff --git a/source/MaterialXTest/External/Catch/catch.hpp b/source/MaterialXTest/External/Catch/catch.hpp index d2a12427b2..9b309bddc6 100644 --- a/source/MaterialXTest/External/Catch/catch.hpp +++ b/source/MaterialXTest/External/Catch/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v2.13.9 - * Generated: 2022-04-12 22:37:23.260201 + * Catch v2.13.10 + * Generated: 2022-10-16 11:01:23.452308 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. @@ -15,7 +15,7 @@ #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 13 -#define CATCH_VERSION_PATCH 9 +#define CATCH_VERSION_PATCH 10 #ifdef __clang__ # pragma clang system_header @@ -7395,8 +7395,6 @@ namespace Catch { template struct ObjectStorage { - using TStorage = typename std::aligned_storage::value>::type; - ObjectStorage() : data() {} ObjectStorage(const ObjectStorage& other) @@ -7439,7 +7437,7 @@ namespace Catch { return *static_cast(static_cast(&data)); } - TStorage data; + struct { alignas(T) unsigned char data[sizeof(T)]; } data; }; } @@ -7949,7 +7947,7 @@ namespace Catch { #if defined(__i386__) || defined(__x86_64__) #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ #elif defined(__aarch64__) - #define CATCH_TRAP() __asm__(".inst 0xd4200000") + #define CATCH_TRAP() __asm__(".inst 0xd43e0000") #endif #elif defined(CATCH_PLATFORM_IPHONE) @@ -13558,7 +13556,7 @@ namespace Catch { // Handle list request if( Option listed = list( m_config ) ) - return static_cast( *listed ); + return (std::min) (MaxExitCode, static_cast(*listed)); TestGroup tests { m_config }; auto const totals = tests.execute(); @@ -15391,7 +15389,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 13, 9, "", 0 ); + static Version version( 2, 13, 10, "", 0 ); return version; } @@ -17526,12 +17524,20 @@ namespace Catch { #ifndef __OBJC__ +#ifndef CATCH_INTERNAL_CDECL +#ifdef _MSC_VER +#define CATCH_INTERNAL_CDECL __cdecl +#else +#define CATCH_INTERNAL_CDECL +#endif +#endif + #if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point -extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { +extern "C" int CATCH_INTERNAL_CDECL wmain (int argc, wchar_t * argv[], wchar_t * []) { #else // Standard C/C++ main entry point -int main (int argc, char * argv[]) { +int CATCH_INTERNAL_CDECL main (int argc, char * argv[]) { #endif return Catch::Session().run( argc, argv ); 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/MaterialXCore/Element.cpp b/source/MaterialXTest/MaterialXCore/Element.cpp index fc4939a74f..3865934ccb 100644 --- a/source/MaterialXTest/MaterialXCore/Element.cpp +++ b/source/MaterialXTest/MaterialXCore/Element.cpp @@ -54,6 +54,9 @@ TEST_CASE("Element", "[element]") REQUIRE(*doc2 != *doc); doc2->setChildIndex("elem1", doc2->getChildIndex("elem2")); REQUIRE(*doc2 == *doc); + REQUIRE_THROWS_AS(doc2->setChildIndex("elem1", -100), mx::Exception); + REQUIRE_THROWS_AS(doc2->setChildIndex("elem1", -1), mx::Exception); + REQUIRE_THROWS_AS(doc2->setChildIndex("elem1", 2), mx::Exception); REQUIRE_THROWS_AS(doc2->setChildIndex("elem1", 100), mx::Exception); REQUIRE(*doc2 == *doc); diff --git a/source/MaterialXTest/MaterialXCore/Geom.cpp b/source/MaterialXTest/MaterialXCore/Geom.cpp index 46a9531006..2457d4e524 100644 --- a/source/MaterialXTest/MaterialXCore/Geom.cpp +++ b/source/MaterialXTest/MaterialXCore/Geom.cpp @@ -11,6 +11,21 @@ namespace mx = MaterialX; TEST_CASE("Geom strings", "[geom]") { + // Test conversion between geometry strings and paths. + mx::StringVec geomStrings = + { + "", + "/", + "/robot1", + "/robot1/left_arm" + }; + for (const std::string& geomString : geomStrings) + { + mx::GeomPath geomPath(geomString); + std::string newGeomString(geomPath); + REQUIRE(newGeomString == geomString); + } + // Test for overlapping paths. REQUIRE(mx::geomStringsMatch("/", "/robot1")); REQUIRE(mx::geomStringsMatch("/robot1", "/robot1/left_arm")); 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/MaterialXTest/MaterialXFormat/XmlIo.cpp b/source/MaterialXTest/MaterialXFormat/XmlIo.cpp index 1336a080c4..495712381e 100644 --- a/source/MaterialXTest/MaterialXFormat/XmlIo.cpp +++ b/source/MaterialXTest/MaterialXFormat/XmlIo.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -262,6 +261,51 @@ TEST_CASE("Comments and newlines", "[xmlio]") REQUIRE(origXml == newXml); } +TEST_CASE("Fuzz testing", "[xmlio]") +{ + mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); + mx::FilePath examplesPath = searchPath.find("resources/Materials/Examples/StandardSurface"); + + std::mt19937 rng(0); + std::uniform_int_distribution randChar(0, 255); + + for (const mx::FilePath& filename : examplesPath.getFilesInDirectory(mx::MTLX_EXTENSION)) + { + // Read the example file into an XML string buffer. + const std::string origString = mx::readFile(examplesPath / filename); + REQUIRE(origString.size() > 0); + std::uniform_int_distribution randPos(0, origString.size() - 1); + + // Iterate over test runs. + for (size_t testRun = 0; testRun < 256; testRun++) + { + std::string editString = origString; + + // Iterate over string edits. + for (size_t editIndex = 0; editIndex < 32; editIndex++) + { + // Randomly alter one character in the document. + size_t charIndex = randPos(rng); + size_t newChar = randChar(rng); + editString[charIndex] = (char) newChar; + + // Attempt to interpret the edited string as a document, allowing only MaterialX exceptions. + mx::DocumentPtr doc = mx::createDocument(); + try + { + mx::readFromXmlString(doc, editString, searchPath); + doc->validate(); + } + catch (const mx::Exception&) + { + // On a MaterialX exception, proceed to the next test run. + break; + } + } + } + } +} + TEST_CASE("Locale region testing", "[xmlio]") { // In the United States, the thousands separator is a comma, while in Germany it is a period. diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp index 339d3853cb..2cc4d7ccf4 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp @@ -119,6 +119,17 @@ TEST_CASE("GenShader: Bind Light Shaders", "[genglsl]") REQUIRE_NOTHROW(mx::HwShaderGenerator::bindLightShader(*spotLightShader, 66, context)); } +#ifdef MATERIALX_BUILD_BENCHMARK_TESTS +TEST_CASE("GenShader: Performance Test", "[genglsl]") +{ + mx::GenContext context(mx::GlslShaderGenerator::create()); + BENCHMARK("Load documents, validate and generate shader") + { + return GenShaderUtil::shaderGenPerformanceTest(context); + }; +} +#endif + enum class GlslType { Glsl400, diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index 1a3e127cde..22ad0d456e 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -288,7 +288,10 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so std::string iblFile = (rootPath / "resources/lights/san_giuseppe_bridge.hdr").asString(); renderCommand += " --hdr \"" + iblFile + "\" --hdr_rotate 90"; // set scene - renderCommand += " --uv_scale 0.5 1.0 --uv_offset 0.0 0.0 --uv_repeat --uv_flip"; + renderCommand += " --uv_scale 0.5 1.0 --uv_offset 0.0 0.0 --uv_repeat"; + renderCommand += " --uv_flip"; // this will flip the v coordinate of the vertices, which flips all the + // UV operations. In contrast, the fileTextureVerticalFlip option will + // only flip the image access nodes. renderCommand += " --camera 0 0 3 0 0 0 --fov 45"; // set the material @@ -365,6 +368,19 @@ TEST_CASE("GenShader: MDL Shader Generation", "[genmdl]") mx::GenOptions genOptions; genOptions.targetColorSpaceOverride = "lin_rec709"; + + // Flipping the texture lookups for the test renderer only. + // This is because OSL testrender does not allow to change the UV layout of their sphere (yet) and the MaterialX test suite + // adopts the OSL behavior in order to produce comparable results. This means that raw texture coordinates, or procedurals + // that use the texture coordinates, do not match what might be expected when reading the MaterialX spec: + // "[...] the image is mapped onto the geometry based on geometry UV coordinates, with the lower-left corner of an image + // mapping to the (0,0) UV coordinate [...]" + // This means for MDL: here, and only here in the test suite, we flip the UV coordinates of mesh using the `--uv_flip` option + // of the renderer, and to correct the image orientation, we apply `fileTextureVerticalFlip`. + // In regular MDL integrations this is not needed because MDL and MaterialX define the texture space equally with the origin + // at the bottom left. + genOptions.fileTextureVerticalFlip = true; + mx::FilePath optionsFilePath = searchPath.find("resources/Materials/TestSuite/_options.mtlx"); tester.validate(genOptions, optionsFilePath); } diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 863cd1af05..1280ff390d 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -314,6 +314,84 @@ void testUniqueNames(mx::GenContext& context, const std::string& stage) REQUIRE(sgNode1->getOutput()->getVariable() == "unique_names_out"); } +// Test ShaderGen performance +void shaderGenPerformanceTest(mx::GenContext& context) +{ + mx::DocumentPtr nodeLibrary = mx::createDocument(); + mx::FilePath currentPath = mx::FilePath::getCurrentPath(); + const mx::FileSearchPath libSearchPath(currentPath); + + // Load the standard libraries. + loadLibraries({ "libraries" }, libSearchPath, nodeLibrary); + context.registerSourceCodeSearchPath(libSearchPath); + + // Enable Color Management + mx::ColorManagementSystemPtr colorManagementSystem = + mx::DefaultColorManagementSystem::create(context.getShaderGenerator().getTarget()); + + REQUIRE(colorManagementSystem); + if (colorManagementSystem) + { + context.getShaderGenerator().setColorManagementSystem(colorManagementSystem); + colorManagementSystem->loadLibrary(nodeLibrary); + } + + // Enable Unit System + mx::UnitSystemPtr unitSystem = mx::UnitSystem::create(context.getShaderGenerator().getTarget()); + REQUIRE(unitSystem); + if (unitSystem) + { + context.getShaderGenerator().setUnitSystem(unitSystem); + unitSystem->loadLibrary(nodeLibrary); + // Setup Unit converters + unitSystem->setUnitConverterRegistry(mx::UnitConverterRegistry::create()); + mx::UnitTypeDefPtr distanceTypeDef = nodeLibrary->getUnitTypeDef("distance"); + unitSystem->getUnitConverterRegistry()->addUnitConverter(distanceTypeDef, mx::LinearUnitConverter::create(distanceTypeDef)); + mx::UnitTypeDefPtr angleTypeDef = nodeLibrary->getUnitTypeDef("angle"); + unitSystem->getUnitConverterRegistry()->addUnitConverter(angleTypeDef, mx::LinearUnitConverter::create(angleTypeDef)); + context.getOptions().targetDistanceUnit = "meter"; + } + + // Read mtlx documents + mx::FilePathVec testRootPaths; + testRootPaths.push_back("resources/Materials/Examples/StandardSurface"); + + std::vector loadedDocuments; + mx::StringVec documentsPaths; + mx::StringVec errorLog; + + for (const auto& testRoot : testRootPaths) + { + mx::loadDocuments(testRoot, libSearchPath, {}, {}, loadedDocuments, documentsPaths, + nullptr, &errorLog); + } + + REQUIRE(loadedDocuments.size() > 0); + REQUIRE(loadedDocuments.size() == documentsPaths.size()); + + // Shuffle the order of documents and perform document library import validatation and shadergen + std::mt19937 rng(0); + std::shuffle(loadedDocuments.begin(), loadedDocuments.end(), rng); + for (const auto& doc : loadedDocuments) + { + doc->importLibrary(nodeLibrary); + std::vector elements = mx::findRenderableElements(doc); + + REQUIRE(elements.size() > 0); + + std::string message; + bool docValid = doc->validate(&message); + + REQUIRE(docValid == true); + + mx::StringVec sourceCode; + mx::ShaderPtr shader = nullptr; + shader = context.getShaderGenerator().generate(elements[0]->getName(), elements[0], context); + + REQUIRE(shader != nullptr); + REQUIRE(shader->getSourceCode(mx::Stage::PIXEL).length() > 0); + } +} void ShaderGeneratorTester::checkImplementationUsage(const mx::StringSet& usedImpls, const mx::GenContext& context, @@ -480,27 +558,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..9c471466aa 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h @@ -52,6 +52,9 @@ void checkImplementations(mx::GenContext& context, // Utility test to check unique name generation on a shader generator void testUniqueNames(mx::GenContext& context, const std::string& stage); +// Utility to perfrom simple performance test to load, validate and generate shaders +void shaderGenPerformanceTest(mx::GenContext& context); + // // Render validation options. Reflects the _options.mtlx // file in the test suite area. @@ -180,13 +183,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 +271,6 @@ class ShaderGeneratorTester mx::StringSet _usedImplementations; }; - - } // namespace GenShaderUtil #endif 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/Editor.cpp b/source/MaterialXView/Editor.cpp index ff91f0f129..090937d6e5 100644 --- a/source/MaterialXView/Editor.cpp +++ b/source/MaterialXView/Editor.cpp @@ -18,14 +18,13 @@ namespace class EditorColorPicker : public ng::ColorPicker { public: - EditorColorPicker(ng::Widget *parent, const ng::Color& color) : + EditorColorPicker(ng::Widget* parent, const ng::Color& color) : ng::ColorPicker(parent, color) { - ng::Popup *popup = this->popup(); - ng::Widget *floatGroup = new ng::Widget(popup); - auto layout = - new ng::GridLayout(ng::Orientation::Horizontal, 2, - ng::Alignment::Middle, 2, 2); + ng::Popup* popup = this->popup(); + ng::Widget* floatGroup = new ng::Widget(popup); + auto layout = new ng::GridLayout(ng::Orientation::Horizontal, 2, + ng::Alignment::Middle, 2, 2); layout->set_col_alignment({ ng::Alignment::Fill, ng::Alignment::Fill }); layout->set_spacing(1, 1); floatGroup->set_layout(layout); @@ -51,7 +50,8 @@ class EditorColorPicker : public ng::ColorPicker // The color wheel does not handle alpha properly, so only // overwrite RGB in the callback. - m_callback = [this](const ng::Color &value) { + m_callback = [this](const ng::Color& value) + { _colorWidgets[0]->set_value(value[0]); _colorWidgets[1]->set_value(value[1]); _colorWidgets[2]->set_value(value[2]); @@ -110,7 +110,7 @@ void PropertyEditor::create(Viewer& parent) _window->set_position(previousPosition); _window->set_visible(_visible); - ng::VScrollPanel *scroll_panel = new ng::VScrollPanel(_window); + ng::VScrollPanel* scroll_panel = new ng::VScrollPanel(_window); scroll_panel->set_fixed_height(300); _container = new ng::Widget(scroll_panel); _container->set_layout(new ng::GroupLayout(1, 1, 1, 1)); @@ -122,7 +122,7 @@ void PropertyEditor::create(Viewer& parent) // 3 cell layout for label plus widget value pair. _gridLayout3 = new ng::GridLayout(ng::Orientation::Horizontal, 3, - ng::Alignment::Minimum, 2, 2); + ng::Alignment::Minimum, 2, 2); _gridLayout3->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum, ng::Alignment::Maximum }); } @@ -150,7 +150,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st { ng::Widget* twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); - ng::Label* groupLabel = new ng::Label(twoColumns, group); + ng::Label* groupLabel = new ng::Label(twoColumns, group); groupLabel->set_font_size(20); groupLabel->set_font("sans-bold"); new ng::Label(twoColumns, ""); @@ -163,7 +163,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st auto indexInEnumeration = [&value, &enumValues, &enumeration]() { size_t index = 0; - for (auto& enumValue: enumValues) + for (auto& enumValue : enumValues) { if (value->getValueString() == enumValue->getValueString()) { @@ -172,7 +172,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st index++; } index = 0; - for (auto& enumName: enumeration) + for (auto& enumName : enumeration) { if (value->getValueString() == enumName) { @@ -191,7 +191,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, {""}); + ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(static_cast(valueIndex)); @@ -259,7 +259,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st mx::MaterialPtr material = viewer->getSelectedMaterial(); if (material) { - material->modifyUniform(path, mx::Value::createValue(value)); + material->modifyUniform(path, mx::Value::createValue(value)); } }); floatBox->set_fixed_size(ng::Vector2i(100, 20)); @@ -333,12 +333,12 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st { mx::Color3 v = value->asA(); ng::Color c(v[0], v[1], v[2], 1.0); - + new ng::Label(twoColumns, label); auto colorVar = new EditorColorPicker(twoColumns, c); colorVar->set_fixed_size({ 100, 20 }); colorVar->set_font_size(15); - colorVar->set_final_callback([path, viewer](const ng::Color &c) + colorVar->set_final_callback([path, viewer](const ng::Color& c) { mx::MaterialPtr material = viewer->getSelectedMaterial(); if (material) @@ -362,7 +362,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st auto colorVar = new EditorColorPicker(twoColumns, c); colorVar->set_fixed_size({ 100, 20 }); colorVar->set_font_size(15); - colorVar->set_final_callback([path, viewer](const ng::Color &c) + colorVar->set_final_callback([path, viewer](const ng::Color& c) { mx::MaterialPtr material = viewer->getSelectedMaterial(); if (material) @@ -583,10 +583,10 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st else { new ng::Label(twoColumns, label); - ng::TextBox* stringVar = new ng::TextBox(twoColumns, v); + ng::TextBox* stringVar = new ng::TextBox(twoColumns, v); stringVar->set_fixed_size({ 100, 20 }); stringVar->set_font_size(15); - stringVar->set_callback([path, viewer](const std::string &v) + stringVar->set_callback([path, viewer](const std::string& v) { mx::MaterialPtr material = viewer->getSelectedMaterial(); mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; @@ -646,7 +646,7 @@ void PropertyEditor::updateContents(Viewer* viewer) mx::UIPropertyGroup groups; mx::UIPropertyGroup unnamedGroups; const std::string pathSeparator(":"); - mx::createUIPropertyGroups(elem->getDocument(), *publicUniforms, groups, unnamedGroups, pathSeparator); + mx::createUIPropertyGroups(elem->getDocument(), *publicUniforms, groups, unnamedGroups, pathSeparator); // First add items with named groups. std::string previousFolder; @@ -691,7 +691,7 @@ ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& la { new ng::Label(parent, label); - ng::Slider *slider = new ng::Slider(parent); + ng::Slider* slider = new ng::Slider(parent); slider->set_value(value); ng::FloatBox* box = new ng::FloatBox(parent, value); @@ -732,7 +732,7 @@ ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& la } } - slider->set_callback([box, callback](float value) + slider->set_callback([box, callback](float value) { box->set_value(value); callback(value); @@ -747,12 +747,12 @@ ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& la } ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback) + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider *slider = new ng::Slider(parent); - slider->set_value((float)value); + ng::Slider* slider = new ng::Slider(parent); + slider->set_value((float) value); ng::IntBox* box = new ng::IntBox(parent, value); box->set_fixed_width(60); @@ -781,7 +781,7 @@ ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, i } if (range.first != range.second) { - std::pair float_range((float)range.first, (float)range.second); + std::pair float_range((float) range.first, (float) range.second); slider->set_range(float_range); } if (ui->uiStep) @@ -794,12 +794,12 @@ ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, i slider->set_callback([box, callback](float value) { - box->set_value((int)value); - callback((int)value); + box->set_value((int) value); + callback((int) value); }); box->set_callback([slider, callback](int value) { - slider->set_value((float)value); + slider->set_value((float) value); callback(value); }); diff --git a/source/MaterialXView/Editor.h b/source/MaterialXView/Editor.h index 8e74ca987d..b1fb4a3ade 100644 --- a/source/MaterialXView/Editor.h +++ b/source/MaterialXView/Editor.h @@ -19,7 +19,7 @@ namespace ng = nanogui; class Viewer; -class PropertyEditor +class PropertyEditor { public: PropertyEditor(); @@ -58,7 +58,7 @@ class PropertyEditor }; ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties*ui, std::function callback = nullptr); + const mx::UIProperties* ui, std::function callback = nullptr); ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, const mx::UIProperties* ui, std::function callback); diff --git a/source/MaterialXView/Main.cpp b/source/MaterialXView/Main.cpp index 99104f7fa2..c703e48883 100644 --- a/source/MaterialXView/Main.cpp +++ b/source/MaterialXView/Main.cpp @@ -13,40 +13,40 @@ NANOGUI_FORCE_DISCRETE_GPU(); -const std::string options = -" Options: \n" -" --material [FILENAME] Specify the filename of the MTLX document to be displayed in the viewer\n" -" --mesh [FILENAME] Specify the filename of the OBJ mesh to be displayed in the viewer\n" -" --meshRotation [VECTOR3] Specify the rotation of the displayed mesh as three comma-separated floats, representing rotations in degrees about the X, Y, and Z axes (defaults to 0,0,0)\n" -" --meshScale [FLOAT] Specify the uniform scale of the displayed mesh\n" -" --enableTurntable[BOOLEAN] Specify whether to enable turntable rendering of the scene\n" -" --turntableSteps [INTEGER] Specify the number of steps for a complete turntable rotation. Defaults to 360\n" -" --cameraPosition [VECTOR3] Specify the position of the camera as three comma-separated floats (defaults to 0,0,5)\n" -" --cameraTarget [VECTOR3] Specify the position of the camera target as three comma-separated floats (defaults to 0,0,0)\n" -" --cameraViewAngle [FLOAT] Specify the view angle of the camera, or zero for an orthographic projection (defaults to 45)\n" -" --cameraZoom [FLOAT] Specify the zoom factor for the camera, implemented as a mesh scale multiplier (defaults to 1)\n" -" --envRad [FILENAME] Specify the filename of the environment light to display, stored as HDR environment radiance in the latitude-longitude format\n" -" --envMethod [INTEGER] Specify the environment lighting method (0 = filtered importance sampling, 1 = prefiltered environment maps, defaults to 0)\n" -" --envSampleCount [INTEGER] Specify the environment sample count (defaults to 16)\n" -" --lightRotation [FLOAT] Specify the rotation in degrees of the lighting environment about the Y axis (defaults to 0)\n" -" --shadowMap [BOOLEAN] Specify whether shadow mapping is enabled (defaults to true)\n" -" --path [FILEPATH] Specify an additional data search path location (e.g. '/projects/MaterialX'). This absolute path will be queried when locating data libraries, XInclude references, and referenced images.\n" -" --library [FILEPATH] Specify an additional data library folder (e.g. 'vendorlib', 'studiolib'). This relative path will be appended to each location in the data search path when loading data libraries.\n" -" --screenWidth [INTEGER] Specify the width of the screen image in pixels (defaults to 1280)\n" -" --screenHeight [INTEGER] Specify the height of the screen image in pixels (defaults to 960)\n" -" --screenColor [VECTOR3] Specify the background color of the viewer as three comma-separated floats (defaults to 0.3,0.3,0.32)\n" -" --drawEnvironment [BOOLEAN] Specify whether to render the environment as the background (defaults to false)\n" -" --captureFilename [FILENAME] Specify the filename to which the first rendered frame should be written\n" -" --bakeWidth [INTEGER] Specify the target width for texture baking (defaults to maximum image width of the source document)\n" -" --bakeHeight [INTEGER] Specify the target height for texture baking (defaults to maximum image height of the source document)\n" -" --bakeFilename [STRING] Specify the output document filename for texture baking\n" -" --refresh [FLOAT] Specify the refresh period for the viewer in milliseconds (defaults to 50, set to -1 to disable)\n" -" --remap [TOKEN1:TOKEN2] Specify the remapping from one token to another when MaterialX document is loaded\n" -" --skip [NAME] Specify to skip elements matching the given name attribute\n" -" --terminator [STRING] Specify to enforce the given terminator string for file prefixes\n" -" --help Display the complete list of command-line options\n"; +const std::string options = + " Options: \n" + " --material [FILENAME] Specify the filename of the MTLX document to be displayed in the viewer\n" + " --mesh [FILENAME] Specify the filename of the OBJ mesh to be displayed in the viewer\n" + " --meshRotation [VECTOR3] Specify the rotation of the displayed mesh as three comma-separated floats, representing rotations in degrees about the X, Y, and Z axes (defaults to 0,0,0)\n" + " --meshScale [FLOAT] Specify the uniform scale of the displayed mesh\n" + " --enableTurntable[BOOLEAN] Specify whether to enable turntable rendering of the scene\n" + " --turntableSteps [INTEGER] Specify the number of steps for a complete turntable rotation. Defaults to 360\n" + " --cameraPosition [VECTOR3] Specify the position of the camera as three comma-separated floats (defaults to 0,0,5)\n" + " --cameraTarget [VECTOR3] Specify the position of the camera target as three comma-separated floats (defaults to 0,0,0)\n" + " --cameraViewAngle [FLOAT] Specify the view angle of the camera, or zero for an orthographic projection (defaults to 45)\n" + " --cameraZoom [FLOAT] Specify the zoom factor for the camera, implemented as a mesh scale multiplier (defaults to 1)\n" + " --envRad [FILENAME] Specify the filename of the environment light to display, stored as HDR environment radiance in the latitude-longitude format\n" + " --envMethod [INTEGER] Specify the environment lighting method (0 = filtered importance sampling, 1 = prefiltered environment maps, defaults to 0)\n" + " --envSampleCount [INTEGER] Specify the environment sample count (defaults to 16)\n" + " --lightRotation [FLOAT] Specify the rotation in degrees of the lighting environment about the Y axis (defaults to 0)\n" + " --shadowMap [BOOLEAN] Specify whether shadow mapping is enabled (defaults to true)\n" + " --path [FILEPATH] Specify an additional data search path location (e.g. '/projects/MaterialX'). This absolute path will be queried when locating data libraries, XInclude references, and referenced images.\n" + " --library [FILEPATH] Specify an additional data library folder (e.g. 'vendorlib', 'studiolib'). This relative path will be appended to each location in the data search path when loading data libraries.\n" + " --screenWidth [INTEGER] Specify the width of the screen image in pixels (defaults to 1280)\n" + " --screenHeight [INTEGER] Specify the height of the screen image in pixels (defaults to 960)\n" + " --screenColor [VECTOR3] Specify the background color of the viewer as three comma-separated floats (defaults to 0.3,0.3,0.32)\n" + " --drawEnvironment [BOOLEAN] Specify whether to render the environment as the background (defaults to false)\n" + " --captureFilename [FILENAME] Specify the filename to which the first rendered frame should be written\n" + " --bakeWidth [INTEGER] Specify the target width for texture baking (defaults to maximum image width of the source document)\n" + " --bakeHeight [INTEGER] Specify the target height for texture baking (defaults to maximum image height of the source document)\n" + " --bakeFilename [STRING] Specify the output document filename for texture baking\n" + " --refresh [FLOAT] Specify the refresh period for the viewer in milliseconds (defaults to 50, set to -1 to disable)\n" + " --remap [TOKEN1:TOKEN2] Specify the remapping from one token to another when MaterialX document is loaded\n" + " --skip [NAME] Specify to skip elements matching the given name attribute\n" + " --terminator [STRING] Specify to enforce the given terminator string for file prefixes\n" + " --help Display the complete list of command-line options\n"; -template void parseToken(std::string token, std::string type, T& res) +template void parseToken(std::string token, std::string type, T& res) { if (token.empty()) { @@ -64,7 +64,7 @@ template void parseToken(std::string token, std::string type, T& res) } int main(int argc, char* const argv[]) -{ +{ std::vector tokens; for (int i = 1; i < argc; i++) { @@ -131,7 +131,7 @@ int main(int argc, char* const argv[]) else if (token == "--turntableSteps") { parseToken(nextToken, "integer", turntableSteps); - turntableSteps = std::clamp(turntableSteps, 2, 360);; + turntableSteps = std::clamp(turntableSteps, 2, 360); } else if (token == "--cameraPosition") { @@ -159,7 +159,7 @@ int main(int argc, char* const argv[]) else if (token == "--envSampleCount") { parseToken(nextToken, "integer", envSampleCount); - } + } else if (token == "--lightRotation") { parseToken(nextToken, "float", lightRotation); diff --git a/source/MaterialXView/RenderPipeline.h b/source/MaterialXView/RenderPipeline.h index 82f5990513..87baac3fa4 100644 --- a/source/MaterialXView/RenderPipeline.h +++ b/source/MaterialXView/RenderPipeline.h @@ -44,16 +44,16 @@ class RenderPipeline virtual ~RenderPipeline() { } virtual void initialize(void* device, void* command_queue) = 0; - + virtual mx::ImageHandlerPtr createImageHandler() = 0; - virtual mx::MaterialPtr createMaterial() = 0; + virtual mx::MaterialPtr createMaterial() = 0; virtual void bakeTextures() = 0; - + virtual void updateAlbedoTable(int tableSize) = 0; virtual std::shared_ptr createTextureBaker(unsigned int width, unsigned int height, mx::Image::BaseType baseType) = 0; - + virtual void renderFrame(void* color_texture, int shadowMapSize, const char* dirLightNodeCat) = 0; virtual void initFramebuffer(int width, int height, @@ -62,9 +62,9 @@ class RenderPipeline void* color_texture) = 0; virtual mx::ImagePtr getShadowMap(int shadowMapSize) = 0; - + virtual mx::ImagePtr getFrameImage() = 0; - + public: Viewer* _viewer; }; diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index ebba46e185..665036415a 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()) { @@ -1400,7 +1380,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) diff --git a/source/PyMaterialX/PyMaterialX.h b/source/PyMaterialX/PyMaterialX.h index 7af67ac4bd..1e7bc7ff87 100644 --- a/source/PyMaterialX/PyMaterialX.h +++ b/source/PyMaterialX/PyMaterialX.h @@ -16,4 +16,16 @@ #include #include +// Define a macro to import a PyMaterialX module, e.g. `PyMaterialXCore`, +// either within the `MaterialX` Python package, e.g. in `installed/python/`, +// or as a standalone module, e.g. in `lib/` +#define PYMATERIALX_IMPORT_MODULE(MODULE_NAME) \ + try \ + { \ + pybind11::module::import("MaterialX." #MODULE_NAME); \ + } \ + catch (const py::error_already_set&) \ + { \ + pybind11::module::import(#MODULE_NAME); \ + } #endif diff --git a/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp b/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp index 842087d24f..3965f48753 100644 --- a/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp @@ -15,6 +15,9 @@ PYBIND11_MODULE(PyMaterialXFormat, mod) { mod.doc() = "Module containing Python bindings for the MaterialXFormat library"; + // PyMaterialXFormat depends on types defined in PyMaterialXCore + PYMATERIALX_IMPORT_MODULE(PyMaterialXCore); + bindPyFile(mod); bindPyXmlIo(mod); bindPyUtil(mod); diff --git a/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp index a36b815d32..9ab46e514d 100644 --- a/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp @@ -16,6 +16,9 @@ PYBIND11_MODULE(PyMaterialXGenGlsl, mod) { mod.doc() = "Module containing Python bindings for the MaterialXGenGlsl library"; + // PyMaterialXGenGlsl depends on types defined in PyMaterialXGenShader + PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); + bindPyGlslShaderGenerator(mod); bindPyGlslResourceBindingContext(mod); diff --git a/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp index 020c944e63..a34b28a729 100644 --- a/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp @@ -13,5 +13,8 @@ PYBIND11_MODULE(PyMaterialXGenMdl, mod) { mod.doc() = "Module containing Python bindings for the MaterialXGenMdl library"; + // PyMaterialXGenMdl depends on types defined in PyMaterialXGenShader + PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); + bindPyMdlShaderGenerator(mod); }; diff --git a/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp index 6eda44871b..b3dcdb10a8 100644 --- a/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp @@ -14,6 +14,9 @@ PYBIND11_MODULE(PyMaterialXGenMsl, mod) { mod.doc() = "Module containing Python bindings for the MaterialXGenMsl library"; + // PyMaterialXGenMsl depends on types defined in PyMaterialXGenShader + PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); + bindPyMslShaderGenerator(mod); bindPyMslResourceBindingContext(mod); } diff --git a/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp index d772d18b6a..54d7d2439a 100644 --- a/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp @@ -13,5 +13,8 @@ PYBIND11_MODULE(PyMaterialXGenOsl, mod) { mod.doc() = "Module containing Python bindings for the MaterialXGenOsl library"; + // PyMaterialXGenOsl depends on types defined in PyMaterialXGenShader + PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); + bindPyOslShaderGenerator(mod); } diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyShaderPort.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyShaderPort.cpp index 343442e071..146674c222 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyShaderPort.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyShaderPort.cpp @@ -24,6 +24,7 @@ void bindPyShaderPort(py::module& mod) .def("getSemantic", &mx::ShaderPort::getSemantic) .def("setValue", &mx::ShaderPort::setValue) .def("getValue", &mx::ShaderPort::getValue) + .def("getValueString", &mx::ShaderPort::getValueString) .def("setGeomProp", &mx::ShaderPort::setGeomProp) .def("getGeomProp", &mx::ShaderPort::getGeomProp) .def("setPath", &mx::ShaderPort::setPath) diff --git a/source/PyMaterialX/PyMaterialXRender/PyModule.cpp b/source/PyMaterialX/PyMaterialXRender/PyModule.cpp index 1c60142346..bbf9688403 100644 --- a/source/PyMaterialX/PyMaterialXRender/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXRender/PyModule.cpp @@ -25,6 +25,9 @@ PYBIND11_MODULE(PyMaterialXRender, mod) { mod.doc() = "Module containing Python bindings for the MaterialXRender library"; + // PyMaterialXRender depends on types defined in PyMaterialXCore + PYMATERIALX_IMPORT_MODULE(PyMaterialXCore); + bindPyMesh(mod); bindPyGeometryHandler(mod); bindPyLightHandler(mod); diff --git a/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp index 32fb79239d..d0ef04158d 100644 --- a/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp @@ -16,6 +16,9 @@ PYBIND11_MODULE(PyMaterialXRenderGlsl, mod) { mod.doc() = "Module containing Python bindings for the MaterialXRenderGlsl library"; + // PyMaterialXRenderGlsl depends on types defined in PyMaterialXRender + PYMATERIALX_IMPORT_MODULE(PyMaterialXRender); + bindPyGlslProgram(mod); bindPyGlslRenderer(mod); bindPyGLTextureHandler(mod); diff --git a/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm b/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm index 10b440d21c..f4d0dbeaeb 100644 --- a/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm +++ b/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm @@ -16,6 +16,9 @@ { mod.doc() = "Module containing Python bindings for the MaterialXRenderMsl library"; + // PyMaterialXRenderMsl depends on types defined in PyMaterialXRender + PYMATERIALX_IMPORT_MODULE(PyMaterialXRender); + bindPyMslProgram(mod); bindPyMslRenderer(mod); bindPyMetalTextureHandler(mod); diff --git a/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp index 15610066f3..4019d364ab 100644 --- a/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp @@ -13,5 +13,8 @@ PYBIND11_MODULE(PyMaterialXRenderOsl, mod) { mod.doc() = "Module containing Python bindings for the MaterialXRenderOsl library"; + // PyMaterialXRenderOsl depends on types defined in PyMaterialXRender + PYMATERIALX_IMPORT_MODULE(PyMaterialXRender); + bindPyOslRenderer(mod); }