From ac11732c9fd7a0aeda6a21b8093dc08bcf22f11d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 2 Jul 2024 08:04:31 -0700 Subject: [PATCH 001/137] Update cibuildwheel to v2.19.2 This changelist updates cibuildwheel to v2.19.2, which contains a fix for the usage of CentOS 7 (now past-EOL) in manylinux2014. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d96309b0c2..6c2b8d1ebc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -401,7 +401,7 @@ jobs: path: sdist - name: Build Wheel - uses: pypa/cibuildwheel@v2.17.0 + uses: pypa/cibuildwheel@v2.19.2 with: package-dir: ${{ github.workspace }}/sdist/${{ needs.sdist.outputs.sdist_filename }} env: From 30f694f42670c4eb5e7386ce931a6e3690bbe2a3 Mon Sep 17 00:00:00 2001 From: Pablo Delgado Date: Wed, 3 Jul 2024 20:17:29 +0200 Subject: [PATCH 002/137] Update normalmap node to 1.39 (#1911) - I have added the null-check from GLSL and MSL to the OSL and MDL backends for consistency. As an alternative, it could be removed from all implementations. - Tangent vector renormalization in OSL seems like a concern that should be handled by the implementation providing the geometry streams. I removed it. --- libraries/stdlib/genglsl/mx_normalmap.glsl | 18 ++++------- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 4 +-- libraries/stdlib/genmsl/mx_normalmap.metal | 18 ++++------- libraries/stdlib/genosl/mx_normalmap.osl | 21 ++++++------- libraries/stdlib/stdlib_defs.mtlx | 4 +-- .../normalmapped_surfaceshader.mtlx | 2 -- .../pbrlib/surfaceshader/usd_normal_map.mtlx | 1 - .../color_management/color3_vec3_cm_test.mtlx | 1 - .../definition_using_definitions.mtlx | 1 - source/MaterialXCore/Version.cpp | 20 ++++++++++++- .../mdl/materialx/stdlib_1_6.mdl | 30 +++++-------------- .../MslPipelineStateObject.mm | 7 +++++ 12 files changed, 57 insertions(+), 70 deletions(-) diff --git a/libraries/stdlib/genglsl/mx_normalmap.glsl b/libraries/stdlib/genglsl/mx_normalmap.glsl index 19e0797c4f..9fe8c66920 100644 --- a/libraries/stdlib/genglsl/mx_normalmap.glsl +++ b/libraries/stdlib/genglsl/mx_normalmap.glsl @@ -1,21 +1,13 @@ -void mx_normalmap_vector2(vec3 value, int map_space, vec2 normal_scale, vec3 N, vec3 T, out vec3 result) +void mx_normalmap_vector2(vec3 value, vec2 normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) { - // Decode the normal map. - value = (value == vec3(0.0f)) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; + value = (value == vec3(0.0)) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; - // Transform from tangent space if needed. - if (map_space == 0) - { - vec3 B = normalize(cross(N, T)); - value.xy *= normal_scale; - value = T * value.x + B * value.y + N * value.z; - } + value = T * value.x * normal_scale.x + B * value.y * normal_scale.y + N * value.z; - // Normalize the result. result = normalize(value); } -void mx_normalmap_float(vec3 value, int map_space, float normal_scale, vec3 N, vec3 T, out vec3 result) +void mx_normalmap_float(vec3 value, float normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) { - mx_normalmap_vector2(value, map_space, vec2(normal_scale), N, T, result); + mx_normalmap_vector2(value, vec2(normal_scale), N, T, B, result); } diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index 32bf05aeac..ec4af76961 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -44,8 +44,8 @@ - - + + diff --git a/libraries/stdlib/genmsl/mx_normalmap.metal b/libraries/stdlib/genmsl/mx_normalmap.metal index a3ffedaad5..3674756d8b 100644 --- a/libraries/stdlib/genmsl/mx_normalmap.metal +++ b/libraries/stdlib/genmsl/mx_normalmap.metal @@ -1,21 +1,13 @@ -void mx_normalmap_vector2(vec3 value, int map_space, vec2 normal_scale, vec3 N, vec3 T, out vec3 result) +void mx_normalmap_vector2(vec3 value, vec2 normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) { - // Decode the normal map. - value = all(value == vec3(0.0f)) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; + value = all(value == vec3(0.0)) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; - // Transform from tangent space if needed. - if (map_space == 0) - { - vec3 B = normalize(cross(N, T)); - value.xy *= normal_scale; - value = T * value.x + B * value.y + N * value.z; - } + value = T * value.x * normal_scale.x + B * value.y * normal_scale.y + N * value.z; - // Normalize the result. result = normalize(value); } -void mx_normalmap_float(vec3 value, int map_space, float normal_scale, vec3 N, vec3 T, out vec3 result) +void mx_normalmap_float(vec3 value, float normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) { - mx_normalmap_vector2(value, map_space, vec2(normal_scale), N, T, result); + mx_normalmap_vector2(value, vec2(normal_scale), N, T, B, result); } diff --git a/libraries/stdlib/genosl/mx_normalmap.osl b/libraries/stdlib/genosl/mx_normalmap.osl index 79b31df69d..88c12cc389 100644 --- a/libraries/stdlib/genosl/mx_normalmap.osl +++ b/libraries/stdlib/genosl/mx_normalmap.osl @@ -1,22 +1,19 @@ -void mx_normalmap_vector2(vector value, string map_space, vector2 normal_scale, vector N, vector U, output vector result) +void mx_normalmap_vector2(vector value, vector2 normal_scale, vector N, vector T, vector B, output vector result) { - // Tangent space - if (map_space == "tangent") + vector decodedValue; + if (value == vector(0.0)) { - vector v = value * 2.0 - 1.0; - vector T = normalize(U - dot(U, N) * N); - vector B = normalize(cross(N, T)); - result = normalize(T * v[0] * normal_scale.x + B * v[1] * normal_scale.y + N * v[2]); + decodedValue = vector(0.0, 0.0, 1.0); } - // Object space else { - vector n = value * 2.0 - 1.0; - result = normalize(n); + decodedValue = value * 2.0 - 1.0; } + + result = normalize(T * decodedValue[0] * normal_scale.x + B * decodedValue[1] * normal_scale.y + N * decodedValue[2]); } -void mx_normalmap_float(vector value, string map_space, float normal_scale, vector N, vector U, output vector result) +void mx_normalmap_float(vector value, float normal_scale, vector N, vector T, vector B, output vector result) { - mx_normalmap_vector2(value, map_space, vector2(normal_scale, normal_scale), N, U, result); + mx_normalmap_vector2(value, vector2(normal_scale, normal_scale), N, T, B, result); } diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index c9c3fc8431..943e36ec88 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -2604,18 +2604,18 @@ --> - + - + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx index e3c1eee089..defa4c4bbd 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx @@ -15,7 +15,6 @@ - @@ -40,7 +39,6 @@ - diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx index 621fba621d..dbdc8f3ac3 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx @@ -14,7 +14,6 @@ - diff --git a/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx b/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx index d1c1fd5626..62c6033222 100644 --- a/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx +++ b/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx @@ -26,7 +26,6 @@ - diff --git a/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx b/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx index e3503d68f6..55a8cfa707 100644 --- a/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx +++ b/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx @@ -274,7 +274,6 @@ - diff --git a/source/MaterialXCore/Version.cpp b/source/MaterialXCore/Version.cpp index 9c0022bd6a..5195a1e049 100644 --- a/source/MaterialXCore/Version.cpp +++ b/source/MaterialXCore/Version.cpp @@ -1316,10 +1316,28 @@ void Document::upgradeVersion() input2->setName("inx"); } } - else if (node->getNodeDefString() == "ND_normalmap") + else if (nodeCategory == "normalmap") { // ND_normalmap was renamed to ND_normalmap_float node->setNodeDefString("ND_normalmap_float"); + + node->removeInput("space"); + + // If the normal or tangent inputs are set, the bitangent input should be normalize(cross(N, T)) + InputPtr normalInput = node->getInput("normal"); + InputPtr tangentInput = node->getInput("tangent"); + if (normalInput || tangentInput) + { + GraphElementPtr graph = node->getAncestorOfType(); + NodePtr crossNode = graph->addNode("crossproduct", graph->createValidChildName("normalmap_cross"), "vector3"); + copyInputWithBindings(node, "normal", crossNode, "in1"); + copyInputWithBindings(node, "tangent", crossNode, "in2"); + + NodePtr normalizeNode = graph->addNode("normalize", graph->createValidChildName("normalmap_cross_norm"), "vector3"); + normalizeNode->addInput("in", "vector3")->setConnectedNode(crossNode); + + node->addInput("bitangent", "vector3")->setConnectedNode(normalizeNode); + } } } for (NodePtr node : unusedNodes) diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl index cd47e35d17..8cfedd56a0 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl @@ -2094,46 +2094,32 @@ export float4 mx_transformmatrix_vector4( export float3 mx_normalmap_vector2( float3 mxp_in = float3(0.5, 0.5, 1.0), - uniform string mxp_space = string("tangent") - [[ - anno::description("Enumeration {tangent, object}.") - ]], float2 mxp_scale = float2(1.0, 1.0), float3 mxp_normal = float3(::state::transform_normal(::state::coordinate_internal,::state::coordinate_world,::state::normal())), - float3 mxp_tangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))) + float3 mxp_tangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))), + float3 mxp_bitangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_v(0))) ) [[ anno::description("Node Group: math") ]] { - if (mxp_space == "tangent") - { - float3 v = mxp_in * 2.0 - 1.0; - float3 binormal = ::math::normalize(::math::cross(mxp_normal, mxp_tangent)); - return ::math::normalize(mxp_tangent * v.x * mxp_scale.x + binormal * v.y * mxp_scale.y + mxp_normal * v.z); - } - else - { - float3 n = mxp_in * 2.0 - 1.0; - return ::math::normalize(n); - } + float3 v = (mxp_in == float3(0.0)) ? float3(0.0, 0.0, 1.0) : mxp_in * 2.0 - 1.0; + + return ::math::normalize(mxp_tangent * v.x * mxp_scale.x + mxp_bitangent * v.y * mxp_scale.y + mxp_normal * v.z); } export float3 mx_normalmap_float( float3 mxp_in = float3(0.5, 0.5, 1.0), - uniform string mxp_space = string("tangent") - [[ - anno::description("Enumeration {tangent, object}.") - ]], float mxp_scale = float(1.0), float3 mxp_normal = float3(::state::transform_normal(::state::coordinate_internal,::state::coordinate_world,::state::normal())), - float3 mxp_tangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))) + float3 mxp_tangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))), + float3 mxp_bitangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_v(0))) ) [[ anno::description("Node Group: math") ]] { - return mx_normalmap_vector2(mxp_in, mxp_space, float2(mxp_scale, mxp_scale), mxp_normal, mxp_tangent); + return mx_normalmap_vector2(mxp_in, float2(mxp_scale, mxp_scale), mxp_normal, mxp_tangent, mxp_bitangent); } export float3x3 mx_transpose_matrix33( diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm index c570b68fc4..cb1d58916a 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm @@ -490,6 +490,13 @@ int GetStrideOfMetalType(MTLDataType type) bindAttribute(renderCmdEncoder, foundList, mesh); } + // Bind bitangents + findInputs(HW::IN_BITANGENT, attributeList, foundList, true); + if (foundList.size()) + { + bindAttribute(renderCmdEncoder, foundList, mesh); + } + // Bind colors // Search for anything that starts with the color prefix findInputs(HW::IN_COLOR + "_", attributeList, foundList, false); From e1644f75e6927fd23ebad3935250df6b786aa1c3 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 3 Jul 2024 15:38:34 -0700 Subject: [PATCH 003/137] Update changelog for recent work --- CHANGELOG.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 495feae6dc..e9b4c1b393 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,35 +3,43 @@ ## [1.39.0] - Development ### Added -- Added a [MaterialX implementation](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1816) of the [OpenPBR Surface](https://academysoftwarefoundation.github.io/OpenPBR/) shading model. -- Added support for [Hoffman-Schlick Fresnel](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1727), [Zeltner-Burley sheen](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1825), and [energy-compensated Oren-Nayar diffuse](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1822) in physically based shading. +- Added support for the [OpenPBR Surface](https://academysoftwarefoundation.github.io/OpenPBR/) shading model, including the [MaterialX definition](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/open_pbr_surface.mtlx) and [example materials](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples/OpenPbr) for OpenPBR Surface v1.1. +- Added support for [Hoffman-Schlick Fresnel](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1727), [Zeltner sheen](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1880), and [energy-compensated Oren-Nayar diffuse](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1822), with initial implementations in hardware shading languages. +- Added support for the [LamaGeneralizedSchlick and LamaIridescence](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1897) nodes, with definitions provided as MaterialX graphs. - Added support for integer-type [add, subtract](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1777), and [conditional](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1786) nodes. - Added support for matrix-type [switch](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1779) and [conditional](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1780) nodes. +- Added support for additional [convert node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1905) input and output types. - Added support for [monolithic builds](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1725) of MaterialX. -- Added support for [Python 3.12](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1802) in Python wheel generation. - Added support for the [full set of shader generators](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1771) in JavaScript. -- Added an example script to [generate a MaterialX document](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1746) from a folder of textures. - Added support for [frame timing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1739) in the MaterialX Viewer. +- Added a [uiScale option](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1586) for adjusting DPI in the Graph Editor. +- Added an example script to [generate a MaterialX document](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1746) from a folder of textures. - Added unit tests for [core utilities](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1768) and [ESSL shader generation](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1781). +- Added support for [Python 3.12](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1802) in Python wheel generation. +- Added [GCC 14](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1913) and [Clang 18](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1820) builds to GitHub Actions CI. ### Changed - Raised the minimum C++ version for MaterialX builds to [C++17](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1712). - Updated the [PyBind11 library](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1839) to version 2.12.0, enabling support for recent compilers and CMake versions. - Improved the expression of [thin-film layering](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1413) in MaterialX 1.39, with automatic upgrade logic for legacy documents. +- Improved the generality of the [normalmap node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1911) in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Extended the [switch node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1660) to ten inputs in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Renamed the inputs of the [atan2 node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1659) in MaterialX 1.39, with automatic upgrade logic for legacy documents. +- Changed the type of [subsurface_bsdf radius](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1834) from vector3 to color3 in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Renamed the [normalmap nodedef](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1677) in MaterialX 1.39, with automatic upgrade logic for legacy documents. +- Improved the support for [double-sided materials](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1866) in MaterialX 1.39. - Optimized [Fresnel](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1732) [computations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1733) in [GLSL](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1736), improving the performance of physically based shading in real-time renders. - Applied [lossless optimization](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1738) to PNG and JPG textures in the MaterialX repository. +### Fixed +- Fixed default values for the [creatematrix node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1788). +- Fixed an issue with [keyboard input focus](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1596) in the Graph Editor. + ### Removed - Removed the [swizzle node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1793) in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Removed the [channels attribute](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1804) in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Removed the unimplemented [arrayappend node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1707) in MaterialX 1.39. -### Fixed -- Fixed default values for the [creatematrix node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1788). - ## [1.38.10] - 2024-04-12 ### Added From 6369847f57b6b40053584adb440cfeedd847e99e Mon Sep 17 00:00:00 2001 From: ld-kerley <154285602+ld-kerley@users.noreply.github.com> Date: Wed, 3 Jul 2024 16:40:37 -0700 Subject: [PATCH 004/137] Specification update for struct support (#1908) This is a first pass at updating the specification to reflect the upcoming struct support in PR #1831. A lot of this is lifted from the old 1.38 specification pdf, as that was largely the inspiration for the implementation. --- .../Specification/MaterialX.Specification.md | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index e6f4bae531..681f36ea36 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -258,7 +258,7 @@ While colorN and vectorN types both describe vectors of floati ## Custom Data Types -In addition to the standard data types, MaterialX supports the specification of custom data types for the inputs and outputs of shaders and custom nodes. This allows documents to describe data streams of any complex type an application may require; examples might include spectral color samples or compound geometric data. +In addition to the standard data types, MaterialX supports the specification of custom data types for the inputs and outputs of shaders and custom nodes. This allows documents to describe data streams of any complex type an application may require; examples might include spectral color samples or compound geometric data. The structure of a custom type's contents may be described using a number of elements, though it is also permissible to only declare the custom type's name and treat the type as "blind data". Types can be declared to have a specific semantic, which can be used to determine how values of that type should be interpreted, and how nodes outputting that type can be connected. Currently, MaterialX defines three semantics: @@ -272,12 +272,15 @@ Custom types are defined using the <typedef> element: ```xml - + + + + ``` Attributes for <typedef> elements: -* `name` (string, required): the name of this type. Cannot be the same as a built-in MaterialX type. +* `name` (string, required): the name of this type. Cannot be the same as a built-in MaterialX type. To reduce the possible symbol conflict between custom type names and possible variable names created by code generation, we suggest the convention of using `_struct` as a suffix to the type name. * `semantic` (string, optional): the semantic for this type (see above); the default semantic is "default". * `context` (string, optional): a semantic-specific context in which this type should be applied. For "shader" semantic types, `context` defines the rendering context in which the shader output is interpreted; please see the [Shader Nodes](#shader-nodes) section for details. * `inherit` (string, optional): the name of another type that this type inherits from, which can be either a built-in type or a custom type. Applications that do not have a definition for this type can use the inherited type as a "fallback" type. @@ -285,6 +288,32 @@ Attributes for <typedef> elements: * "halfprecision": the values within this type are half-precision * "doubleprecision: the values within this type are double-precision +Attributes for <member> elements: + +* `name` (string, required): the name of the member variable. Must be unique within the list of other member names for this custom type. +* `type` (string, required): the type of the member variable; can be any built-in MaterialX type, or any previously defined custom type; recursive inclusion for <member> types is not supported. +* `value` (string, required): the default value of the member variable. + +If a number of elements are provided, then a MaterialX file can specify a value for that type any place it is used, as a brace surrounded, semicolon-separated list of numbers and strings, with the expectation that the numbers and strings between semicolons exactly line up with the expected types in order. The use of the braces allows for custom struct types initializers to be nested. For example, if the following was declared: + +```xml + + + + + + + +``` + +Then a permissible input declaration in a custom node using that type could be: + +```xml + +``` + +If child elements are not provided, e.g. if the contents of the custom type cannot be represented as a list of MaterialX types, then a value cannot be provided, and this type can only be used to pass blind data from one custom node's output to another custom node or shader input. + Once a custom type is defined by a <typedef>, it can then be used in any MaterialX element that allows "any MaterialX type"; the list of MaterialX types is effectively expanded to include the new custom type. It should be noted however that the <typedef> is only declaring the existence of the type and perhaps some hints about its intended definition, but it is up to each application and code generator to provide its own precise definition for any type. The standard MaterialX distribution includes definitions for four "shader"-semantic data types: **surfaceshader**, **displacementshader**, **volumeshader**, and **lightshader**. These types are discussed in more detail in the [Shader Nodes](#shader-nodes) section below. From 75a733708a2564ab33974ffae3105e6b86e806bd Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 3 Jul 2024 17:45:07 -0700 Subject: [PATCH 005/137] Updates to specification README - Add a link to the NPR Shading Nodes specification. - Delete a line about the removal of typedef members, as these remain active in the 1.39 specification. --- documents/Specification/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documents/Specification/README.md b/documents/Specification/README.md index 92677999fc..82e0a81566 100644 --- a/documents/Specification/README.md +++ b/documents/Specification/README.md @@ -8,6 +8,7 @@ The documents in this folder comprise the complete MaterialX Specification, vers * [**MaterialX Specification**](./MaterialX.Specification.md) - the main Specification, describing definitions, core functionality and the standard node library * [**MaterialX Physically Based Shading Nodes**](./MaterialX.PBRSpec.md) - describes BSDF and other shading function nodes useful in constructing complex layered rendering shaders using node graphs +* [**MaterialX NPR Shading Nodes**](./MaterialX.NPRSpec.md) - specifies shading nodes that are designed for use in non-photorealistic and stylized rendering * [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) - additional MaterialX elements to define geometry-related information such as collections, properties and material assignments * [**MaterialX Supplemental Notes**](./MaterialX.Supplement.md) - describes recommended naming and structuring conventions for libraries of custom node definitions @@ -96,7 +97,6 @@ The following new standard physically based shading nodes have been added: **Other Changes** -* The <member> element for <typedef>s and the "member" attribute for inputs have been removed from the Specification, as they had never been implemented and it was not clear how they could be implemented generally. * The "valuerange" and "valuecurve" attributes describing expressions and function curves have been removed, in favor of using the new <curveinversecubic> / <curveuniformcubic> / etc. nodes. * The <geomcolor>, <geompropvalue> and <geompropvalueuniform> nodes for color3/4-type values can now take a "colorspace" attribute to declare the colorspace of the property value. * The <cellnoise2d> and <cellnoise3d> nodes now support vectorN output types in addition to float output. From f679db7875a928fd0162cd38bdc7461b2aa81c0f Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 5 Jul 2024 07:59:21 -0700 Subject: [PATCH 006/137] Finalize changelog for 1.39.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9b4c1b393..3923541d27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## [1.39.0] - Development +## [1.39.0] - 2024-07-05 ### Added - Added support for the [OpenPBR Surface](https://academysoftwarefoundation.github.io/OpenPBR/) shading model, including the [MaterialX definition](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/open_pbr_surface.mtlx) and [example materials](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples/OpenPbr) for OpenPBR Surface v1.1. From a012594fa2eb0dfb7cfa5731c6aebead4ac7c1f2 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 8 Jul 2024 16:13:22 -0700 Subject: [PATCH 007/137] Update development build to 1.39.1 --- CHANGELOG.md | 2 ++ CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3923541d27..40a8f23983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Change Log +## [1.39.1] - Development + ## [1.39.0] - 2024-07-05 ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index 4505ab106b..ffb7118303 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # MaterialX Version set(MATERIALX_MAJOR_VERSION 1) set(MATERIALX_MINOR_VERSION 39) -set(MATERIALX_BUILD_VERSION 0) +set(MATERIALX_BUILD_VERSION 1) set(MATERIALX_LIBRARY_VERSION ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}) # Cmake setup From e0e69ca6badc2a4b22661b5cf0b295b0872713ee Mon Sep 17 00:00:00 2001 From: ld-kerley <154285602+ld-kerley@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:57:08 -0700 Subject: [PATCH 008/137] Fix missing include install (#1923) The `mx_add_library` refactor introduced in #1725, introduced a few bugs with installing files. `Generated.h` was incorrectly being ignored, instead `Generated.h.in` was being installed, and also the mdl library files were missing, also some resources were also not being installed. Should now be corrected in both monolithic and non-monolithic builds. --- CMakeLists.txt | 51 +++++++++++++++++++----- source/CMakeLists.txt | 13 +----- source/MaterialXGenMdl/CMakeLists.txt | 5 +++ source/MaterialXGenShader/CMakeLists.txt | 5 +++ source/MaterialXRender/CMakeLists.txt | 4 +- 5 files changed, 55 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ffb7118303..8ea130353e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -286,6 +286,7 @@ function(mx_add_library MATERIALX_MODULE_NAME) set(multiValueArgs SOURCE_FILES HEADER_FILES + INLINED_FILES LIBRARIES) cmake_parse_arguments(args "${options}" @@ -301,11 +302,12 @@ function(mx_add_library MATERIALX_MODULE_NAME) endif() assign_source_group("Source Files" ${args_SOURCE_FILES}) + assign_source_group("Source Files" ${args_INLINED_FILES}) assign_source_group("Header Files" ${args_HEADER_FILES}) if (NOT MATERIALX_BUILD_MONOLITHIC) set(TARGET_NAME ${MATERIALX_MODULE_NAME}) - add_library(${TARGET_NAME} ${args_SOURCE_FILES} ${args_HEADER_FILES}) + add_library(${TARGET_NAME}) # Create version resource if(MATERIALX_BUILD_SHARED_LIBS AND MSVC) @@ -336,15 +338,30 @@ function(mx_add_library MATERIALX_MODULE_NAME) else() set(TARGET_NAME ${MATERIALX_MONOLITHIC_TARGET}) - target_sources(${TARGET_NAME} PRIVATE ${args_SOURCE_FILES}) - target_sources(${TARGET_NAME} PRIVATE ${args_HEADER_FILES}) - add_library(${MATERIALX_MODULE_NAME} ALIAS ${MATERIALX_MONOLITHIC_TARGET}) # Store the aliased MaterialX modules name to create cmake export aliases later. set_property(GLOBAL APPEND PROPERTY MATERIALX_MODULES ${MATERIALX_MODULE_NAME}) endif() + target_sources(${TARGET_NAME} + PRIVATE + ${args_SOURCE_FILES} + PUBLIC + FILE_SET + mxHeaders + TYPE + HEADERS + BASE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_BINARY_DIR}/.. + FILES + ${args_HEADER_FILES} + ${args_INLINED_FILES}) + + target_include_directories(${TARGET_NAME} PUBLIC + $) + target_compile_definitions(${TARGET_NAME} PRIVATE "-D${args_EXPORT_DEFINE}") if(NOT SKBUILD) @@ -353,15 +370,10 @@ function(mx_add_library MATERIALX_MODULE_NAME) EXPORT MaterialX ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) + RUNTIME DESTINATION bin + FILE_SET mxHeaders) endif() - install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER - FILES_MATCHING - PATTERN "*.h*" - PATTERN "*.inl") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) endif() @@ -452,6 +464,23 @@ if(MATERIALX_BUILD_JS) add_subdirectory(source/JsMaterialX) endif() +if (MATERIALX_BUILD_MONOLITHIC) + # MaterialX monolithic build target needs to be installed after any other included + # modules to ensure the correct files are in mxHeaders + if(NOT SKBUILD) + install(TARGETS ${MATERIALX_MONOLITHIC_TARGET} + EXPORT MaterialX + ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} + LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} + RUNTIME DESTINATION bin + FILE_SET mxHeaders) + + # Note : we don't install the headers etc. here, and rely on each separate modules CMakeLists.txt + # to do that installation, thus we respect the build options configuration, and only install + # the headers for the modules we've built in to the monolithic build. + endif() +endif() + if(MATERIALX_BUILD_VIEWER) set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MaterialXView) elseif(MATERIALX_BUILD_GRAPH_EDITOR) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 10279959bb..d2dec4c632 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -32,15 +32,6 @@ if (MATERIALX_BUILD_MONOLITHIC) PRIVATE ${EXTERNAL_INCLUDE_DIRS}) - if(NOT SKBUILD) - install(TARGETS ${MATERIALX_MODULE_NAME} - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) - - # Note : we don't install the headers etc. here, and rely on each separate modules CMakeLists.txt - # to do that installation, thus we respect the build options configuration, and only install - # the headers for the modules we've built in to the monolithic build. - endif() + # Monolithic target is installed in the root CMakeLists.txt to allow for collection + # of all necessary headers. endif() diff --git a/source/MaterialXGenMdl/CMakeLists.txt b/source/MaterialXGenMdl/CMakeLists.txt index 25e1e218a6..b53b2c1954 100644 --- a/source/MaterialXGenMdl/CMakeLists.txt +++ b/source/MaterialXGenMdl/CMakeLists.txt @@ -11,3 +11,8 @@ mx_add_library(MaterialXGenMdl MaterialXCore EXPORT_DEFINE MATERIALX_GENMDL_EXPORTS) + +if(NOT SKBUILD) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/mdl + DESTINATION "${MATERIALX_INSTALL_MDL_MODULE_PATH}") +endif() diff --git a/source/MaterialXGenShader/CMakeLists.txt b/source/MaterialXGenShader/CMakeLists.txt index ebdf814234..1e028973d0 100644 --- a/source/MaterialXGenShader/CMakeLists.txt +++ b/source/MaterialXGenShader/CMakeLists.txt @@ -11,3 +11,8 @@ mx_add_library(MaterialXGenShader MaterialXCore EXPORT_DEFINE MATERIALX_GENSHADER_EXPORTS) + +if(NOT SKBUILD) + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../resources" + DESTINATION . MESSAGE_NEVER) +endif() diff --git a/source/MaterialXRender/CMakeLists.txt b/source/MaterialXRender/CMakeLists.txt index d96fc203e7..22a9f55900 100644 --- a/source/MaterialXRender/CMakeLists.txt +++ b/source/MaterialXRender/CMakeLists.txt @@ -8,7 +8,9 @@ endif() mx_add_library(MaterialXRender SOURCE_FILES - ${materialx_source} ${materialx_inlined} + ${materialx_source} + INLINED_FILES + ${materialx_inlined} HEADER_FILES ${materialx_headers} LIBRARIES From 8160f46a587ed985b25a787c089e438052979276 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 9 Jul 2024 10:54:16 -0700 Subject: [PATCH 009/137] Remove extra resources install (#1927) This change removes an extra install of the resources folder in MaterialXGenShader, as this dependency does not appear to be required in 1.39. --- source/MaterialXGenShader/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/source/MaterialXGenShader/CMakeLists.txt b/source/MaterialXGenShader/CMakeLists.txt index 1e028973d0..ebdf814234 100644 --- a/source/MaterialXGenShader/CMakeLists.txt +++ b/source/MaterialXGenShader/CMakeLists.txt @@ -11,8 +11,3 @@ mx_add_library(MaterialXGenShader MaterialXCore EXPORT_DEFINE MATERIALX_GENSHADER_EXPORTS) - -if(NOT SKBUILD) - install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../resources" - DESTINATION . MESSAGE_NEVER) -endif() From d8660148b05484c184009fc55cd85defbea9428e Mon Sep 17 00:00:00 2001 From: Dhruv Govil Date: Tue, 9 Jul 2024 12:40:20 -0700 Subject: [PATCH 010/137] Upgrade required CMake to 3.24 (#1929) This change updates the minimum required CMake to 3.24. It also removes a workaround needed for CMake 3.16 that required tricking CMake into thinking the `.mm` file was a CXX file instead of ObjC++. With newer CMake versions, this can implicitly be handled as long as the `.mm` file doesn't share a name with an existing CXX file. --- CMakeLists.txt | 2 +- source/MaterialXGraphEditor/CMakeLists.txt | 3 +-- .../{FileDialog.mm => FileDialog_Darwin.mm} | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename source/MaterialXGraphEditor/{FileDialog.mm => FileDialog_Darwin.mm} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ea130353e..68df4e1183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(MATERIALX_BUILD_VERSION 1) set(MATERIALX_LIBRARY_VERSION ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}) # Cmake setup -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.24) set(CMAKE_CXX_STANDARD 17) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) set(CMAKE_MACOSX_RPATH ON) diff --git a/source/MaterialXGraphEditor/CMakeLists.txt b/source/MaterialXGraphEditor/CMakeLists.txt index 495213bfb6..bd2405d432 100644 --- a/source/MaterialXGraphEditor/CMakeLists.txt +++ b/source/MaterialXGraphEditor/CMakeLists.txt @@ -18,8 +18,7 @@ file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") if (APPLE) - list(APPEND materialx_source ${CMAKE_CURRENT_SOURCE_DIR}/FileDialog.mm) - set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/FileDialog.mm" PROPERTIES LANGUAGE CXX) + list(APPEND materialx_source ${CMAKE_CURRENT_SOURCE_DIR}/FileDialog_Darwin.mm) endif () file(GLOB imgui_source "${DEAR_IMGUI_PREFIX}/*.cpp") diff --git a/source/MaterialXGraphEditor/FileDialog.mm b/source/MaterialXGraphEditor/FileDialog_Darwin.mm similarity index 100% rename from source/MaterialXGraphEditor/FileDialog.mm rename to source/MaterialXGraphEditor/FileDialog_Darwin.mm From dfffe83f74e742edc3743f004da359c35cef5652 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 10 Jul 2024 08:32:45 -0700 Subject: [PATCH 011/137] Update pre-built binary links This changelist updates the links to pre-built binaries on the front page, bringing them to the latest versions on each platform. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d495b7735c..74bb3173f5 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,9 @@ The Open Chess Set is an open reference asset, consisting of a [MaterialX file]( The following packages contain pre-built binaries for the latest release, including the MaterialX viewer, Python libraries, and example assets: -- [Microsoft Windows (Visual Studio 2022, Python 3.11)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Windows_VS2022_x64_Python311.zip) -- [MacOS (Xcode 14, Python 3.11)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_MacOS_Xcode_14_Python311.zip) -- [Linux (GCC 12, Python 3.11)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Linux_GCC_12_Python311.zip) +- [Microsoft Windows (Visual Studio 2022, Python 3.12)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Windows_VS2022_x64_Python312.zip) +- [MacOS (Xcode 15, Python 3.12)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_MacOS_Xcode_15_Python312.zip) +- [Linux (GCC 14, Python 3.12)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Linux_GCC_14_Python312.zip) ### Additional Resources From a86f677d4d5bda1abc6c1d83a53d29b6a942bb97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E5=A4=A9?= Date: Sun, 14 Jul 2024 01:06:56 +0800 Subject: [PATCH 012/137] Update related input attribute when renaming a nodegraph (#1930) Fixes https://github.com/AcademySoftwareFoundation/MaterialX/issues/1912 The problem is that after renaming, the input PortElement's `_attributeMap` still hold the old name, so when drawing the graph, `getConnectedOutput` failed. --- source/MaterialXGraphEditor/Graph.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index f2382e288e..d9efb73151 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -2752,6 +2752,10 @@ void Graph::deleteLinkInfo(int startAttr, int endAttr) { int upNode = getNodeId(startAttr); int downNode = getNodeId(endAttr); + if (upNode == -1 || downNode == -1) + { + return; + } // Change input to default value if (_graphNodes[downNode]->getNode()) @@ -3354,6 +3358,23 @@ void Graph::propertyEditor() std::string name = _currUiNode->getNodeGraph()->getParent()->createValidChildName(temp); _currUiNode->getNodeGraph()->setName(name); _currUiNode->setName(name); + + for (UiNodePtr node : _graphNodes) + { + if (!node->getInput()) + { + std::vector inputs = node->inputPins; + for (size_t i = 0; i < inputs.size(); i++) + { + const std::string& inputName = inputs[i]->_name; + UiNodePtr inputNode = node->getConnectedNode(inputName); + if (inputNode && inputNode->getName() == name && node->getNode()) + { + node->getNode()->getInput(inputName)->setAttribute("nodegraph", name); + } + } + } + } } } From 77687a3b2944ab857b168a220135ab0a5206ba93 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 13 Jul 2024 15:42:51 -0700 Subject: [PATCH 013/137] Upgrade minimum CMake for GLFW This changelist upgrades the minimum version of CMake for the custom GLFW build in the Graph Editor, resolving warnings when building with the recommended versions of CMake in MaterialX. --- source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt b/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt index 2ec553856f..0bd2ffe59c 100644 --- a/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt +++ b/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(GLFW VERSION 3.4.0 LANGUAGES C) From a090c73c911cbfc57ec77aaea5a688a12729ed32 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 14 Jul 2024 15:55:08 -0700 Subject: [PATCH 014/137] Static analysis fixes This changelist addresses a handful of static analysis warnings flagged by Cppcheck. - Remove the virtual keyword from PortElement::getConnectedOutput, which is never overridden in subclasses. - Fix an unintended duplication of InterfaceElement::setConnectedOutput and InterfaceElement::getConnectedOutput in the Node class. - Simplify the implementation of the removeExtension helper method. - Mark iterators as const references for efficiency and clarity. --- source/MaterialXCore/Interface.h | 2 +- source/MaterialXCore/Node.cpp | 24 ------------------- source/MaterialXCore/Node.h | 9 ------- source/MaterialXFormat/File.h | 2 +- .../GlslResourceBindingContext.cpp | 2 +- source/MaterialXGenShader/ShaderGenerator.cpp | 2 +- 6 files changed, 4 insertions(+), 37 deletions(-) diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index c19bc82da5..39fd888b94 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -129,7 +129,7 @@ class MX_CORE_API PortElement : public ValueElement void setConnectedOutput(ConstOutputPtr output); /// Return the output, if any, to which this input is connected. - virtual OutputPtr getConnectedOutput() const; + OutputPtr getConnectedOutput() const; /// Return the output string of this element. const string& getOutputString() const diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index 7694bb6c6b..9080036c39 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -68,30 +68,6 @@ string Node::getConnectedNodeName(const string& inputName) const return input->getNodeName(); } -void Node::setConnectedOutput(const string& inputName, OutputPtr output) -{ - InputPtr input = getInput(inputName); - if (!input) - { - input = addInput(inputName, DEFAULT_TYPE_STRING); - } - if (output) - { - input->setType(output->getType()); - } - input->setConnectedOutput(output); -} - -OutputPtr Node::getConnectedOutput(const string& inputName) const -{ - InputPtr input = getInput(inputName); - if (!input) - { - return OutputPtr(); - } - return input->getConnectedOutput(); -} - NodeDefPtr Node::getNodeDef(const string& target, bool allowRoughMatch) const { if (hasNodeDefString()) diff --git a/source/MaterialXCore/Node.h b/source/MaterialXCore/Node.h index b42d18074e..5a6b7c4144 100644 --- a/source/MaterialXCore/Node.h +++ b/source/MaterialXCore/Node.h @@ -78,15 +78,6 @@ class MX_CORE_API Node : public InterfaceElement /// input is not present, then an empty string is returned. string getConnectedNodeName(const string& inputName) const; - /// Set the output to which the given input is connected, creating a - /// child input if needed. If the node argument is null, then any - /// existing output connection on the input will be cleared. - void setConnectedOutput(const string& inputName, OutputPtr output); - - /// Return the output connected to the given input. If the given input is - /// not present, then an empty OutputPtr is returned. - OutputPtr getConnectedOutput(const string& inputName) const; - /// @} /// @name NodeDef References /// @{ diff --git a/source/MaterialXFormat/File.h b/source/MaterialXFormat/File.h index a1d1813e86..d58eb97946 100644 --- a/source/MaterialXFormat/File.h +++ b/source/MaterialXFormat/File.h @@ -146,7 +146,7 @@ class MX_FORMAT_API FilePath size_t i = baseName.rfind('.'); if (i != string::npos) { - baseName = baseName.substr(0, i); + baseName.resize(i); } } } diff --git a/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp b/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp index e8863da008..bed3bc9ccb 100644 --- a/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp +++ b/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp @@ -50,7 +50,7 @@ void GlslResourceBindingContext::emitDirectives(GenContext& context, ShaderStage } } - for (auto& extension : _requiredExtensions) + for (const string& extension : _requiredExtensions) { generator.emitLine("#extension " + extension + " : enable", stage, false); } diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index a37f0981bd..6c23382f81 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -383,7 +383,7 @@ void ShaderGenerator::registerShaderMetadata(const DocumentPtr& doc, GenContext& ShaderMetadata(ValueElement::UNIT_ATTRIBUTE, Type::STRING), ShaderMetadata(ValueElement::COLOR_SPACE_ATTRIBUTE, Type::STRING) }; - for (auto data : DEFAULT_METADATA) + for (const ShaderMetadata& data : DEFAULT_METADATA) { registry->addMetadata(data.name, data.type); } From 81a851bef3106dc42a66aff36491003789186bc2 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 15 Jul 2024 10:13:02 -0700 Subject: [PATCH 015/137] Apply Clang formatting This changelist applies Clang formatting to source files in the MaterialX codebase, and includes no functional changes. --- source/MaterialXCore/Document.cpp | 14 +- source/MaterialXCore/Document.h | 2 +- source/MaterialXCore/Unit.cpp | 8 +- source/MaterialXCore/Version.cpp | 8 +- .../GlslResourceBindingContext.cpp | 11 +- .../VkResourceBindingContext.cpp | 2 +- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 10 +- .../Nodes/ClosureLayerNodeMdl.cpp | 5 +- .../Nodes/SourceCodeNodeMdl.cpp | 40 +- source/MaterialXGenShader/GenContext.h | 4 +- source/MaterialXGenShader/Nodes/BlurNode.h | 4 +- source/MaterialXGenShader/ShaderGraph.h | 2 +- source/MaterialXGenShader/Syntax.cpp | 1 - source/MaterialXGenShader/TypeDesc.cpp | 35 +- source/MaterialXGenShader/TypeDesc.h | 18 +- source/MaterialXGraphEditor/RenderView.cpp | 2 +- source/MaterialXRender/OiioImageLoader.h | 7 +- source/MaterialXRender/Util.cpp | 4 +- .../MaterialXRenderGlsl/GLTextureHandler.cpp | 8 +- source/MaterialXRenderGlsl/GlslMaterial.cpp | 9 +- source/MaterialXRenderMsl/MetalFramebuffer.h | 22 +- source/MaterialXRenderMsl/MetalFramebuffer.mm | 56 +-- source/MaterialXRenderMsl/MetalState.h | 46 +-- source/MaterialXRenderMsl/MetalState.mm | 208 +++++----- .../MaterialXRenderMsl/MetalTextureHandler.h | 23 +- .../MaterialXRenderMsl/MetalTextureHandler.mm | 159 ++++---- source/MaterialXRenderMsl/MslMaterial.h | 8 +- source/MaterialXRenderMsl/MslMaterial.mm | 52 ++- .../MslPipelineStateObject.h | 45 ++- .../MslPipelineStateObject.mm | 376 +++++++++--------- source/MaterialXRenderMsl/MslRenderer.h | 26 +- source/MaterialXRenderMsl/MslRenderer.mm | 74 ++-- source/MaterialXRenderOsl/OslRenderer.cpp | 8 +- 33 files changed, 646 insertions(+), 651 deletions(-) diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index dd3d9b2602..7ebdab0aa7 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -12,7 +12,6 @@ MATERIALX_NAMESPACE_BEGIN const string Document::CMS_ATTRIBUTE = "cms"; const string Document::CMS_CONFIG_ATTRIBUTE = "cmsconfig"; - // // Document factory function // @@ -164,7 +163,7 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n { throw Exception("Cannot create duplicate nodegraph: " + newGraphName); } - + // Create a new functional nodegraph, and copy over the // contents from the compound nodegraph NodeGraphPtr graph = addNodeGraph(newGraphName); @@ -174,7 +173,7 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n { graphChild->removeAttribute(Element::XPOS_ATTRIBUTE); graphChild->removeAttribute(Element::YPOS_ATTRIBUTE); - } + } graph->setNodeDefString(nodeDefName); // Create a new nodedef and set its category @@ -182,11 +181,11 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n nodeDef->setNodeString(category); // Expose any existing interfaces from the graph. - // Any connection attributes ("nodegraph", "nodename", "interfacename") on the + // Any connection attributes ("nodegraph", "nodename", "interfacename") on the // existing interface should be removed from the definition as well as any source URI. // Attributes which should not be copied over - StringSet filterAttributes = { PortElement::NODE_GRAPH_ATTRIBUTE, PortElement::NODE_NAME_ATTRIBUTE, + StringSet filterAttributes = { PortElement::NODE_GRAPH_ATTRIBUTE, PortElement::NODE_NAME_ATTRIBUTE, PortElement::INTERFACE_NAME_ATTRIBUTE, Element::XPOS_ATTRIBUTE, Element::YPOS_ATTRIBUTE }; // Transfer input interface from the graph to the nodedef @@ -196,13 +195,13 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n if (nodeDefInput) { nodeDefInput->copyContentFrom(input); - for (const string& filterAttribute : filterAttributes ) + for (const string& filterAttribute : filterAttributes) { nodeDefInput->removeAttribute(filterAttribute); } nodeDefInput->setSourceUri(EMPTY_STRING); input->setInterfaceName(nodeDefInput->getName()); - } + } } // Remove interfaces from the nodegraph for (InputPtr input : graph->getInputs()) @@ -412,5 +411,4 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n return addNodeDefFromGraph(nodeGraph, nodeDefName, node, newGraphName); } - MATERIALX_NAMESPACE_END diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index 08b3e1d22e..a14a5edf7b 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -335,7 +335,7 @@ class MX_CORE_API Document : public GraphElement /// Create a NodeDef and Functional Graph based on a Compound NodeGraph /// @param nodeGraph Compound NodeGraph. - /// @param newGraphName Name of new functional NodeGraph. + /// @param newGraphName Name of new functional NodeGraph. /// @param nodeDefName Name of new NodeDef /// @param category Category of the new NodeDef /// @return New declaration if successful. diff --git a/source/MaterialXCore/Unit.cpp b/source/MaterialXCore/Unit.cpp index fc919c3609..266d317cee 100644 --- a/source/MaterialXCore/Unit.cpp +++ b/source/MaterialXCore/Unit.cpp @@ -154,10 +154,10 @@ int LinearUnitConverter::getUnitAsInteger(const string& unitName) const string LinearUnitConverter::getUnitFromInteger(int index) const { auto it = std::find_if(_unitEnumeration.begin(), _unitEnumeration.end(), - [&index](const std::pair &e)->bool - { - return (e.second == index); - }); + [&index](const std::pair& e) -> bool + { + return (e.second == index); + }); if (it != _unitEnumeration.end()) { diff --git a/source/MaterialXCore/Version.cpp b/source/MaterialXCore/Version.cpp index 5195a1e049..6fe1dc7e16 100644 --- a/source/MaterialXCore/Version.cpp +++ b/source/MaterialXCore/Version.cpp @@ -1102,7 +1102,7 @@ void Document::upgradeVersion() NodePtr base = node->getConnectedNode("base"); if (top && base && top->getCategory() == "thin_film_bsdf") { - // Apply thin-film parameters to all supported BSDF's upstream. + // Apply thin-film parameters to all supported BSDF's upstream. const StringSet BSDF_WITH_THINFILM = { "dielectric_bsdf", "conductor_bsdf", "generalized_schlick_bsdf" }; for (Edge edge : node->traverseGraph()) { @@ -1171,9 +1171,9 @@ void Document::upgradeVersion() string channelString = channelsInput ? channelsInput->getValueString() : EMPTY_STRING; size_t sourceChannelCount = CHANNEL_COUNT_MAP.at(inInput->getType()); size_t destChannelCount = CHANNEL_COUNT_MAP.at(node->getType()); - + // Resolve the invalid case of having both a connection and a value - // by removing the value attribute. + // by removing the value attribute. if (inInput->hasValue()) { if (inInput->hasNodeName() || inInput->hasNodeGraphString() || inInput->hasInterfaceName()) @@ -1264,7 +1264,7 @@ void Document::upgradeVersion() // Replace swizzle with separate and combine. GraphElementPtr graph = node->getAncestorOfType(); NodePtr separateNode = graph->addNode(std::string("separate") + std::to_string(sourceChannelCount), - graph->createValidChildName("separate"), MULTI_OUTPUT_TYPE_STRING); + graph->createValidChildName("separate"), MULTI_OUTPUT_TYPE_STRING); int childIndex = graph->getChildIndex(node->getName()); if (childIndex != -1) { diff --git a/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp b/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp index bed3bc9ccb..d29ee65851 100644 --- a/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp +++ b/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp @@ -153,9 +153,9 @@ void GlslResourceBindingContext::emitStructuredResourceBindings(GenContext& cont // Sort order from largest to smallest std::sort(memberOrder.begin(), memberOrder.end(), [](const std::pair& a, const std::pair& b) - { - return a.first > b.first; - }); + { + return a.first > b.first; + }); // Emit the struct generator.emitLine("struct " + uniforms.getName(), stage, false); @@ -181,8 +181,9 @@ void GlslResourceBindingContext::emitStructuredResourceBindings(GenContext& cont // Emit binding information generator.emitLineBreak(stage); generator.emitLine("layout (std140, binding=" + std::to_string(_hwUniformBindLocation++) + - ") " + syntax.getUniformQualifier() + " " + uniforms.getName() + "_" + - stage.getName(), stage, false); + ") " + syntax.getUniformQualifier() + " " + uniforms.getName() + "_" + + stage.getName(), + stage, false); generator.emitScopeBegin(stage); generator.emitLine(uniforms.getName() + " " + structInstanceName + arraySuffix, stage); generator.emitScopeEnd(stage, true); diff --git a/source/MaterialXGenGlsl/VkResourceBindingContext.cpp b/source/MaterialXGenGlsl/VkResourceBindingContext.cpp index 543b2c2e02..214cb75e25 100644 --- a/source/MaterialXGenGlsl/VkResourceBindingContext.cpp +++ b/source/MaterialXGenGlsl/VkResourceBindingContext.cpp @@ -140,7 +140,7 @@ void VkResourceBindingContext::emitStructuredResourceBindings(GenContext& contex // Sort order from largest to smallest std::sort(memberOrder.begin(), memberOrder.end(), [](const std::pair& a, const std::pair& b) - { + { return a.first > b.first; }); diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index dbf1667d13..76cd7587fd 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -41,14 +41,14 @@ const vector DEFAULT_IMPORTS = "using ::materialx::sampling import *", }; -const vector DEFAULT_VERSIONED_IMPORTS = { +const vector DEFAULT_VERSIONED_IMPORTS = +{ "using ::materialx::stdlib_", "using ::materialx::pbrlib_", }; const string IMPORT_ALL = " import *"; - const string MDL_VERSION_1_6 = "1.6"; const string MDL_VERSION_1_7 = "1.7"; const string MDL_VERSION_1_8 = "1.8"; @@ -223,7 +223,8 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G 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); + "b: math::dot(displacement__, state::normal()))", + stage); } else { @@ -602,7 +603,6 @@ void emitInputAnnotations(const MdlShaderGenerator& _this, const DocumentPtr doc } // anonymous namespace - void MdlShaderGenerator::emitShaderInputs(const DocumentPtr doc, const VariableBlock& inputs, ShaderStage& stage) const { const string uniformPrefix = _syntax->getUniformQualifier() + " "; @@ -641,7 +641,6 @@ void MdlShaderGenerator::emitShaderInputs(const DocumentPtr doc, const VariableB } } - void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const { GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); @@ -684,7 +683,6 @@ const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& contex } } - void MdlShaderGenerator::emitMdlVersionFilenameSuffix(GenContext& context, ShaderStage& stage) const { emitString(getMdlVersionFilenameSuffix(context), stage); diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index 1dfa45317f..e3484b0171 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -69,8 +69,9 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // Join the BSDF and VDF into a single material. shadergen.emitLine("material " + output->getVariable() + - " = material(surface: " + t + ".surface, backface: " + t + - ".backface, ior: " + t + ".ior, volume: " + b + ".volume)", stage); + " = material(surface: " + t + ".surface, backface: " + t + + ".backface, ior: " + t + ".ior, volume: " + b + ".volume)", + stage); return; } diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp index 8ce86263d4..f237a0db54 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp @@ -78,9 +78,9 @@ void SourceCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); StringVec code = replaceSourceCodeMarkers(getName(), functionName, [&versionSuffix](const string& marker) - { - return marker == MARKER_MDL_VERSION_SUFFIX ? versionSuffix : EMPTY_STRING; - }); + { + return marker == MARKER_MDL_VERSION_SUFFIX ? versionSuffix : EMPTY_STRING; + }); functionName = std::accumulate(code.begin(), code.end(), EMPTY_STRING); _returnStruct = functionName + "__result"; } @@ -105,26 +105,26 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con { const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); StringVec code = replaceSourceCodeMarkers(node.getName(), _functionSource, - [&shadergenMdl, &context, &node, &versionSuffix](const string& marker) + [&shadergenMdl, &context, &node, &versionSuffix](const string& marker) + { + // Special handling for the version suffix of MDL source code modules. + if (marker == MARKER_MDL_VERSION_SUFFIX) { - // Special handling for the version suffix of MDL source code modules. - if (marker == MARKER_MDL_VERSION_SUFFIX) - { - return versionSuffix; - } - // Insert inputs based on parameter names. - else + return versionSuffix; + } + // Insert inputs based on parameter names. + else + { + const ShaderInput* input = node.getInput(marker); + if (!input) { - const ShaderInput* input = node.getInput(marker); - if (!input) - { - throw ExceptionShaderGenError("Could not find an input named '" + marker + - "' on node '" + node.getName() + "'"); - } - - return shadergenMdl.getUpstreamResult(input, context); + throw ExceptionShaderGenError("Could not find an input named '" + marker + + "' on node '" + node.getName() + "'"); } - }); + + return shadergenMdl.getUpstreamResult(input, context); + } + }); if (!_returnStruct.empty()) { diff --git a/source/MaterialXGenShader/GenContext.h b/source/MaterialXGenShader/GenContext.h index 8ddf92771f..0f565ded6e 100644 --- a/source/MaterialXGenShader/GenContext.h +++ b/source/MaterialXGenShader/GenContext.h @@ -125,7 +125,7 @@ class MX_GENSHADER_API GenContext return _closureContexts.size() ? _closureContexts.back() : nullptr; } - /// Push a parent node onto the stack + /// Push a parent node onto the stack void pushParentNode(ConstNodePtr node) { _parentNodes.push_back(node); @@ -292,7 +292,7 @@ class MX_GENSHADER_API ClosureContext auto it = _suffix.find(nodeType); return it != _suffix.end() ? it->second : EMPTY_STRING; } - [[deprecated]] const string& getSuffix(const TypeDesc* nodeType) const { return getSuffix(*nodeType); } + [[deprecated]] const string& getSuffix(const TypeDesc* nodeType) const { return getSuffix(*nodeType); } /// Set extra parameters to use for evaluating a closure. void setClosureParams(const ShaderNode* closure, const ClosureParams* params) diff --git a/source/MaterialXGenShader/Nodes/BlurNode.h b/source/MaterialXGenShader/Nodes/BlurNode.h index 2d6d479a10..fa41d11678 100644 --- a/source/MaterialXGenShader/Nodes/BlurNode.h +++ b/source/MaterialXGenShader/Nodes/BlurNode.h @@ -35,8 +35,8 @@ class MX_GENSHADER_API BlurNode : public ConvolutionNode virtual void outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, TypeDesc inputType, const string& sampleName, const StringVec& sampleStrings) const; [[deprecated]] void outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, const TypeDesc* inputType, - const string& sampleName, const StringVec& sampleStrings) const - { + const string& sampleName, const StringVec& sampleStrings) const + { return outputSampleArray(shadergen, stage, *inputType, sampleName, sampleStrings); } diff --git a/source/MaterialXGenShader/ShaderGraph.h b/source/MaterialXGenShader/ShaderGraph.h index 2b1d3d5d0b..6320d04296 100644 --- a/source/MaterialXGenShader/ShaderGraph.h +++ b/source/MaterialXGenShader/ShaderGraph.h @@ -104,7 +104,7 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode /// Add output sockets ShaderGraphOutputSocket* addOutputSocket(const string& name, TypeDesc type); - [[deprecated]] ShaderGraphOutputSocket* addOutputSocket(const string& name, const TypeDesc* type) { return addOutputSocket(name, *type); } + [[deprecated]] ShaderGraphOutputSocket* addOutputSocket(const string& name, const TypeDesc* type) { return addOutputSocket(name, *type); } /// Add a default geometric node and connect to the given input. void addDefaultGeomNode(ShaderInput* input, const GeomPropDef& geomprop, GenContext& context); diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index e270909e0f..661aa41660 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -190,7 +190,6 @@ bool Syntax::remapEnumeration(const string&, TypeDesc, const string&, std::pair< return false; } - const StringVec TypeSyntax::EMPTY_MEMBERS; TypeSyntax::TypeSyntax(const string& name, const string& defaultValue, const string& uniformDefaultValue, diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp index 5f631f67e3..1267caf14d 100644 --- a/source/MaterialXGenShader/TypeDesc.cpp +++ b/source/MaterialXGenShader/TypeDesc.cpp @@ -11,21 +11,22 @@ MATERIALX_NAMESPACE_BEGIN namespace { - using TypeDescMap = std::unordered_map; - using TypeDescNameMap = std::unordered_map; - - // Internal storage of registered type descriptors - TypeDescMap& typeMap() - { - static TypeDescMap map; - return map; - } - - TypeDescNameMap& typeNameMap() - { - static TypeDescNameMap map; - return map; - } + +using TypeDescMap = std::unordered_map; +using TypeDescNameMap = std::unordered_map; + +// Internal storage of registered type descriptors +TypeDescMap& typeMap() +{ + static TypeDescMap map; + return map; +} + +TypeDescNameMap& typeNameMap() +{ + static TypeDescNameMap map; + return map; +} } // anonymous namespace @@ -56,7 +57,7 @@ TypeDescRegistry::TypeDescRegistry(TypeDesc type, const std::string& name) namespace Type { -/// +/// /// Register type descriptors for standard types. /// TYPEDESC_REGISTER_TYPE(NONE, "none") @@ -83,6 +84,6 @@ TYPEDESC_REGISTER_TYPE(DISPLACEMENTSHADER, "displacementshader") TYPEDESC_REGISTER_TYPE(LIGHTSHADER, "lightshader") TYPEDESC_REGISTER_TYPE(MATERIAL, "material") -} +} // namespace Type MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index 4560df8a0c..1a537b7e58 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -17,23 +17,23 @@ MATERIALX_NAMESPACE_BEGIN /// @class TypeDesc /// A type descriptor for MaterialX data types. -/// +/// /// All types need to have a type descriptor registered in order for shader generators /// to know about the type. It can be used for type comparisons as well as getting more /// information about the type. Type descriptors for all standard library data types are /// registered by default and can be accessed from the Type namespace, e.g. Type::FLOAT. /// /// To register custom types use the macro TYPEDESC_DEFINE_TYPE to define it in a header -/// and the macro TYPEDESC_REGISTER_TYPE to register it in the type registry. Registration +/// and the macro TYPEDESC_REGISTER_TYPE to register it in the type registry. Registration /// must be done in order to access the type's name later using getName() and to find the /// type by name using TypeDesc::get(). -/// +/// /// The class is a POD type of 64-bits and can efficiently be stored and passed by value. /// Type compare operations and hash operations are done using a precomputed hash value. /// class MX_GENSHADER_API TypeDesc { -public: + public: enum BaseType { BASETYPE_NONE, @@ -60,7 +60,8 @@ class MX_GENSHADER_API TypeDesc }; /// Empty constructor. - constexpr TypeDesc() noexcept : _id(0), _basetype(BASETYPE_NONE), _semantic(SEMANTIC_NONE), _size(0) {} + constexpr TypeDesc() noexcept : + _id(0), _basetype(BASETYPE_NONE), _semantic(SEMANTIC_NONE), _size(0) { } /// Constructor. constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1) noexcept : @@ -68,7 +69,8 @@ class MX_GENSHADER_API TypeDesc _basetype(basetype), _semantic(semantic), _size(size) - {} + { + } /// Return the unique id assigned to this type. /// The id is a hash of the given type name. @@ -143,7 +145,7 @@ class MX_GENSHADER_API TypeDesc static const string NONE_TYPE_NAME; -private: + private: /// Simple constexpr hash function, good enough for the small set of short strings that /// are used for our data type names. constexpr uint32_t constexpr_hash(std::string_view str, uint32_t n = 0, uint32_t h = 2166136261) @@ -161,7 +163,7 @@ class MX_GENSHADER_API TypeDesc /// Helper class for type registration. class MX_GENSHADER_API TypeDescRegistry { -public: + public: TypeDescRegistry(TypeDesc type, const string& name); }; diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index 3c2e01dff9..dbc9b4f980 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -223,7 +223,7 @@ mx::ElementPredicate RenderView::getElementPredicate() return (_xincludeFiles.count(elem->getSourceUri()) == 0); } return true; - }; + }; } void RenderView::updateGeometrySelections() diff --git a/source/MaterialXRender/OiioImageLoader.h b/source/MaterialXRender/OiioImageLoader.h index 5a81e69051..05a8d20e2c 100644 --- a/source/MaterialXRender/OiioImageLoader.h +++ b/source/MaterialXRender/OiioImageLoader.h @@ -5,8 +5,9 @@ #ifndef MATERIALX_OIIOIMAGELOADER_H #define MATERIALX_OIIOIMAGELOADER_H - + #if MATERIALX_BUILD_OIIO + /// @file /// Image loader wrapper using OpenImageIO @@ -56,5 +57,7 @@ class MX_RENDER_API OiioImageLoader : public ImageLoader }; MATERIALX_NAMESPACE_END -#endif //MATERIALX_BUILD_OIIO + +#endif // MATERIALX_BUILD_OIIO + #endif diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index 5a9b116d59..881f1b7eea 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -77,8 +77,8 @@ ShaderPtr createAlbedoTableShader(GenContext& context, } ShaderPtr createEnvPrefilterShader(GenContext& context, - DocumentPtr stdLib, - const string& shaderName) + DocumentPtr stdLib, + const string& shaderName) { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); diff --git a/source/MaterialXRenderGlsl/GLTextureHandler.cpp b/source/MaterialXRenderGlsl/GLTextureHandler.cpp index cd130654f6..47536243cf 100644 --- a/source/MaterialXRenderGlsl/GLTextureHandler.cpp +++ b/source/MaterialXRenderGlsl/GLTextureHandler.cpp @@ -53,7 +53,7 @@ bool GLTextureHandler::bindImage(ImagePtr image, const ImageSamplingProperties& { std::cerr << "Exceeded maximum number of bound textures in GLTextureHandler::bindImage" << std::endl; return false; - } + } _boundTextureLocations[textureUnit] = image->getResourceId(); glActiveTexture(GL_TEXTURE0 + textureUnit); @@ -116,10 +116,10 @@ bool GLTextureHandler::createRenderResources(ImagePtr image, bool generateMipMap int glType, glFormat, glInternalFormat; mapTextureFormatToGL(image->getBaseType(), image->getChannelCount(), false, - glType, glFormat, glInternalFormat); + glType, glFormat, glInternalFormat); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, image->getWidth(), image->getHeight(), - 0, glFormat, glType, image->getResourceBuffer()); + 0, glFormat, glType, image->getResourceBuffer()); if (image->getChannelCount() == 1) { GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; @@ -134,7 +134,7 @@ bool GLTextureHandler::createRenderResources(ImagePtr image, bool generateMipMap return true; } - + void GLTextureHandler::releaseRenderResources(ImagePtr image) { if (!image) diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index 2586cc4ef8..788af713b2 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -327,11 +327,10 @@ ShaderPort* GlslMaterial::findUniform(const std::string& path) const if (publicUniforms) { // Scan block based on path match predicate - port = publicUniforms->find( - [path](ShaderPort* port) - { - return (port && stringEndsWith(port->getPath(), path)); - }); + port = publicUniforms->find([path](ShaderPort* port) + { + return (port && stringEndsWith(port->getPath(), path)); + }); // Check if the uniform exists in the shader program if (port && !_glProgram->getUniformsList().count(port->getVariable())) diff --git a/source/MaterialXRenderMsl/MetalFramebuffer.h b/source/MaterialXRenderMsl/MetalFramebuffer.h index ba38365da4..6c8f061a12 100644 --- a/source/MaterialXRenderMsl/MetalFramebuffer.h +++ b/source/MaterialXRenderMsl/MetalFramebuffer.h @@ -48,7 +48,7 @@ class MX_RENDERMSL_API MetalFramebuffer /// to the framebuffer are encoded to the sRGB color space. void setEncodeSrgb(bool encode) { - if(encode != _encodeSrgb) + if (encode != _encodeSrgb) { _encodeSrgb = encode; resize(_width, _height, true); @@ -60,13 +60,13 @@ class MX_RENDERMSL_API MetalFramebuffer { return _encodeSrgb; } - + /// Return the framebuffer width unsigned int getWidth() const { return _width; } /// Return the framebuffer height unsigned int getHeight() const { return _height; } - + /// Bind the framebuffer for rendering. void bind(MTLRenderPassDescriptor* renderpassDesc); @@ -78,18 +78,18 @@ class MX_RENDERMSL_API MetalFramebuffer { return _colorTexture; } - + void setColorTexture(id newColorTexture) { auto sameDim = [](id tex0, id tex1) -> bool { - return [tex0 width] == [tex1 width] && - [tex0 height] == [tex1 height]; + return [tex0 width] == [tex1 width] && + [tex0 height] == [tex1 height]; }; - if((!_colorTextureOwned || sameDim(_colorTexture, newColorTexture)) && - sameDim(newColorTexture, _depthTexture)) + if ((!_colorTextureOwned || sameDim(_colorTexture, newColorTexture)) && + sameDim(newColorTexture, _depthTexture)) { - if(_colorTextureOwned) + if (_colorTextureOwned) [_colorTexture release]; _colorTexture = newColorTexture; } @@ -122,10 +122,10 @@ class MX_RENDERMSL_API MetalFramebuffer Image::BaseType _baseType; bool _encodeSrgb; - id _device = nil; + id _device = nil; id _colorTexture = nil; id _depthTexture = nil; - + bool _colorTextureOwned = false; }; diff --git a/source/MaterialXRenderMsl/MetalFramebuffer.mm b/source/MaterialXRenderMsl/MetalFramebuffer.mm index 432d533fd3..17ee9de9a1 100644 --- a/source/MaterialXRenderMsl/MetalFramebuffer.mm +++ b/source/MaterialXRenderMsl/MetalFramebuffer.mm @@ -71,19 +71,19 @@ if (width != _width || _height != height || forceRecreate) { // Convert texture format to Metal - MTLDataType dataType; - if(pixelFormat == MTLPixelFormatInvalid) + MTLDataType dataType; + if (pixelFormat == MTLPixelFormatInvalid) MetalTextureHandler::mapTextureFormatToMetal(_baseType, _channelCount, _encodeSrgb, dataType, pixelFormat); MTLTextureDescriptor* texDescriptor = [MTLTextureDescriptor - texture2DDescriptorWithPixelFormat:pixelFormat - width:width - height:height - mipmapped:NO]; + texture2DDescriptorWithPixelFormat:pixelFormat + width:width + height:height + mipmapped:NO]; [texDescriptor setStorageMode:MTLStorageModePrivate]; - [texDescriptor setUsage:MTLTextureUsageRenderTarget|MTLTextureUsageShaderRead]; - - if(extColorTexture == nil) + [texDescriptor setUsage:MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead]; + + if (extColorTexture == nil) { _colorTexture = [_device newTextureWithDescriptor:texDescriptor]; _colorTextureOwned = true; @@ -93,7 +93,7 @@ _colorTexture = extColorTexture; _colorTextureOwned = false; } - + texDescriptor.pixelFormat = MTLPixelFormatDepth32Float; [texDescriptor setUsage:MTLTextureUsageRenderTarget]; _depthTexture = [_device newTextureWithDescriptor:texDescriptor]; @@ -108,13 +108,13 @@ [renderpassDesc.colorAttachments[0] setTexture:getColorTexture()]; [renderpassDesc.colorAttachments[0] setLoadAction:MTLLoadActionClear]; [renderpassDesc.colorAttachments[0] setStoreAction:MTLStoreActionStore]; - + [renderpassDesc.depthAttachment setTexture:getDepthTexture()]; [renderpassDesc.depthAttachment setClearDepth:1.0]; [renderpassDesc.depthAttachment setLoadAction:MTLLoadActionClear]; [renderpassDesc.depthAttachment setStoreAction:MTLStoreActionStore]; [renderpassDesc setStencilAttachment:nil]; - + [renderpassDesc setRenderTargetWidth:_width]; [renderpassDesc setRenderTargetHeight:_height]; } @@ -130,45 +130,45 @@ image = Image::create(_width, _height, _channelCount, _baseType); image->createResourceBuffer(); } - - if(cmdQueue == nil) + + if (cmdQueue == nil) { return image; } - - size_t bytesPerRow = _width*_channelCount*MetalTextureHandler::getTextureBaseTypeSize(_baseType); + + size_t bytesPerRow = _width * _channelCount * MetalTextureHandler::getTextureBaseTypeSize(_baseType); size_t bytesPerImage = _height * bytesPerRow; - + id buffer = [_device newBufferWithLength:bytesPerImage options:MTLResourceStorageModeShared]; - + id cmdBuffer = [cmdQueue commandBuffer]; - + id blitCmdEncoder = [cmdBuffer blitCommandEncoder]; [blitCmdEncoder copyFromTexture:_colorTexture sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(_width, _height, 1) - toBuffer:buffer destinationOffset:0 + toBuffer:buffer + destinationOffset:0 destinationBytesPerRow:bytesPerRow destinationBytesPerImage:bytesPerImage options:MTLBlitOptionNone]; - - + [blitCmdEncoder endEncoding]; - + [cmdBuffer commit]; [cmdBuffer waitUntilCompleted]; std::vector imageData(bytesPerImage); memcpy(imageData.data(), [buffer contents], bytesPerImage); - - if([_colorTexture pixelFormat] == MTLPixelFormatBGRA8Unorm) + + if ([_colorTexture pixelFormat] == MTLPixelFormatBGRA8Unorm) { - for(unsigned int j = 0; j < _height; ++j) + for (unsigned int j = 0; j < _height; ++j) { unsigned int rawStart = j * (_width * _channelCount); - for(unsigned int i = 0; i < _width; ++i) + for (unsigned int i = 0; i < _width; ++i) { unsigned int offset = rawStart + _channelCount * i; unsigned char tmp = imageData[offset + 0]; @@ -177,7 +177,7 @@ } } } - + memcpy(image->getResourceBuffer(), imageData.data(), bytesPerImage); [buffer release]; diff --git a/source/MaterialXRenderMsl/MetalState.h b/source/MaterialXRenderMsl/MetalState.h index 15eacc360a..963603a341 100644 --- a/source/MaterialXRenderMsl/MetalState.h +++ b/source/MaterialXRenderMsl/MetalState.h @@ -11,7 +11,7 @@ #include #include -#import +#import #include @@ -25,15 +25,15 @@ struct MetalState { static MetalState* getSingleton() { - if(!singleton) + if (!singleton) { singleton = std::unique_ptr(new MetalState()); } return singleton.get(); } - + MetalState(); - + void initialize(id mtlDevice, id mtlCmdQueue); void initLinearToSRGBKernel(); void triggerProgrammaticCapture(); @@ -42,36 +42,36 @@ struct MetalState void beginEncoder(MTLRenderPassDescriptor* renderpassDesc); void endEncoder(); void endCommandBuffer(); - + void waitForComplition(); - + MaterialX::MetalFramebufferPtr currentFramebuffer(); - + static std::unique_ptr singleton; - - id device = nil; - id cmdQueue = nil; - id cmdBuffer = nil; - id linearToSRGB_pso = nil; - id renderCmdEncoder = nil; + + id device = nil; + id cmdQueue = nil; + id cmdBuffer = nil; + id linearToSRGB_pso = nil; + id renderCmdEncoder = nil; std::stack framebufferStack; - + bool supportsTiledPipeline; - + id opaqueDepthStencilState = nil; id transparentDepthStencilState = nil; id envMapDepthStencilState = nil; - + std::condition_variable inFlightCV; - std::mutex inFlightMutex; - std::atomic inFlightCommandBuffers; + std::mutex inFlightMutex; + std::atomic inFlightCommandBuffers; }; -#define MTL(a) (MetalState::getSingleton()->a) +#define MTL(a) (MetalState::getSingleton()->a) #define MTL_DEPTHSTENCIL_STATE(a) (MetalState::getSingleton()->a##DepthStencilState) -#define MTL_TRIGGER_CAPTURE MetalState::getSingleton()->triggerProgrammaticCapture() -#define MTL_STOP_CAPTURE MetalState::getSingleton()->stopProgrammaticCapture() -#define MTL_PUSH_FRAMEBUFFER(a) MetalState::getSingleton()->framebufferStack.push(a) -#define MTL_POP_FRAMEBUFFER(a) MetalState::getSingleton()->framebufferStack.pop() +#define MTL_TRIGGER_CAPTURE MetalState::getSingleton()->triggerProgrammaticCapture() +#define MTL_STOP_CAPTURE MetalState::getSingleton()->stopProgrammaticCapture() +#define MTL_PUSH_FRAMEBUFFER(a) MetalState::getSingleton()->framebufferStack.push(a) +#define MTL_POP_FRAMEBUFFER(a) MetalState::getSingleton()->framebufferStack.pop() #endif // MATERIALXVIEW_METALSTATE_H diff --git a/source/MaterialXRenderMsl/MetalState.mm b/source/MaterialXRenderMsl/MetalState.mm index 941b00c526..6396057726 100644 --- a/source/MaterialXRenderMsl/MetalState.mm +++ b/source/MaterialXRenderMsl/MetalState.mm @@ -18,7 +18,7 @@ { device = mtlDevice; cmdQueue = mtlCmdQueue; - + #ifdef MAC_OS_VERSION_11_0 if (@available(macOS 11.0, ios 14.0, *)) { @@ -27,20 +27,20 @@ #else supportsTiledPipeline = false; #endif - + MTLDepthStencilDescriptor* depthStencilDesc = [MTLDepthStencilDescriptor new]; - depthStencilDesc.depthWriteEnabled = true; + depthStencilDesc.depthWriteEnabled = true; depthStencilDesc.depthCompareFunction = MTLCompareFunctionLess; opaqueDepthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDesc]; - - depthStencilDesc.depthWriteEnabled = false; + + depthStencilDesc.depthWriteEnabled = false; depthStencilDesc.depthCompareFunction = MTLCompareFunctionLess; transparentDepthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDesc]; - - depthStencilDesc.depthWriteEnabled = true; + + depthStencilDesc.depthWriteEnabled = true; depthStencilDesc.depthCompareFunction = MTLCompareFunctionAlways; envMapDepthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDesc]; - + initLinearToSRGBKernel(); } @@ -55,49 +55,49 @@ #endif options.languageVersion = MTLLanguageVersion2_0; options.fastMathEnabled = true; - + #ifdef MAC_OS_VERSION_11_0 bool useTiledPipeline = supportsTiledPipeline; - if(useTiledPipeline) + if (useTiledPipeline) { - if(@available(macOS 11.0, ios 14.0, *)) + if (@available(macOS 11.0, ios 14.0, *)) { NSString* linearToSRGB_kernel = - @"#include \n" - "#include \n" - " \n" - "using namespace metal; \n" - " \n" - "struct RenderTarget { \n" - " half4 colorTarget [[color(0)]]; \n" - "}; \n" - " \n" - " \n" - " \n" - "half4 linearToSRGB(half4 color_linear) \n" - "{ \n" - " half4 color_srgb; \n" - " for(int i = 0; i < 3; ++i) \n" - " color_srgb[i] = (color_linear[i] < 0.0031308) ? \n" - " (12.92 * color_linear[i]) : \n" - " (1.055 * pow(color_linear[i], 1.0h / 2.2h) - 0.055); \n" - " color_srgb[3] = color_linear[3]; \n" - " return color_srgb; \n" - "} \n" - " \n" - "kernel void LinearToSRGB_kernel( \n" - " imageblock imageBlock, \n" - " ushort2 tid [[ thread_position_in_threadgroup ]]) \n" - "{ \n" - " RenderTarget linearValue = imageBlock.read(tid); \n" - " RenderTarget srgbValue; \n" - " srgbValue.colorTarget = linearToSRGB(linearValue.colorTarget); \n" - " imageBlock.write(srgbValue, tid); \n" - "} \n"; - + @"#include \n" + "#include \n" + " \n" + "using namespace metal; \n" + " \n" + "struct RenderTarget { \n" + " half4 colorTarget [[color(0)]]; \n" + "}; \n" + " \n" + " \n" + " \n" + "half4 linearToSRGB(half4 color_linear) \n" + "{ \n" + " half4 color_srgb; \n" + " for(int i = 0; i < 3; ++i) \n" + " color_srgb[i] = (color_linear[i] < 0.0031308) ? \n" + " (12.92 * color_linear[i]) : \n" + " (1.055 * pow(color_linear[i], 1.0h / 2.2h) - 0.055); \n" + " color_srgb[3] = color_linear[3]; \n" + " return color_srgb; \n" + "} \n" + " \n" + "kernel void LinearToSRGB_kernel( \n" + " imageblock imageBlock, \n" + " ushort2 tid [[ thread_position_in_threadgroup ]]) \n" + "{ \n" + " RenderTarget linearValue = imageBlock.read(tid); \n" + " RenderTarget srgbValue; \n" + " srgbValue.colorTarget = linearToSRGB(linearValue.colorTarget); \n" + " imageBlock.write(srgbValue, tid); \n" + "} \n"; + id library = [device newLibraryWithSource:linearToSRGB_kernel options:options error:&error]; id function = [library newFunctionWithName:@"LinearToSRGB_kernel"]; - + MTLTileRenderPipelineDescriptor* renderPipelineDescriptor = [MTLTileRenderPipelineDescriptor new]; [renderPipelineDescriptor setRasterSampleCount:1]; [[renderPipelineDescriptor colorAttachments][0] setPixelFormat:MTLPixelFormatBGRA8Unorm]; @@ -109,63 +109,63 @@ useTiledPipeline = false; } } - - if(!useTiledPipeline) + + if (!useTiledPipeline) #endif { NSString* linearToSRGB_kernel = - @"#include \n" - "#include \n" - " \n" - "using namespace metal; \n" - " \n" - "struct VSOutput \n" - "{ \n" - " float4 position [[position]]; \n" - "}; \n" - " \n" - "vertex VSOutput VertexMain(uint vertexId [[ vertex_id ]]) \n" - "{ \n" - " VSOutput vsOut; \n" - " \n" - " switch(vertexId) \n" - " { \n" - " case 0: vsOut.position = float4(-1, -1, 0.5, 1); break; \n" - " case 1: vsOut.position = float4(-1, 3, 0.5, 1); break; \n" - " case 2: vsOut.position = float4( 3, -1, 0.5, 1); break; \n" - " }; \n" - " \n" - " return vsOut; \n" - "} \n" - " \n" - "half4 linearToSRGB(half4 color_linear) \n" - "{ \n" - " half4 color_srgb; \n" - " for(int i = 0; i < 3; ++i) \n" - " color_srgb[i] = (color_linear[i] < 0.0031308) ? \n" - " (12.92 * color_linear[i]) : \n" - " (1.055 * pow(color_linear[i], 1.0h / 2.2h) - 0.055);\n" - " color_srgb[3] = color_linear[3]; \n" - " return color_srgb; \n" - "} \n" - " \n" - "fragment half4 FragmentMain( \n" - " texture2d inputTex [[ texture(0) ]], \n" - " float4 fragCoord [[ position ]] \n" - ") \n" - "{ \n" - " constexpr sampler ss( \n" - " coord::pixel, \n" - " address::clamp_to_border, \n" - " filter::linear); \n" - " return linearToSRGB(inputTex.sample(ss, fragCoord.xy)); \n" - "} \n"; + @"#include \n" + "#include \n" + " \n" + "using namespace metal; \n" + " \n" + "struct VSOutput \n" + "{ \n" + " float4 position [[position]]; \n" + "}; \n" + " \n" + "vertex VSOutput VertexMain(uint vertexId [[ vertex_id ]]) \n" + "{ \n" + " VSOutput vsOut; \n" + " \n" + " switch(vertexId) \n" + " { \n" + " case 0: vsOut.position = float4(-1, -1, 0.5, 1); break; \n" + " case 1: vsOut.position = float4(-1, 3, 0.5, 1); break; \n" + " case 2: vsOut.position = float4( 3, -1, 0.5, 1); break; \n" + " }; \n" + " \n" + " return vsOut; \n" + "} \n" + " \n" + "half4 linearToSRGB(half4 color_linear) \n" + "{ \n" + " half4 color_srgb; \n" + " for(int i = 0; i < 3; ++i) \n" + " color_srgb[i] = (color_linear[i] < 0.0031308) ? \n" + " (12.92 * color_linear[i]) : \n" + " (1.055 * pow(color_linear[i], 1.0h / 2.2h) - 0.055);\n" + " color_srgb[3] = color_linear[3]; \n" + " return color_srgb; \n" + "} \n" + " \n" + "fragment half4 FragmentMain( \n" + " texture2d inputTex [[ texture(0) ]], \n" + " float4 fragCoord [[ position ]] \n" + ") \n" + "{ \n" + " constexpr sampler ss( \n" + " coord::pixel, \n" + " address::clamp_to_border, \n" + " filter::linear); \n" + " return linearToSRGB(inputTex.sample(ss, fragCoord.xy)); \n" + "} \n"; id library = [device newLibraryWithSource:linearToSRGB_kernel options:options error:&error]; id vertexfunction = [library newFunctionWithName:@"VertexMain"]; id Fragmentfunction = [library newFunctionWithName:@"FragmentMain"]; - + MTLRenderPipelineDescriptor* renderPipelineDesc = [MTLRenderPipelineDescriptor new]; [renderPipelineDesc setVertexFunction:vertexfunction]; [renderPipelineDesc setFragmentFunction:Fragmentfunction]; @@ -177,13 +177,13 @@ void MetalState::triggerProgrammaticCapture() { - MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager]; + MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager]; MTLCaptureDescriptor* captureDescriptor = [MTLCaptureDescriptor new]; - + [captureDescriptor setCaptureObject:device]; - + NSError* error = nil; - if(![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) + if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) { NSLog(@"Failed to start capture, error %@", error); } @@ -204,7 +204,7 @@ void MetalState::beginEncoder(MTLRenderPassDescriptor* renderpassDesc) { renderCmdEncoder = [cmdBuffer - renderCommandEncoderWithDescriptor:renderpassDesc]; + renderCommandEncoderWithDescriptor:renderpassDesc]; } void MetalState::endEncoder() @@ -216,8 +216,8 @@ { endEncoder(); [cmdBuffer addCompletedHandler:^(id _Nonnull) { - inFlightCommandBuffers--; - inFlightCV.notify_one(); + inFlightCommandBuffers--; + inFlightCV.notify_one(); }]; [cmdBuffer commit]; [cmdBuffer waitUntilCompleted]; @@ -226,8 +226,12 @@ void MetalState::waitForComplition() { std::unique_lock lock(inFlightMutex); - while (inFlightCommandBuffers != 0){ - inFlightCV.wait(lock, [this]{ return inFlightCommandBuffers.load() == 0; }); + while (inFlightCommandBuffers != 0) + { + inFlightCV.wait(lock, [this] + { + return inFlightCommandBuffers.load() == 0; + }); } } diff --git a/source/MaterialXRenderMsl/MetalTextureHandler.h b/source/MaterialXRenderMsl/MetalTextureHandler.h index c78469a4ce..7504c951ea 100644 --- a/source/MaterialXRenderMsl/MetalTextureHandler.h +++ b/source/MaterialXRenderMsl/MetalTextureHandler.h @@ -28,34 +28,35 @@ using MetalTextureHandlerPtr = std::shared_ptr; class MX_RENDERMSL_API MetalTextureHandler : public ImageHandler { friend class MslProgram; + public: static MetalTextureHandlerPtr create(id device, ImageLoaderPtr imageLoader) { return MetalTextureHandlerPtr(new MetalTextureHandler(device, imageLoader)); } - /// This method binds image and its corresponding sampling properties. /// It also creates the underlying resource if needed. /// Actual binding of texture and sampler to command encoder happens autoamt bool bindImage(ImagePtr image, const ImageSamplingProperties& samplingProperties) override; - -protected: + + protected: /// Bind an image. This method will bind the texture to an active texture /// unit as defined by the corresponding image description. The method /// will fail if there are not enough available image units to bind to. bool bindImage(id renderCmdEncoder, int textureUnit, ImagePtr image); -public: + + public: id getSamplerState(const ImageSamplingProperties& samplingProperties); - + /// Unbind an image. bool unbindImage(ImagePtr image) override; - id getMTLTextureForImage(unsigned int index) const; + id getMTLTextureForImage(unsigned int index) const; id getMTLSamplerStateForImage(unsigned int index); - + /// Create rendering resources for the given image. bool createRenderResources(ImagePtr image, bool generateMipMaps, bool useAsRenderTarget = false) override; @@ -75,9 +76,9 @@ class MX_RENDERMSL_API MetalTextureHandler : public ImageHandler /// Utility to map generic texture properties to Metal texture formats. static void mapTextureFormatToMetal(Image::BaseType baseType, unsigned int channelCount, bool srgb, MTLDataType& dataType, MTLPixelFormat& pixelFormat); - + static size_t getTextureBaseTypeSize(Image::BaseType baseType); - + id getAssociatedMetalTexture(ImagePtr image); protected: @@ -86,11 +87,11 @@ class MX_RENDERMSL_API MetalTextureHandler : public ImageHandler protected: std::vector _boundTextureLocations; - + std::unordered_map> _metalTextureMap; std::unordered_map> _imageBindingInfo; std::unordered_map, ImageSamplingKeyHasher> _imageSamplerStateMap; - + id _device = nil; }; diff --git a/source/MaterialXRenderMsl/MetalTextureHandler.mm b/source/MaterialXRenderMsl/MetalTextureHandler.mm index ab8da46f1f..6a8b5c2ef4 100644 --- a/source/MaterialXRenderMsl/MetalTextureHandler.mm +++ b/source/MaterialXRenderMsl/MetalTextureHandler.mm @@ -35,7 +35,7 @@ id MetalTextureHandler::getSamplerState(const ImageSamplingProperties& samplingProperties) { - if(_imageSamplerStateMap.find(samplingProperties) == _imageSamplerStateMap.end()) + if (_imageSamplerStateMap.find(samplingProperties) == _imageSamplerStateMap.end()) { MTLSamplerDescriptor* samplerDesc = [MTLSamplerDescriptor new]; [samplerDesc setSAddressMode:mapAddressModeToMetal(samplingProperties.uaddressMode)]; @@ -43,17 +43,17 @@ [samplerDesc setTAddressMode:mapAddressModeToMetal(samplingProperties.vaddressMode)]; [samplerDesc setBorderColor:samplingProperties.defaultColor[0] == 0 ? MTLSamplerBorderColorOpaqueBlack : MTLSamplerBorderColorOpaqueWhite]; MTLSamplerMinMagFilter minmagFilter; - MTLSamplerMipFilter mipFilter; + MTLSamplerMipFilter mipFilter; mapFilterTypeToMetal(samplingProperties.filterType, samplingProperties.enableMipmaps, minmagFilter, mipFilter); // Magnification filters are more restrictive than minification [samplerDesc setMagFilter:MTLSamplerMinMagFilterLinear]; [samplerDesc setMinFilter:minmagFilter]; [samplerDesc setMipFilter:mipFilter]; [samplerDesc setMaxAnisotropy:16]; - + _imageSamplerStateMap[samplingProperties] = [_device newSamplerStateWithDescriptor:samplerDesc]; } - + return _imageSamplerStateMap[samplingProperties]; } @@ -70,7 +70,7 @@ } _boundTextureLocations[textureUnit] = image->getResourceId(); - + [renderCmdEncoder setFragmentTexture:_metalTextureMap[image->getResourceId()] atIndex:textureUnit]; [renderCmdEncoder setFragmentSamplerState:getSamplerState(_imageBindingInfo[image->getResourceId()].second) atIndex:textureUnit]; @@ -79,10 +79,10 @@ id MetalTextureHandler::getAssociatedMetalTexture(ImagePtr image) { - if(image) + if (image) { auto tex = _metalTextureMap.find(image->getResourceId()); - if(tex != _metalTextureMap.end()) + if (tex != _metalTextureMap.end()) return (tex->second); } return nil; @@ -91,23 +91,23 @@ id MetalTextureHandler::getMTLTextureForImage(unsigned int index) const { auto imageInfo = _imageBindingInfo.find(index); - if(imageInfo != _imageBindingInfo.end()) + if (imageInfo != _imageBindingInfo.end()) { - if(!imageInfo->second.first) + if (!imageInfo->second.first) return nil; - + auto metalTexture = _metalTextureMap.find(imageInfo->second.first->getResourceId()); - if(metalTexture != _metalTextureMap.end()) + if (metalTexture != _metalTextureMap.end()) return metalTexture->second; } - + return nil; } id MetalTextureHandler::getMTLSamplerStateForImage(unsigned int index) { auto imageInfo = _imageBindingInfo.find(index); - if(imageInfo != _imageBindingInfo.end()) + if (imageInfo != _imageBindingInfo.end()) { return getSamplerState(imageInfo->second.second); } @@ -131,44 +131,44 @@ bool MetalTextureHandler::createRenderResources(ImagePtr image, bool generateMipMaps, bool useAsRenderTarget) { id texture = nil; - + MTLPixelFormat pixelFormat; - MTLDataType dataType; - + MTLDataType dataType; + if (image->getResourceId() == MslProgram::UNDEFINED_METAL_RESOURCE_ID) { static unsigned int resourceId = 0; ++resourceId; - + mapTextureFormatToMetal(image->getBaseType(), image->getChannelCount(), false, dataType, pixelFormat); - + MTLTextureDescriptor* texDesc = [MTLTextureDescriptor new]; [texDesc setTextureType:MTLTextureType2D]; texDesc.width = image->getWidth(); texDesc.height = image->getHeight(); texDesc.mipmapLevelCount = generateMipMaps ? image->getMaxMipCount() : 1; texDesc.usage = MTLTextureUsageShaderRead | - (useAsRenderTarget ? MTLTextureUsageRenderTarget : 0); + (useAsRenderTarget ? MTLTextureUsageRenderTarget : 0); texDesc.resourceOptions = MTLResourceStorageModePrivate; texDesc.pixelFormat = pixelFormat; - if(generateMipMaps) + if (generateMipMaps) { - if(image->getChannelCount() == 1) + if (image->getChannelCount() == 1) { texDesc.swizzle = MTLTextureSwizzleChannelsMake( - MTLTextureSwizzleRed, - MTLTextureSwizzleRed, - MTLTextureSwizzleRed, - MTLTextureSwizzleRed); + MTLTextureSwizzleRed, + MTLTextureSwizzleRed, + MTLTextureSwizzleRed, + MTLTextureSwizzleRed); } - else if(image->getChannelCount() == 2) + else if (image->getChannelCount() == 2) { texDesc.swizzle = MTLTextureSwizzleChannelsMake( - MTLTextureSwizzleRed, - MTLTextureSwizzleGreen, - MTLTextureSwizzleRed, - MTLTextureSwizzleGreen); + MTLTextureSwizzleRed, + MTLTextureSwizzleGreen, + MTLTextureSwizzleRed, + MTLTextureSwizzleGreen); } } texture = [_device newTextureWithDescriptor:texDesc]; @@ -179,18 +179,17 @@ { mapTextureFormatToMetal(image->getBaseType(), image->getChannelCount(), false, dataType, pixelFormat); - + texture = _metalTextureMap[image->getResourceId()]; } - id cmdQueue = [_device newCommandQueue]; id cmdBuffer = [cmdQueue commandBuffer]; - + id blitCmdEncoder = [cmdBuffer blitCommandEncoder]; - + NSUInteger channelCount = image->getChannelCount(); - + NSUInteger sourceBytesPerRow = image->getWidth() * channelCount * @@ -198,63 +197,64 @@ NSUInteger sourceBytesPerImage = sourceBytesPerRow * image->getHeight(); - - std::vector rearrangedDataF; + + std::vector rearrangedDataF; std::vector rearrangedDataC; void* imageData = image->getResourceBuffer(); - + if ((pixelFormat == MTLPixelFormatRGBA32Float || pixelFormat == MTLPixelFormatRGBA8Unorm) && channelCount == 3) { bool isFloat = pixelFormat == MTLPixelFormatRGBA32Float; - - sourceBytesPerRow = sourceBytesPerRow / 3 * 4; + + sourceBytesPerRow = sourceBytesPerRow / 3 * 4; sourceBytesPerImage = sourceBytesPerImage / 3 * 4; - + size_t srcIdx = 0; - - if(isFloat) + + if (isFloat) { rearrangedDataF.resize(sourceBytesPerImage / sizeof(float)); - for(size_t dstIdx = 0; dstIdx < rearrangedDataF.size(); ++dstIdx) + for (size_t dstIdx = 0; dstIdx < rearrangedDataF.size(); ++dstIdx) { - if((dstIdx & 0x3) == 3) + if ((dstIdx & 0x3) == 3) { rearrangedDataF[dstIdx] = 1.0f; continue; } - - rearrangedDataF[dstIdx] = ((float*)imageData)[srcIdx++]; + + rearrangedDataF[dstIdx] = ((float*) imageData)[srcIdx++]; } - + imageData = rearrangedDataF.data(); } else { rearrangedDataC.resize(sourceBytesPerImage); - for(size_t dstIdx = 0; dstIdx < rearrangedDataC.size(); ++dstIdx) + for (size_t dstIdx = 0; dstIdx < rearrangedDataC.size(); ++dstIdx) { - if((dstIdx & 0x3) == 3) + if ((dstIdx & 0x3) == 3) { rearrangedDataC[dstIdx] = 255; continue; } - - rearrangedDataC[dstIdx] = ((unsigned char*)imageData)[srcIdx++]; + + rearrangedDataC[dstIdx] = ((unsigned char*) imageData)[srcIdx++]; } - + imageData = rearrangedDataC.data(); } - + channelCount = 4; } - + id buffer = nil; - if(imageData) + if (imageData) { buffer = [_device newBufferWithBytes:imageData - length:sourceBytesPerImage - options:MTLStorageModeShared]; - [blitCmdEncoder copyFromBuffer:buffer sourceOffset:0 + length:sourceBytesPerImage + options:MTLStorageModeShared]; + [blitCmdEncoder copyFromBuffer:buffer + sourceOffset:0 sourceBytesPerRow:sourceBytesPerRow sourceBytesPerImage:sourceBytesPerImage sourceSize:MTLSizeMake(image->getWidth(), image->getHeight(), 1) @@ -263,26 +263,26 @@ destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)]; } - - if(generateMipMaps && image->getMaxMipCount() > 1) + + if (generateMipMaps && image->getMaxMipCount() > 1) [blitCmdEncoder generateMipmapsForTexture:texture]; - + [blitCmdEncoder endEncoding]; - + [cmdBuffer commit]; [cmdBuffer waitUntilCompleted]; - - if(buffer) + + if (buffer) [buffer release]; - + return true; } - + void MetalTextureHandler::releaseRenderResources(ImagePtr image) { - if(!image) + if (!image) return; - + if (image->getResourceId() == MslProgram::UNDEFINED_METAL_RESOURCE_ID) { return; @@ -291,7 +291,7 @@ unbindImage(image); unsigned int resourceId = image->getResourceId(); auto tex = _metalTextureMap.find(resourceId); - if(tex != _metalTextureMap.end()) + if (tex != _metalTextureMap.end()) { [tex->second release]; } @@ -339,11 +339,11 @@ void MetalTextureHandler::mapFilterTypeToMetal(ImageSamplingProperties::FilterType filterTypeEnum, bool enableMipmaps, MTLSamplerMinMagFilter& minMagFilter, MTLSamplerMipFilter& mipFilter) { - if(enableMipmaps) + if (enableMipmaps) { - if(filterTypeEnum == ImageSamplingProperties::FilterType::LINEAR || - filterTypeEnum == ImageSamplingProperties::FilterType::CUBIC || - filterTypeEnum == ImageSamplingProperties::FilterType::UNSPECIFIED) + if (filterTypeEnum == ImageSamplingProperties::FilterType::LINEAR || + filterTypeEnum == ImageSamplingProperties::FilterType::CUBIC || + filterTypeEnum == ImageSamplingProperties::FilterType::UNSPECIFIED) { minMagFilter = MTLSamplerMinMagFilterLinear; mipFilter = MTLSamplerMipFilterLinear; @@ -356,9 +356,9 @@ } else { - if(filterTypeEnum == ImageSamplingProperties::FilterType::LINEAR || - filterTypeEnum == ImageSamplingProperties::FilterType::CUBIC || - filterTypeEnum == ImageSamplingProperties::FilterType::UNSPECIFIED) + if (filterTypeEnum == ImageSamplingProperties::FilterType::LINEAR || + filterTypeEnum == ImageSamplingProperties::FilterType::CUBIC || + filterTypeEnum == ImageSamplingProperties::FilterType::UNSPECIFIED) { minMagFilter = MTLSamplerMinMagFilterLinear; mipFilter = MTLSamplerMipFilterNotMipmapped; @@ -372,7 +372,7 @@ } void MetalTextureHandler::mapTextureFormatToMetal(Image::BaseType baseType, unsigned int channelCount, bool srgb, - MTLDataType& dataType, MTLPixelFormat& pixelFormat) + MTLDataType& dataType, MTLPixelFormat& pixelFormat) { if (baseType == Image::BaseType::UINT8) { @@ -413,7 +413,7 @@ switch (channelCount) { case 4: pixelFormat = MTLPixelFormatRGBA32Float; dataType = MTLDataTypeFloat4; break; - case 3: pixelFormat = MTLPixelFormatRGBA32Float; dataType = MTLDataTypeFloat3; break; + case 3: pixelFormat = MTLPixelFormatRGBA32Float; dataType = MTLDataTypeFloat3; break; case 2: pixelFormat = MTLPixelFormatRG32Float; dataType = MTLDataTypeFloat2; break; case 1: pixelFormat = MTLPixelFormatR32Float; dataType = MTLDataTypeFloat; break; default: throw Exception("Unsupported channel count in mapTextureFormatToMetal"); @@ -445,5 +445,4 @@ } } - MATERIALX_NAMESPACE_END diff --git a/source/MaterialXRenderMsl/MslMaterial.h b/source/MaterialXRenderMsl/MslMaterial.h index cc80af1e18..0f6e45a9ce 100644 --- a/source/MaterialXRenderMsl/MslMaterial.h +++ b/source/MaterialXRenderMsl/MslMaterial.h @@ -26,7 +26,8 @@ using MslMaterialPtr = std::shared_ptr; class MX_RENDERMSL_API MslMaterial : public ShaderMaterial { public: - MslMaterial() : ShaderMaterial() + MslMaterial() : + ShaderMaterial() { } ~MslMaterial() { } @@ -47,7 +48,7 @@ class MX_RENDERMSL_API MslMaterial : 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 { @@ -113,9 +114,10 @@ class MX_RENDERMSL_API MslMaterial : public ShaderMaterial GeometryHandlerPtr geometryHandler, ImageHandlerPtr imageHandler, LightHandlerPtr lightHandler); + protected: void clearShader() override; - + protected: MslProgramPtr _glProgram; }; diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm index 4177403a99..311d84acee 100644 --- a/source/MaterialXRenderMsl/MslMaterial.mm +++ b/source/MaterialXRenderMsl/MslMaterial.mm @@ -38,7 +38,7 @@ } // 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 = MslProgram::create(); @@ -105,19 +105,19 @@ } void MslMaterial::prepareUsedResources(CameraPtr cam, - GeometryHandlerPtr geometryHandler, - ImageHandlerPtr imageHandler, - LightHandlerPtr lightHandler) + GeometryHandlerPtr geometryHandler, + ImageHandlerPtr imageHandler, + LightHandlerPtr lightHandler) { if (!_glProgram) { return; } - + _glProgram->prepareUsedResources(MTL(renderCmdEncoder), - cam, geometryHandler, - imageHandler, - lightHandler); + cam, geometryHandler, + imageHandler, + lightHandler); } void MslMaterial::bindMesh(MeshPtr mesh) @@ -176,14 +176,14 @@ _boundImages.clear(); _glProgram->setEnableMipMaps(enableMipmaps); - + // Texture and Samplers being bound to the right texture and sampler in MslPipelineStateObject automatically. } ImagePtr MslMaterial::bindImage(const FilePath& filePath, - const std::string& uniformName, - ImageHandlerPtr imageHandler, - const ImageSamplingProperties& samplingProperties) + const std::string& uniformName, + ImageHandlerPtr imageHandler, + const ImageSamplingProperties& samplingProperties) { if (!_glProgram) { @@ -203,8 +203,8 @@ } void MslMaterial::bindLighting(LightHandlerPtr lightHandler, - ImageHandlerPtr imageHandler, - const ShadowState& shadowState) + ImageHandlerPtr imageHandler, + const ShadowState& shadowState) { if (!_glProgram) { @@ -239,7 +239,7 @@ _glProgram->bindTexture(imageHandler, TEXTURE_NAME(HW::AMB_OCC_MAP), shadowState.ambientOcclusionMap, samplingProperties); - + _glProgram->bindUniform(HW::AMB_OCC_GAIN, Value::createValue(shadowState.ambientOcclusionGain)); } } @@ -253,10 +253,10 @@ MeshIndexBuffer& indexData = part->getIndices(); [MTL(renderCmdEncoder) drawIndexedPrimitives:MTLPrimitiveTypeTriangle - indexCount:indexData.size() - indexType:MTLIndexTypeUInt32 - indexBuffer:_glProgram->getIndexBuffer(part) - indexBufferOffset:0]; + indexCount:indexData.size() + indexType:MTLIndexTypeUInt32 + indexBuffer:_glProgram->getIndexBuffer(part) + indexBufferOffset:0]; } void MslMaterial::unbindGeometry() @@ -288,16 +288,15 @@ if (publicUniforms) { // Scan block based on path match predicate - port = publicUniforms->find( - [path](ShaderPort* port) - { - return (port && stringEndsWith(port->getPath(), path)); - }); + port = publicUniforms->find([path](ShaderPort* port) + { + return (port && stringEndsWith(port->getPath(), path)); + }); // Check if the uniform exists in the shader program if (port && !_glProgram->getUniformsList().count( - publicUniforms->getInstance() + "." + - port->getVariable())) + publicUniforms->getInstance() + "." + + port->getVariable())) { port = nullptr; } @@ -335,4 +334,3 @@ } MATERIALX_NAMESPACE_END - diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.h b/source/MaterialXRenderMsl/MslPipelineStateObject.h index 2f54abea22..b335e29af5 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.h +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.h @@ -106,7 +106,7 @@ class MX_RENDERMSL_API MslProgram string path; /// Unit string unit; - /// Colorspace + /// Colorspace string colorspace; /// Program input constructor @@ -116,7 +116,8 @@ class MX_RENDERMSL_API MslProgram size(inputSize), isConstant(false), path(inputPath) - { } + { + } }; /// Program input structure shared pointer type using InputPtr = std::shared_ptr; @@ -153,7 +154,7 @@ class MX_RENDERMSL_API MslProgram /// @param renderCmdEncoder encoder that binds the pipeline state object. /// @return False if failed bool bind(id renderCmdEncoder); - + /// Bind inputs /// @param renderCmdEncoder encoder that inputs will be bound to. /// @param cam Camera object use to view the object @@ -162,10 +163,10 @@ class MX_RENDERMSL_API MslProgram /// @param lightHandler /// @return void - No return value void prepareUsedResources(id renderCmdEncoder, - CameraPtr cam, - GeometryHandlerPtr geometryHandler, - ImageHandlerPtr imageHandler, - LightHandlerPtr lightHandler); + CameraPtr cam, + GeometryHandlerPtr geometryHandler, + ImageHandlerPtr imageHandler, + LightHandlerPtr lightHandler); /// Return true if a uniform with the given name is present. bool hasUniform(const string& name); @@ -188,15 +189,15 @@ class MX_RENDERMSL_API MslProgram /// Bind input geometry streams void bindMesh(id renderCmdEncoder, MeshPtr mesh); - + /// Queries the index buffer assinged to a mesh partition - id getIndexBuffer(MeshPartitionPtr mesh) { - if(_indexBufferIds.find(mesh) != _indexBufferIds.end()) + id getIndexBuffer(MeshPartitionPtr mesh) + { + if (_indexBufferIds.find(mesh) != _indexBufferIds.end()) return _indexBufferIds[mesh]; return nil; } - /// Unbind any bound geometry void unbindGeometry(); @@ -204,7 +205,7 @@ class MX_RENDERMSL_API MslProgram void bindTextures(id renderCmdEncoder, LightHandlerPtr lightHandler, ImageHandlerPtr imageHandler); - + void bindTexture(ImageHandlerPtr imageHandler, string shaderTextureName, ImagePtr imagePtr, @@ -215,17 +216,17 @@ class MX_RENDERMSL_API MslProgram /// Bind view information void bindViewInformation(CameraPtr camera); - + /// Bind time and frame void bindTimeAndFrame(float time = 1.0f, float frame = 1.0f); /// @} /// @name Utilities /// @{ - + /// Returns if alpha blending is enabled. bool isTransparent() const { return _alphaBlendingEnabled; } - + /// Specify textures bound to this program shouldn't be mip mapped. void setEnableMipMaps(bool enableMipMapping) { _enableMipMapping = enableMipMapping; } @@ -263,13 +264,13 @@ class MX_RENDERMSL_API MslProgram const FilePath& filePath, ImageSamplingProperties samplingProperties, ImageHandlerPtr imageHandler); - + // Bind an individual texture to a program uniform location ImagePtr bindTexture(id renderCmdEncoder, unsigned int uniformLocation, ImagePtr imagePtr, ImageHandlerPtr imageHandler); - + void bindUniformBuffers(id renderCmdEncoder, LightHandlerPtr lightHandler, CameraPtr camera); @@ -294,7 +295,7 @@ class MX_RENDERMSL_API MslProgram std::unordered_map _globalUniformNameList; // List of program input attributes InputMap _attributeList; - + std::unordered_map _explicitBoundImages; // Hardware shader (if any) used for program creation @@ -309,18 +310,18 @@ class MX_RENDERMSL_API MslProgram // Program texture map std::unordered_map _programTextures; - + // Metal Device Object id _device = nil; - + // Currently bound mesh MeshPtr _boundMesh = nullptr; bool _alphaBlendingEnabled = false; - + float _time = 0.0f; float _frame = 0.0f; - + bool _enableMipMapping = true; }; diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm index cb1d58916a..2d5685646f 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm @@ -61,7 +61,7 @@ // 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()); @@ -96,7 +96,7 @@ MTLVertexFormat GetMetalFormatFromMetalType(MTLDataType type) { - switch(type) + switch (type) { case MTLDataTypeFloat : return MTLVertexFormatFloat; case MTLDataTypeFloat2: return MTLVertexFormatFloat2; @@ -113,10 +113,10 @@ MTLVertexFormat GetMetalFormatFromMetalType(MTLDataType type) int GetStrideOfMetalType(MTLDataType type) { - switch(type) + switch (type) { case MTLDataTypeInt: - case MTLDataTypeFloat : return 1 * 4; + case MTLDataTypeFloat: return 1 * 4; case MTLDataTypeInt2: case MTLDataTypeFloat2: return 2 * 4; case MTLDataTypeInt3: @@ -125,7 +125,7 @@ int GetStrideOfMetalType(MTLDataType type) case MTLDataTypeFloat4: return 4 * 4; default: return 0; } - + return 0; } @@ -135,9 +135,9 @@ int GetStrideOfMetalType(MTLDataType type) const string errorType("MSL program creation error."); NSError* error = nil; - + reset(); - + _device = device; unsigned int stagesBuilt = 0; @@ -147,7 +147,7 @@ int GetStrideOfMetalType(MTLDataType type) if (it.second.length()) desiredStages++; } - + MTLCompileOptions* options = [MTLCompileOptions new]; #ifdef MAC_OS_VERSION_11_0 if (@available(macOS 11.0, ios 14.0, *)) @@ -160,31 +160,31 @@ int GetStrideOfMetalType(MTLDataType type) // Create vertex shader id vertexShaderId = nil; { - string &vertexShaderSource = _stages[Stage::VERTEX]; + string& vertexShaderSource = _stages[Stage::VERTEX]; if (vertexShaderSource.length() < 1) { errors.push_back("Vertex Shader is empty."); return nil; } - + NSString* sourcCode = [NSString stringWithUTF8String:vertexShaderSource.c_str()]; id library = [device newLibraryWithSource:sourcCode options:options error:&error]; - - if(library == nil) + + if (library == nil) { errors.push_back("Error in compiling vertex shader:"); - if(error) + if (error) { errors.push_back([[error localizedDescription] UTF8String]); } return nil; } - + vertexShaderId = [library newFunctionWithName:@"VertexMain"]; - - if(vertexShaderId) + + if (vertexShaderId) { stagesBuilt++; } @@ -197,16 +197,16 @@ int GetStrideOfMetalType(MTLDataType type) errors.push_back("Fragment Shader is empty."); return nil; } - + // Fragment shader compilation code id fragmentShaderId = nil; { - NSString* sourcCode = [NSString stringWithUTF8String:fragmentShaderSource.c_str()]; + NSString* sourcCode = [NSString stringWithUTF8String:fragmentShaderSource.c_str()]; id library = [device newLibraryWithSource:sourcCode options:options error:&error]; - if(!library) + if (!library) { errors.push_back("Error in compiling fragment shader:"); - if(error) + if (error) { std::string libCompilationError = [[error localizedDescription] UTF8String]; printf("Compilation Errors:%s\n", libCompilationError.c_str()); @@ -214,16 +214,15 @@ int GetStrideOfMetalType(MTLDataType type) return nil; } } - + fragmentShaderId = [library newFunctionWithName:@"FragmentMain"]; assert(fragmentShaderId); - - if(library) + + if (library) { stagesBuilt++; } } - // Link stages to a programs if (stagesBuilt == desiredStages) @@ -231,28 +230,28 @@ int GetStrideOfMetalType(MTLDataType type) MTLRenderPipelineDescriptor* psoDesc = [MTLRenderPipelineDescriptor new]; psoDesc.vertexFunction = vertexShaderId; psoDesc.fragmentFunction = fragmentShaderId; - psoDesc.colorAttachments[0].pixelFormat = framebuffer->getColorTexture().pixelFormat; + psoDesc.colorAttachments[0].pixelFormat = framebuffer->getColorTexture().pixelFormat; psoDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float; - + if (_shader->hasAttribute(HW::ATTR_TRANSPARENT)) { psoDesc.colorAttachments[0].blendingEnabled = YES; - psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; psoDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; - + _alphaBlendingEnabled = true; } - - MTLVertexDescriptor *vd = [MTLVertexDescriptor new]; - - for( int i = 0; i < vertexShaderId.vertexAttributes.count; ++i) + + MTLVertexDescriptor* vd = [MTLVertexDescriptor new]; + + for (int i = 0; i < vertexShaderId.vertexAttributes.count; ++i) { MTLVertexAttribute* vertexAttrib = vertexShaderId.vertexAttributes[i]; - + vd.attributes[i].bufferIndex = i; vd.attributes[i].format = GetMetalFormatFromMetalType(vertexAttrib.attributeType); vd.attributes[i].offset = 0; @@ -275,23 +274,22 @@ int GetStrideOfMetalType(MTLDataType type) } _attributeList[sattributeName] = inputPtr; - - vd.layouts[i].stride = GetStrideOfMetalType(vertexAttrib.attributeType);; + + vd.layouts[i].stride = GetStrideOfMetalType(vertexAttrib.attributeType); vd.layouts[i].stepFunction = MTLVertexStepFunctionPerVertex; - } - + psoDesc.vertexDescriptor = vd; - + _pso = [device newRenderPipelineStateWithDescriptor:psoDesc - options:MTLPipelineOptionArgumentInfo|MTLPipelineOptionBufferTypeInfo - reflection:&_psoReflection error:&error]; - + options:MTLPipelineOptionArgumentInfo | MTLPipelineOptionBufferTypeInfo + reflection:&_psoReflection + error:&error]; + [_pso retain]; [_psoReflection retain]; - - - if(error) + + if (error) { errors.push_back("Error in linking program:"); errors.push_back([[error localizedDescription] UTF8String]); @@ -327,10 +325,10 @@ int GetStrideOfMetalType(MTLDataType type) } void MslProgram::prepareUsedResources(id renderCmdEncoder, - CameraPtr cam, - GeometryHandlerPtr geometryHandler, - ImageHandlerPtr imageHandler, - LightHandlerPtr lightHandler) + CameraPtr cam, + GeometryHandlerPtr geometryHandler, + ImageHandlerPtr imageHandler, + LightHandlerPtr lightHandler) { // Bind the program to use if (!bind(renderCmdEncoder)) @@ -344,7 +342,7 @@ int GetStrideOfMetalType(MTLDataType type) // Parse for uniforms and attributes getUniformsList(); getAttributesList(); - + // Bind based on inputs found bindViewInformation(cam); bindTimeAndFrame(); @@ -392,25 +390,25 @@ int GetStrideOfMetalType(MTLDataType type) std::vector restructuredData; const void* bufferData = nullptr; size_t bufferSize = 0; - + int shaderStride = input.second->size / FLOAT_SIZE; - - if(shaderStride == stride) + + if (shaderStride == stride) { bufferData = &attributeData[0]; - bufferSize = attributeData.size()*FLOAT_SIZE; + bufferSize = attributeData.size() * FLOAT_SIZE; } else { - size_t nElements = attributeData.size()/stride; - bufferSize = nElements*shaderStride*FLOAT_SIZE; + size_t nElements = attributeData.size() / stride; + bufferSize = nElements * shaderStride * FLOAT_SIZE; restructuredData.resize(bufferSize, 0.0f); size_t j = 0; - for(int i = 0; i < nElements; ++i) + for (int i = 0; i < nElements; ++i) { memcpy(&restructuredData[j], - &attributeData[i*stride], - stride*FLOAT_SIZE); + &attributeData[i * stride], + stride * FLOAT_SIZE); j += shaderStride * FLOAT_SIZE; } bufferData = &restructuredData[0]; @@ -420,7 +418,7 @@ int GetStrideOfMetalType(MTLDataType type) id buffer = [_device newBufferWithBytes:bufferData length:bufferSize options:MTLResourceStorageModeShared]; _attributeBufferIds[input.first] = buffer; } - + [renderCmdEncoder setVertexBuffer:_attributeBufferIds[input.first] offset:0 atIndex:location]; } } @@ -561,17 +559,15 @@ int GetStrideOfMetalType(MTLDataType type) { // Acquire the image. string error; - if (static_cast(imageHandler.get())->bindImage( - renderCmdEncoder, uniformLocation, image)) + if (static_cast(imageHandler.get())->bindImage(renderCmdEncoder, uniformLocation, image)) { return image; } return nullptr; } -MaterialX::ValuePtr MslProgram::findUniformValue( - const string& uniformName, - const MslProgram::InputMap& uniformList) +MaterialX::ValuePtr MslProgram::findUniformValue(const string& uniformName, + const MslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -590,71 +586,69 @@ int GetStrideOfMetalType(MTLDataType type) ImageHandlerPtr imageHandler) { const VariableBlock& publicUniforms = _shader->getStage(Stage::PIXEL).getUniformBlock(HW::PUBLIC_UNIFORMS); - for (MTLArgument *arg in _psoReflection.fragmentArguments) + for (MTLArgument* arg in _psoReflection.fragmentArguments) { if (arg.type == MTLArgumentTypeTexture) { bool found = false; - - if(lightHandler) + + if (lightHandler) { // Bind environment lights. ImageMap envLights = { - { HW::ENV_RADIANCE, lightHandler->getUsePrefilteredMap() ? lightHandler->getEnvPrefilteredMap() : lightHandler->getEnvRadianceMap() }, + { HW::ENV_RADIANCE, lightHandler->getUsePrefilteredMap() ? lightHandler->getEnvPrefilteredMap() : lightHandler->getEnvRadianceMap() }, { HW::ENV_IRRADIANCE, lightHandler->getEnvIrradianceMap() } }; for (const auto& env : envLights) { std::string str(arg.name.UTF8String); size_t loc = str.find(env.first); - if(loc != std::string::npos && env.second) + if (loc != std::string::npos && env.second) { ImageSamplingProperties samplingProperties; samplingProperties.uaddressMode = ImageSamplingProperties::AddressMode::PERIODIC; samplingProperties.vaddressMode = ImageSamplingProperties::AddressMode::CLAMP; samplingProperties.filterType = ImageSamplingProperties::FilterType::LINEAR; - - static_cast - (imageHandler.get())->bindImage(env.second, samplingProperties); - bindTexture(renderCmdEncoder, (unsigned int)arg.index, env.second, imageHandler); + + static_cast(imageHandler.get())->bindImage(env.second, samplingProperties); + bindTexture(renderCmdEncoder, (unsigned int) arg.index, env.second, imageHandler); found = true; } - } } - - if(!found) + + if (!found) { ImagePtr image = nullptr; - if(_explicitBoundImages.find(arg.name.UTF8String) != _explicitBoundImages.end()) + if (_explicitBoundImages.find(arg.name.UTF8String) != _explicitBoundImages.end()) { image = _explicitBoundImages[arg.name.UTF8String]; } - if(image && (image->getWidth() > 1 || image->getHeight() > 1)) + if (image && (image->getWidth() > 1 || image->getHeight() > 1)) { - bindTexture(renderCmdEncoder, (unsigned int)arg.index, image, imageHandler); + bindTexture(renderCmdEncoder, (unsigned int) arg.index, image, imageHandler); found = true; } } - - if(!found) + + if (!found) { auto uniform = _uniformList.find(arg.name.UTF8String); - if(uniform != _uniformList.end()) + if (uniform != _uniformList.end()) { string fileName = uniform->second->value ? uniform->second->value->getValueString() : ""; ImageSamplingProperties samplingProperties; string uniformNameWithoutPostfix = uniform->first; { size_t pos = uniformNameWithoutPostfix.find_last_of(IMAGE_PROPERTY_SEPARATOR); - if(pos != std::string::npos) + if (pos != std::string::npos) uniformNameWithoutPostfix = uniformNameWithoutPostfix.substr(0, pos); } samplingProperties.setProperties(uniformNameWithoutPostfix, publicUniforms); samplingProperties.enableMipmaps = _enableMipMapping; - bindTexture(renderCmdEncoder, (unsigned int)arg.index, fileName, samplingProperties, imageHandler); + bindTexture(renderCmdEncoder, (unsigned int) arg.index, fileName, samplingProperties, imageHandler); } } } @@ -666,7 +660,7 @@ int GetStrideOfMetalType(MTLDataType type) ImagePtr imagePtr, ImageSamplingProperties samplingProperties) { - if(imageHandler->bindImage(imagePtr, samplingProperties)) + if (imageHandler->bindImage(imagePtr, samplingProperties)) { _explicitBoundImages[shaderTextureName] = imagePtr; } @@ -820,9 +814,9 @@ int GetStrideOfMetalType(MTLDataType type) bool MslProgram::hasUniform(const string& name) { const MslProgram::InputMap& uniformList = getUniformsList(); - if(uniformList.find(name) != uniformList.end()) + if (uniformList.find(name) != uniformList.end()) return true; - if(_globalUniformNameList.find(name) != _globalUniformNameList.end() && uniformList.find(_globalUniformNameList[name]) != uniformList.end()) + if (_globalUniformNameList.find(name) != _globalUniformNameList.end() && uniformList.find(_globalUniformNameList[name]) != uniformList.end()) return true; return false; } @@ -838,7 +832,7 @@ int GetStrideOfMetalType(MTLDataType type) else { auto globalNameMapping = _globalUniformNameList.find(name); - if(globalNameMapping != _globalUniformNameList.end()) + if (globalNameMapping != _globalUniformNameList.end()) { bindUniform(globalNameMapping->second, value, errorIfMissing); } @@ -911,45 +905,45 @@ int GetStrideOfMetalType(MTLDataType type) errors.push_back("Cannot parse for uniforms without a valid program"); throw ExceptionRenderError(errorType, errors); } - - for (MTLArgument *arg in _psoReflection.vertexArguments) + + for (MTLArgument* arg in _psoReflection.vertexArguments) { if (arg.bufferDataType == MTLDataTypeStruct) { for (MTLStructMember* member in arg.bufferStructType.members) { InputPtr inputPtr = std::make_shared(arg.index, member.dataType, arg.bufferDataSize, EMPTY_STRING); - std::string memberName = member.name.UTF8String; + std::string memberName = member.name.UTF8String; std::string uboDotMemberName = std::string(arg.name.UTF8String) + "." + member.name.UTF8String; _uniformList[uboDotMemberName] = inputPtr; _globalUniformNameList[member.name.UTF8String] = uboDotMemberName; } } } - - for (MTLArgument *arg in _psoReflection.fragmentArguments) + + for (MTLArgument* arg in _psoReflection.fragmentArguments) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { for (MTLStructMember* member in arg.bufferStructType.members) { std::string uboObjectName = std::string(arg.name.UTF8String); - std::string memberName = member.name.UTF8String; + std::string memberName = member.name.UTF8String; std::string uboDotMemberName = uboObjectName + "." + memberName; - + InputPtr inputPtr = std::make_shared(arg.index, member.dataType, arg.bufferDataSize, EMPTY_STRING); _uniformList[uboDotMemberName] = inputPtr; _globalUniformNameList[memberName] = uboDotMemberName; - - if(MTLArrayType* arrayMember = member.arrayType) + + if (MTLArrayType* arrayMember = member.arrayType) { - for(int i = 0; i < arrayMember.arrayLength; ++i) + for (int i = 0; i < arrayMember.arrayLength; ++i) { for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) { std::string memberNameDotSubmember = memberName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; std::string uboDotMemberNameDotSubmemberName = uboObjectName + "." + memberNameDotSubmember; - + InputPtr inputPtr = std::make_shared(ArrayOfStructMember.argumentIndex, ArrayOfStructMember.dataType, ArrayOfStructMember.offset, EMPTY_STRING); _uniformList[uboDotMemberNameDotSubmemberName] = inputPtr; _globalUniformNameList[memberNameDotSubmember] = uboDotMemberNameDotSubmemberName; @@ -958,10 +952,10 @@ int GetStrideOfMetalType(MTLDataType type) } } } - - if(arg.type == MTLArgumentTypeTexture) + + if (arg.type == MTLArgumentTypeTexture) { - if(HW::ENV_RADIANCE != arg.name.UTF8String && HW::ENV_IRRADIANCE != arg.name.UTF8String) + if (HW::ENV_RADIANCE != arg.name.UTF8String && HW::ENV_IRRADIANCE != arg.name.UTF8String) { std::string texture_name = arg.name.UTF8String; InputPtr inputPtr = std::make_shared(arg.index, MTLDataTypeTexture, -1, EMPTY_STRING); @@ -981,7 +975,7 @@ int GetStrideOfMetalType(MTLDataType type) // 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 @@ -1118,73 +1112,72 @@ int GetStrideOfMetalType(MTLDataType type) { Matrix44 viewInverse = cam->getViewMatrix().getInverse(); MaterialX::Vector3 viewPosition(viewInverse[3][0], viewInverse[3][1], viewInverse[3][2]); - memcpy((void*)&data[offset], viewPosition.data(), 3 * sizeof(float)); + memcpy((void*) &data[offset], viewPosition.data(), 3 * sizeof(float)); return true; } if (uniformName == HW::VIEW_DIRECTION) { - memcpy((void*)&data[offset], cam->getViewPosition().data(), 3 * sizeof(float)); + memcpy((void*) &data[offset], cam->getViewPosition().data(), 3 * sizeof(float)); return true; } - + // World matrix variants const Matrix44& world = cam->getWorldMatrix(); Matrix44 invWorld = world.getInverse(); Matrix44 invTransWorld = invWorld.getTranspose(); if (uniformName == HW::WORLD_MATRIX) { - memcpy((void*)&data[offset], world.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], world.data(), 4 * 4 * sizeof(float)); return false; } if (uniformName == HW::WORLD_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], world.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], world.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::WORLD_INVERSE_MATRIX) { - memcpy((void*)&data[offset], invWorld.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], invWorld.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::WORLD_INVERSE_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], invTransWorld.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], invTransWorld.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } - if(uniformName == HW::FRAME) + if (uniformName == HW::FRAME) { - memcpy((void*)&data[offset], (const void*)&_frame, sizeof(float)); + memcpy((void*) &data[offset], (const void*) &_frame, sizeof(float)); return true; } - if(uniformName == HW::TIME) + if (uniformName == HW::TIME) { - memcpy((void*)&data[offset], (const void*)&_time, sizeof(float)); + memcpy((void*) &data[offset], (const void*) &_time, sizeof(float)); return true; } - // Projection matrix variants const Matrix44& proj = cam->getProjectionMatrix(); if (uniformName == HW::PROJ_MATRIX) { - memcpy((void*)&data[offset], proj.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], proj.data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::PROJ_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], proj.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], proj.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } - const Matrix44& projInverse= proj.getInverse(); + const Matrix44& projInverse = proj.getInverse(); if (uniformName == HW::PROJ_INVERSE_MATRIX) { - memcpy((void*)&data[offset], projInverse.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], projInverse.data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::PROJ_INVERSE_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], projInverse.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], projInverse.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } @@ -1193,48 +1186,48 @@ int GetStrideOfMetalType(MTLDataType type) Matrix44 viewInverse = view.getInverse(); if (uniformName == HW::VIEW_MATRIX) { - memcpy((void*)&data[offset], view.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], view.data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::VIEW_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], view.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], view.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::VIEW_INVERSE_MATRIX) { - memcpy((void*)&data[offset], viewInverse.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], viewInverse.data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::VIEW_INVERSE_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], viewInverse.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], viewInverse.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } - + // View-projection matrix const Matrix44& viewProj = view * proj; if (uniformName == HW::VIEW_PROJECTION_MATRIX) { - memcpy((void*)&data[offset], viewProj.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], viewProj.data(), 4 * 4 * sizeof(float)); return true; } - + // View-projection-world matrix const Matrix44& viewProjWorld = viewProj * world; if (uniformName == HW::WORLD_VIEW_PROJECTION_MATRIX) { - memcpy((void*)&data[offset], viewProjWorld.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], viewProjWorld.data(), 4 * 4 * sizeof(float)); return true; } - + if (uniformName == HW::ENV_RADIANCE_MIPS) { unsigned int maxMipCount = lightHandler->getEnvRadianceMap()->getMaxMipCount(); - memcpy((void*)&data[offset], &maxMipCount, sizeof(maxMipCount)); + memcpy((void*) &data[offset], &maxMipCount, sizeof(maxMipCount)); return true; } - + return false; }; @@ -1243,55 +1236,55 @@ int GetStrideOfMetalType(MTLDataType type) if (value->getTypeString() == "float") { float v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(float)); + memcpy((void*) &data[offset], &v, sizeof(float)); } else if (value->getTypeString() == "integer") { int v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(int)); + memcpy((void*) &data[offset], &v, sizeof(int)); } else if (value->getTypeString() == "boolean") { bool v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(bool)); + memcpy((void*) &data[offset], &v, sizeof(bool)); } else if (value->getTypeString() == "color3") { Color3 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Color3)); + memcpy((void*) &data[offset], &v, sizeof(Color3)); } else if (value->getTypeString() == "color4") { Color4 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Color4)); + memcpy((void*) &data[offset], &v, sizeof(Color4)); } else if (value->getTypeString() == "vector2") { Vector2 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Vector2)); + memcpy((void*) &data[offset], &v, sizeof(Vector2)); } else if (value->getTypeString() == "vector3") { Vector3 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Vector3)); + memcpy((void*) &data[offset], &v, sizeof(Vector3)); } else if (value->getTypeString() == "vector4") { Vector4 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Vector4)); + memcpy((void*) &data[offset], &v, sizeof(Vector4)); } else if (value->getTypeString() == "matrix33") { Matrix33 m = value->asA(); - float tmp[12] = {m[0][0], m[0][1], m[0][2], 0.0f, - m[1][0], m[1][1], m[1][2], 0.0f, - m[2][0], m[2][1], m[2][2], 0.0f}; - memcpy((void*)&data[offset], &tmp, sizeof(tmp)); + float tmp[12] = { m[0][0], m[0][1], m[0][2], 0.0f, + m[1][0], m[1][1], m[1][2], 0.0f, + m[2][0], m[2][1], m[2][2], 0.0f }; + memcpy((void*) &data[offset], &tmp, sizeof(tmp)); } else if (value->getTypeString() == "matrix44") { Matrix44 m = value->asA(); - memcpy((void*)&data[offset], &m, sizeof(Matrix44)); + memcpy((void*) &data[offset], &m, sizeof(Matrix44)); } else if (value->getTypeString() == "string") { @@ -1301,63 +1294,61 @@ int GetStrideOfMetalType(MTLDataType type) { throw ExceptionRenderError( "MSL input binding error.", - { "Unsupported data type when setting uniform value" } - ); + { "Unsupported data type when setting uniform value" }); } }; - - for (MTLArgument *arg in _psoReflection.vertexArguments) + + for (MTLArgument* arg in _psoReflection.vertexArguments) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { std::vector uniformBufferData(arg.bufferDataSize); for (MTLStructMember* member in arg.bufferStructType.members) { - if(!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) + if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { MaterialX::ValuePtr value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; - if(value) + if (value) { setValue(value, uniformBufferData, member.offset); } } } - - if(arg.bufferStructType) - [renderCmdEncoder setVertexBytes:(void*)uniformBufferData.data() length:arg.bufferDataSize atIndex:arg.index]; + + if (arg.bufferStructType) + [renderCmdEncoder setVertexBytes:(void*) uniformBufferData.data() length:arg.bufferDataSize atIndex:arg.index]; } } - - for (MTLArgument *arg in _psoReflection.fragmentArguments) + + for (MTLArgument* arg in _psoReflection.fragmentArguments) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { std::vector uniformBufferData(arg.bufferDataSize); - + for (MTLStructMember* member in arg.bufferStructType.members) { string uniformName = string(arg.name.UTF8String) + "." + member.name.UTF8String; - - if(!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) + + if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { auto uniformInfo = _uniformList.find(uniformName); if (uniformInfo != _uniformList.end()) { MaterialX::ValuePtr value = uniformInfo->second->value; - if(value) + if (value) { setValue(value, uniformBufferData, member.offset); } } else { - } } - - if(MTLArrayType* arrayMember = member.arrayType) + + if (MTLArrayType* arrayMember = member.arrayType) { - for(int i = 0; i < arrayMember.arrayLength; ++i) + for (int i = 0; i < arrayMember.arrayLength; ++i) { for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) { @@ -1367,7 +1358,7 @@ throw ExceptionRenderError( if (uniformInfo != _uniformList.end()) { MaterialX::ValuePtr value = uniformInfo->second->value; - if(value) + if (value) { setValue(value, uniformBufferData, member.offset + i * arrayMember.stride + ArrayOfStructMember.offset); } @@ -1376,9 +1367,9 @@ throw ExceptionRenderError( } } } - - if(arg.bufferStructType) - [renderCmdEncoder setFragmentBytes:(void*)uniformBufferData.data() length:arg.bufferDataSize atIndex:arg.index]; + + if (arg.bufferStructType) + [renderCmdEncoder setFragmentBytes:(void*) uniformBufferData.data() length:arg.bufferDataSize atIndex:arg.index]; } } } @@ -1387,13 +1378,13 @@ throw ExceptionRenderError( { if (_pso != nil) { - [_pso release]; + [_pso release]; } _pso = nil; - - if(_psoReflection != nil) + + if (_psoReflection != nil) { - [_psoReflection release]; + [_psoReflection release]; } _psoReflection = nil; @@ -1424,13 +1415,13 @@ throw ExceptionRenderError( // A "filename" is not indicative of type, so just return a 2d sampler. return MTLDataTypeTexture; } - else if (type == Type::BSDF || - type == Type::MATERIAL || + else if (type == Type::BSDF || + type == Type::MATERIAL || type == Type::DISPLACEMENTSHADER || - type == Type::EDF || - type == Type::VDF || - type == Type::SURFACESHADER || - type == Type::LIGHTSHADER || + type == Type::EDF || + type == Type::VDF || + type == Type::SURFACESHADER || + type == Type::LIGHTSHADER || type == Type::VOLUMESHADER) return MTLDataTypeStruct; @@ -1460,11 +1451,11 @@ throw ExceptionRenderError( for (size_t i = 0; i < vertexInputs.size(); ++i) { const ShaderPort* v = vertexInputs[i]; - + string variableName = v->getVariable(); size_t dotPos = variableName.find('.'); string variableMemberName = variableName.substr(dotPos + 1); - + auto inputIt = _attributeList.find(variableMemberName); if (inputIt != _attributeList.end()) { @@ -1500,9 +1491,9 @@ throw ExceptionRenderError( } void MslProgram::findInputs(const string& variable, - const InputMap& variableList, - InputMap& foundList, - bool exactMatch) + const InputMap& variableList, + InputMap& foundList, + bool exactMatch) { foundList.clear(); @@ -1549,9 +1540,9 @@ throw ExceptionRenderError( string colorspace = input.second->colorspace; bool isConstant = input.second->isConstant; outputStream << "Program Uniform: \"" << input.first - << "\". Location:" << location - << ". ResourceType: " << std::hex << resourceType - << ". Size: " << std::dec << size; + << "\". Location:" << location + << ". ResourceType: " << std::hex << resourceType + << ". Size: " << std::dec << size; if (!type.empty()) outputStream << ". TypeString: \"" << type << "\""; if (!value.empty()) @@ -1569,7 +1560,6 @@ throw ExceptionRenderError( } } - void MslProgram::printAttributes(std::ostream& outputStream) { updateAttributesList(); @@ -1581,9 +1571,9 @@ throw ExceptionRenderError( string type = input.second->typeString; string value = input.second->value ? input.second->value->getValueString() : EMPTY_STRING; outputStream << "Program Attribute: \"" << input.first - << "\". Location:" << location - << ". ResourceType: " << std::hex << resourceType - << ". Size: " << std::dec << size; + << "\". Location:" << location + << ". ResourceType: " << std::hex << resourceType + << ". Size: " << std::dec << size; if (!type.empty()) outputStream << ". TypeString: \"" << type << "\""; if (!value.empty()) diff --git a/source/MaterialXRenderMsl/MslRenderer.h b/source/MaterialXRenderMsl/MslRenderer.h index ca87d9dd3e..f18afd683f 100644 --- a/source/MaterialXRenderMsl/MslRenderer.h +++ b/source/MaterialXRenderMsl/MslRenderer.h @@ -45,13 +45,13 @@ class MX_RENDERMSL_API MslRenderer : public ShaderRenderer public: /// Create a MSL renderer instance static MslRendererPtr create(unsigned int width = 512, unsigned int height = 512, Image::BaseType baseType = Image::BaseType::UINT8); - + /// Create a texture handler for Metal textures ImageHandlerPtr createImageHandler(ImageLoaderPtr imageLoader) { return MetalTextureHandler::create(_device, imageLoader); } - + /// Returns Metal Device used for rendering id getMetalDevice() const; @@ -84,13 +84,13 @@ class MX_RENDERMSL_API MslRenderer : public ShaderRenderer /// Update the program with value of the uniform. void updateUniform(const string& name, ConstValuePtr value) override; - + /// Set the size of the rendered image void setSize(unsigned int width, unsigned int height) override; /// Render the current program to an offscreen buffer. void render() override; - + /// Render the current program in texture space to an off-screen buffer. void renderTextureSpace(const Vector2& uvMin, const Vector2& uvMax); @@ -126,23 +126,23 @@ class MX_RENDERMSL_API MslRenderer : public ShaderRenderer } /// @} - + protected: MslRenderer(unsigned int width, unsigned int height, Image::BaseType baseType); - + void triggerProgrammaticCapture(); void stopProgrammaticCapture(); - + void createFrameBuffer(bool encodeSrgb); - + private: - MslProgramPtr _program; + MslProgramPtr _program; - id _device = nil; - id _cmdQueue = nil; + id _device = nil; + id _cmdQueue = nil; id _cmdBuffer = nil; - - MetalFramebufferPtr _framebuffer; + + MetalFramebufferPtr _framebuffer; bool _initialized; diff --git a/source/MaterialXRenderMsl/MslRenderer.mm b/source/MaterialXRenderMsl/MslRenderer.mm index f5e794c2b3..1a01b8bebf 100644 --- a/source/MaterialXRenderMsl/MslRenderer.mm +++ b/source/MaterialXRenderMsl/MslRenderer.mm @@ -54,7 +54,7 @@ _device = MTLCreateSystemDefaultDevice(); _cmdQueue = [_device newCommandQueue]; createFrameBuffer(true); - + _initialized = true; } } @@ -78,22 +78,22 @@ void MslRenderer::renderTextureSpace(const Vector2& uvMin, const Vector2& uvMax) { bool captureRenderTextureSpace = false; - if(captureRenderTextureSpace) + if (captureRenderTextureSpace) triggerProgrammaticCapture(); - + MTLRenderPassDescriptor* desc = [MTLRenderPassDescriptor new]; _framebuffer->bind(desc); - + _cmdBuffer = [_cmdQueue commandBuffer]; - + id rendercmdEncoder = [_cmdBuffer renderCommandEncoderWithDescriptor:desc]; _program->bind(rendercmdEncoder); _program->prepareUsedResources(rendercmdEncoder, - _camera, - _geometryHandler, - _imageHandler, - _lightHandler); - + _camera, + _geometryHandler, + _imageHandler, + _lightHandler); + MeshPtr mesh = _geometryHandler->createQuadMesh(uvMin, uvMax, true); _program->bindMesh(rendercmdEncoder, mesh); MeshPartitionPtr part = mesh->getPartition(0); @@ -104,16 +104,16 @@ indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; - + _framebuffer->unbind(); [rendercmdEncoder endEncoding]; - + [_cmdBuffer commit]; [_cmdBuffer waitUntilCompleted]; - + [desc release]; - - if(captureRenderTextureSpace) + + if (captureRenderTextureSpace) stopProgrammaticCapture(); } @@ -149,17 +149,16 @@ _height = height; createFrameBuffer(true); } - } void MslRenderer::triggerProgrammaticCapture() { - MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager]; + MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager]; MTLCaptureDescriptor* captureDescriptor = [MTLCaptureDescriptor new]; captureDescriptor.captureObject = _device; - + NSError* error = nil; - if(![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) + if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) { NSLog(@"Failed to start capture, error %@", error); } @@ -174,26 +173,25 @@ void MslRenderer::render() { bool captureFrame = false; - if(captureFrame) + if (captureFrame) triggerProgrammaticCapture(); - + _cmdBuffer = [_cmdQueue commandBuffer]; MTLRenderPassDescriptor* renderpassDesc = [MTLRenderPassDescriptor new]; - + _framebuffer->bind(renderpassDesc); [renderpassDesc.colorAttachments[0] setClearColor: - MTLClearColorMake(_screenColor[0], _screenColor[1], _screenColor[2], 1.0f)]; - + MTLClearColorMake(_screenColor[0], _screenColor[1], _screenColor[2], 1.0f)]; + id renderCmdEncoder = [_cmdBuffer renderCommandEncoderWithDescriptor:renderpassDesc]; MTLDepthStencilDescriptor* depthStencilDesc = [MTLDepthStencilDescriptor new]; - depthStencilDesc.depthWriteEnabled = !(_program->isTransparent()); + depthStencilDesc.depthWriteEnabled = !(_program->isTransparent()); depthStencilDesc.depthCompareFunction = MTLCompareFunctionLess; - + id depthStencilState = [_device newDepthStencilStateWithDescriptor:depthStencilDesc]; [renderCmdEncoder setDepthStencilState:depthStencilState]; - [renderCmdEncoder setCullMode:MTLCullModeBack]; try @@ -215,15 +213,15 @@ auto part = mesh->getPartition(i); _program->bindPartition(part); MeshIndexBuffer& indexData = part->getIndices(); - - if(_program->isTransparent()) + + if (_program->isTransparent()) { [renderCmdEncoder setCullMode:MTLCullModeFront]; - [renderCmdEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:(int)indexData.size() indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; + [renderCmdEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:(int) indexData.size() indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; [renderCmdEncoder setCullMode:MTLCullModeBack]; } - - [renderCmdEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:(int)indexData.size() indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; + + [renderCmdEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:(int) indexData.size() indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; } } } @@ -233,18 +231,18 @@ _framebuffer->unbind(); throw e; } - + [renderCmdEncoder endEncoding]; - + _framebuffer->unbind(); - + [_cmdBuffer commit]; [_cmdBuffer waitUntilCompleted]; - + [_cmdBuffer release]; _cmdBuffer = nil; - - if(captureFrame) + + if (captureFrame) stopProgrammaticCapture(); } diff --git a/source/MaterialXRenderOsl/OslRenderer.cpp b/source/MaterialXRenderOsl/OslRenderer.cpp index 14dd81a090..71cc63753e 100644 --- a/source/MaterialXRenderOsl/OslRenderer.cpp +++ b/source/MaterialXRenderOsl/OslRenderer.cpp @@ -252,7 +252,7 @@ void OslRenderer::shadeOSL(const FilePath& dirPath, const string& shaderName, co StringVec results; string line; string successfulOutputSubString("Output " + outputName + " to " + - outputFileName); + outputFileName); while (std::getline(errorStream, line)) { if (!line.empty() && @@ -295,7 +295,7 @@ void OslRenderer::compileOSL(const FilePath& oslFilePath) // Run the command and get back the result. If non-empty string throw exception with error string command = _oslCompilerExecutable.asString() + " -q "; for (FilePath p : _oslIncludePath) - { + { command += " -I\"" + p.asString() + "\" "; } command += oslFilePath.asString() + " -o " + outputFileName.asString() + " > " + errorFile + redirectString; @@ -320,7 +320,7 @@ void OslRenderer::compileOSL(const FilePath& oslFilePath) void OslRenderer::createProgram(ShaderPtr shader) { - StageMap stages = { {Stage::PIXEL, shader->getStage(Stage::PIXEL).getSourceCode()} }; + StageMap stages = { { Stage::PIXEL, shader->getStage(Stage::PIXEL).getSourceCode() } }; createProgram(stages); } @@ -341,7 +341,7 @@ void OslRenderer::createProgram(const StageMap& stages) // Dump string to disk. For OSL assume shader is in stage 0 slot. FilePath filePath(_oslOutputFilePath); - filePath = filePath / _oslShaderName; + filePath = filePath / _oslShaderName; string fileName = filePath.asString(); if (fileName.empty()) { From 5988645f1c15d4551112691fbd0f83e5713ed704 Mon Sep 17 00:00:00 2001 From: Malia Kuo Date: Wed, 17 Jul 2024 10:55:08 -0700 Subject: [PATCH 016/137] Initial translation from `standard_surface` to `open_pbr_surface` (#1934) 1. Authored an initial pass at the translation graph between standard surface and OpenPBR 2. Added units to standard surface thin film thickness documentation --- libraries/bxdf/standard_surface.mtlx | 2 +- .../standard_surface_to_open_pbr.mtlx | 306 ++++++++++++++++++ 2 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx diff --git a/libraries/bxdf/standard_surface.mtlx b/libraries/bxdf/standard_surface.mtlx index 20ef806699..495958448d 100644 --- a/libraries/bxdf/standard_surface.mtlx +++ b/libraries/bxdf/standard_surface.mtlx @@ -82,7 +82,7 @@ + doc="The thickness of the thin film layer on a surface. Use for materials such as multitone car paint or soap bubbles (in nanometers)." /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3a5b53b2915c15c2d5056a50cd03a2d885c20788 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 17 Jul 2024 15:41:08 -0700 Subject: [PATCH 017/137] Fix edge case in version upgrade This changelist fixes an edge case in the version upgrade logic from 1.38 to 1.39, where a swizzle node with a single-channel input and an empty channels string would upgrade incorrectly, generating a graph with a cycle. --- source/MaterialXCore/Version.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/source/MaterialXCore/Version.cpp b/source/MaterialXCore/Version.cpp index 6fe1dc7e16..668c233bb7 100644 --- a/source/MaterialXCore/Version.cpp +++ b/source/MaterialXCore/Version.cpp @@ -1240,21 +1240,13 @@ void Document::upgradeVersion() for (size_t i = 0; i < destChannelCount; i++) { InputPtr combineInInput = node->addInput(std::string("in") + std::to_string(i + 1), "float"); - if (i < channelString.size()) + if (i < channelString.size() && CHANNEL_CONSTANT_MAP.count(channelString[i])) { - if (CHANNEL_CONSTANT_MAP.count(channelString[i])) - { - combineInInput->setValue(CHANNEL_CONSTANT_MAP.at(channelString[i])); - } - else - { - copyInputWithBindings(node, inInput->getName(), node, combineInInput->getName()); - } + combineInInput->setValue(CHANNEL_CONSTANT_MAP.at(channelString[i])); } else { - combineInInput->setConnectedNode(node); - combineInInput->setOutputString(combineInInput->isColorType() ? "outr" : "outx"); + copyInputWithBindings(node, inInput->getName(), node, combineInInput->getName()); } } node->removeInput(inInput->getName()); From 55b52ec512a5c585a45a6633b8e6518980e9d22f Mon Sep 17 00:00:00 2001 From: Malia Kuo Date: Tue, 30 Jul 2024 13:41:30 -0700 Subject: [PATCH 018/137] Initial translation from `open_pbr_surface` to `standard_surface` (#1949) - Authored an initial pass at the translation from OpenPBR to standard surface. - This would help to support OpenPBR in applications using earlier versions of MaterialX, which only have access to Standard Surface, but may want to participate in the OpenPBR ecosystem before they upgrade. --- .../open_pbr_to_standard_surface.mtlx | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx diff --git a/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx b/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx new file mode 100644 index 0000000000..9d970985b4 --- /dev/null +++ b/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 6021128ccbbde91b23898661f808da83c438ff6e Mon Sep 17 00:00:00 2001 From: Malia Kuo Date: Thu, 1 Aug 2024 08:31:37 -0700 Subject: [PATCH 019/137] Update `standard_surface` to `open_pbr` translation graph (#1956) Replacing coat_affect_roughness with a constant value, since a coating always affects roughness in OpenPBR and is not dependent on the value of coat_darkening. --- .../bxdf/translation/open_pbr_to_standard_surface.mtlx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx b/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx index 9d970985b4..c884a5fb8b 100644 --- a/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx +++ b/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx @@ -198,9 +198,9 @@ - - - + + + From 1d066bb2e1d2c5c7ffc7ccea3bdcea271d940740 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Thu, 1 Aug 2024 12:16:10 -0400 Subject: [PATCH 020/137] Add code generation hints support (#1954) Initial implementation of code generation hints, as described in the 1.39 specification --- libraries/bxdf/open_pbr_surface.mtlx | 4 +-- .../surfaceshader/transparency_hints.mtlx | 15 ++++++++++ source/MaterialXCore/Definition.cpp | 13 +++++++++ source/MaterialXCore/Definition.h | 7 +++++ source/MaterialXCore/Interface.cpp | 4 +++ source/MaterialXCore/Interface.h | 26 +++++++++++++++++ source/MaterialXGenShader/Util.cpp | 29 +++++++++++++++---- 7 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx diff --git a/libraries/bxdf/open_pbr_surface.mtlx b/libraries/bxdf/open_pbr_surface.mtlx index 8186482cf8..87084bf7fe 100644 --- a/libraries/bxdf/open_pbr_surface.mtlx +++ b/libraries/bxdf/open_pbr_surface.mtlx @@ -23,7 +23,7 @@ doc="Index of refraction of the dielectric base." /> - @@ -75,7 +75,7 @@ doc="The amount of emitted light, as a luminance in nits." /> - diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx new file mode 100644 index 0000000000..0773e7e654 --- /dev/null +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 842330c95c..9bbaefb16a 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -100,6 +100,19 @@ InterfaceElementPtr NodeDef::getImplementation(const string& target) const return InterfaceElementPtr(); } +const StringMap NodeDef::getInputHints() const +{ + StringMap hints; + for (InputPtr input : getActiveInputs()) + { + if (input->hasHint()) + { + hints[input->getName()] = input->getHint(); + } + } + return hints; +} + bool NodeDef::validate(string* message) const { bool res = true; diff --git a/source/MaterialXCore/Definition.h b/source/MaterialXCore/Definition.h index 9ec7251221..e3aecbe24a 100644 --- a/source/MaterialXCore/Definition.h +++ b/source/MaterialXCore/Definition.h @@ -146,6 +146,13 @@ class MX_CORE_API NodeDef : public InterfaceElement /// an Implementation element or a NodeGraph element. InterfaceElementPtr getImplementation(const string& target = EMPTY_STRING) const; + /// @} + /// @name Hints + /// @{ + + /// Return list of input hint pairs of the form { input_name, hint_string } + const StringMap getInputHints() const; + /// @} /// @name Validation /// @{ diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index 6b200a8dcf..24d3ccfe0d 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -20,6 +20,10 @@ const string InterfaceElement::TARGET_ATTRIBUTE = "target"; const string InterfaceElement::VERSION_ATTRIBUTE = "version"; const string InterfaceElement::DEFAULT_VERSION_ATTRIBUTE = "isdefaultversion"; const string Input::DEFAULT_GEOM_PROP_ATTRIBUTE = "defaultgeomprop"; +const string Input::HINT_ATTRIBUTE = "hint"; +const string Input::TRANSPARENCY_HINT = "transparency"; +const string Input::OPACITY_HINT = "opacity"; +const string Input::ANISOTROPY_HINT = "anisotropy"; const string Output::DEFAULT_INPUT_ATTRIBUTE = "defaultinput"; // diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index 39fd888b94..599f85ed9d 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -219,6 +219,28 @@ class MX_CORE_API Input : public PortElement /// for this input. InputPtr getInterfaceInput() const; + /// @} + /// @name Hints + /// @{ + + /// Return true if the input has a hint + bool hasHint() const + { + return hasAttribute(HINT_ATTRIBUTE); + } + + /// Return the code generation hint + const string& getHint() const + { + return getAttribute(HINT_ATTRIBUTE); + } + + // Set the code generation hint + void setHint(const string& hint) + { + setAttribute(HINT_ATTRIBUTE, hint); + } + /// @} /// @name Validation /// @{ @@ -232,6 +254,10 @@ class MX_CORE_API Input : public PortElement public: static const string CATEGORY; static const string DEFAULT_GEOM_PROP_ATTRIBUTE; + static const string HINT_ATTRIBUTE; + static const string TRANSPARENCY_HINT; + static const string OPACITY_HINT; + static const string ANISOTROPY_HINT; }; /// @class Output diff --git a/source/MaterialXGenShader/Util.cpp b/source/MaterialXGenShader/Util.cpp index 9722952390..af34fa1b2a 100644 --- a/source/MaterialXGenShader/Util.cpp +++ b/source/MaterialXGenShader/Util.cpp @@ -16,10 +16,10 @@ using OpaqueTestPair = std::pair; using OpaqueTestPairList = vector; // Inputs on a surface shader which are checked for transparency -const OpaqueTestPairList inputPairList = { { "opacity", 1.0f }, - { "existence", 1.0f }, - { "alpha", 1.0f }, - { "transmission", 0.0f } }; +const OpaqueTestPairList DEFAULT_INPUT_PAIR_LIST = { { "opacity", 1.0f }, + { "existence", 1.0f }, + { "alpha", 1.0f }, + { "transmission", 0.0f } }; const string MIX_CATEGORY("mix"); const string MIX_FG_INPUT("fg"); @@ -116,6 +116,23 @@ bool isTransparentShaderNode(NodePtr node, NodePtr interfaceNode) return false; } + // Check against nodedef input hints + OpaqueTestPairList inputPairList = DEFAULT_INPUT_PAIR_LIST; + NodeDefPtr nodeDef = node->getNodeDef(); + StringMap nodeDefList = nodeDef ? nodeDef->getInputHints() : StringMap(); + for (auto &item : nodeDefList) + { + string inputName = item.first; + if (item.second == Input::TRANSPARENCY_HINT) + { + inputPairList.push_back(std::make_pair(inputName, 0.0f) ); + } + else if (item.second == Input::OPACITY_HINT) + { + inputPairList.push_back(std::make_pair(inputName, 1.0f)); + } + } + // Check against the interface if a node is passed in to check against OpaqueTestPairList interfaceNames; if (interfaceNode) @@ -167,8 +184,8 @@ bool isTransparentShaderNode(NodePtr node, NodePtr interfaceNode) NodePtr inputNode = checkInput->getConnectedNode(); if (inputNode) { - NodeDefPtr nodeDef = inputNode->getNodeDef(); - string nodeGroup = nodeDef ? nodeDef->getAttribute(NodeDef::NODE_GROUP_ATTRIBUTE) : EMPTY_STRING; + NodeDefPtr inputNodeDef = inputNode->getNodeDef(); + string nodeGroup = inputNodeDef ? inputNodeDef->getAttribute(NodeDef::NODE_GROUP_ATTRIBUTE) : EMPTY_STRING; if (nodeGroup != NodeDef::ADJUSTMENT_NODE_GROUP && nodeGroup != NodeDef::CHANNEL_NODE_GROUP) { From 1775a6d8e7f1295d8910896c8f3f60ac0ab5d4a9 Mon Sep 17 00:00:00 2001 From: Malia Kuo Date: Sat, 3 Aug 2024 12:43:00 -0700 Subject: [PATCH 021/137] Improved `open_pbr_surface` to `standard_surface` translation (#1958) Integrated the logic of coat_darkening from OpenPBR into the calculations of base_color and subsurface_color. --- .../open_pbr_to_standard_surface.mtlx | 100 ++++++++++++++++-- 1 file changed, 89 insertions(+), 11 deletions(-) diff --git a/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx b/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx index c884a5fb8b..57b3f99d23 100644 --- a/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx +++ b/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx @@ -81,7 +81,6 @@ - @@ -96,19 +95,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + @@ -154,9 +235,10 @@ - - - + + + + @@ -195,9 +277,6 @@ - - - @@ -267,7 +346,6 @@ - From dd075c0f4fcdf23009c07770386a44f7ac365344 Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Sat, 3 Aug 2024 13:25:09 -0700 Subject: [PATCH 022/137] Simplify OSL test setup (#1868) Use the OSL cmake exports to configure the variables needed to enable OSL testing. Also remove the need for specifying the standard OSL include path, an oslc install will already know where these are. --- CMakeLists.txt | 19 ++++++++++++++++--- source/MaterialXRenderOsl/OslRenderer.cpp | 12 ++++-------- .../MaterialXRenderOsl/CMakeLists.txt | 5 +++++ .../MaterialXRenderOsl/GenReference.cpp | 1 - .../MaterialXRenderOsl/RenderOsl.cpp | 1 - 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 68df4e1183..4f5fc23fcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,10 +180,23 @@ if (MATERIALX_BUILD_USE_CCACHE) endif() endif() +# Attempt to configure OSL testing if it can be found by cmake. +# This will not override any explicitly provided oslc and testrender +if(MATERIALX_BUILD_RENDER AND MATERIALX_BUILD_GEN_OSL AND MATERIALX_BUILD_TESTS) + # We currently only need the actual OSL binaries if we're running tests with Render and GenOSL enabled. + find_package(OSL QUIET) + if(OSL_FOUND) + if(NOT MATERIALX_OSL_BINARY_OSLC) + set(MATERIALX_OSL_BINARY_OSLC $) + endif() + if(NOT MATERIALX_OSL_BINARY_TESTRENDER) + # currently OSL does not export a cmake target for testrender, but once that's added this can be simplified. + set(MATERIALX_OSL_BINARY_TESTRENDER $/testrender) + endif() + endif() +endif() + # Add global definitions -add_definitions(-DMATERIALX_OSL_BINARY_OSLC=\"${MATERIALX_OSL_BINARY_OSLC}\") -add_definitions(-DMATERIALX_OSL_BINARY_TESTRENDER=\"${MATERIALX_OSL_BINARY_TESTRENDER}\") -add_definitions(-DMATERIALX_OSL_INCLUDE_PATH=\"${MATERIALX_OSL_INCLUDE_PATH}\") if (MATERIALX_OSL_LEGACY_CLOSURES) add_definitions(-DMATERIALX_OSL_LEGACY_CLOSURES) endif() diff --git a/source/MaterialXRenderOsl/OslRenderer.cpp b/source/MaterialXRenderOsl/OslRenderer.cpp index 71cc63753e..bcddb08123 100644 --- a/source/MaterialXRenderOsl/OslRenderer.cpp +++ b/source/MaterialXRenderOsl/OslRenderer.cpp @@ -48,10 +48,6 @@ void OslRenderer::setSize(unsigned int width, unsigned int height) void OslRenderer::initialize(RenderContextHandle) { - if (_oslIncludePath.isEmpty()) - { - throw ExceptionRenderError("OSL validation include path is empty"); - } if (_oslTestShadeExecutable.isEmpty() && _oslCompilerExecutable.isEmpty()) { throw ExceptionRenderError("OSL validation executables not set"); @@ -61,7 +57,7 @@ void OslRenderer::initialize(RenderContextHandle) void OslRenderer::renderOSL(const FilePath& dirPath, const string& shaderName, const string& outputName) { // If command options missing, skip testing. - if (_oslTestRenderExecutable.isEmpty() || _oslIncludePath.isEmpty() || + if (_oslTestRenderExecutable.isEmpty() || _oslTestRenderSceneTemplateFile.isEmpty() || _oslUtilityOSOPath.isEmpty()) { throw ExceptionRenderError("Command input arguments are missing"); @@ -218,7 +214,7 @@ void OslRenderer::renderOSL(const FilePath& dirPath, const string& shaderName, c void OslRenderer::shadeOSL(const FilePath& dirPath, const string& shaderName, const string& outputName) { // If no command and include path specified then skip checking. - if (_oslTestShadeExecutable.isEmpty() || _oslIncludePath.isEmpty()) + if (_oslTestShadeExecutable.isEmpty()) { return; } @@ -279,7 +275,7 @@ void OslRenderer::shadeOSL(const FilePath& dirPath, const string& shaderName, co void OslRenderer::compileOSL(const FilePath& oslFilePath) { // If no command and include path specified then skip checking. - if (_oslCompilerExecutable.isEmpty() || _oslIncludePath.isEmpty()) + if (_oslCompilerExecutable.isEmpty()) { return; } @@ -333,7 +329,7 @@ void OslRenderer::createProgram(const StageMap& stages) throw ExceptionRenderError("No shader code to validate"); } - bool haveCompiler = !_oslCompilerExecutable.isEmpty() && !_oslIncludePath.isEmpty(); + bool haveCompiler = !_oslCompilerExecutable.isEmpty(); if (!haveCompiler) { throw ExceptionRenderError("No OSL compiler specified for validation"); diff --git a/source/MaterialXTest/MaterialXRenderOsl/CMakeLists.txt b/source/MaterialXTest/MaterialXRenderOsl/CMakeLists.txt index b132376c95..3d5728361b 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/CMakeLists.txt +++ b/source/MaterialXTest/MaterialXRenderOsl/CMakeLists.txt @@ -3,6 +3,11 @@ file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h") target_sources(MaterialXTest PUBLIC ${source} ${headers}) +target_compile_definitions(MaterialXTest PRIVATE + MATERIALX_OSL_BINARY_OSLC=\"${MATERIALX_OSL_BINARY_OSLC}\" + MATERIALX_OSL_BINARY_TESTRENDER=\"${MATERIALX_OSL_BINARY_TESTRENDER}\" +) + add_tests("${source}") assign_source_group("Source Files" ${source}) diff --git a/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp b/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp index a7f7293755..e77c0a2541 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp +++ b/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp @@ -34,7 +34,6 @@ TEST_CASE("GenReference: OSL Reference", "[genreference]") oslRenderer = mx::OslRenderer::create(); oslRenderer->setOslCompilerExecutable(MATERIALX_OSL_BINARY_OSLC); mx::FileSearchPath oslIncludePaths; - oslIncludePaths.append(mx::FilePath(MATERIALX_OSL_INCLUDE_PATH)); // Add in library include path for compile testing as the generated // shader's includes are not added with absolute paths. oslIncludePaths.append(searchPath.find("libraries/stdlib/genosl/include")); diff --git a/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp b/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp index c23f74cba3..ba54ba4b96 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp +++ b/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp @@ -126,7 +126,6 @@ void OslShaderRenderTester::createRenderer(std::ostream& log) _renderer->setOslCompilerExecutable(oslcExecutable); const std::string testRenderExecutable(MATERIALX_OSL_BINARY_TESTRENDER); _renderer->setOslTestRenderExecutable(testRenderExecutable); - _renderer->setOslIncludePath(mx::FileSearchPath(MATERIALX_OSL_INCLUDE_PATH)); try { From e98d05f99f34f8771ff8dcb4c524ecf4a4f00f30 Mon Sep 17 00:00:00 2001 From: Doug Smythe Date: Sat, 3 Aug 2024 14:24:51 -0700 Subject: [PATCH 023/137] Move proposed Specification changes to separate Proposals doc (#1953) Nodes, Elements and other things that were described in the MaterialX Specification but which have not actully been implemented yet are now moved out of tyhe Spec docs and into a separate MaterialX Proposals document. Also adds table-of-content links in the PBR Spec for Khronos glTF PBR and OpenPBR Surface shading model examples, and removes duplicate descriptions of the Logical "and", "or" and "not" operators. --- documents/Specification/MaterialX.PBRSpec.md | 2 + .../Specification/MaterialX.Proposals.md | 331 ++++++++++++++++++ .../Specification/MaterialX.Specification.md | 245 +------------ documents/Specification/README.md | 1 + 4 files changed, 338 insertions(+), 241 deletions(-) create mode 100644 documents/Specification/MaterialX.Proposals.md diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md index 32cef574c6..2e314d479d 100644 --- a/documents/Specification/MaterialX.PBRSpec.md +++ b/documents/Specification/MaterialX.PBRSpec.md @@ -43,6 +43,8 @@ This document describes a number of shader-semantic nodes implementing widely-us **[Shading Model Examples](#shading-model-examples)**  [Autodesk Standard Surface](#autodesk-standard-surface)  [UsdPreviewSurface](#usdpreviewsurface) + [Khronos glTF PBR](#khronos-gltf-pbr) + [OpenPBR Surface](#openpbr-surface) **[References](#references)** diff --git a/documents/Specification/MaterialX.Proposals.md b/documents/Specification/MaterialX.Proposals.md new file mode 100644 index 0000000000..97b37787ba --- /dev/null +++ b/documents/Specification/MaterialX.Proposals.md @@ -0,0 +1,331 @@ + + + +# MaterialX: Proposed Additions and Changes + +**Proposals for Version 1.39** +July 26, 2024 + + +# Introduction + +The [MaterialX Specification](./MaterialX.Specification.md) has historically included descriptions of not just current functionality, but also forward-looking proposed functionality intended for eventual implementation. We believe it will be beneficial to provide clarity on which functionality is currently supported in the library, and which sections document proposed additions. + +As such, those forward-looking proposals have been moved from the formal Specification documents into this Proposed Additions and Changes document to be discussed and debated. These descriptions can then be migrated into the appropriate formal Specification document once actually implemented in the code base. New proposals for changes and additions to MaterialX may be added to this document once a generally favorable consensus from the community is reached. + + + +## Table of Contents + +**[Introduction](#introduction)** + +**[Proposals: General](#propose-general)** + +**[Proposals: Elements](#propose-elements)** + +**[Proposals: Stdlib Nodes](#propose-stdlib-nodes)** + +**[Proposals: PBR Nodes](#propose-pbr-nodes)** + +**[Proposals: NPR Nodes](#propose-npr-nodes)** + + +

 


+ +# Proposals: General + + +## Color Spaces + +When the OCIO NanoColor library (provide link) becomes available, MaterialX should support the official colorspace names in that spec, with the current MaterialX colorspace names supported as aliases. + +MaterialX should also support the following color spaces: +* `lin_rec2020` +* `g22_rec2020` + + + +

 


+ +# Proposals: Elements + + +### AOV Output Elements + +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 + +``` + +The attributes for <aovoutput> elements are: + +* name (string, required): a user-chosen name for this aov output definition element. +* type (string, required): the type of the AOV, which must be one of the supported types listed above. +* aovname (string, required): the name that the renderer should use for the AOV. +* nodename (string, required): the name of the node whose output defines the AOV value. +* sourceaov (string, optional): If nodename is a surfaceshader type, the name of the output AOV defined within nodename to pass along as the output AOV. The type of the sourceaov defined within nodename must match the <aovoutput> type. + +Examples: + +```xml + + + nodename="diffuse_bsdf"/> +``` + +#### AovOutput Example + +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 + + + + + + + + + + + + + + + + + + + + + +``` + +Layered shaders or materials must internally handle blending of AOV-like values from source layers before outputting them as AOVs: there is currently no facility for blending AOVs defined within post-shading blended surfaceshaders. + +Note: while it is syntactically possible to create <aovoutput>s for geometric primitive values such as shading surface point and normal accessed within a nodegraph, it is preferred that renderers derive such information directly from their internal shading state or geometric primvars. + + + +#### Implementation AOV Elements + +An <implementation> 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 + + ...... + + + +``` + + + +### Material Inheritance + +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 + + + + + + + + + + + +``` + +Inheritance of material-type custom nodes is also allowed, so that new or changed input values can be applied on top of those specified in the inherited material. + + +

 


+ +# Proposals: Stdlib Nodes + + +### Procedural Nodes + + + +* **`tokenvalue`**: a constant "interface token" value, may only be connected to <token>s in nodes, not to <input>s. + * `value` (any uniform non-shader-semantic type): the token value to output; "enum" and "enumvalues" attributes may be provided to define a specific set of allowed token values. + + + +### Noise Nodes + + + +We have a standard 3d fractal noise, but a 2d variant would be useful as well. + +* **`fractal2d`**: Zero-centered 2D Fractal noise in 1, 2, 3 or 4 channels, created by summing several octaves of 2D Perlin noise, increasing the frequency and decreasing the amplitude at each octave. + * `amplitude` (float or vectorN): the center-to-peak amplitude of the noise (peak-to-peak amplitude is 2x this value). Default is 1.0. + * `octaves` (integer): the number of octaves of noise to be summed. Default is 3. + * `lacunarity` (float or vectorN): the exponential scale between successive octaves of noise; must be an integer value if period is non-zero so the result is properly tileable. VectorN-output types can provide either a float (isotropic) or vectorN (anisotropic) values for lacunarity and diminish. Default is 2.0. + * `diminish` (float or vectorN): the rate at which noise amplitude is diminished for each octave. Should be between 0.0 and 1.0; default is 0.5. VectorN-output types can provide either a float (isotropic) or vectorN (anisotropic) values for lacunarity and diminish. + * `period` (float or vectorN): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + * `texcoord` (vector2): the 2D texture coordinate at which the noise is evaluated. Default is to use the first set of texture coordinates. + + + +1D Cell noise was proposed an an alternative approach to random value generation. + +* **`cellnoise1d`**: 1D cellular noise, 1 or 3 channels (type float or vector3). + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for input coordinate repeated at that step. Default is 0, meaning the noise is not periodic. + * `in` (float): the 1D coordinate at which the noise is evaluated. + + + +### Shape Nodes + + + + +### Geometric Nodes + + + +* **`bump`**: Existing node, proposal to add a vector3 `bitangent` input + + + +* **`geompropvalueuniform`**: the value of the specified uniform geometric property (defined using <geompropdef>) of the currently-bound geometry. This node's type must match that of the referenced geomprop. + * `geomprop` (uniform string): the geometric property to be referenced. + * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. + + + +### Global Nodes + + + +* **`ambientocclusion`**: Compute the ambient occlusion at the current surface point, returning a scalar value between 0 and 1. Ambient occlusion represents the accessibility of each surface point to ambient lighting, with larger values representing greater accessibility to light. This node must be of type float. + * `coneangle` (float): the half-angle of a cone about the surface normal, within which geometric surface features are considered as potential occluders. The unit for this input is degrees, and its default value is 90.0 (full hemisphere). + * `maxdistance` (float): the maximum distance from the surface point at which geometric surface features are considered as potential occluders. Defaults to 1e38, e.g. "unlimited". + + + +### Application Nodes + + + +* **`updirection`**: the current scene "up vector" direction, as defined by the shading environment. This node must be of type vector3. + * `space` (uniform string): the space in which to return the up vector direction, defaults to "world". + + + +### Math Nodes + + + +* **`transformcolor`**: transform the incoming color from one specified colorspace to another, ignoring any colorspace declarations that may have been provided upstream. For color4 types, the alpha channel value is unaffected. + * `in` (color3 or color4): the input color. + * `fromspace` (uniform string): the name of a standard colorspace or a colorspace understood by the application to transform the `in` color from; may be empty (the default) to specify the document's working colorspace. + * `tospace` (uniform string): the name of a standard colorspace or a colorspace understood by the application to transform the `in` color to; may be empty (the default) to specify the document's working colorspace. + + + +* **`triplanarblend`** (NG): samples data from three inputs, and projects a tiled representation of the images along each of the three respective coordinate axes, computing a weighted blend of the three samples using the geometric normal. + * `inx` (float or colorN): the image to be projected in the direction from the +X axis back toward the origin. Default is 0 in all channels. + * `iny` (float or colorN): the image to be projected in the direction from the +Y axis back toward the origin with the +X axis to the right. Default is 0 in all channels. + * `inz` (float or colorN): the image to be projected in the direction from the +Z axis back toward the origin. Default is 0 in all channels. + * `position` (vector3): a spatially-varying input specifying the 3D position at which the projection is evaluated. Default is to use the current 3D object-space coordinate. + * `normal` (vector3): a spatially-varying input specifying the 3D normal vector used for blending. Default is to use the current object-space surface normal. + * `blend` (float): a 0-1 weighting factor for blending the three axis samples using the geometric normal, with higher values giving softer blending. Default is 1.0. + * `filtertype` (uniform string): the type of texture filtering to use; standard values include "closest" (nearest-neighbor single-sample), "linear", and "cubic". If not specified, an application may use its own default texture filtering method. + + + +### Adjustment Nodes + + + +* **`curveinversecubic`**: remap a 0-1 input float value using an inverse Catmull-Rom spline lookup on the input `knots` values. Outputs a 0-1 float interpolant value. + * `in` (float): the input value or nodename + * `knots` (uniform floatarray): the list of non-uniformly distributed input values defining the curve for the remapping. At least 2 values must be provided, and the first and last knot have multiplicity 2. + + + +* **`curveuniformlinear`**: output a float, colorN or vectorN value linearly interpolated between a number of `knotvalues` values, using the value of `in` as the interpolant. + * `in` (float): the input interpolant value or nodename + * `knotvalues` (uniform floatarray or colorNarray or vectorNarray): the array of at least 2 values to interpolate between. + + + +* **`curveuniformcubic`**: output a float, colorN or vectorN value smoothly interpolated between a number of `knotvalues` values using a Catmull-Rom spline with the value of `in` as the interpolant. + * `in` (float): the input interpolant value or nodename + * `knotvalues` (uniform floatarray or colorNarray or vectorNarray): the array of at least 2 values to interpolate between. + + + +* **`curveadjust`** (NG): output a smooth remapping of input values using the centripetal Catmull-Rom cubic spline curve defined by specified knot values, using an inverse spline lookup on input knot values and a forward spline through output knot values. All channels of the input will be remapped using the same curve. + * `in` (float or colorN or vectorN): the input value or nodename + * `numknots` (uniform integer): the number of values in the knots and knotvalues arrays + * `knots` (uniform floatarray): the list of input values defining the curve for the remapping. At least 2 and at most 16 values must be provided. + * `knotvalues` (uniform floatarray): the list of output values defining the curve for the remapping. Must be the same length as knots. + + + +* **`curvelookup`** (NG): output a float, colorN or vectorN value smoothly interpolated between a number of knotvalue values, using the position of in within knots as the knotvalues interpolant. + * `in` (float): the input interpolant value or nodename + * `numknots` (uniform integer): the number of values in the knots and knotvalues arrays + * `knots` (uniform floatarray): the list of knot values to interpolate in within. At least 2 and at most 16 values must be provided. + * `knotvalues` (uniform floatarray or colorNarray or vectorNarray): the values at each knot position to interpolate between. Must be the same length as knots. + + + +### Compositing Nodes + + + +### Conditional Nodes + + + +* **`ifelse`**: output the value of one of two input streams, according to whether the value of a boolean selector input is true or false + * `infalse`, `intrue` (float or colorN or vectorN): the values or nodenames to select from based on the value of the `which` input. The types of the various `inN` inputs must match the type of the `switch` node itself. The default value of all `inN` inputs is 0.0 in all channels. + * `which` (boolean): a selector to choose which input to take values from; default is "false". + + + +### Channel Nodes + + + +* **`extractrowvector`**: extract the specified row vector number from a matrixN stream. + * `in` (matrixN): the input value or nodename + * `index` (integer): the row number to extract, should be 0-2 for matrix33 streams, or 0-3 for matrix44 streams. + + + +* **`separatecolor4`** (NG): output the RGB and alpha channels of a color4 as separate outputs. + * `in` (color4): the input value or nodename + * `outcolor` (output, color3): the RGB channel values. + * `outa` (output, float): the value of the alpha channel. + + + +

 


+ +# Proposals: PBR Nodes + + + +

 


+ +# Proposals: NPR Nodes + diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 681f36ea36..0232074701 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -8,7 +8,7 @@ MaterialX Specification v1.39 **Version 1.39** Doug Smythe - Industrial Light & Magic Jonathan Stone - Lucasfilm Advanced Development Group -May 9, 2024 +July 26, 2024 # Introduction @@ -24,7 +24,7 @@ At least four distinct interrelated data relationships are required to specify t **MaterialX** addresses the need for an open, platform-independent, well-defined standard for specifying the "look" of computer graphics objects built using node networks by defining a material content schema along with a corresponding XML-based file format to read and write MaterialX content. The MaterialX schema defines a number of primary element types plus several supplemental and sub-element types, as well as a set of **standard nodes** with specific functionality for defining data-processing graphs, shaders and materials. -This document describes the core MaterialX specification. Companion documents [**MaterialX Physically Based Shading Nodes**](./MaterialX.PBRSpec.md), [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) and [**MaterialX Supplemental Notes**](./MaterialX.Supplement.md) describe additional node and element types and other information about the library. +This document describes the core MaterialX specification. Companion documents [**MaterialX Physically Based Shading Nodes**](./MaterialX.PBRSpec.md), [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) and [**MaterialX Supplemental Notes**](./MaterialX.Supplement.md) describe additional node and element types and other information about the library, while [**MaterialX: Proposed Additions and Changes**](./MaterialX.Proposals.md) describes forward-looking proposed funnctionality for MaterialX. @@ -56,7 +56,6 @@ This document describes the core MaterialX specification. Companion documents [   [Noise Nodes](#noise-nodes)   [Shape Nodes](#shape-nodes)   [Geometric Nodes](#geometric-nodes) -  [Global Nodes](#global-nodes)   [Application Nodes](#application-nodes)  [Standard Operator Nodes](#standard-operator-nodes) @@ -84,7 +83,6 @@ This document describes the core MaterialX specification. Companion documents [    [NodeDef Token Elements](#nodedef-token-elements)    [NodeDef Output Elements](#nodedef-output-elements)   [Custom Node Definition Using Implementation Elements](#custom-node-definition-using-implementation-elements) -   [Implementation AOV Elements](#implementation-aov-elements)    [Example Custom Nodes Defined by External File Implementations](#example-custom-nodes-defined-by-external-file-implementations)   [Custom Node Definition Using Node Graphs](#custom-node-definition-using-node-graphs)    [Functional Nodegraphs](#functional-nodegraphs) @@ -93,10 +91,7 @@ This document describes the core MaterialX specification. Companion documents [   [Custom Node Use](#custom-node-use)  [Shader Nodes](#shader-nodes)   [Standard Library Shader Nodes](#standard-library-shader-nodes) -  [AOV Output Elements](#aov-output-elements) -   [AOVOutput Example](#aovoutput-example)  [Material Nodes](#material-nodes) -  [Material Inheritance](#material-inheritance)   [Example Pre-Shader Compositing Material](#example-pre-shader-compositing-material)  [Material Variants](#material-variants) @@ -668,7 +663,7 @@ MaterialX also supports the following additional attributes for Output elements Source nodes use external data and/or procedural functions to form an output; they do not have any required inputs. Each source node must define its output type. -This section defines the Source Nodes that all MaterialX implementations are expected to support. Standard Source Nodes are grouped into the following classifications: [Texture Nodes](#texture-nodes), [Procedural Nodes](#procedural-nodes), [Noise Nodes](#noise-nodes), [Shape Nodes](#shape-nodes), [Geometric Nodes](#geometric-nodes), [Global Nodes](#global-nodes) and [Application Nodes](#application-nodes). +This section defines the Source Nodes that all MaterialX implementations are expected to support. Standard Source Nodes are grouped into the following classifications: [Texture Nodes](#texture-nodes), [Procedural Nodes](#procedural-nodes), [Noise Nodes](#noise-nodes), [Shape Nodes](#shape-nodes), [Geometric Nodes](#geometric-nodes) and [Application Nodes](#application-nodes). ### Texture Nodes @@ -774,11 +769,6 @@ Standard Procedural nodes: * **`constant`**: a constant value. * `value` (any non-shader-semantic type): the value to output - - -* **`tokenvalue`**: a constant "interface token" value, may only be connected to <token>s in nodes, not to <input>s. - * `value` (any uniform non-shader-semantic type): the token value to output; "enum" and "enumvalues" attributes may be provided to define a specific set of allowed token values. - * **`ramplr`**: a left-to-right linear value ramp. @@ -872,16 +862,6 @@ Standard Noise nodes: * `period` (float or vectorN): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. - - -* **`fractal2d`**: Zero-centered 2D Fractal noise in 1, 2, 3 or 4 channels, created by summing several octaves of 2D Perlin noise, increasing the frequency and decreasing the amplitude at each octave. - * `amplitude` (float or vectorN): the center-to-peak amplitude of the noise (peak-to-peak amplitude is 2x this value). Default is 1.0. - * `octaves` (integer): the number of octaves of noise to be summed. Default is 3. - * `lacunarity` (float or vectorN): the exponential scale between successive octaves of noise; must be an integer value if period is non-zero so the result is properly tileable. VectorN-output types can provide either a float (isotropic) or vectorN (anisotropic) values for lacunarity and diminish. Default is 2.0. - * `diminish` (float or vectorN): the rate at which noise amplitude is diminished for each octave. Should be between 0.0 and 1.0; default is 0.5. VectorN-output types can provide either a float (isotropic) or vectorN (anisotropic) values for lacunarity and diminish. - * `period` (float or vectorN): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. - * `texcoord` (vector2): the 2D texture coordinate at which the noise is evaluated. Default is to use the first set of texture coordinates. - * **`fractal3d`**: Zero-centered 3D Fractal noise in 1, 2, 3 or 4 channels, created by summing several octaves of 3D Perlin noise, increasing the frequency and decreasing the amplitude at each octave. @@ -892,12 +872,6 @@ Standard Noise nodes: * `period` (float or vectorN): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. - - -* **`cellnoise1d`**: 1D cellular noise, 1 or 3 channels (type float or vector3). - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for input coordinate repeated at that step. Default is 0, meaning the noise is not periodic. - * `in` (float): the 1D coordinate at which the noise is evaluated. - * **`cellnoise2d`**: 2D cellular noise, 1 or 3 channels (type float or vector3). @@ -1144,26 +1118,6 @@ Applications may also reference other renderer-specific named spaces, at the exp -### Global Nodes - -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 - - - -``` - -Standard Global nodes: - - - -* **`ambientocclusion`**: Compute the ambient occlusion at the current surface point, returning a scalar value between 0 and 1. Ambient occlusion represents the accessibility of each surface point to ambient lighting, with larger values representing greater accessibility to light. This node must be of type float. - * `coneangle` (float): the half-angle of a cone about the surface normal, within which geometric surface features are considered as potential occluders. The unit for this input is degrees, and its default value is 90.0 (full hemisphere). - * `maxdistance` (float): the maximum distance from the surface point at which geometric surface features are considered as potential occluders. Defaults to 1e38, e.g. "unlimited". - - - ### Application Nodes Application nodes are used to reference application-defined properties within a node graph, and have no inputs: @@ -1183,11 +1137,6 @@ Standard Application nodes: * **`time`**: the current time in seconds, as defined by the host environment. This node must be of type float. Applications may use whatever method is appropriate to communicate the current time to the <time> node's implementation, whether via an internal state variable, a custom input, dividing the current frame number by a local "frames per second" value, or other method; real-time applications may return some variation of wall-clock time. - - -* **`updirection`**: the current scene "up vector" direction, as defined by the shading environment. This node must be of type vector3. - * `space` (uniform string): the space in which to return the up vector direction, defaults to "world". - ## Standard Operator Nodes @@ -1363,23 +1312,6 @@ Math nodes have one or two spatially-varying inputs, and are used to perform a m * `in1` (float or colorN or vectorN): the first value or nodename * `in2` (same type as `in1` or float): the second value or nodename - - -* **`and`**: boolean "and" of the two incoming boolean values - * `in1` (boolean): the first value or nodename - * `in2` (boolean): the second value or nodename - - - -* **`or`**: boolean "or" of the two incoming boolean values - * `in1` (boolean): the first value or nodename - * `in2` (boolean): the second value or nodename - - - -* **`not`**: boolean "not" of the incoming boolean value - * `in` (boolean): the value or nodename - * **`normalize`**: output the normalized vectorN from the incoming vectorN stream; cannot be used on float or colorN streams. Note: the fourth channel in vector4 streams is not treated any differently, e.g. not as a homogeneous "w" value. @@ -1436,13 +1368,6 @@ Math nodes have one or two spatially-varying inputs, and are used to perform a m * `in` (vectorN): the input vector. If needed, an additional 1.0 component will be temporarily appended to the `in` vector to make it match the dimension of the transforming `mat` matrix, then removed after transformation. * `mat` matrix33/44): the matrix used to transform the vector; a vector2 `in` can be transformed by a matrix33, a vector3 by a matrix33 or a matrix44, and a vector4 by a matrix44. Default is the identity matrix. - - -* **`transformcolor`**: transform the incoming color from one specified colorspace to another, ignoring any colorspace declarations that may have been provided upstream. For color4 types, the alpha channel value is unaffected. - * `in` (color3 or color4): the input color. - * `fromspace` (uniform string): the name of a standard colorspace or a colorspace understood by the application to transform the `in` color from; may be empty (the default) to specify the document's working colorspace. - * `tospace` (uniform string): the name of a standard colorspace or a colorspace understood by the application to transform the `in` color to; may be empty (the default) to specify the document's working colorspace. - * **`normalmap`**: transform a normal vector from encoded tangent space to world space. The input normal vector is assumed to be encoded with all channels in the [0-1] range, as would commonly be output from a normal map. @@ -1501,7 +1426,6 @@ Math nodes have one or two spatially-varying inputs, and are used to perform a m * `normal` (vector3): the normal vector about which to reflect "in", defaults to the value of the "Nworld" (world space view direction) geometric property. This vector is expected to be prenormalized to length 1.0. * `ior` (float): the index of refraction of the surface, defaults to 1.0. - * **`place2d`** (NG): transform incoming UV texture coordinates for 2D texture placement. @@ -1512,17 +1436,6 @@ Math nodes have one or two spatially-varying inputs, and are used to perform a m * `offset` (vector2): subtract this amount from the scaled/rotated/“pivot added back” UV coordinate; since U0,V0 is typically the lower left corner, a positive offset moves the texture image up and right. Default is (0,0). * `operationorder` (integer enum): the order in which to perform the transform operations. "0" or "SRT" performs "-pivot scale rotate translate +pivot" as per the original implementation matching the behavior of certain DCC packages, and "1" or "TRS" performs "-pivot translate rotate scale +pivot" which does not introduce texture shear. Default is 0 "SRT" for backward compatibility. - - -* **`triplanarblend`** (NG): samples data from three inputs, and projects a tiled representation of the images along each of the three respective coordinate axes, computing a weighted blend of the three samples using the geometric normal. - * `inx` (float or colorN): the image to be projected in the direction from the +X axis back toward the origin. Default is 0 in all channels. - * `iny` (float or colorN): the image to be projected in the direction from the +Y axis back toward the origin with the +X axis to the right. Default is 0 in all channels. - * `inz` (float or colorN): the image to be projected in the direction from the +Z axis back toward the origin. Default is 0 in all channels. - * `position` (vector3): a spatially-varying input specifying the 3D position at which the projection is evaluated. Default is to use the current 3D object-space coordinate. - * `normal` (vector3): a spatially-varying input specifying the 3D normal vector used for blending. Default is to use the current object-space surface normal. - * `blend` (float): a 0-1 weighting factor for blending the three axis samples using the geometric normal, with higher values giving softer blending. Default is 1.0. - * `filtertype` (uniform string): the type of texture filtering to use; standard values include "closest" (nearest-neighbor single-sample), "linear", and "cubic". If not specified, an application may use its own default texture filtering method. - * **`dot`**: a no-op, passes its input through to its output unchanged. Users can use dot nodes to shape edge connection paths or provide documentation checkpoints in node graph layout UI's. Dot nodes may also pass uniform values from <constant>, <tokenvalue> or other nodes with uniform="true" outputs to uniform <input>s and <token>s. @@ -1596,40 +1509,6 @@ Adjustment nodes have one input named "in", and apply a specified function to va * `low` (same type as `in` or float): input low value; an input value of this or lower will result in an output value of 0; default is 0.0 in all channels * `high` (same type as `in` or float): input high value; an input value of this or higher will result in an output value of 1; default is 1.0 in all channels - - -* **`curveinversecubic`**: remap a 0-1 input float value using an inverse Catmull-Rom spline lookup on the input `knots` values. Outputs a 0-1 float interpolant value. - * `in` (float): the input value or nodename - * `knots` (uniform floatarray): the list of non-uniformly distributed input values defining the curve for the remapping. At least 2 values must be provided, and the first and last knot have multiplicity 2. - - - -* **`curveuniformlinear`**: output a float, colorN or vectorN value linearly interpolated between a number of `knotvalues` values, using the value of `in` as the interpolant. - * `in` (float): the input interpolant value or nodename - * `knotvalues` (uniform floatarray or colorNarray or vectorNarray): the array of at least 2 values to interpolate between. - - - -* **`curveuniformcubic`**: output a float, colorN or vectorN value smoothly interpolated between a number of `knotvalues` values using a Catmull-Rom spline with the value of `in` as the interpolant. - * `in` (float): the input interpolant value or nodename - * `knotvalues` (uniform floatarray or colorNarray or vectorNarray): the array of at least 2 values to interpolate between. - - - -* **`curveadjust`** (NG): output a smooth remapping of input values using the centripetal Catmull-Rom cubic spline curve defined by specified knot values, using an inverse spline lookup on input knot values and a forward spline through output knot values. All channels of the input will be remapped using the same curve. - * `in` (float or colorN or vectorN): the input value or nodename - * `numknots` (uniform integer): the number of values in the knots and knotvalues arrays - * `knots` (uniform floatarray): the list of input values defining the curve for the remapping. At least 2 and at most 16 values must be provided. - * `knotvalues` (uniform floatarray): the list of output values defining the curve for the remapping. Must be the same length as knots. - - - -* **`curvelookup`** (NG): output a float, colorN or vectorN value smoothly interpolated between a number of knotvalue values, using the position of in within knots as the knotvalues interpolant. - * `in` (float): the input interpolant value or nodename - * `numknots` (uniform integer): the number of values in the knots and knotvalues arrays - * `knots` (uniform floatarray): the list of knot values to interpolate in within. At least 2 and at most 16 values must be provided. - * `knotvalues` (uniform floatarray or colorNarray or vectorNarray): the values at each knot position to interpolate between. Must be the same length as knots. - * **`luminance`**: (color3 or color4 only) output a grayscale value containing the luminance of the incoming RGB color in all color channels, computed using the dot product of the incoming color with the luma coefficients of the working colorspace; the alpha channel is left unchanged if present. @@ -1808,12 +1687,6 @@ Conditional nodes are used to compare values of two streams, or to select a valu * `in1`, `in2`, `in3`, `in4`, `in5`, `in6`, `in7`, `in8`, `in9`, `in10` (float or colorN or vectorN or matrixNN): the values or nodenames to select from based on the value of the `which` input. The types of the various `in`N inputs must match the type of the `switch` node itself. The default value of all `in`N inputs is 0.0 in all channels. * `which` (integer or float): a selector to choose which input to take values from; the output comes from input "floor(`which`)+1", clamped to the 1-10 range. So `which`<1 will pass on the value from in1, 1<=`which`<2 will pass the value from in2, 2<=`which`<3 will pass the value from in3, and so on up to 9<=`which` will pass the value from in10. The default value of `which` is 0. - - -* **`ifelse`**: output the value of one of two input streams, according to whether the value of a boolean selector input is true or false - * `infalse`, `intrue` (float or colorN or vectorN): the values or nodenames to select from based on the value of the `which` input. The types of the various `inN` inputs must match the type of the `switch` node itself. The default value of all `inN` inputs is 0.0 in all channels. - * `which` (boolean): a selector to choose which input to take values from; default is "false". - ### Channel Nodes @@ -1827,12 +1700,6 @@ Channel nodes are used to perform channel manipulations and data type conversion * `in` (colorN or vectorN): the input value or nodename * `index` (integer): the channel number to extract. For colorN streams, use "0" to extract the red channel, "1" for green, "2" for blue and "3" for alpha; for vectorN streams, use "0" to extract the x channel, "1" for y, "2" for z and "3" for w. Default is 0. - - -* **`extractrowvector`**: extract the specified row vector number from a matrixN stream. - * `in` (matrixN): the input value or nodename - * `index` (integer): the row number to extract, should be 0-2 for matrix33 streams, or 0-3 for matrix44 streams. - * **`convert`**: convert a stream from one data type to another. Only certain unambiguous conversions are supported; see list below. @@ -1872,13 +1739,6 @@ Channel nodes are used to perform channel manipulations and data type conversion * `outb`/`outz` (**output**, float): the value of the blue (for color4 streams) or z (for vector4 streams) channel. * `outa`/`outw` (**output**, float): the value of the alpha (for color4 streams) or w (for vector4 streams) channel. - - -* **`separatecolor4`** (NG): output the RGB and alpha channels of a color4 as separate outputs. - * `in` (color4): the input value or nodename - * `outcolor` (output, color3): the RGB channel values. - * `outa` (output, float): the value of the alpha channel. - The following input/output data type conversions are supported by **`convert`**: @@ -2198,7 +2058,7 @@ Attributes for <nodedef> elements: * `name` (string, required): a unique name for this <nodedef> * `node` (string, required): the name of the custom node being defined * `inherit` (string, optional): the `name` of a <nodedef> to inherit node definitions from; the output types of this nodedef and the inherited one must match, and the input/output definitions of this nodedef will be applied on top of those in the inherited-from one. -* `nodegroup` (string, optional): an optional group to which this node declaration belongs. Standard MaterialX nodes have `nodegroup` values matching the titles of the section headings in which they are described, e.g. "texture2d", "procedural", "geometric", "global", "application", "math", "adjustment", "compositing", "conditional", "channel", "convolution", or "organization". +* `nodegroup` (string, optional): an optional group to which this node declaration belongs. Standard MaterialX nodes have `nodegroup` values matching the titles of the section headings in which they are described, e.g. "texture2d", "procedural", "geometric", "application", "math", "adjustment", "compositing", "conditional", "channel", "convolution", or "organization". * `version` (string, optional): a version string for this nodedef, allowing usage of a node to reference a specific version of a node. Version strings should be of the format "_major_[._minor_]", i.e. one or two integer numbers separated by a dot (the minor version is assumed to be "0" if not provided). If there are multiple nodedefs for the same `node` and `target` with the same combination of input and output types, they must each specify a `version`. * `isdefaultversion` (boolean, optional): If true, then this nodedef should be used for node instances which do not request a specific version. Specifying `isdefaultversion` "true" is only required if there are multiple nodedefs for a node declaring a `version`, and it is not permissible for multiple nodedefs for the same `node` and `target` with the same combination of input and output types to set `isdefaultversion` "true". Defaults to "false". * `target` (stringarray, optional): the set of targets to which this nodedef is restricted. By default, a nodedef is considered universal, not restricted to any specific targets, but it is possible that certain targets may have different parameter names or usage for the same node. @@ -2341,20 +2201,6 @@ For uniform inputs and tokens whose nodedef description includes an enum list of ``` -#### Implementation AOV Elements - -An <implementation> 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 - - ...... - - - -``` - #### Example Custom Nodes Defined by External File Implementations ```xml @@ -2612,69 +2458,6 @@ The Standard MaterialX Library defines the following nodes and node variants ope -### AOV Output Elements - -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 - -``` - -The attributes for <aovoutput> elements are: - -* name (string, required): a user-chosen name for this aov output definition element. -* type (string, required): the type of the AOV, which must be one of the supported types listed above. -* aovname (string, required): the name that the renderer should use for the AOV. -* nodename (string, required): the name of the node whose output defines the AOV value. -* sourceaov (string, optional): If nodename is a surfaceshader type, the name of the output AOV defined within nodename to pass along as the output AOV. The type of the sourceaov defined within nodename must match the <aovoutput> type. - -Examples: - -```xml - - - nodename="diffuse_bsdf"/> -``` - -#### AovOutput Example - -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 - - - - - - - - - - - - - - - - - - - - - -``` - -Layered shaders or materials must internally handle blending of AOV-like values from source layers before outputting them as AOVs: there is currently no facility for blending AOVs defined within post-shading blended surfaceshaders. - -Note: while it is syntactically possible to create <aovoutput>s for geometric primitive values such as shading surface point and normal accessed within a nodegraph, it is preferred that renderers derive such information directly from their internal shading state or geometric primvars. - - - ## Material Nodes 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: @@ -2749,26 +2532,6 @@ Creating materials with specific values bound to shader inputs involves instanti Alternatively, and perhaps more usefully, a complete network of multiple shader nodes of different types or for different targets along with a material node to collect them all can be packaged within a nodegraph, and the various inputs of the shader nodes and any other nodes connected to their inputs can be connected to a single material nodedef interface to provide parameter values for the entire multi-shader network. Because nodedef inputs can be referenced by more than one node, a single unified interface could be created for several shaders for different targets, and the networks for those targets could contain input value conversion nodes as needed to handle differences in parametrization or shading methodologies. -#### Material Inheritance - -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 - - - - - - - - - - - -``` - -Inheritance of material-type custom nodes is also allowed, so that new or changed input values can be applied on top of those specified in the inherited material. - #### Example Pre-Shader Compositing Material 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. diff --git a/documents/Specification/README.md b/documents/Specification/README.md index 82e0a81566..e8425c07bd 100644 --- a/documents/Specification/README.md +++ b/documents/Specification/README.md @@ -11,6 +11,7 @@ The documents in this folder comprise the complete MaterialX Specification, vers * [**MaterialX NPR Shading Nodes**](./MaterialX.NPRSpec.md) - specifies shading nodes that are designed for use in non-photorealistic and stylized rendering * [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) - additional MaterialX elements to define geometry-related information such as collections, properties and material assignments * [**MaterialX Supplemental Notes**](./MaterialX.Supplement.md) - describes recommended naming and structuring conventions for libraries of custom node definitions +* [**MaterialX: Proposed Additions and Changes**](./MaterialX.Proposals.md) - describes proposed future updates to various components of the Specification

From cfa6f7b68b228560def11906bd21398e62b7d6ce Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Tue, 6 Aug 2024 09:56:06 -0700 Subject: [PATCH 024/137] Hide PugiXML symbols via cmake (#1944) In response to #1941. Updating cmake to hide the PugiXML symbols. Creates separate static library for PugiXML and hide the symbols using cmake, so it should be portable. --- CMakeLists.txt | 14 +++++++++++--- source/CMakeLists.txt | 3 +++ source/MaterialXCore/Library.h | 10 ++++------ source/MaterialXFormat/CMakeLists.txt | 11 +++++++++-- .../External/PugiXML/CMakeLists.txt | 13 +++++++++++++ .../External/PugiXML/readme.txt | 8 ++++++++ source/MaterialXGenShader/Util.h | 4 ++-- source/MaterialXRenderGlsl/CMakeLists.txt | 16 ++++++++-------- source/MaterialXRenderHw/CMakeLists.txt | 12 ++++++------ source/MaterialXRenderMsl/CMakeLists.txt | 16 ++++++++-------- source/MaterialXRenderMsl/MetalState.h | 18 ++++++++++-------- source/MaterialXRenderMsl/MetalState.mm | 4 ++++ 12 files changed, 86 insertions(+), 43 deletions(-) create mode 100644 source/MaterialXFormat/External/PugiXML/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f5fc23fcc..54dff0df0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,7 +300,8 @@ function(mx_add_library MATERIALX_MODULE_NAME) SOURCE_FILES HEADER_FILES INLINED_FILES - LIBRARIES) + LIBRARIES + PRIVATE_LIBRARIES) cmake_parse_arguments(args "${options}" "${oneValueArgs}" @@ -328,11 +329,15 @@ function(mx_add_library MATERIALX_MODULE_NAME) target_sources(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) endif() - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC ${args_LIBRARIES} ${CMAKE_DL_LIBS}) + target_link_libraries(${TARGET_NAME} + PRIVATE + ${args_PRIVATE_LIBRARIES}) + target_include_directories(${TARGET_NAME} PUBLIC $ @@ -357,6 +362,9 @@ function(mx_add_library MATERIALX_MODULE_NAME) set_property(GLOBAL APPEND PROPERTY MATERIALX_MODULES ${MATERIALX_MODULE_NAME}) endif() + set_target_properties(${TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) + set_target_properties(${TARGET_NAME} PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1) + target_sources(${TARGET_NAME} PRIVATE ${args_SOURCE_FILES} diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d2dec4c632..0f52bdb4a9 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -5,6 +5,9 @@ if (MATERIALX_BUILD_MONOLITHIC) # such that the individual module would have been built if not in monolithic build mode add_library(${MATERIALX_MODULE_NAME} "" "" ) + set_target_properties(${MATERIALX_MODULE_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) + set_target_properties(${MATERIALX_MODULE_NAME} PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1) + # Create version resource if(MATERIALX_BUILD_SHARED_LIBS AND MSVC) configure_file(${CMAKE_SOURCE_DIR}/cmake/modules/MaterialXVersion.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc) diff --git a/source/MaterialXCore/Library.h b/source/MaterialXCore/Library.h index 4d69b2d0ae..1a92c634a7 100644 --- a/source/MaterialXCore/Library.h +++ b/source/MaterialXCore/Library.h @@ -32,12 +32,10 @@ #define MATERIALX_EXPORT_EXTERN_TEMPLATE(...) template class MATERIALX_SYMBOL_EXPORT __VA_ARGS__ #define MATERIALX_IMPORT_EXTERN_TEMPLATE(...) extern template class MATERIALX_SYMBOL_IMPORT __VA_ARGS__ #else - // Presently non-Windows platforms just export all symbols from - // shared libraries rather than using the explicit declarations. - #define MATERIALX_SYMBOL_EXPORT - #define MATERIALX_SYMBOL_IMPORT - #define MATERIALX_EXPORT_EXTERN_TEMPLATE(...) - #define MATERIALX_IMPORT_EXTERN_TEMPLATE(...) + #define MATERIALX_SYMBOL_EXPORT __attribute__((__visibility__("default"))) + #define MATERIALX_SYMBOL_IMPORT __attribute__((__visibility__("default"))) + #define MATERIALX_EXPORT_EXTERN_TEMPLATE(...) template class MATERIALX_SYMBOL_EXPORT __VA_ARGS__ + #define MATERIALX_IMPORT_EXTERN_TEMPLATE(...) extern template class MATERIALX_SYMBOL_IMPORT __VA_ARGS__ #endif #else #define MATERIALX_SYMBOL_EXPORT diff --git a/source/MaterialXFormat/CMakeLists.txt b/source/MaterialXFormat/CMakeLists.txt index b58ab0b166..2f65ab09b2 100644 --- a/source/MaterialXFormat/CMakeLists.txt +++ b/source/MaterialXFormat/CMakeLists.txt @@ -1,5 +1,7 @@ -file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") -file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") +add_subdirectory(External/PugiXML) + +file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") +file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") mx_add_library(MaterialXFormat SOURCE_FILES @@ -8,5 +10,10 @@ mx_add_library(MaterialXFormat ${materialx_headers} LIBRARIES MaterialXCore + PRIVATE_LIBRARIES + "$" EXPORT_DEFINE MATERIALX_FORMAT_EXPORTS) + +# we need to use BUILD_INTERFACE here to hide the use of pugixml from the cmake export when we're building +# MaterialX as a static library - feels like maybe a cmake bug? diff --git a/source/MaterialXFormat/External/PugiXML/CMakeLists.txt b/source/MaterialXFormat/External/PugiXML/CMakeLists.txt new file mode 100644 index 0000000000..7c0e14e8e9 --- /dev/null +++ b/source/MaterialXFormat/External/PugiXML/CMakeLists.txt @@ -0,0 +1,13 @@ +add_library(pugixml STATIC) +add_library(pugixml::pugixml ALIAS pugixml) + +target_sources(pugixml + PRIVATE + pugixml.cpp + PUBLIC + pugixml.hpp + pugiconfig.hpp +) + +set_target_properties(pugixml PROPERTIES CXX_VISIBILITY_PRESET hidden) +set_target_properties(pugixml PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1) diff --git a/source/MaterialXFormat/External/PugiXML/readme.txt b/source/MaterialXFormat/External/PugiXML/readme.txt index 5beb08a90a..522e7bf025 100644 --- a/source/MaterialXFormat/External/PugiXML/readme.txt +++ b/source/MaterialXFormat/External/PugiXML/readme.txt @@ -50,3 +50,11 @@ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +---------------------------------------------------------------- + +These files are taken from https://github.com/zeux/pugixml/tree/v1.9 + +The following MaterialX-specific modifications have been applied the original source: + * Adding tracking for new-line characters + * Adding support for serialization of `<` and `>` instead of `<` and `>` diff --git a/source/MaterialXGenShader/Util.h b/source/MaterialXGenShader/Util.h index bb0586a214..23a59e0437 100644 --- a/source/MaterialXGenShader/Util.h +++ b/source/MaterialXGenShader/Util.h @@ -90,8 +90,8 @@ MX_GENSHADER_API bool hasElementAttributes(OutputPtr output, const StringVec& at // These are deprecated wrappers for older versions of the function interfaces in this module. // Clients using these interfaces should update them to the latest API. // -MX_GENSHADER_API [[deprecated]] void findRenderableMaterialNodes(ConstDocumentPtr doc, vector& elements, bool, std::unordered_set&); -MX_GENSHADER_API [[deprecated]] void findRenderableElements(ConstDocumentPtr doc, vector& elements, bool includeReferencedGraphs = false); +[[deprecated]] MX_GENSHADER_API void findRenderableMaterialNodes(ConstDocumentPtr doc, vector& elements, bool, std::unordered_set&); +[[deprecated]] MX_GENSHADER_API void findRenderableElements(ConstDocumentPtr doc, vector& elements, bool includeReferencedGraphs = false); MATERIALX_NAMESPACE_END diff --git a/source/MaterialXRenderGlsl/CMakeLists.txt b/source/MaterialXRenderGlsl/CMakeLists.txt index 2f0cefde1f..eb4548ed43 100644 --- a/source/MaterialXRenderGlsl/CMakeLists.txt +++ b/source/MaterialXRenderGlsl/CMakeLists.txt @@ -53,25 +53,25 @@ endif() if(WIN32) if(MSVC) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC Opengl32) elseif(MINGW) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC Opengl32 gdi32) endif() elseif(APPLE) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework OpenGL" "-framework Foundation" "-framework Cocoa" "-framework Metal") elseif(UNIX) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC OpenGL::GL X11::X11 X11::Xt) diff --git a/source/MaterialXRenderHw/CMakeLists.txt b/source/MaterialXRenderHw/CMakeLists.txt index ac9b20e2bf..375ac7cead 100644 --- a/source/MaterialXRenderHw/CMakeLists.txt +++ b/source/MaterialXRenderHw/CMakeLists.txt @@ -27,19 +27,19 @@ mx_add_library(MaterialXRenderHw ADD_OBJECTIVE_C_CODE) if(APPLE) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework Foundation" "-framework Metal") if (NOT MATERIALX_BUILD_IOS) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework Cocoa" ) endif() elseif(UNIX) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC X11::X11 X11::Xt) endif() diff --git a/source/MaterialXRenderMsl/CMakeLists.txt b/source/MaterialXRenderMsl/CMakeLists.txt index 7807251ad9..81f4731bb9 100644 --- a/source/MaterialXRenderMsl/CMakeLists.txt +++ b/source/MaterialXRenderMsl/CMakeLists.txt @@ -46,23 +46,23 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() if(MSVC) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC Opengl32) elseif(APPLE) if(NOT MATERIALX_BUILD_IOS) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework Cocoa" "-framework OpenGL") endif() - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework Foundation" "-framework Metal") elseif(UNIX) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC OpenGL::GL X11::X11 X11::Xt) diff --git a/source/MaterialXRenderMsl/MetalState.h b/source/MaterialXRenderMsl/MetalState.h index 963603a341..b22470de69 100644 --- a/source/MaterialXRenderMsl/MetalState.h +++ b/source/MaterialXRenderMsl/MetalState.h @@ -14,14 +14,14 @@ #import #include +#include MATERIALX_NAMESPACE_BEGIN class MetalFramebuffer; // Shared pointer to a MetalFramebuffer using MetalFramebufferPtr = std::shared_ptr; -MATERIALX_NAMESPACE_END -struct MetalState +struct MX_RENDERMSL_API MetalState { static MetalState* getSingleton() { @@ -67,11 +67,13 @@ struct MetalState std::atomic inFlightCommandBuffers; }; -#define MTL(a) (MetalState::getSingleton()->a) -#define MTL_DEPTHSTENCIL_STATE(a) (MetalState::getSingleton()->a##DepthStencilState) -#define MTL_TRIGGER_CAPTURE MetalState::getSingleton()->triggerProgrammaticCapture() -#define MTL_STOP_CAPTURE MetalState::getSingleton()->stopProgrammaticCapture() -#define MTL_PUSH_FRAMEBUFFER(a) MetalState::getSingleton()->framebufferStack.push(a) -#define MTL_POP_FRAMEBUFFER(a) MetalState::getSingleton()->framebufferStack.pop() +MATERIALX_NAMESPACE_END + +#define MTL(a) (MaterialX::MetalState::getSingleton()->a) +#define MTL_DEPTHSTENCIL_STATE(a) (MaterialX::MetalState::getSingleton()->a##DepthStencilState) +#define MTL_TRIGGER_CAPTURE MaterialX::MetalState::getSingleton()->triggerProgrammaticCapture() +#define MTL_STOP_CAPTURE MaterialX::MetalState::getSingleton()->stopProgrammaticCapture() +#define MTL_PUSH_FRAMEBUFFER(a) MaterialX::MetalState::getSingleton()->framebufferStack.push(a) +#define MTL_POP_FRAMEBUFFER(a) MaterialX::MetalState::getSingleton()->framebufferStack.pop() #endif // MATERIALXVIEW_METALSTATE_H diff --git a/source/MaterialXRenderMsl/MetalState.mm b/source/MaterialXRenderMsl/MetalState.mm index 6396057726..01903dbd89 100644 --- a/source/MaterialXRenderMsl/MetalState.mm +++ b/source/MaterialXRenderMsl/MetalState.mm @@ -8,6 +8,8 @@ #include +MATERIALX_NAMESPACE_BEGIN + std::unique_ptr MetalState::singleton = nullptr; MetalState::MetalState() @@ -239,3 +241,5 @@ { return framebufferStack.top(); } + +MATERIALX_NAMESPACE_END From a20bef0534e87ce61671940c0e25e1c90318fdad Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Wed, 7 Aug 2024 09:00:00 -0700 Subject: [PATCH 025/137] Fix incorrectly transposed matrix for displayp3 colorspaces (#1960) When originally authored the matrix was authored transposed. Further internal testing revealed this to manifest as an undesired shift towards red. --- libraries/cmlib/cmlib_ng.mtlx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/cmlib/cmlib_ng.mtlx b/libraries/cmlib/cmlib_ng.mtlx index f6f844f48e..4ac94c2f7a 100644 --- a/libraries/cmlib/cmlib_ng.mtlx +++ b/libraries/cmlib/cmlib_ng.mtlx @@ -315,7 +315,8 @@ - + @@ -354,7 +355,8 @@ - + From 65dc595340e1595f8ea7d4eaa4bea7d7066299dd Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 7 Aug 2024 09:00:25 -0700 Subject: [PATCH 026/137] Assign PugiXML to External source folder (#1961) This changelist assigns the PugiXML project to the External source folder, improving clarity in Visual Studio builds. --- source/MaterialXFormat/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/source/MaterialXFormat/CMakeLists.txt b/source/MaterialXFormat/CMakeLists.txt index 2f65ab09b2..d75bbc537c 100644 --- a/source/MaterialXFormat/CMakeLists.txt +++ b/source/MaterialXFormat/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(External/PugiXML) +set_property(TARGET pugixml PROPERTY FOLDER "External") file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") From 67702daa934d6bb397ec6e540b7dd41bc5c12650 Mon Sep 17 00:00:00 2001 From: Malia Kuo Date: Wed, 7 Aug 2024 13:05:31 -0700 Subject: [PATCH 027/137] Additional improvements to MaterialX Lama nodes (#1955) - Updated LamaGeneralizedSchlick implementation (changed the transmission component from a dielectric BSDF to a generalized schlick BSDF, adjusted implementation of reflectionTint) - Updated LamaSSS and LamaTranslucent (removed LobeName and matte inputs as they are renderer-specific) - Updated default values and help documentation of MaterialX Lama nodes to be consistent with Renderman Lama nodes. --- libraries/bxdf/lama/lama_conductor.mtlx | 18 ++- libraries/bxdf/lama/lama_dielectric.mtlx | 24 ++-- libraries/bxdf/lama/lama_emission.mtlx | 2 +- .../bxdf/lama/lama_generalized_schlick.mtlx | 116 ++++++++---------- libraries/bxdf/lama/lama_iridescence.mtlx | 34 ++++- libraries/bxdf/lama/lama_sheen.mtlx | 2 +- libraries/bxdf/lama/lama_sss.mtlx | 26 ++-- libraries/bxdf/lama/lama_surface.mtlx | 6 +- libraries/bxdf/lama/lama_translucent.mtlx | 4 - .../surfaceshader/lama/lama_conductor.mtlx | 2 +- .../surfaceshader/lama/lama_emission.mtlx | 2 +- .../surfaceshader/lama/lama_iridescence.mtlx | 1 + .../surfaceshader/lama/lama_translucent.mtlx | 2 - 13 files changed, 115 insertions(+), 124 deletions(-) diff --git a/libraries/bxdf/lama/lama_conductor.mtlx b/libraries/bxdf/lama/lama_conductor.mtlx index 07a7b7fcd6..4b6b80f64a 100644 --- a/libraries/bxdf/lama/lama_conductor.mtlx +++ b/libraries/bxdf/lama/lama_conductor.mtlx @@ -3,15 +3,15 @@ - + - @@ -21,7 +21,7 @@ doc="Defines the amount of anisotropy, changing the co-tangent axis roughness from the original value to 1 (or to 0 with a negative value)." /> - @@ -40,13 +40,13 @@ - - + + - - + + @@ -110,8 +110,6 @@ - - diff --git a/libraries/bxdf/lama/lama_dielectric.mtlx b/libraries/bxdf/lama/lama_dielectric.mtlx index 5e98670dd7..eb5509033c 100644 --- a/libraries/bxdf/lama/lama_dielectric.mtlx +++ b/libraries/bxdf/lama/lama_dielectric.mtlx @@ -5,12 +5,12 @@ doc="Color multiplier for external reflection. It should be used with parcimony, as a non-white value breaks physicality." /> - + - + - - + doc="Interior volume absorption color. It is defined as the negative logarithm of the extinction coefficient, with values between 0 and 1, such that the object itself and its shadows are tinted proportionnally. If set to 1, there is no absorption, and if set to 0, the object will be completely opaque. Note that for single scattering to kick in, the value must be inferior to 1. This value will also act as coating color, when this node is used as the top material in a layer node." /> + + doc="Color (aka scattering albedo) of the medium, defines what proportion of the light hitting volumetric particles is scattered around by the phase function (as opposed to just absorbed), for each color channel. Only takes effect if the corresponding channel has a non-null density, in other words if the Absorption Color value for that channel is inferior to 1." /> + doc="Anisotropy of the medium's phase function, ranging from full backward scattering at -1 to forward scattering at 1. Only takes effect if the Scatter Color is non-null." /> @@ -47,8 +47,8 @@ - - + + diff --git a/libraries/bxdf/lama/lama_emission.mtlx b/libraries/bxdf/lama/lama_emission.mtlx index 87da14bd91..3f731442c1 100644 --- a/libraries/bxdf/lama/lama_emission.mtlx +++ b/libraries/bxdf/lama/lama_emission.mtlx @@ -1,7 +1,7 @@ - diff --git a/libraries/bxdf/lama/lama_generalized_schlick.mtlx b/libraries/bxdf/lama/lama_generalized_schlick.mtlx index c8c5f40f5b..fd7c2ade5d 100644 --- a/libraries/bxdf/lama/lama_generalized_schlick.mtlx +++ b/libraries/bxdf/lama/lama_generalized_schlick.mtlx @@ -4,47 +4,41 @@ - + doc="Color multiplier for rays going inside the medium (covers external transmission and internal reflection). It should be used sparingly, as a non-white value breaks physicality. The prefered way to define the color of a dielectric is through the Interior attributes right below." /> + + doc="Index of refraction (often denoted by eta), defining the amount reflected by the surface in the normal direction, and how the rays are bent by refraction. A separate value can be specified for each color channel, if desired." /> - - - + - - + doc="Interior volume absorption color. It is defined as the negative logarithm of the extinction coefficient, with values between 0 and 1, such that the object itself and its shadows are tinted proportionally. If set to 1, there is no absorption, and if set to 0, the object will be completely opaque. Note that for single scattering to kick in, the value must be inferior to 1. This value will also act as coating color, when this node is used as top layer in a stack." /> + + doc="Color (aka scattering albedo) of the medium, defines what proportion of the light hitting volumetric particles is scattered around by the phase function (as opposed to just absorbed), for each color channel. Only takes effect if the corresponding channel has a non-null density, in other words if the Absorption Color value for that channel is inferior to 1." /> + doc="Anisotropy of the medium's phase function, ranging from full backward scattering at -1 to forward scattering at 1. Only takes effect if the Scatter Color is non-null." /> - - - - - - - + @@ -64,25 +58,19 @@ - - - - - + - - - - - + - - - - - - + + + + + + + + @@ -91,30 +79,15 @@ - - - - - - - + - - - + - - - - - - - - - + + - + @@ -156,27 +129,32 @@ - - + + - - + + + - - + + + + + + - + - - + + @@ -184,10 +162,14 @@ + + + + - + diff --git a/libraries/bxdf/lama/lama_iridescence.mtlx b/libraries/bxdf/lama/lama_iridescence.mtlx index 914f70ae1b..aaf3617965 100644 --- a/libraries/bxdf/lama/lama_iridescence.mtlx +++ b/libraries/bxdf/lama/lama_iridescence.mtlx @@ -5,13 +5,17 @@ doc="Micro-facet distribution roughness." /> - + + - - - @@ -53,6 +57,27 @@ + + + + + + + + + + + + + + + + /> + + + + + @@ -66,6 +91,7 @@ + diff --git a/libraries/bxdf/lama/lama_sheen.mtlx b/libraries/bxdf/lama/lama_sheen.mtlx index 76c7b9597d..8accb41837 100644 --- a/libraries/bxdf/lama/lama_sheen.mtlx +++ b/libraries/bxdf/lama/lama_sheen.mtlx @@ -4,7 +4,7 @@ + doc="Roughness of the sheen effect. Very rough sheen can be used to create a rough diffuse look (when combined with a diffuse node by a layer or mix)." /> diff --git a/libraries/bxdf/lama/lama_sss.mtlx b/libraries/bxdf/lama/lama_sss.mtlx index ded26871ff..f09d2da51d 100644 --- a/libraries/bxdf/lama/lama_sss.mtlx +++ b/libraries/bxdf/lama/lama_sss.mtlx @@ -6,39 +6,29 @@ - + doc="Diffuse Mean Free Path, expressed for each color channel in mm. Indicates on average how much the light travels under the surface before being scattered. The higher the value, the softer the result will be. If zero (black), which is the default value, the computation simplifies to a Lambertian reflection lobe with no subsurface scattering." /> + - + - + doc="Controls how strongly normals are considered in the subsurface computation. For path-traced sss (sssMode 0 and 1), the followTopology parameter reduces sss paths being blocked by backsides behind a surface, but also reduces sss from one side to another in convex regions such as ridges and ears. For diffusion sss (sssMode 2 and 3), the followTopology parameter reduces sss from one side to another in concave regions such as crevasses and wrinkles." /> + doc="This is the multiplier that converts between millimeters and scene units. Both mean free path and diffuse mean free path are specified in millimeters and this parameter is used for the unit conversion. The default value of 0.00328 converts millimeters to feet. For centimeter scene units, this would be 0.1, for meters it would be 0.001 etc." /> - - - - - diff --git a/libraries/bxdf/lama/lama_surface.mtlx b/libraries/bxdf/lama/lama_surface.mtlx index 4ffa9a63df..b7e84a510c 100644 --- a/libraries/bxdf/lama/lama_surface.mtlx +++ b/libraries/bxdf/lama/lama_surface.mtlx @@ -2,11 +2,11 @@ + doc="Material used on the front side (as defined by the geometric normal)." /> + doc="Material used on the back side (as defined by the geometric normal)." /> + doc="Connect a mask here to apply a cutout pattern to your object. This is useful for cutouts like creating leaves and other thin, complex shapes. It can also be used as opacity for gray values for semi-opaque results when seen directly by the camera." /> diff --git a/libraries/bxdf/lama/lama_translucent.mtlx b/libraries/bxdf/lama/lama_translucent.mtlx index 9577e9c14f..ec3e968e09 100644 --- a/libraries/bxdf/lama/lama_translucent.mtlx +++ b/libraries/bxdf/lama/lama_translucent.mtlx @@ -9,10 +9,6 @@ doc="Shading normal, typically defined by bump or normal mapping. Defaults to the smooth surface normal if not set." /> - - diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx index ee0852899f..87cc8211e7 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx @@ -8,7 +8,7 @@ - + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx index cae5722d1f..f21d752d20 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx @@ -3,7 +3,7 @@ - + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx index a6bc228773..1125e34aa7 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx @@ -5,6 +5,7 @@ + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx index a5d9b80bc3..3b7fa03988 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx @@ -6,8 +6,6 @@ - - From 67d2e2836fb3d7aee4ddd3cea273a9f85f82725a Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 8 Aug 2024 13:46:56 -0700 Subject: [PATCH 028/137] Fix Fresnel computation in GLSL transmission (#1962) This changelist fixes an error in the Fresnel computation for GLSL transmission, improving the visual parity of transmissive materials across shading languages. With this fix in place, the graph definition of LamaGeneralizedSchlick no longer requires a manual inversion of its F0 and F90 inputs for transmission, as this inversion is handled correctly in GLSL as well as OSL and MDL. --- .../bxdf/lama/lama_generalized_schlick.mtlx | 12 +---- .../genglsl/lib/mx_environment_fis.glsl | 4 +- .../genglsl/mx_generalized_schlick_bsdf.glsl | 2 +- .../pbrlib/bsdf/generalized_schlick.mtlx | 54 +++++++------------ 4 files changed, 24 insertions(+), 48 deletions(-) diff --git a/libraries/bxdf/lama/lama_generalized_schlick.mtlx b/libraries/bxdf/lama/lama_generalized_schlick.mtlx index fd7c2ade5d..887273de45 100644 --- a/libraries/bxdf/lama/lama_generalized_schlick.mtlx +++ b/libraries/bxdf/lama/lama_generalized_schlick.mtlx @@ -63,14 +63,6 @@ - - - - - - - - @@ -132,8 +124,8 @@ - - + + diff --git a/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl b/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl index 0b28f3645f..1d61576650 100644 --- a/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl @@ -43,8 +43,8 @@ vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distributio // Compute the geometric term. float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); - // Compute the combined FG term, which is inverted for refraction. - vec3 FG = fd.refraction ? vec3(1.0) - (F * G) : F * G; + // Compute the combined FG term, which simplifies to inverted Fresnel for refraction. + vec3 FG = fd.refraction ? vec3(1.0) - F : F * G; // Add the radiance contribution of this sample. // From https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf diff --git a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl index 764412b90d..f4598dd0d0 100644 --- a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl @@ -66,7 +66,7 @@ void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, { float avgF0 = dot(safeColor0, vec3(1.0 / 3.0)); fd.ior = vec3(mx_f0_to_ior(avgF0)); - bsdf.response = mx_surface_transmission(N, V, X, safeAlpha, distribution, fd, safeColor0) * weight; + bsdf.response = mx_surface_transmission(N, V, X, safeAlpha, distribution, fd, vec3(1.0)) * weight; } } diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx index 05eb071558..bc31308a47 100644 --- a/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx +++ b/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx @@ -2,11 +2,8 @@ - - - - - + + @@ -15,11 +12,8 @@ - - - - - + + @@ -28,11 +22,8 @@ - - - - - + + @@ -50,11 +41,9 @@ - - - - - + + + @@ -63,11 +52,9 @@ - - - - - + + + @@ -76,11 +63,9 @@ - - - - - + + + @@ -98,11 +83,10 @@ - - - - - + + + + From 3ec6e873d1ba0a65d07ae065f235685225242752 Mon Sep 17 00:00:00 2001 From: Krzysztof Jakubowski Date: Fri, 9 Aug 2024 01:55:59 +0200 Subject: [PATCH 029/137] Fix swizzle edge cases in version upgrade (#1957) This PR fixes 2 edge cases when upgrading materials from version 1.38 to 1.39 involving swizzle nodes: - swizzle xyz -> xyz, rgb -> rgb wasn't handled properly, because convert nodedefs were missing for such cases - swizzle xy -> xxx is incorrectly changed to convert node --- source/MaterialXCore/Version.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/source/MaterialXCore/Version.cpp b/source/MaterialXCore/Version.cpp index 668c233bb7..34d9b3b02c 100644 --- a/source/MaterialXCore/Version.cpp +++ b/source/MaterialXCore/Version.cpp @@ -992,16 +992,19 @@ void Document::upgradeVersion() { "color3", 3 }, { "color4", 4 }, { "vector2", 2 }, { "vector3", 3 }, { "vector4", 4 } }; - const StringSet CHANNEL_CONVERT_PATTERNS = - { - "rgb", "rgba", "xyz", "xyzw", "rrr", "xxx" - }; - const vector> CHANNEL_ATTRIBUTE_PATTERNS = - { + const std::array, 10> CHANNEL_CONVERT_PATTERNS = + { { + { "rgb", 3 }, { "rgb", 4 }, { "rgba", 4 }, + { "xyz", 3 }, { "xyz", 4 }, { "xyzw", 4 }, + { "rr", 1 }, { "rrr", 1 }, + { "xx", 1 }, { "xxx", 1 } + } }; + const std::array, 3> CHANNEL_ATTRIBUTE_PATTERNS = + { { { { "xx", "xxx", "xxxx" }, "float" }, { { "xyz", "x", "y", "z" }, "vector3" }, { { "rgba", "a" }, "color4" } - }; + } }; // Convert channels attributes to legacy swizzle nodes, which are then converted // to modern nodes in a second pass. @@ -1169,8 +1172,10 @@ void Document::upgradeVersion() CHANNEL_COUNT_MAP.count(node->getType())) { string channelString = channelsInput ? channelsInput->getValueString() : EMPTY_STRING; - size_t sourceChannelCount = CHANNEL_COUNT_MAP.at(inInput->getType()); - size_t destChannelCount = CHANNEL_COUNT_MAP.at(node->getType()); + string sourceType = inInput->getType(); + string destType = node->getType(); + size_t sourceChannelCount = CHANNEL_COUNT_MAP.at(sourceType); + size_t destChannelCount = CHANNEL_COUNT_MAP.at(destType); // Resolve the invalid case of having both a connection and a value // by removing the value attribute. @@ -1228,7 +1233,8 @@ void Document::upgradeVersion() node->setInputValue("index", (int) CHANNEL_INDEX_MAP.at(channelString[0])); } } - else if (CHANNEL_CONVERT_PATTERNS.count(channelString)) + else if (sourceType != destType && std::find(CHANNEL_CONVERT_PATTERNS.begin(), CHANNEL_CONVERT_PATTERNS.end(), + std::make_pair(channelString, sourceChannelCount)) != CHANNEL_CONVERT_PATTERNS.end()) { // Replace swizzle with convert. node->setCategory("convert"); From 2884d74bb5d1707b19740b1c6d14f6b175a43042 Mon Sep 17 00:00:00 2001 From: Malia Kuo Date: Fri, 9 Aug 2024 13:51:26 -0700 Subject: [PATCH 030/137] Update documentation of OpenPBR and Standard Surface translations (#1963) Clarified documentation where the motivation for the conversion might not be clear - both for the translation graph from OpenPBR to Standard Surface, and the translation graph from Standard Surface to OpenPBR. --- libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx | 4 +++- libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx b/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx index 57b3f99d23..ec7bb19a98 100644 --- a/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx +++ b/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx @@ -198,6 +198,7 @@ + @@ -206,7 +207,7 @@ - + @@ -256,6 +257,7 @@ + diff --git a/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx b/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx index b454af4384..535f65b700 100644 --- a/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx @@ -116,6 +116,7 @@ + @@ -129,7 +130,7 @@ - + @@ -190,12 +191,14 @@ + + From 588337873278d142cdbc12aa8df967d66dde465d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 9 Aug 2024 15:29:37 -0700 Subject: [PATCH 031/137] Update changelog for recent work (#1964) --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40a8f23983..025a3b3627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ ## [1.39.1] - Development +### Added +- Added initial shader translation graphs between [Standard Surface](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1934) and [OpenPBR Surface](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1949). +- Added initial support for [code generation hints](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1954). + +### Changed +- Raised the minimum CMake version to [CMake 3.24](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1929). +- Moved feature proposals from the main specification to a new [MaterialX Proposals](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1953) document. +- Updated the open definitions of the [MaterialX Lama nodes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1955) to improve alignment with RenderMan. + +### Fixed +- Fixed errors in the [installation steps](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1923) for CMake builds. +- Fixed the computation of [Fresnel transmission](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1962) in GLSL. +- Fixed transposed matrices in color transforms for the [displayp3 space](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1960). +- Fixed edge cases in the version upgrade process for [swizzle](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1945) [nodes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1957). +- Fixed a crash in the Graph Editor when [renaming a node graph](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1930). +- Fixed the exporting of [PugiXML symbols](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1944) in MaterialXFormat. + +### Removed +- Removed an extra installation of the [resources folder](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1927) in MaterialXGenShader. + ## [1.39.0] - 2024-07-05 ### Added From fb225ae6cefe4c1662b21767ae14634a3fe7a691 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 10 Aug 2024 15:28:54 -0700 Subject: [PATCH 032/137] Update specification example (#1965) This changelist updates a specification example for clarity, reflecting the recent move of the `updirection` node to the MaterialX Proposals document. --- documents/Specification/MaterialX.Specification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 0232074701..60e62d9ce2 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -1124,7 +1124,7 @@ Application nodes are used to reference application-defined properties within a ```xml - +

" + args.lang1 + " (in: " + dir1 + ") vs "+ args.lang2 + " (in: " + dir2 + ") vs "+ args.lang3 + " (in: " + dir3 + ")

\n") + fh.write("

" + args.lang1 + " (in: " + args.inputdir1 + ") vs "+ args.lang2 + " (in: " + args.inputdir2 + ") vs "+ args.lang3 + " (in: " + args.inputdir3 + ")

\n") else: - fh.write("

" + args.lang1 + " (in: " + dir1 + ") vs "+ args.lang2 + " (in: " + dir2 + ")

\n") + fh.write("

" + args.lang1 + " (in: " + args.inputdir1 + ") vs "+ args.lang2 + " (in: " + args.inputdir2 + ")

\n") if not DIFF_ENABLED and args.CREATE_DIFF: print("--diff argument ignored. Diff utility not installed.") - if not args.inputdir2: - args.inputdir2 = args.inputdir1 - if useThirdLang and not args.inputdir3: - args.inputdir3 = args.inputdir1 + # Remove potential trailing path separators + if args.inputdir1[-1:] == '/' or args.inputdir1[-1:] == '\\': + args.inputdir1 = args.inputdir1[:-1] + if args.inputdir2[-1:] == '/' or args.inputdir2[-1:] == '\\': + args.inputdir2 = args.inputdir2[:-1] + if args.inputdir3[-1:] == '/' or args.inputdir3[-1:] == '\\': + args.inputdir3 = args.inputdir3[:-1] # Get all source files langFiles1 = [] @@ -93,21 +106,22 @@ def main(args=None): for curFile in files: if curFile.endswith(args.lang1 + ".png"): langFiles1.append(curFile) - langPaths1.append(subdir) + langPaths1.append(subdir) # Get all destination files, matching source files langFiles2 = [] langPaths2 = [] langFiles3 = [] langPaths3 = [] - postFix = args.lang1 + ".png" + preFixLen: int = len(args.inputdir1) + 1 # including the path separator + postFix: str = args.lang1 + ".png" for file1, path1 in zip(langFiles1, langPaths1): # Allow for just one language to be shown if source and dest are the same. # Otherwise add in equivalent name with dest language replacement if # pointing to the same directory if args.inputdir1 != args.inputdir2 or args.lang1 != args.lang2: file2 = file1[:-len(postFix)] + args.lang2 + ".png" - path2 = os.path.join(args.inputdir2, path1) + path2 = os.path.join(args.inputdir2, path1[len(args.inputdir1)+1:]) else: file2 = "" path2 = None @@ -116,7 +130,7 @@ def main(args=None): if useThirdLang: file3 = file1[:-len(postFix)] + args.lang3 + ".png" - path3 = os.path.join(args.inputdir2, path1) + path3 = os.path.join(args.inputdir2, path1[len(args.inputdir1)+1:]) else: file3 = "" path3 = None @@ -142,33 +156,34 @@ def main(args=None): curPath = path1 if file1 and file2 and DIFF_ENABLED and args.CREATE_DIFF: - diffPath1 = fullPath1[0:-8] + "_" + args.lang1 + "_vs_" + args.lang2 + "_diff.png" + diffPath1 = fullPath1[0:-8] + "_" + args.lang1 + "-1_vs_" + args.lang2 + "-2_diff.png" createDiff(fullPath1, fullPath2, diffPath1) if useThirdLang and file1 and file3 and DIFF_ENABLED and args.CREATE_DIFF: - diffPath2 = fullPath1[0:-8] + "_" + args.lang1 + "_vs_" + args.lang3 + "_diff.png" + diffPath2 = fullPath1[0:-8] + "_" + args.lang1 + "-1_vs_" + args.lang3 + "-3_diff.png" createDiff(fullPath1, fullPath3, diffPath2) - diffPath3 = fullPath1[0:-8] + "_" + args.lang2 + "_vs_" + args.lang3 + "_diff.png" + diffPath3 = fullPath1[0:-8] + "_" + args.lang2 + "-2_vs_" + args.lang3 + "-3_diff.png" createDiff(fullPath2, fullPath3, diffPath3) - if os.path.isabs(args.outputfile): - fileUri = 'file:///' - else: - fileUri ='' + def prependFileUri(filepath: str) -> str: + if os.path.isabs(filepath): + return 'file:///' + filepath + else: + return filepath fh.write("\n") if fullPath1: - fh.write("\n") + fh.write("\n") if fullPath2: - fh.write("\n") + fh.write("\n") if fullPath3: - fh.write("\n") + fh.write("\n") if diffPath1: - fh.write("\n") + fh.write("\n") if diffPath2: - fh.write("\n") + fh.write("\n") if diffPath3: - fh.write("\n") + fh.write("\n") fh.write("\n") fh.write("\n") From 51c19aec6fee900d5011c8227a646b8e56ca7e86 Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Wed, 28 Aug 2024 14:03:28 -0700 Subject: [PATCH 043/137] compile pugixml source directly in to MaterialXFormat (#1992) --- source/MaterialXFormat/CMakeLists.txt | 10 ++----- .../External/PugiXML/CMakeLists.txt | 29 ++++++++++--------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/source/MaterialXFormat/CMakeLists.txt b/source/MaterialXFormat/CMakeLists.txt index 767c08068f..65fb91fb63 100644 --- a/source/MaterialXFormat/CMakeLists.txt +++ b/source/MaterialXFormat/CMakeLists.txt @@ -1,5 +1,4 @@ add_subdirectory(External/PugiXML) -set_property(TARGET pugixml PROPERTY FOLDER "External") file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") @@ -7,16 +6,11 @@ file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") mx_add_library(MaterialXFormat SOURCE_FILES ${materialx_source} + ${pugixml_source} HEADER_FILES ${materialx_headers} + ${pugixml_headers} MTLX_MODULES MaterialXCore EXPORT_DEFINE MATERIALX_FORMAT_EXPORTS) - -# we need to use BUILD_INTERFACE here to hide the use of pugixml from the cmake export when we're building -# MaterialX as a static library - feels like maybe a cmake bug? - -target_link_libraries(${TARGET_NAME} - PRIVATE - "$") \ No newline at end of file diff --git a/source/MaterialXFormat/External/PugiXML/CMakeLists.txt b/source/MaterialXFormat/External/PugiXML/CMakeLists.txt index 7c0e14e8e9..154a4e7a1c 100644 --- a/source/MaterialXFormat/External/PugiXML/CMakeLists.txt +++ b/source/MaterialXFormat/External/PugiXML/CMakeLists.txt @@ -1,13 +1,16 @@ -add_library(pugixml STATIC) -add_library(pugixml::pugixml ALIAS pugixml) - -target_sources(pugixml - PRIVATE - pugixml.cpp - PUBLIC - pugixml.hpp - pugiconfig.hpp -) - -set_target_properties(pugixml PROPERTIES CXX_VISIBILITY_PRESET hidden) -set_target_properties(pugixml PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1) +# Don't actually build a library for PugiXML as if we are building MaterialX as a static library +# then we would also need to ship the PugiXML library, instead we just compile the sources +# directly into MaterialXFormat, but take care to hide the symbols. + +file(GLOB pugixml_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") +file(GLOB pugixml_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h") + +set_source_files_properties(${pugixml_source} PROPERTIES CXX_VISIBILITY_PRESET hidden) +set_source_files_properties(${pugixml_source} PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1) + +set_source_files_properties(${pugixml_source} PROPERTIES FOLDER External) +set_source_files_properties(${pugixml_headers} PROPERTIES FOLDER External) + +set(pugixml_source ${pugixml_source} PARENT_SCOPE) +set(pugixml_headers ${pugixml_headers} PARENT_SCOPE) + From 1947299282643bea1829cddd7e601fa96f3ca498 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 28 Aug 2024 17:34:51 -0700 Subject: [PATCH 044/137] Update presentation link (#1993) This changelist updates a presentation link on the front page, bringing it up to date with the latest slide deck for ASWF Open Source Days 2024. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 74bb3173f5..41e7d5aeca 100644 --- a/README.md +++ b/README.md @@ -69,4 +69,4 @@ The following packages contain pre-built binaries for the latest release, includ - The [Developer Guide](http://www.materialx.org/docs/api/index.html) contains a developer-oriented overview of MaterialX with API documentation. - The [Python Scripts](python/Scripts) folder contains standalone examples of MaterialX Python code. - The [JavaScript](javascript) folder contains details on building JavaScript bindings for MaterialX. -- Presentations at [ASWF Open Source Days](https://materialx.org/assets/ASWF_OSD2023_MaterialX_Final.pdf) and the [SIGGRAPH Physically Based Shading Course](https://blog.selfshadow.com/publications/s2020-shading-course/#materialx) provide details on the roadmap for MaterialX development. +- Presentations at [ASWF Open Source Days](https://materialx.org/assets/ASWF_OSD2024_MaterialX_Final.pdf) and the [SIGGRAPH Physically Based Shading Course](https://blog.selfshadow.com/publications/s2020-shading-course/#materialx) provide details on the roadmap for MaterialX development. From de64c319eaf07e2afcae0be3dc5165d78569f008 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 29 Aug 2024 09:23:08 -0700 Subject: [PATCH 045/137] Assign glfw_minimal to External source folder (#1994) This changelist assigns the glfw_minimal project in MaterialXGraphEditor to the External source folder, improving clarity in Visual Studio builds. --- source/MaterialXGraphEditor/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/source/MaterialXGraphEditor/CMakeLists.txt b/source/MaterialXGraphEditor/CMakeLists.txt index bd2405d432..00acfc6902 100644 --- a/source/MaterialXGraphEditor/CMakeLists.txt +++ b/source/MaterialXGraphEditor/CMakeLists.txt @@ -61,6 +61,7 @@ set(GLFW_INSTALL OFF) set(BUILD_SHARED_LIBS OFF) add_subdirectory(External/Glfw) +set_property(TARGET glfw_minimal PROPERTY FOLDER "External") if(MSVC) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:mainCRTStartup") From 18c06ea9077d26fc707d58a6637712b2508b9d4c Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 1 Sep 2024 21:01:50 -0700 Subject: [PATCH 046/137] Update sheen paper link (#1997) This changelist updates a link to the 2017 Conty-Kulla paper in the GLSL implementation of sheen. --- libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl index fe4eee34e9..a5c3ade7a8 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl @@ -1,6 +1,6 @@ #include "mx_microfacet.glsl" -// http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf +// https://fpsunflower.github.io/ckulla/data/s2017_pbs_imageworks_sheen.pdf // Equation 2 float mx_imageworks_sheen_NDF(float NdotH, float roughness) { From 1117ab991d103735ae7186fd8b107dd4a4b35b73 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 3 Sep 2024 12:01:31 -0700 Subject: [PATCH 047/137] Finalize changelog for 1.39.1 (#2001) --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bc94b3132..4f628d4e34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## [1.39.1] - Release Candidate +## [1.39.1] - 2024-09-03 ### Added - Added initial shader translation graphs between [Standard Surface](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1934) and [OpenPBR Surface](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1949). @@ -14,6 +14,7 @@ ### Fixed - Fixed errors in the [installation steps](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1923) for CMake builds. - Fixed the computation of [Fresnel transmission](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1962) in GLSL. +- Fixed an implementation of the [combine2 node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1975) in MDL. - Fixed transposed matrices in color transforms for the [displayp3 space](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1960). - Fixed edge cases in the version upgrade process for [swizzle](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1945) [nodes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1957). - Fixed a crash in the Graph Editor when [renaming a node graph](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1930). From 9ad29d5cf6cab6798e685f37faca494a5ed511d8 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 3 Sep 2024 20:56:37 -0700 Subject: [PATCH 048/137] Update development build to 1.39.2 (#2002) --- CHANGELOG.md | 2 ++ CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f628d4e34..3fedc1ceaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Change Log +## [1.39.2] - Development + ## [1.39.1] - 2024-09-03 ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index 98843adfed..f0d21e6f0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # MaterialX Version set(MATERIALX_MAJOR_VERSION 1) set(MATERIALX_MINOR_VERSION 39) -set(MATERIALX_BUILD_VERSION 1) +set(MATERIALX_BUILD_VERSION 2) set(MATERIALX_LIBRARY_VERSION ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}) # Cmake setup From 29dc40aaa5e3741918c54a9050db07d130171660 Mon Sep 17 00:00:00 2001 From: shill-lucasfilm <40578207+shill-lucasfilm@users.noreply.github.com> Date: Tue, 3 Sep 2024 21:25:40 -0700 Subject: [PATCH 049/137] Fix banding artifacts in macOS viewer (#1977) This addresses subtle banding on macOS with 10 bit / EDR displays. I'm not a Metal expert and I suspect that the conversion code I added for screenshot saving could be improved (see commit comment), or ideally avoided (by saving to an HDR format such as EXR), but it gets the job done. --- source/MaterialXRenderMsl/CMakeLists.txt | 3 +- source/MaterialXRenderMsl/MetalFramebuffer.mm | 2 +- source/MaterialXRenderMsl/MetalState.h | 2 +- source/MaterialXRenderMsl/MetalState.mm | 6 ++-- source/MaterialXView/RenderPipelineMetal.mm | 30 ++++++++++++++----- source/MaterialXView/Viewer.cpp | 7 ++++- 6 files changed, 36 insertions(+), 14 deletions(-) diff --git a/source/MaterialXRenderMsl/CMakeLists.txt b/source/MaterialXRenderMsl/CMakeLists.txt index 296c454e2b..014c99eaae 100644 --- a/source/MaterialXRenderMsl/CMakeLists.txt +++ b/source/MaterialXRenderMsl/CMakeLists.txt @@ -59,7 +59,8 @@ elseif(APPLE) target_link_libraries(${TARGET_NAME} PUBLIC "-framework Foundation" - "-framework Metal") + "-framework Metal" + "-framework MetalPerformanceShaders") elseif(UNIX) target_link_libraries(${TARGET_NAME} PUBLIC diff --git a/source/MaterialXRenderMsl/MetalFramebuffer.mm b/source/MaterialXRenderMsl/MetalFramebuffer.mm index 17ee9de9a1..7309da6bfe 100644 --- a/source/MaterialXRenderMsl/MetalFramebuffer.mm +++ b/source/MaterialXRenderMsl/MetalFramebuffer.mm @@ -81,7 +81,7 @@ height:height mipmapped:NO]; [texDescriptor setStorageMode:MTLStorageModePrivate]; - [texDescriptor setUsage:MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead]; + [texDescriptor setUsage:MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite]; if (extColorTexture == nil) { diff --git a/source/MaterialXRenderMsl/MetalState.h b/source/MaterialXRenderMsl/MetalState.h index b22470de69..ff742b857c 100644 --- a/source/MaterialXRenderMsl/MetalState.h +++ b/source/MaterialXRenderMsl/MetalState.h @@ -43,7 +43,7 @@ struct MX_RENDERMSL_API MetalState void endEncoder(); void endCommandBuffer(); - void waitForComplition(); + void waitForCompletion(); MaterialX::MetalFramebufferPtr currentFramebuffer(); diff --git a/source/MaterialXRenderMsl/MetalState.mm b/source/MaterialXRenderMsl/MetalState.mm index 01903dbd89..4ce170a6ba 100644 --- a/source/MaterialXRenderMsl/MetalState.mm +++ b/source/MaterialXRenderMsl/MetalState.mm @@ -102,7 +102,7 @@ MTLTileRenderPipelineDescriptor* renderPipelineDescriptor = [MTLTileRenderPipelineDescriptor new]; [renderPipelineDescriptor setRasterSampleCount:1]; - [[renderPipelineDescriptor colorAttachments][0] setPixelFormat:MTLPixelFormatBGRA8Unorm]; + [[renderPipelineDescriptor colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA16Float]; [renderPipelineDescriptor setTileFunction:function]; linearToSRGB_pso = [device newRenderPipelineStateWithTileDescriptor:renderPipelineDescriptor options:0 reflection:nil error:&error]; } @@ -171,7 +171,7 @@ MTLRenderPipelineDescriptor* renderPipelineDesc = [MTLRenderPipelineDescriptor new]; [renderPipelineDesc setVertexFunction:vertexfunction]; [renderPipelineDesc setFragmentFunction:Fragmentfunction]; - [[renderPipelineDesc colorAttachments][0] setPixelFormat:MTLPixelFormatBGRA8Unorm]; + [[renderPipelineDesc colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA16Float]; [renderPipelineDesc setDepthAttachmentPixelFormat:MTLPixelFormatDepth32Float]; linearToSRGB_pso = [device newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&error]; } @@ -225,7 +225,7 @@ [cmdBuffer waitUntilCompleted]; } -void MetalState::waitForComplition() +void MetalState::waitForCompletion() { std::unique_lock lock(inFlightMutex); while (inFlightCommandBuffers != 0) diff --git a/source/MaterialXView/RenderPipelineMetal.mm b/source/MaterialXView/RenderPipelineMetal.mm index 872ec8e10d..59da87a847 100644 --- a/source/MaterialXView/RenderPipelineMetal.mm +++ b/source/MaterialXView/RenderPipelineMetal.mm @@ -15,6 +15,8 @@ #include +#include + namespace { @@ -59,10 +61,10 @@ MTL(device), width * _viewer->m_pixel_ratio, height * _viewer->m_pixel_ratio, - 4, mx::Image::BaseType::UINT8, + 4, mx::Image::BaseType::HALF, MTL(supportsTiledPipeline) ? (id)color_texture : nil, - false, MTLPixelFormatBGRA8Unorm)); + false, MTLPixelFormatRGBA16Float)); } void MetalRenderPipeline::resizeFramebuffer(int width, int height, @@ -697,16 +699,30 @@ unsigned int width = MTL(currentFramebuffer())->getWidth(); unsigned int height = MTL(currentFramebuffer())->getHeight(); - MTL(waitForComplition()); + MTL(waitForCompletion()); + + id srcTexture = MTL(supportsTiledPipeline) ? + (id)_viewer->_colorTexture : + MTL(currentFramebuffer())->getColorTexture(); + mx::MetalFramebufferPtr framebuffer = mx::MetalFramebuffer::create( MTL(device), width, height, 4, mx::Image::BaseType::UINT8, - MTL(supportsTiledPipeline) ? - (id)_viewer->_colorTexture : - MTL(currentFramebuffer())->getColorTexture(), + nil, false, MTLPixelFormatBGRA8Unorm); - mx::ImagePtr frame = framebuffer->getColorImage(MTL(cmdQueue)); + id dstTexture = framebuffer->getColorTexture(); + + id cmdQueue = MTL(cmdQueue); + + // Copy with format conversion + MPSImageConversion* conversion = [[MPSImageConversion alloc] initWithDevice:MTL(device)]; + id cmdBuffer = [cmdQueue commandBuffer]; + [conversion encodeToCommandBuffer:cmdBuffer sourceTexture:srcTexture destinationTexture:dstTexture]; + [cmdBuffer commit]; + [cmdBuffer waitUntilCompleted]; + + mx::ImagePtr frame = framebuffer->getColorImage(cmdQueue); // Flips the captured image std::vector tmp(frame->getRowStride()); diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index c3910c4f1e..71cccf36c8 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -52,6 +52,11 @@ const float DEFAULT_CAMERA_ZOOM = 1.0f; namespace { +#ifdef MATERIALXVIEW_METAL_BACKEND +const bool USE_FLOAT_BUFFER = true; +#else +const bool USE_FLOAT_BUFFER = false; +#endif const int MIN_ENV_SAMPLE_COUNT = 4; const int MAX_ENV_SAMPLE_COUNT = 1024; @@ -152,7 +157,7 @@ Viewer::Viewer(const std::string& materialFilename, int screenHeight, const mx::Color3& screenColor) : ng::Screen(ng::Vector2i(screenWidth, screenHeight), "MaterialXView", - true, false, true, true, false, 4, 0), + true, false, true, true, USE_FLOAT_BUFFER, 4, 0), _window(nullptr), _materialFilename(materialFilename), _meshFilename(meshFilename), From 81e3e24f7f9940c0a2f31d6e519d55857a9fc909 Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:34:43 -0700 Subject: [PATCH 050/137] Align smoothstep edge cases with OSL (#1985) Following a conversation on ASWF slack this PR was posted to OSL refining the edge cases for `smoothstep()`. https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/pull/1851 This PR aligns the GLSL/MSL code with this change. --- libraries/stdlib/genglsl/mx_smoothstep_float.glsl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/stdlib/genglsl/mx_smoothstep_float.glsl b/libraries/stdlib/genglsl/mx_smoothstep_float.glsl index 1bca2e4d9b..0b317bdf33 100644 --- a/libraries/stdlib/genglsl/mx_smoothstep_float.glsl +++ b/libraries/stdlib/genglsl/mx_smoothstep_float.glsl @@ -1,9 +1,9 @@ void mx_smoothstep_float(float val, float low, float high, out float result) { - if (val <= low) - result = 0.0; - else if (val >= high) + if (val >= high) result = 1.0; + else if (val <= low) + result = 0.0; else result = smoothstep(low, high, val); } From 093b8195db3386f5d2f19dfdfee6eb9165116b09 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 6 Sep 2024 17:12:55 -0700 Subject: [PATCH 051/137] Initial implementation of Disney Principled (#2004) This changelist adds an initial MaterialX graph for the Disney Principled BSDF, as described in Brent Burley's 2012 and 2015 presentations. For simplicity, the original separated interfaces for `disney_brdf_2012` and `disney_bsdf_2015` have been merged into a single `disney_principled` interface, providing artists with a unified entry point for the shading model. Where possible, the original empirical approach of Disney Principled has been preserved, including the use of the `burley_diffuse_bsdf` and `generalized_schlick_bsdf` nodes, though a few simplifications have been employed, including the use of the `layer` node for physically based layering and the `sheen_bsdf` node for the sheen layer. --- documents/Specification/MaterialX.PBRSpec.md | 10 ++ .../Specification/MaterialX.Specification.md | 4 +- libraries/bxdf/disney_brdf_2015.mtlx | 25 ---- libraries/bxdf/disney_principled.mtlx | 140 ++++++++++++++++++ .../disney_principled_carpaint.mtlx | 12 ++ .../disney_principled_default.mtlx | 17 ++- .../disney_principled_glass.mtlx | 12 ++ .../disney_principled_gold.mtlx | 11 ++ .../disney_principled_plastic.mtlx | 10 ++ 9 files changed, 206 insertions(+), 35 deletions(-) delete mode 100644 libraries/bxdf/disney_brdf_2015.mtlx create mode 100644 libraries/bxdf/disney_principled.mtlx create mode 100644 resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx rename libraries/bxdf/disney_brdf_2012.mtlx => resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx (60%) create mode 100644 resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx create mode 100644 resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx create mode 100644 resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md index 2e314d479d..298f0fb0b2 100644 --- a/documents/Specification/MaterialX.PBRSpec.md +++ b/documents/Specification/MaterialX.PBRSpec.md @@ -381,6 +381,14 @@ Note that the standard library includes definitions for [**`displacement`**](./M This section contains examples of shading model implementations using the MaterialX PBS library. For all examples, the shading model is defined via a <nodedef> interface plus a nodegraph implementation. The resulting nodes can be used as shaders by a MaterialX material definition. +## Disney Principled BSDF + +This shading model was presented by Brent Burley from Walt Disney Animation Studios in 2012[^Burley2012], with additional refinements presented in 2015[^Burley2015]. + +A MaterialX definition and nodegraph implementation of the Disney Principled BSDF can be found here: +[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/disney_principled.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/disney_principled.mtlx) + + ## Autodesk Standard Surface This is a surface shading model used in Autodesk products created by the Solid Angle team for the Arnold renderer. It is an über shader built from ten different BSDF layers[^Georgiev2019]. @@ -430,6 +438,8 @@ The MaterialX PBS Library includes a number of nodegraphs that can be used to ap [^Burley2012]: Brent Burley, **Physically-Based Shading at Disney**, , 2012 +[^Burley2015]: Brent Burley, **Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering**, , 2015 + [^Christensen2015]: Per H. Christensen, Brent Burley, **Approximate Reflectance Profiles for Efficient Subsurface Scattering**, 2015 [^Conty2017]: Alejandro Conty, Christopher Kulla, **Production Friendly Microfacet Sheen BRDF**, , 2017 diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 60e62d9ce2..29b480f7cb 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -2387,7 +2387,7 @@ Custom nodes that output data types with a "shader" semantic are referred to in The attributes for <nodedef> elements as they pertain to the declaration of shaders are: * `name` (string, required): a user-chosen name for this shader node definition element. -* `node` (string, required): the name of the shader node being defined, which typically matches the name of an associated shader function such as “blinn_phong”, “Disney_BRDF_2012”, “volumecloud_vol”. Just as for custom nodes, this shading program may be defined precisely through an <implementation> or <nodegraph>, or left to the application to locate by name using any shader definition method that it chooses. +* `node` (string, required): the name of the shader node being defined, which typically matches the name of an associated shader function such as “blinn_phong”, “disney_principled”, “volumecloud_vol”. Just as for custom nodes, this shading program may be defined precisely through an <implementation> or <nodegraph>, or left to the application to locate by name using any shader definition method that it chooses. The child <output> element within the <nodedef> defines the "data type" of the output for this shader, which must have been defined with a "shader" semantic; see the [Custom Data Types](#custom-data-types) section above and discussion below for details. @@ -2707,8 +2707,6 @@ Example uses for variants include defining a number of allowable colors and text Variants and variantsets are not intrinsically associated with any particular material; they merely state a number of values for a number of named inputs/tokens. However, variantsets may state that they are associated with specific shader-semantic nodes and/or <nodedef> declarations by providing stringarray-type `node` and/or `nodedef` attributes: ```xml - - ... ... ``` diff --git a/libraries/bxdf/disney_brdf_2015.mtlx b/libraries/bxdf/disney_brdf_2015.mtlx deleted file mode 100644 index 916c7d55af..0000000000 --- a/libraries/bxdf/disney_brdf_2015.mtlx +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/bxdf/disney_principled.mtlx b/libraries/bxdf/disney_principled.mtlx new file mode 100644 index 0000000000..72394cb84f --- /dev/null +++ b/libraries/bxdf/disney_principled.mtlx @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx new file mode 100644 index 0000000000..7c5a0ae94f --- /dev/null +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/libraries/bxdf/disney_brdf_2012.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx similarity index 60% rename from libraries/bxdf/disney_brdf_2012.mtlx rename to resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx index d65e7dbc55..717d769870 100644 --- a/libraries/bxdf/disney_brdf_2012.mtlx +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx @@ -1,18 +1,21 @@ - + - - - + - - - + + + + + + + + diff --git a/resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx new file mode 100644 index 0000000000..dfb1fab67d --- /dev/null +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx new file mode 100644 index 0000000000..f0dde69049 --- /dev/null +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx new file mode 100644 index 0000000000..7b2561b5ec --- /dev/null +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + From 8bc6fbc1b71688795775c32baedf296c883a2635 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 7 Sep 2024 16:21:48 -0700 Subject: [PATCH 052/137] Updates to GitHub CI (#2008) - Update MacOS from Xcode 15.0 to 15.4. - Update MacOS from Python 3.7 to 3.9. - Update Linux from GCC 12 to 13. - Consolidate Linux builds for efficiency. --- .github/workflows/main.yml | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 987aaa4839..c9750eb355 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,22 +23,15 @@ jobs: compiler: gcc compiler_version: "9" python: 3.7 - cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON + cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON -DMATERIALX_BUILD_MONOLITHIC=ON - - name: Linux_GCC_12_Python311 - os: ubuntu-22.04 + - name: Linux_GCC_13_Python311 + os: ubuntu-24.04 compiler: gcc - compiler_version: "12" + compiler_version: "13" python: 3.11 build_javascript: ON - - name: Linux_GCC_12_Python311_Static_Monolithic - os: ubuntu-22.04 - compiler: gcc - compiler_version: "12" - python: 3.11 - cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON -DMATERIALX_BUILD_MONOLITHIC=ON - - name: Linux_GCC_14_Python312 os: ubuntu-24.04 compiler: gcc @@ -48,7 +41,7 @@ jobs: cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: Linux_GCC_CoverageAnalysis - os: ubuntu-22.04 + os: ubuntu-24.04 compiler: gcc compiler_version: "None" python: None @@ -70,12 +63,12 @@ jobs: test_render: ON clang_format: ON - - name: MacOS_Xcode_13_Python37 + - name: MacOS_Xcode_13_Python39 os: macos-12 compiler: xcode compiler_version: "13.1" cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON - python: 3.7 + python: 3.9 - name: MacOS_Xcode_14_Python311 os: macos-14 @@ -86,14 +79,14 @@ jobs: - name: MacOS_Xcode_15_Python312 os: macos-14 compiler: xcode - compiler_version: "15.0" + compiler_version: "15.4" python: 3.12 test_shaders: ON - name: MacOS_Xcode_DynamicAnalysis os: macos-14 compiler: xcode - compiler_version: "15.0" + compiler_version: "15.4" python: None dynamic_analysis: ON cmake_config: -DMATERIALX_DYNAMIC_ANALYSIS=ON @@ -101,7 +94,7 @@ jobs: - name: iOS_Xcode_15 os: macos-14 compiler: xcode - compiler_version: "15.0" + compiler_version: "15.4" python: None cmake_config: -DMATERIALX_BUILD_IOS=ON -DCMAKE_OSX_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path` -DCMAKE_OSX_ARCHITECTURES=arm64 From 64b96968ef2432a542defe5fa8b365c467d97ed0 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 8 Sep 2024 19:39:43 -0700 Subject: [PATCH 053/137] Add release signing to GitHub CI (#2009) This changelist adds a release signing workflow to the GitHub CI for MaterialX, leveraging https://github.com/sigstore/sigstore-python to sign each release and upload the resulting artifacts. --- .github/workflows/release.yml | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..6ddb62f2b4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: release + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + + release: + name: Release Signing + runs-on: ubuntu-latest + env: + RELEASE_TAG: ${{ github.ref_name }} + permissions: + contents: write + id-token: write + repository-projects: write + + steps: + - name: Sync Repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Create Archive Name + run: echo "MATERIALX_ARCHIVE=MaterialX-${RELEASE_TAG//v}" >> $GITHUB_ENV + + - name: Generate Archives + run: | + git archive --prefix ${MATERIALX_ARCHIVE}/ --output ${MATERIALX_ARCHIVE}.zip ${RELEASE_TAG} + git archive --prefix ${MATERIALX_ARCHIVE}/ --output ${MATERIALX_ARCHIVE}.tar.gz ${RELEASE_TAG} + + - name: Sign and Upload Archives + uses: sigstore/gh-action-sigstore-python@v3.0.0 + with: + inputs: | + ${{ env.MATERIALX_ARCHIVE }}.zip + ${{ env.MATERIALX_ARCHIVE }}.tar.gz + upload-signing-artifacts: true + release-signing-artifacts: false From 34907af2b1614d9aa3f172e64885bf612021a970 Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Thu, 12 Sep 2024 16:58:23 -0700 Subject: [PATCH 054/137] Unhide inversesqrt() function in mx_math.metal (#2010) `inversesqrt()` is currently inside of a `#ifdef __DECL_GL_MATH_FUNCTIONS__` guard, which means it is not visible inside of OpenUSD's Storm hdMetal backend. This PR moves it outside of the guard, and renames the function to `mx_inversesqrt()` to avoid possible name conflicts in other shader generators. --- libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl | 4 ++-- libraries/stdlib/genglsl/lib/mx_math.glsl | 5 +++++ libraries/stdlib/genmsl/lib/mx_math.metal | 8 +++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl index a5c3ade7a8..6301105dd1 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl @@ -123,7 +123,7 @@ mat3 mx_orthonormal_basis_ltc(vec3 V, vec3 N, float NdotV) float lenSqr = dot(X, X); if (lenSqr > 0.0) { - X *= inversesqrt(lenSqr); + X *= mx_inversesqrt(lenSqr); vec3 Y = cross(N, X); return mat3(X, Y, N); } @@ -173,7 +173,7 @@ vec3 mx_zeltner_sheen_importance_sample(vec2 Xi, vec3 V, vec3 N, float roughness vec3 w = vec3(wo.x/aInv - wo.z*bInv/aInv, wo.y / aInv, wo.z); float lenSqr = dot(w, w); - w *= inversesqrt(lenSqr); + w *= mx_inversesqrt(lenSqr); // D(w) = Do(wo) . ||M.wo||^3 / |M| // = Do(wo / ||M.wo||) . ||M.wo||^4 / |M| diff --git a/libraries/stdlib/genglsl/lib/mx_math.glsl b/libraries/stdlib/genglsl/lib/mx_math.glsl index 781a24a6e7..cff7835a4c 100644 --- a/libraries/stdlib/genglsl/lib/mx_math.glsl +++ b/libraries/stdlib/genglsl/lib/mx_math.glsl @@ -22,3 +22,8 @@ vec3 mx_srgb_encode(vec3 color) vec3 powSeg = 1.055 * pow(max(color, vec3(0.0)), vec3(1.0 / 2.4)) - 0.055; return mix(linSeg, powSeg, isAbove); } + +float mx_inversesqrt(float x) +{ + return inversesqrt(x); +} diff --git a/libraries/stdlib/genmsl/lib/mx_math.metal b/libraries/stdlib/genmsl/lib/mx_math.metal index 7c4851ea31..46a8c5d57e 100644 --- a/libraries/stdlib/genmsl/lib/mx_math.metal +++ b/libraries/stdlib/genmsl/lib/mx_math.metal @@ -21,6 +21,11 @@ T1 mx_mod(T1 x, T2 y) return x - y * floor(x/y); } +float mx_inversesqrt(float x) +{ + return ::rsqrt(x); +} + #ifdef __DECL_GL_MATH_FUNCTIONS__ float radians(float degree) { return (degree * M_PI_F / 180.0f); } @@ -97,9 +102,6 @@ T atan(T y_over_x) { return ::atan(y_over_x); } template T atan(T y, T x) { return ::atan2(y, x); } -template -T inversesqrt(T x) { return ::rsqrt(x); } - #define lessThan(a, b) ((a) < (b)) #define lessThanEqual(a, b) ((a) <= (b)) #define greaterThan(a, b) ((a) > (b)) From 4fd38f0763165b99df49a472cefbbf231c45ef01 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 12 Sep 2024 21:55:53 -0700 Subject: [PATCH 055/137] Improvements to CONTRIBUTING.md (#2013) This changelist implements a number of improvements to the CONTRIBUTING.md page of the MaterialX project, borrowing a number of ideas from the documentation of our sibling OpenEXR project. --- CONTRIBUTING.md | 211 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 196 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5cebfc0499..7c3ea19e54 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,33 +1,214 @@ # Contributing to MaterialX -Thank you for your interest in contributing to MaterialX! This document explains our contribution process and procedures. +Thank you for your interest in contributing to MaterialX! This document +explains our contribution process and procedures. ## Community and Discussion There are two primary ways to connect with the MaterialX community: -* The MaterialX channel of the [Academy Software Foundation Slack](http://academysoftwarefdn.slack.com/). This platform is appropriate for general questions, feature requests, and discussion of the MaterialX project as a whole. You can request an invitation to join the Academy Software Foundation Slack at https://slack.aswf.io/. -* The [Issues](https://github.com/AcademySoftwareFoundation/MaterialX/issues) panel of the MaterialX GitHub, which is used to report and discuss bugs and build issues. +- The MaterialX channel of the +[Academy Software Foundation Slack](http://academysoftwarefdn.slack.com/). +This platform is appropriate for general questions, feature requests, and +discussion of the MaterialX project as a whole. +You can request an invitation to join the Academy Software Foundation Slack +at https://www.aswf.io/get-involved/. +- The [Issues](https://github.com/AcademySoftwareFoundation/MaterialX/issues) +panel of the MaterialX GitHub, which is used both to track bugs and to discuss +feature requests. -## Contributor License Agreements +### How to Ask for Help -To contribute to MaterialX, you must sign a Contributor License Agreement through the *EasyCLA* system, which is integrated with GitHub as a pull request check. +If you have trouble installing, building, or using the library, but there's +not yet reason to suspect you've encountered a genuine bug, start by posting +a question to the MaterialX channel of the +[Academy Software Foundation Slack](http://academysoftwarefdn.slack.com/). +This is the place for questions such has "How do I...". -Prior to submitting a pull request, you can sign the form through [this link](https://contributor.easycla.lfx.linuxfoundation.org/#/cla/project/68fa91fe-51fe-41ac-a21d-e0a0bf688a53/user/564e571e-12d7-4857-abd4-898939accdd7). If you submit a pull request before the form is signed, the EasyCLA check will fail with a red *NOT COVERED* message, and you'll have another opportunity to sign the form through the provided link. +### How to Report a Bug -* If you are an individual writing the code on your own time and you're sure you are the sole owner of any intellectual property you contribute, you can sign the CLA as an Individual Contributor. -* If you are writing the code as part of your job, or if your employer retains ownership to intellectual property you create, then your company's legal affairs representatives should sign a Corporate Contributor License Agreement. If your company already has a signed CCLA on file, ask your local CLA manager to add you to your company's approved list. +MaterialX uses +[GitHub Issues](https://github.com/AcademySoftwareFoundation/MaterialX/issues) +for reporting and tracking bugs, enhancements, and feature requests. -The MaterialX CLAs are the standard forms used by Linux Foundation projects and [recommended by the ASWF TAC](https://github.com/AcademySoftwareFoundation/tac/blob/main/process/contributing.md#contributor-license-agreement-cla). +If you are submitting a bug report, please be sure to note which version of +MaterialX you are using, on what platform (OS/version, which compiler you used, +and any special build flags or other unusual environmental issues). Please +give a specific account of the following, with enough detail that others can +reproduce the problem: -## Coding Conventions +- What you tried. +- What happened. +- What you expected to happen instead. -The coding style of the MaterialX project is defined by a [clang-format](.clang-format) file in the repository, which is supported by Clang versions 13 and newer. +### How to Report a Security Vulnerability -When adding new source files to the repository, use the provided clang-format file to automatically align the code to MaterialX conventions. When modifying existing code, follow the surrounding formatting conventions so that new or modified code blends in with the current code. +If you think you've found a potential vulnerability in MaterialX, please refer +to [SECURITY.md](SECURITY.md) to responsibly disclose it. -## Unit Tests +### How to Contribute a Bug Fix or Change -Each MaterialX module has a companion folder within the [MaterialXTest](source/MaterialXTest) module, containing a set of unit tests that validate its functionality. +To contribute code to the project, you'll need: -When contributing new code to MaterialX, make sure to include appropriate unit tests in MaterialXTest to validate the expected behavior of the new code. +- Basic knowledge of Git. +- A fork of the MaterialX repository on GitHub. +- An understanding of the project's development workflow. +- Legal authorization, that is, you need to have signed a contributor + License Agreement. See below for details. + +## Legal Requirements + +MaterialX is a project of the Academy Software Foundation and follows the +open source software best practice policies of the Linux Foundation. + +### License + +MaterialX is licensed under the [Apache 2.0](LICENSE.md) license. +Contributions to the project should abide by that standard license. + +### Contributor License Agreements + +To contribute to MaterialX, you must sign a Contributor License Agreement +through the *EasyCLA* system, which is integrated with GitHub as a pull +request check. + +Prior to submitting a pull request, you can sign the form through +[this link](https://contributor.easycla.lfx.linuxfoundation.org/#/cla/project/68fa91fe-51fe-41ac-a21d-e0a0bf688a53/user/564e571e-12d7-4857-abd4-898939accdd7). +If you submit a pull request before the form is signed, the EasyCLA check +will fail with a red *NOT COVERED* message, and you'll have another +opportunity to sign the form through the provided link. + +- If you are an individual writing the code on your own time and you're sure +you are the sole owner of any intellectual property you contribute, you can +sign the CLA as an Individual Contributor. +- If you are writing the code as part of your job, or if your employer +retains ownership to intellectual property you create, then your company's +legal affairs representatives should sign a Corporate Contributor License +Agreement. If your company already has a signed CCLA on file, ask your +local CLA manager to add you to your company's approved list. + +The MaterialX CLAs are the standard forms used by Linux Foundation projects +and [recommended by the ASWF TAC](https://github.com/AcademySoftwareFoundation/tac/blob/main/process/contributing.md#contributor-license-agreement-cla). + +## Development Workflow + +### Git Basics + +Working with MaterialX requires a basic understanding of Git and GitHub +terminology. If you’re unfamiliar with these concepts, please look at the +[GitHub Glossary](https://help.github.com/articles/github-glossary/) or +browse [GitHub Help](https://help.github.com/). + +To contribute, you need a GitHub account. This is needed in order to push +changes to the upstream repository, via a pull request. + +You will also need [Git](https://git-scm.com/doc) or a Git client such +as [Git Fork](https://git-fork.com/) or +[GitHub Desktop](https://desktop.github.com/download/) installed +on your local development machine. + +### Repository Structure and Commit Policy + +Development work in the MaterialX project is usually done directly +on the `main` branch. This branch represents the cutting edge of the +project and the majority of new work is proposed, tested, reviewed, +and merged there. + +After sufficient work is done on the `main` branch and the MaterialX +leadership determines that a release is due, they will mark a release with +the current version tag and increment the development version for future +work. This basic repository structure keeps maintenance low, while remaining +simple to understand. + +The `main` branch may include untested features and is not generally stable +enough for release. To retrieve a stable version of the source code, use any +of the +[official releases](https://github.com/AcademySoftwareFoundation/MaterialX/releases) +of the project. + +### Use the Fork, Luke. + +In a typical workflow, you should *fork* the MaterialX repository to +your account. This creates a copy of the repository under your user +namespace and serves as the “home base” for your development branches, +from which you will submit *pull requests* to the upstream +repository to be merged. + +Once your Git environment is operational, the next step is to locally +*clone* your forked MaterialX repository, and add a *remote* +pointing to the upstream MaterialX repository. These topics are +covered in the GitHub documentation +[Cloning a repository](https://help.github.com/articles/cloning-a-repository/) +and +[Configuring a remote for a fork](https://help.github.com/articles/configuring-a-remote-for-a-fork/). + +### Pull Requests + +Contributions should be submitted as GitHub pull requests. See +[Creating a pull request](https://help.github.com/articles/creating-a-pull-request/) +if you're unfamiliar with this concept. + +The development cycle for a code change should follow this protocol: + +1. Create a topic branch in your local repository, assigning the branch a +brief name that describes the feature or fix that you're working on. +2. Make changes, compile, and test thoroughly. Code style should match existing +style and conventions, and changes should be focused on the topic the pull +request will be addressing. Make unrelated changes in a separate topic branch +with a separate pull request. +3. Push commits to your fork. +4. Create a GitHub pull request from your topic branch. +5. Pull requests will be reviewed by project maintainers and contributors, +who may discuss, offer constructive feedback, request changes, or approve +the work. +6. Upon receiving the required number of approvals (as outlined in +[Required Approvals](#code-review-and-required-approvals)), a maintainer +may merge changes into the `main` branch. + +### Code Review and Required Approvals + +Modifications of the contents of the MaterialX repository are made on a +collaborative basis. Anyone with a GitHub account may propose a modification +via pull request and it will be considered by the project maintainers. + +Pull requests must meet a minimum number of maintainer approvals prior to +being merged. Rather than having a hard rule for all PRs, the requirement +is based on the complexity and risk of the proposed changes, factoring in +the length of time the PR has been open to discussion. The following +guidelines outline the project's established approval rules for merging: + +- Minor changes that don't modify current behaviors or are straightforward +fixes to existing features can be approved and merged by a single maintainer +of the repository. +- Moderate changes that modify current behaviors or introduce new features +should be approved by *two* maintainers before merging. Unless the change is +an emergency fix, the author should give the community at least 48 hours to +review the proposed change. +- Major new features and core design decisions should be discussed at length +in the ASWF Slack or in TSC meetings before any PR is submitted, in order to +solicit feedback, build consensus, and alert all stakeholders to be on the +lookout for the eventual PR when it appears. + +### Coding Conventions + +The coding style of the MaterialX project is defined by a +[clang-format](.clang-format) file in the repository, which is supported by +Clang versions 13 and newer. + +When adding new source files to the repository, use the provided clang-format +file to automatically align the code to MaterialX conventions. When modifying +existing code, follow the surrounding formatting conventions so that new or +modified code blends in with the current code. + +### Unit Tests + +Each MaterialX module has a companion folder within the +[MaterialXTest](source/MaterialXTest) module, containing a set of unit tests +that validate its functionality. When contributing new code to MaterialX, make +sure to include appropriate unit tests in MaterialXTest to validate the +expected behavior of the new code. + +The MaterialX test suite can be run locally via MaterialXTest before submitting +a pull request. Upon receiving a pull request, the GitHub CI process will +automatically run MaterialXTest across all platforms, and a successful result +is required before merging a change. From d377d0ea778ac8a7a88f316ab972e3405cc5fbb1 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Mon, 16 Sep 2024 11:35:36 -0400 Subject: [PATCH 056/137] Texture caching enhancements for Web Viewer (#1891) - Add in texture cache reuse using ThreeJS cache. - Handle http/blob/data encodings properly. ( This will allow support for interactive image assignment to existing shaders. ) --- javascript/MaterialXView/source/helper.js | 61 ++++++++++++++++++++--- javascript/MaterialXView/source/viewer.js | 18 +++++-- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/javascript/MaterialXView/source/helper.js b/javascript/MaterialXView/source/helper.js index cd3f144f06..3f3be46c79 100644 --- a/javascript/MaterialXView/source/helper.js +++ b/javascript/MaterialXView/source/helper.js @@ -89,7 +89,7 @@ function fromMatrix(matrix, dimension) */ function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY) { - let outValue; + let outValue = null; switch (type) { case 'float': @@ -117,18 +117,63 @@ function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, case 'filename': if (value) { - let fullPath = searchPath + IMAGE_PATH_SEPARATOR + value; - const texture = textureLoader.load(fullPath); - // Set address & filtering mode - if (texture) - setTextureParameters(texture, name, uniforms, flipY); - outValue = texture; + // Cache / reuse texture to avoid reload overhead. + // Note: that data blobs and embedded data textures are not cached as they are transient data. + let checkCache = true; + let texturePath = searchPath + IMAGE_PATH_SEPARATOR + value; + if (value.startsWith('blob:')) + { + texturePath = value; + console.log('Load blob URL:', texturePath); + checkCache = false; + } + else if (value.startsWith('http')) + { + texturePath = value; + console.log('Load HTTP URL:', texturePath); + } + else if (value.startsWith('data:')) + { + texturePath = value; + checkCache = false; + console.log('Load data URL:', texturePath); + } + const cachedTexture = checkCache && THREE.Cache.get(texturePath); + if (cachedTexture) + { + // Get texture from cache + outValue = cachedTexture; + console.log('Use cached texture: ', texturePath, outValue); + } + else + { + outValue = textureLoader.load( + texturePath, + function (texture) { + console.log('Load new texture: ' + texturePath, texture); + outValue = texture; + + // Add texture to ThreeJS cache + if (checkCache) + THREE.Cache.add(texturePath, texture); + }, + undefined, + function (error) { + console.error('Error loading texture: ', error); + }); + + // Set address & filtering mode + if (outValue) + setTextureParameters(outValue, name, uniforms, flipY); + } } break; case 'samplerCube': case 'string': - default: break; + default: + console.log('Value type not supported: ' + type); + outValue = null; } return outValue; diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index 57e155c87b..febe34c809 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -221,9 +221,14 @@ export class Scene orbitControls.update(); } - setUpdateTransforms() + setUpdateTransforms(val=true) { - this.#_updateTransforms = true; + this.#_updateTransforms = val; + } + + getUpdateTransforms() + { + return this.#_updateTransforms; } updateTransforms() @@ -235,7 +240,7 @@ export class Scene { return; } - this.#_updateTransforms = false; + this.setUpdateTransforms(false); const scene = this.getScene(); const camera = this.getCamera(); @@ -622,7 +627,12 @@ export class Material // Load material if (mtlxMaterial) - await mx.readFromXmlString(doc, mtlxMaterial, searchPath); + try { + await mx.readFromXmlString(doc, mtlxMaterial, searchPath); + } + catch (error) { + console.log('Error loading material file: ', error); + } else Material.createFallbackMaterial(doc); From e0d72e75b8d9cf2d266acc2fc236fe5b9fcb8090 Mon Sep 17 00:00:00 2001 From: Doug Smythe Date: Mon, 16 Sep 2024 17:38:56 -0700 Subject: [PATCH 057/137] Specification updates (#2017) Clarifications in the Color Spaces section about colorspace scoping and unbound colors. Correction in the NodeDef Inputs section about the effects of supplying a "colorspace" attribute. Removed references to and , which are proposed (but not yet actual) nodes. --- .../Specification/MaterialX.Proposals.md | 3 ++- .../Specification/MaterialX.Specification.md | 22 +++++++------------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/documents/Specification/MaterialX.Proposals.md b/documents/Specification/MaterialX.Proposals.md index 97b37787ba..b96c688f25 100644 --- a/documents/Specification/MaterialX.Proposals.md +++ b/documents/Specification/MaterialX.Proposals.md @@ -6,7 +6,7 @@ MaterialX Proposals v1.39 # MaterialX: Proposed Additions and Changes **Proposals for Version 1.39** -July 26, 2024 +September 15, 2024 # Introduction @@ -207,6 +207,7 @@ We have a standard 3d fractal noise, but a 2d variant would be useful as well. * `geomprop` (uniform string): the geometric property to be referenced. * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. +Note: when <geompropvalueuniform> is added, the text in the first paragraph of the Specification about Node Inputs should be revised to include "<geompropvalueuniform>" as an example of "or any other node whose output is explicitly declared to be uniform". ### Global Nodes diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 29b480f7cb..070587340c 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -8,7 +8,7 @@ MaterialX Specification v1.39 **Version 1.39** Doug Smythe - Industrial Light & Magic Jonathan Stone - Lucasfilm Advanced Development Group -July 26, 2024 +September 15, 2024 # Introduction @@ -368,9 +368,9 @@ By default, MaterialX supports the following color spaces as defined in ACES 1.2 * `srgb_displayp3` * `lin_displayp3` -The working color space of a MaterialX document is defined by the `colorspace` attribute of its root <materialx> element, and it is strongly recommended that all <materialx> elements define a specific `colorspace` if they wish to use a color-managed workflow rather than relying on a default colorspace setting from an external configuration file. +The working color space of a MaterialX document is defined by the `colorspace` attribute of its root <materialx> element, and it is strongly recommended that all <materialx> elements define a specific `colorspace` if they wish to use a color-managed workflow rather than relying on a default color space setting from an external configuration file. If a MaterialX document is xi:included into another MaterialX document, it will inherit the working color space setting of the parent document, unless it itself declares a specific working color space. -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. +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. Other elements, such as <nodegraph> or a node instance, are allowed to define a `colorspace` attribute that will apply to elements within their scope; color values in inputs and files that do not explicitly provide a `colorspace` attribute will be treated as if they are in the color space of the nearest enclosing scope which does define a `colorspace` attribute. 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 @@ -381,7 +381,7 @@ The color space of individual color image files and values may be defined via a ``` -MaterialX reserves the color space name "none" to mean no color space conversion should be applied to the images and color values within their scope. +MaterialX reserves the color space name "none" to mean no color space conversion should be applied to the images and color values within their scope, regardless of any differences between stated color spaces at the local scope and document or application working color space settings. @@ -603,7 +603,7 @@ MaterialX defines a number of Standard Nodes which all implementations should su ## Inputs -Node elements contain zero or more <input> elements defining the name, type, and value or connection for each node input. Input elements can assign an explicit uniform value by providing a `value` attribute, make a connection to the output of another node by providing a `nodename` attribute, or make a connection to the output of a nodegraph by providing a `nodegraph` attribute. An optional `output` attribute may also be provided for <input> elements, allowing the input to connect to a specific, named output of the referenced upstream node or nodegraph. If the referenced node/nodegraph has multiple outputs, `output` is required; if it has only one output, the `output` attribute of the <input> is ignored. Input elements may be defined to only accept uniform values, in which case the input may provide a `value` or a `nodename` connection to the output of a [<constant> node](#node-constant) (possibly through one or more no-op [<dot> nodes](#node-dot)) or any other node whose output is explicitly declared to be "uniform" (such as [<geompropvalueuniform>](#node-geompropvalueuniform)), but may not provide a `nodename` or `nodegraph` connection to any arbitrary node output or to any nodegraph output. String- and filename-type inputs are required to be "uniform", as are any array-typed inputs. Input elements may be connected to an external parameter interface in the node definition, allowing them to be assigned values from materials or node instantiations; this includes "uniform" and string/filename-type inputs, however, the same connectability restrictions listed above apply to the inputs of the material or node instance. Inputs may only be connected to node/nodegraph outputs or nodedef interface inputs of the same type, though it is permissible for a `string`-type output to be connected to a `filename`-type input (but not the other way around). +Node elements contain zero or more <input> elements defining the name, type, and value or connection for each node input. Input elements can assign an explicit uniform value by providing a `value` attribute, make a connection to the output of another node by providing a `nodename` attribute, or make a connection to the output of a nodegraph by providing a `nodegraph` attribute. An optional `output` attribute may also be provided for <input> elements, allowing the input to connect to a specific, named output of the referenced upstream node or nodegraph. If the referenced node/nodegraph has multiple outputs, `output` is required; if it has only one output, the `output` attribute of the <input> is ignored. Input elements may be defined to only accept uniform values, in which case the input may provide a `value` or a `nodename` connection to the output of a [<constant> node](#node-constant) (possibly through one or more no-op [<dot> nodes](#node-dot)) or any other node whose output is explicitly declared to be "uniform", but may not provide a `nodename` or `nodegraph` connection to any arbitrary node output or to any nodegraph output. String- and filename-type inputs are required to be "uniform", as are any array-typed inputs. Input elements may be connected to an external parameter interface in the node definition, allowing them to be assigned values from materials or node instantiations; this includes "uniform" and string/filename-type inputs, however, the same connectability restrictions listed above apply to the inputs of the material or node instance. Inputs may only be connected to node/nodegraph outputs or nodedef interface inputs of the same type, though it is permissible for a `string`-type output to be connected to a `filename`-type input (but not the other way around). 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. @@ -1095,13 +1095,7 @@ Standard Geometric nodes: * `geomprop` (uniform string): the geometric property to be referenced. * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. - - -* **`geompropvalueuniform`**: the value of the specified uniform geometric property (defined using <geompropdef>) of the currently-bound geometry. This node's type must match that of the referenced geomprop. - * `geomprop` (uniform string): the geometric property to be referenced. - * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. - -Additionally, the `geomcolor`, `geompropvalue` and `geompropvalueuniform` nodes for color3/color4-type properties can take a `colorspace` attribute to declare what colorspace the color property value is in; the default is "none" for no colorspace declaration (and hence no colorspace conversion). +Additionally, the `geomcolor` and `geompropvalue` nodes for color3/color4-type properties can take a `colorspace` attribute to declare what colorspace the color property value is in; the default is "none" for no colorspace declaration (and hence no colorspace conversion). @@ -1438,7 +1432,7 @@ Math nodes have one or two spatially-varying inputs, and are used to perform a m -* **`dot`**: a no-op, passes its input through to its output unchanged. Users can use dot nodes to shape edge connection paths or provide documentation checkpoints in node graph layout UI's. Dot nodes may also pass uniform values from <constant>, <tokenvalue> or other nodes with uniform="true" outputs to uniform <input>s and <token>s. +* **`dot`**: a no-op, passes its input through to its output unchanged. Users can use dot nodes to shape edge connection paths or provide documentation checkpoints in node graph layout UI's. Dot nodes may also pass uniform values from <constant> or other nodes with uniform="true" outputs to uniform <input>s and <token>s. * `in` (any type): the nodename to be connected to the Dot node's "in" input. Unlike inputs on other node types, the <dot> node's input is specifically disallowed to provide a `channels` attribute: input data can only be passed through unmodified. @@ -2103,7 +2097,7 @@ Attributes for NodeDef Input elements: * `defaultgeomprop` (string, optional): for vector2 or vector3 inputs, the name of an intrinsic geometric property that provides the default value for this input, must be one of "position", "normal", "tangent", "bitangent" or "texcoord" or vector3-type custom geometric property for vector3 inputs, or "texcoord" or vector2-type custom geometric property for vector2 inputs. For standard geometric properties, this is effectively the same as declaring a default connection of the input to a Geometric Node with default input values. May not be specified on uniform inputs. * `enum` (stringarray, optional): a comma-separated non-exclusive list of string value descriptors that the input couldmayis allowed to take: for string- and stringarray-type inputs, these are the actual values (or values per array index for stringarrays); for other types, these are the "enum" labels e.g. as shown in the application user interface for each of the actual underlying values specified by `enumvalues`. The enum list can be thought of as a list of commonly used values or UI labels for the input rather than a strict list, and MaterialX itself does not enforce that a specified input enum value is actually in this list, with the exception that if the input is a "string" (or "stringarray") type and an enum list is provided, then the value(s) must in fact be one of the enum stringarray values. * `enumvalues` (typearray, optional): for non-string/stringarray types, a comma-separated list of values of the same base type as the <input>, representing the values that would be used if the corresponding `enum` string was chosen in the UI. MaterialX itself does not enforce that a specified input value is actually in this list. Note that implementations are allowed to redefine `enumvalues` (but not `enum`) for specific targets: see the [Custom Node Definition Using Implementation Elements](#custom-node-definition-using-implementation-elements) section below. -* `colorspace` (string, optional): for color3- or color4-type inputs, the expected colorspace for this input. Nodedef inputs do not typically specify a colorspace; the most common use case is to specify `colorspace="none"` for inputs that are color-like but which should not be affected by colorspace conversions. +* `colorspace` (string, optional): for color3- or color4-type inputs, the colorspace of the default value for this input. * `unittype` (string, optional): the type of unit for this input, e.g. "distance", which must be defined by a <unittypedef>. Default is to not specify a unittype. Only float-, vectorN- and filename-type inputs may specify a `unittype`. * `unit` (string, optional): the specific unit for this input. Nodedef inputs do not typically specify a unit; if it does, that would indicate that the implementation of that node expects values to be specified in that unit, and that any invocation of that node using a different unit should be converted to the nodedef-specified unit for that input rather than to the application's scene unit. The most common instance of this is for angular values, where a nodedef might specify that it expects values to be given in degrees. * `uiname` (string, optional): an alternative name for this input as it appears in the UI. If `uiname` is not provided, then `name` is the presumed UI name for the input. From 322da6ec57d133009424089563b6f2736ceeabcc Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Wed, 18 Sep 2024 08:24:23 -0700 Subject: [PATCH 058/137] Add `parseStructValueString` function (#2019) Adding a simple function that tokenize a c++ style list initializer string, which will be used to initialize struct values. --- source/MaterialXCore/Value.cpp | 54 ++++++++++++++++++++ source/MaterialXCore/Value.h | 5 ++ source/MaterialXTest/MaterialXCore/Value.cpp | 9 ++++ 3 files changed, 68 insertions(+) diff --git a/source/MaterialXCore/Value.cpp b/source/MaterialXCore/Value.cpp index 3e8c1f4462..68da4b5b9d 100644 --- a/source/MaterialXCore/Value.cpp +++ b/source/MaterialXCore/Value.cpp @@ -193,6 +193,60 @@ template T fromValueString(const string& value) return data; } +StringVec parseStructValueString(const string& value) +{ + static const char SEPARATOR = ';'; + static const char OPEN_BRACE = '{'; + static const char CLOSE_BRACE = '}'; + + if (value.empty()) + return StringVec(); + + // Validate the string is correctly formatted - must be at least 2 characters long and start and end with braces + if (value.size() < 2 || (value[0] != OPEN_BRACE || value[value.size()-1] != CLOSE_BRACE)) + { + return StringVec(); + } + + StringVec split; + + // Strip off the surrounding braces + string substring = value.substr(1, value.size()-2); + + // Sequentially examine each character to parse the list initializer. + string part = ""; + int braceDepth = 0; + for (const char c : substring) + { + if (c == OPEN_BRACE) + { + // We've already trimmed the starting brace, so any additional braces indicate members that are themselves list initializers. + // We will just return this as a string of the list initializer. + braceDepth += 1; + } + if (braceDepth > 0 && c == CLOSE_BRACE) + { + braceDepth -= 1; + } + + if (braceDepth == 0 && c == SEPARATOR) + { + // When we hit a separator we store the currently accumulated part, and clear to start collecting the next. + split.emplace_back(part); + part = ""; + } + else + { + part += c; + } + } + + if (!part.empty()) + split.emplace_back(part); + + return split; +} + // // TypedValue methods // diff --git a/source/MaterialXCore/Value.h b/source/MaterialXCore/Value.h index 1bd29b1d2b..764a0ccc01 100644 --- a/source/MaterialXCore/Value.h +++ b/source/MaterialXCore/Value.h @@ -216,6 +216,11 @@ template MX_CORE_API string toValueString(const T& data); /// @throws ExceptionTypeError if the conversion cannot be performed. template MX_CORE_API T fromValueString(const string& value); +/// Tokenize the string representation of a struct value i.e, "{1;2;3}" into a +/// vector of substrings. +/// Note: "{1;2;{3;4;5}}" will be split in to ["1", "2", "{3;4;5}"] +MX_CORE_API StringVec parseStructValueString(const string& value); + /// Forward declaration of specific template instantiations. /// Base types MX_CORE_EXTERN_TEMPLATE(TypedValue); diff --git a/source/MaterialXTest/MaterialXCore/Value.cpp b/source/MaterialXTest/MaterialXCore/Value.cpp index 40d6b120e7..31c333d211 100644 --- a/source/MaterialXTest/MaterialXCore/Value.cpp +++ b/source/MaterialXTest/MaterialXCore/Value.cpp @@ -78,6 +78,15 @@ TEST_CASE("Value strings", "[value]") REQUIRE_THROWS_AS(mx::fromValueString("text"), mx::ExceptionTypeError); REQUIRE_THROWS_AS(mx::fromValueString("1"), mx::ExceptionTypeError); REQUIRE_THROWS_AS(mx::fromValueString("1"), mx::ExceptionTypeError); + + // Parse value strings using structure syntax features. + REQUIRE(mx::parseStructValueString("{{1;2;3};4}") == (std::vector{"{1;2;3}","4"})); + REQUIRE(mx::parseStructValueString("{1;2;3;4}") == (std::vector{"1","2","3","4"})); + REQUIRE(mx::parseStructValueString("{1;{2;3};4}") == (std::vector{"1","{2;3}","4"})); + REQUIRE(mx::parseStructValueString("{1;{2;3;4}}") == (std::vector{"1","{2;3;4}"})); + REQUIRE(mx::parseStructValueString("{1;{2;{3;4}}}") == (std::vector{"1","{2;{3;4}}"})); + REQUIRE(mx::parseStructValueString("{1;2;{3};4}") == (std::vector{"1","2","{3}","4"})); + REQUIRE(mx::parseStructValueString("{1;2;{3};4}") == (std::vector{"1","2","{3}","4"})); } TEST_CASE("Typed values", "[value]") From 777826c402e32aaa6a1ade79e8bb0dc1e85f4cf3 Mon Sep 17 00:00:00 2001 From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:04:30 -0700 Subject: [PATCH 059/137] Add Chiang hair BSDF (#1968) This PR provides Chiang hair BSDF model and related nodes proposed by #1973 The nodes to add are: - `` : The BSDF - `` : User friendly roughness mapping - `` : Absorption coefficient mapping from user input color - `` : Absorption coefficient mapping from melanin parameters It also include `simple_hair_default` material as a node graph example. --- documents/Specification/MaterialX.PBRSpec.md | 43 +++ libraries/pbrlib/genglsl/mx_hair_bsdf.glsl | 343 ++++++++++++++++++ .../pbrlib/genglsl/pbrlib_genglsl_impl.mtlx | 12 + libraries/pbrlib/pbrlib_defs.mtlx | 55 +++ .../SimpleHair/simple_hair_default.mtlx | 81 +++++ .../TestSuite/pbrlib/bsdf/hair_bsdf.mtlx | 25 ++ .../surfaceshader/hair_surfaceshader.mtlx | 81 +++++ .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 7 +- source/MaterialXTest/MaterialXGenMdl/GenMdl.h | 4 + .../MaterialXTest/MaterialXGenMsl/GenMsl.cpp | 7 +- source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 6 + .../MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 7 +- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 7 + 13 files changed, 675 insertions(+), 3 deletions(-) create mode 100644 libraries/pbrlib/genglsl/mx_hair_bsdf.glsl create mode 100644 resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx create mode 100644 resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx create mode 100644 resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md index 298f0fb0b2..67fecd80b3 100644 --- a/documents/Specification/MaterialX.PBRSpec.md +++ b/documents/Specification/MaterialX.PBRSpec.md @@ -243,6 +243,21 @@ The PBS nodes also make use of the following standard MaterialX types: * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. * `mode` (uniform string): Selects between `conty_kulla` and `zeltner` sheen models. Defaults to `conty_kulla`. + + +* **`chiang_hair_bsdf`**: Constructs a hair BSDF based on the Chiang hair shading model[^Chiang2016]. This node does not support vertical layering. + * `tint_R` (color3): Color multiplier for the first R-lobe. Defaults to (1.0, 1.0, 1.0). + * `tint_TT` (color3): Color multiplier for the first TT-lobe. Defaults to (1.0, 1.0, 1.0). + * `tint_TRT` (color3): Color multiplier for the first TRT-lobe. Defaults to (1.0, 1.0, 1.0). + * `ior` (float): Index of refraction. Defaults to 1.55 being the value for keratin. + * `roughness_R` (vector2): Longitudinal and azimuthal roughness (ν, s) for the first R-lobe, range [0.0, ∞). With (0, 0) specifying pure specular scattering. Defaults to (0.1, 0.1). + * `roughness_TT` (vector2): Longitudinal and azimuthal roughness (ν, s) for the first TT-lobe, range [0.0, ∞). With (0, 0) specifying pure specular scattering. Defaults to (0.05, 0.05). + * `roughness_TRT` (vector2): Longitudinal and azimuthal roughness (ν, s) for the first TRT-lobe, range [0.0, ∞). With (0, 0) specifying pure specular scattering. Defaults to (0.2, 0.2). + * `cuticle_angle` (float): Cuticle angle in radians, Values above 0.5 tilt the scales towards the root of the fiber, range [0.0, 1.0]. With 0.5 specifying no tilt. Defaults to 0.5. + * `absorption_coefficient` (vector3): Absorption coefficient normalized to the hair fiber diameter. Defaults to (0.0, 0.0, 0.0). + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + * `curve_direction` (vector3): Direction of the hair geometry. Defaults to world space tangent. + ## EDF Nodes @@ -374,6 +389,27 @@ Note that the standard library includes definitions for [**`displacement`**](./M * `ior` (**output**, vector3): Computed index of refraction. * `extinction` (**output**, vector3): Computed extinction coefficient. + + +* **`chiang_hair_roughness`**: Converts the artistic parameterization hair roughness to roughness for R, TT and TRT lobes, as described in [^Chiang2016]. Output type `multioutput`, `roughness_R`, `roughness_TT` and `roughness_TRT`, `vector2` type. + * `longitudinal` (float): Longitudinal roughness, range [0.0, 1.0]. Defaults to 0.1. + * `azimuthal` (float): Azimuthal roughness, range [0.0, 1.0]. Defaults to 0.2. + * `scale_TT` (float): Roughness scale for TT lobe. Defaults to 0.5[^Marschner2003]. + * `scale_TRT` (float): Roughness scale for TRT lobe. Defaults to 2.0[^Marschner2003]. + + + +* **`deon_hair_absorption_from_melanin`** : Converts the hair melanin parameterization to absorption coefficient based on pigments eumelanin and pheomelanin using the mapping method described in [^d'Eon2011]. The default of `eumelanin_color` and `pheomelanin_color` are `lin_rec709` color converted from the constants[^d'Eon2011] via `exp(-c)`. They may be transformed to scene-linear rendering color space. `Output type `vector3`. + * `melanin_concentration` (float): Amount of melanin affected to the output, range [0.0, 1.0]. Defaults to 0.25. + * `melanin_redness` (float): Amount of redness affected to the output, range [0.0, 1.0]. Defaults to 0.5. + * `eumelanin_color` (color3): Eumelanin color. Defaults to (0.657704, 0.498077, 0.254107) + * `pheomelanin_color` (color3): Pheomelanin color. Defaults to (0.829444, 0.67032, 0.349938) + + + +* **`chiang_hair_absorption_from_color`** : Coverts the hair scattering color to absorption coefficient using the mapping method described in [^Chiang2016]. Output type `vector3`. + * `color` (color3): Scattering color. Defaults to (1.0, 1.0, 1.0). + * `azimuthal_roughness` (float): Azimuthal roughness, range [0.0, 1.0]. Defaults to 0.2. # Shading Model Examples @@ -440,16 +476,23 @@ The MaterialX PBS Library includes a number of nodegraphs that can be used to ap [^Burley2015]: Brent Burley, **Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering**, , 2015 +[^Chiang2016]: Matt Jen-Yuan Chiang et al., **A Practical and Controllable Hair and Fur Model for Production +Path Tracing**, , 2016 + [^Christensen2015]: Per H. Christensen, Brent Burley, **Approximate Reflectance Profiles for Efficient Subsurface Scattering**, 2015 [^Conty2017]: Alejandro Conty, Christopher Kulla, **Production Friendly Microfacet Sheen BRDF**, , 2017 +[^d'Eon2011]: Eugene d'Eon et al., **An Energy-Conserving Hair Reflectance Model**, , 2011 + [^Georgiev2019]: Iliyan Georgiev et al., **Autodesk Standard Surface**, , 2019. [^Gulbrandsen2014]: Ole Gulbrandsen, **Artist Friendly Metallic Fresnel**, , 2014 [^Hoffman2023]: Naty Hoffman, **Generalization of Adobe's Fresnel Model**, 2023 +[^Marschner2003]: Stephen R. Marschner et al., **Light Scattering from Human Hair Fibers**, , 2003 + [^Oren1994]: Michael Oren, Shree K. Nayar, **Generalization of Lambert’s Reflectance Model**, , 1994 [^Pharr2023]: Matt Pharr et al., **Physically Based Rendering: From Theory To Implementation**, , 2023 diff --git a/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl b/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl new file mode 100644 index 0000000000..e3a9ac20d5 --- /dev/null +++ b/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl @@ -0,0 +1,343 @@ +#include "lib/mx_microfacet_specular.glsl" + +// https://eugenedeon.com/pdfs/egsrhair.pdf +void mx_deon_hair_absorption_from_melanin( + float melanin_concentration, + float melanin_redness, + // constants converted to color via exp(-c). the defaults are lin_rec709 colors, they may be + // transformed to scene-linear rendering color space. + vec3 eumelanin_color, // default: (0.657704, 0.498077, 0.254106) == exp(-(0.419, 0.697, 1.37)) + vec3 pheomelanin_color, // default: (0.829443, 0.670320, 0.349937) == exp(-(0.187, 0.4, 1.05)) + out vec3 absorption) +{ + float melanin = -log(max(1.0 - melanin_concentration, 0.0001)); + float eumelanin = melanin * (1.0 - melanin_redness); + float pheomelanin = melanin * melanin_redness; + absorption = max( + eumelanin * -log(eumelanin_color) + pheomelanin * -log(pheomelanin_color), + vec3(0.0) + ); +} + +// https://media.disneyanimation.com/uploads/production/publication_asset/152/asset/eurographics2016Fur_Smaller.pdf +void mx_chiang_hair_absorption_from_color(vec3 color, float betaN, out vec3 absorption) +{ + float b2 = betaN* betaN; + float b4 = b2 * b2; + float b_fac = + 5.969 - + (0.215 * betaN) + + (2.532 * b2) - + (10.73 * b2 * betaN) + + (5.574 * b4) + + (0.245 * b4 * betaN); + vec3 sigma = log(min(max(color, 0.001), vec3(1.0))) / b_fac; + absorption = sigma * sigma; +} + +void mx_chiang_hair_roughness( + float longitudinal, + float azimuthal, + float scale_TT, // empirical roughenss scale from Marschner et al. (2003). + float scale_TRT, // default: scale_TT = 0.5, scale_TRT = 2.0 + out vec2 roughness_R, + out vec2 roughness_TT, + out vec2 roughness_TRT +) +{ + float lr = clamp(longitudinal, 0.001, 1.0); + float ar = clamp(azimuthal, 0.001, 1.0); + + // longitudinal variance + float v = 0.726 * lr + 0.812 * lr * lr + 3.7 * pow(lr, 20); + v = v * v; + + float s = 0.265 * ar + 1.194 * ar * ar + 5.372 * pow(ar, 22); + + roughness_R = vec2(v, s); + roughness_TT = vec2(v * scale_TT * scale_TT, s); + roughness_TRT = vec2(v * scale_TRT * scale_TRT, s); +} + +float mx_hair_transform_sin_cos(float x) +{ + return sqrt(max(1.0 - x * x, 0.0)); +} + +float mx_hair_I0(float x) +{ + float v = 1.0; + float n = 1.0; + float d = 1.0; + float f = 1.0; + float x2 = x * x; + for (int i = 0; i < 9 ; ++i) + { + d *= 4.0 * (f * f); + n *= x2; + v += n / d; + f += 1.0; + } + return v; +} + +float mx_hair_log_I0(float x) +{ + if (x > 12.0) + return x + 0.5 * (-log(2.0 * M_PI) + log(1.0 / x) + 1.0 / (8.0 * x)); + else + return log(mx_hair_I0(x)); +} + +float mx_hair_logistic(float x, float s) +{ + if (x > 0.0) + x = -x; + float f = exp(x / s); + return f / (s * (1.0 + f) * (1.0 + f)); +} + +float mx_hair_logistic_cdf(float x, float s) +{ + return 1.0 / (1.0 + exp(-x / s)); +} + +float mx_hair_trimmed_logistic(float x, float s, float a, float b) +{ + // the constant can be found in Chiang et al. (2016) Appendix A, eq. (12) + s *= 0.626657; // sqrt(M_PI/8) + return mx_hair_logistic(x, s) / (mx_hair_logistic_cdf(b, s) - mx_hair_logistic_cdf(a, s)); +} + +float mx_hair_phi(int p, float gammaO, float gammaT) +{ + return 2.0 * p * gammaT - 2.0 * gammaO + p * M_PI; +} + +float mx_hair_longitudinal_scattering( // Mp + float sinThetaI, + float cosThetaI, + float sinThetaO, + float cosThetaO, + float v +) +{ + float inv_v = 1.0 / v; + float a = cosThetaO * cosThetaI * inv_v; + float b = sinThetaO * sinThetaI * inv_v; + if (v < 0.1) + return exp(mx_hair_log_I0(a) - b - inv_v + 0.6931 + log(0.5 * inv_v)); + else + return ((exp(-b) * mx_hair_I0(a)) / (2.0 * v * sinh(inv_v))); +} + +float mx_hair_azimuthal_scattering( // Np + float phi, + int p, + float s, + float gammaO, + float gammaT +) +{ + if (p >= 3) + return float(0.5 / M_PI); + + float dphi = phi - mx_hair_phi(p, gammaO, gammaT); + if (isinf(dphi)) + return float(0.5 / M_PI); + + while (dphi > M_PI) dphi -= (2.0 * M_PI); + while (dphi < (-M_PI)) dphi += (2.0 * M_PI); + + return mx_hair_trimmed_logistic(dphi, s, -M_PI, M_PI); +} + +void mx_hair_alpha_angles( + float alpha, + float sinThetaI, + float cosThetaI, + out vec2 angles[4] +) +{ + // 0:R, 1:TT, 2:TRT, 3:TRRT+ + for (int i = 0; i <= 3; ++i) + { + if (alpha == 0.0 || i == 3) + angles[i] = vec2(sinThetaI, cosThetaI); + else + { + float m = 2.0 - float(i) * 3.0; + float sa = sin(m * alpha); + float ca = cos(m * alpha); + angles[i].x = sinThetaI * ca + cosThetaI * sa; + angles[i].y = cosThetaI * ca - sinThetaI * sa; + } + } +} + +void mx_hair_attenuation(float f, vec3 T, out vec3 Ap[4]) // Ap +{ + // 0:R, 1:TT, 2:TRT, 3:TRRT+ + Ap[0] = vec3(f); + Ap[1] = (1.0 - f) * (1.0 - f) * T; + Ap[2] = Ap[1] * T * f; + Ap[3] = Ap[2] * T * f / (vec3(1.0) - T * f); +} + +vec3 mx_chiang_hair_bsdf( + vec3 L, + vec3 V, + vec3 tint_R, + vec3 tint_TT, + vec3 tint_TRT, + float ior, + vec2 roughness_R, + vec2 roughness_TT, + vec2 roughness_TRT, + float cuticle_angle, + vec3 absorption_coefficient, + vec3 N, + vec3 X +) +{ + N = mx_forward_facing_normal(N, V); + X = normalize(X - dot(X, N) * N); + vec3 Y = cross(N, X); + + float sinThetaO = dot(V, X); + float sinThetaI = dot(L, X); + float cosThetaO = mx_hair_transform_sin_cos(sinThetaO); + float cosThetaI = mx_hair_transform_sin_cos(sinThetaI); + + float y1 = dot(L, N); + float x1 = dot(L, Y); + float y2 = dot(V, N); + float x2 = dot(V, Y); + float phi = atan(y1 * x2 - y2 * x1, x1 * x2 + y1 * y2); + + vec3 k1_p = normalize(V - X * dot(V, X)); + float cosGammaO = dot(N, k1_p); + float sinGammaO = mx_hair_transform_sin_cos(cosGammaO); + if (dot(k1_p, Y) > 0.0) + sinGammaO = -sinGammaO; + float gammaO = asin(sinGammaO); + + float sinThetaT = sinThetaO / ior; + float cosThetaT = mx_hair_transform_sin_cos(sinThetaT); + float etaP = sqrt(max(ior * ior - sinThetaO * sinThetaO, 0.0)) / max(cosThetaO, 1e-8); + float sinGammaT = max(min(sinGammaO / etaP, 1.0), -1.0); + float cosGammaT = sqrt(1.0 - sinGammaT * sinGammaT); + float gammaT = asin(sinGammaT); + + // attenuation + vec3 Ap[4]; + float fresnel = mx_fresnel_dielectric(cosThetaO * cosGammaO, ior); + vec3 T = exp(-absorption_coefficient * (2.0 * cosGammaT / cosThetaT)); + mx_hair_attenuation(fresnel, T, Ap); + + // parameters for each lobe + vec2 angles[4]; + float alpha = cuticle_angle * M_PI - (M_PI / 2.0); // remap [0, 1] to [-PI/2, PI/2] + mx_hair_alpha_angles(alpha, sinThetaI, cosThetaI, angles); + + vec3 tint[4] = vec3[](tint_R, tint_TT, tint_TRT, tint_TRT); + + roughness_R = clamp(roughness_R, 0.001, 1.0); + roughness_TT = clamp(roughness_TT, 0.001, 1.0); + roughness_TRT = clamp(roughness_TRT, 0.001, 1.0); + vec2 vs[4] = vec2[](roughness_R, roughness_TT, roughness_TRT, roughness_TRT); + + // R, TT, TRT, TRRT+ + vec3 F = vec3(0.0); + for (int i = 0; i <= 3; ++i) + { + if (all(lessThanEqual(tint[i], vec3(0.0)))) + continue; + + float Mp = mx_hair_longitudinal_scattering(angles[i].x, angles[i].y, sinThetaO, cosThetaO, vs[i].x); + float Np = (i == 3) ? (1.0 / 2.0 * M_PI) : mx_hair_azimuthal_scattering(phi, i, vs[i].y, gammaO, gammaT); + F += Mp * Np * tint[i] * Ap[i]; + } + + return F; +} + +void mx_chiang_hair_bsdf_reflection( + vec3 L, + vec3 V, + vec3 P, + float occlusion, + vec3 tint_R, + vec3 tint_TT, + vec3 tint_TRT, + float ior, + vec2 roughness_R, + vec2 roughness_TT, + vec2 roughness_TRT, + float cuticle_angle, + vec3 absorption_coefficient, + vec3 N, + vec3 X, + inout BSDF bsdf +) +{ + vec3 F = mx_chiang_hair_bsdf( + L, + V, + tint_R, + tint_TT, + tint_TRT, + ior, + roughness_R, + roughness_TT, + roughness_TRT, + cuticle_angle, + absorption_coefficient, + N, + X + ); + + bsdf.throughput = vec3(0.0); + bsdf.response = F * occlusion * M_PI_INV; +} + +void mx_chiang_hair_bsdf_indirect( + vec3 V, + vec3 tint_R, + vec3 tint_TT, + vec3 tint_TRT, + float ior, + vec2 roughness_R, + vec2 roughness_TT, + vec2 roughness_TRT, + float cuticle_angle, + vec3 absorption_coefficient, + vec3 N, + vec3 X, + inout BSDF bsdf +) +{ + // this indirect lighing is *very* rough approximation + + N = mx_forward_facing_normal(N, V); + + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + FresnelData fd = mx_init_fresnel_dielectric(ior, 0.0, 1.0); + vec3 F = mx_compute_fresnel(NdotV, fd); + + vec2 roughness = (roughness_R + roughness_TT + roughness_TRT) / vec2(3.0); // ? + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + + // use ggx because the environment map for FIS is preintegrated with ggx + float F0 = mx_ior_to_f0(ior); + vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); + vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp; + + vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, 0, fd); + vec3 tint = (tint_R + tint_TT + tint_TRT) / vec3(3.0); // ? + + bsdf.throughput = vec3(0.0); + bsdf.response = Li * comp * tint; +} diff --git a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx index 2a23886640..1c495cb4bd 100644 --- a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx +++ b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx @@ -25,6 +25,9 @@ + + + @@ -74,4 +77,13 @@ + + + + + + + + + diff --git a/libraries/pbrlib/pbrlib_defs.mtlx b/libraries/pbrlib/pbrlib_defs.mtlx index 2e71f80611..0bb75716e6 100644 --- a/libraries/pbrlib/pbrlib_defs.mtlx +++ b/libraries/pbrlib/pbrlib_defs.mtlx @@ -136,6 +136,25 @@ + + + + + + + + + + + + + + + + @@ -404,4 +423,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx new file mode 100644 index 0000000000..056c79b554 --- /dev/null +++ b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx new file mode 100644 index 0000000000..8d95ffe63f --- /dev/null +++ b/resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx new file mode 100644 index 0000000000..056c79b554 --- /dev/null +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index db75a5ddf6..12a1f33868 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -91,9 +91,14 @@ TEST_CASE("GenShader: MDL Implementation Check", "[genmdl]") mx::StringSet generatorSkipNodeTypes; generatorSkipNodeTypes.insert("light"); + mx::StringSet generatorSkipNodeDefs; + generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); + generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); + generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); + generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 35); } diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h index f40254c5f4..1e617f73fb 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h @@ -49,6 +49,10 @@ class MdlShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester // df_cuda will currently hang on rendering one of the shaders in this file _skipFiles.insert("heighttonormal_in_nodegraph.mtlx"); } + + _skipFiles.insert("hair_bsdf.mtlx"); + _skipFiles.insert("hair_surfaceshader.mtlx"); + ShaderGeneratorTester::addSkipFiles(); } diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp index b0309ea44d..414bc3dd5d 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp @@ -84,7 +84,12 @@ TEST_CASE("GenShader: MSL Implementation Check", "[genmsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 30); + generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); + generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); + generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); + generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); + + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 34); } TEST_CASE("GenShader: MSL Unique Names", "[genmsl]") diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h index 78cb7a8f4e..692c283fda 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h @@ -41,6 +41,12 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester ParentClass::addSkipNodeDefs(); } + void addSkipFiles() override + { + _skipFiles.insert("hair_bsdf.mtlx"); + _skipFiles.insert("hair_surfaceshader.mtlx"); + } + void setupDependentLibraries() override { ParentClass::setupDependentLibraries(); diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp index f31c3d2a9b..c89f9ab19d 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp @@ -87,9 +87,14 @@ TEST_CASE("GenShader: OSL Implementation Check", "[genosl]") mx::StringSet generatorSkipNodeTypes; generatorSkipNodeTypes.insert("light"); + mx::StringSet generatorSkipNodeDefs; + generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); + generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); + generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); + generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 35); } TEST_CASE("GenShader: OSL Unique Names", "[genosl]") diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h index a4ccdc2003..f02f750d26 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h @@ -42,6 +42,13 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { _skipLibraryFiles.insert( "pbrlib_genosl_arnold_impl.mtlx" ); } + + void addSkipFiles() override + { + _skipFiles.insert("hair_bsdf.mtlx"); + _skipFiles.insert("hair_surfaceshader.mtlx"); + } + // Ignore light shaders in the document for OSL void findLights(mx::DocumentPtr /*doc*/, std::vector& lights) override { From 0a5defaf4773a1fbf100182368324023cdd2a38b Mon Sep 17 00:00:00 2001 From: Rafal Jaroszkiewicz Date: Thu, 19 Sep 2024 17:24:07 -0400 Subject: [PATCH 060/137] Fix version upgrade for ND_normalmap_vector2 (#2022) The upgrade code for the normalmap node was indiscriminately renaming all node definitions to "ND_normalmap_float". This included "ND_normalmap_vecto2" nodes, whose nodedef should not be renamed. This commit fixes that, limiting the renaming only to "ND_normalmap", based on the type of the "scale" input, which is the only differentiating factor between the two definitions. --- source/MaterialXCore/Version.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source/MaterialXCore/Version.cpp b/source/MaterialXCore/Version.cpp index 34d9b3b02c..62f83a5660 100644 --- a/source/MaterialXCore/Version.cpp +++ b/source/MaterialXCore/Version.cpp @@ -1317,7 +1317,13 @@ void Document::upgradeVersion() else if (nodeCategory == "normalmap") { // ND_normalmap was renamed to ND_normalmap_float - node->setNodeDefString("ND_normalmap_float"); + NodeDefPtr nodeDef = getShaderNodeDef(node); + InputPtr scaleInput = node->getInput("scale"); + if ((nodeDef && nodeDef->getName() == "ND_normalmap") || + (scaleInput && scaleInput->getType() == "float")) + { + node->setNodeDefString("ND_normalmap_float"); + } node->removeInput("space"); From 80e1b56bdd718f44e0b2d3999826000088f99973 Mon Sep 17 00:00:00 2001 From: Niklas Harrysson Date: Sat, 21 Sep 2024 20:30:54 +0200 Subject: [PATCH 061/137] Fix the call to anisotropic_vdf closure in OSL (#2016) Update the implementation of `anisotropic_vdf` node to call the corresponding closure in OSL. --- libraries/pbrlib/genosl/mx_anisotropic_vdf.osl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl b/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl index 6b2a7d5298..eb48e72e65 100644 --- a/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl +++ b/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl @@ -1,6 +1,8 @@ -void mx_anisotropic_vdf(vector absorption, vector scattering, float anisotropy, output VDF vdf) +void mx_anisotropic_vdf(color absorption, color scattering, float anisotropy, output VDF vdf) { - // TODO: Need to remap parameters to match the new closure, - // or change the MaterialX spec to OSL parameterization. - vdf = 0; + // Convert from absorption and scattering coefficients to + // extinction coefficient and single-scattering albedo. + color extinction = absorption + scattering; + color albedo = scattering / extinction; + vdf = anisotropic_vdf(albedo, extinction, anisotropy); } From e6b96502e965392c8851bab9de847d3135a48396 Mon Sep 17 00:00:00 2001 From: Dhruv Govil Date: Wed, 25 Sep 2024 09:50:50 -0700 Subject: [PATCH 062/137] Add support for Apple framework builds (#2020) This PR makes a few changes that have been derived from a corresponding PR to USD https://github.com/PixarAnimationStudios/OpenUSD/pull/2969 The changes are: 1. Deprecates `MATERIALX_BUILD_IOS` in favor of using `CMAKE_SYSTEM_NAME`. This allows for better support for iPhone derived targets like visionOS. Earlier this would force it to iOS which can cause subtle issues when compiled against other SDKs. See https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos 2. Changes `TARGET_OS_IOS` define to `TARGET_OS_IPHONE` which is more correct to support iPhone derivatives. See https://chaosinmotion.com/2021/08/02/things-to-remember-compiler-conditionals-for-macos-ios-etc/ . But the gist is `TARGET_OS_IOS` refers specifically to the modern iOS/iPadOS SDK, whereas `TARGET_OS_IPHONE` refers to all Apple SDKs that derived from the original iPhone. 3. Add support for building as a Framework. This creates a special directory structure that streamlines embedding of MaterialX within Apps on Apple platforms to just dragging the project into the app in Xcode. No other linker and compiler configuration is necessary. See Framework notes below. --- .github/workflows/main.yml | 2 +- CMakeLists.txt | 52 +++++++- cmake/modules/AppleFrameworkBuild.zsh.in | 113 ++++++++++++++++++ cmake/modules/Info.plist.in | 24 ++++ source/MaterialXFormat/Util.cpp | 26 +++- source/MaterialXRenderHw/CMakeLists.txt | 4 +- source/MaterialXRenderHw/SimpleWindowIOS.cpp | 2 +- source/MaterialXRenderHw/SimpleWindowMac.cpp | 2 +- .../MaterialXRenderHw/WindowCocoaWrappers.m | 2 +- source/MaterialXRenderHw/WindowWrapper.cpp | 2 +- source/MaterialXRenderMsl/CMakeLists.txt | 4 +- 11 files changed, 220 insertions(+), 13 deletions(-) create mode 100644 cmake/modules/AppleFrameworkBuild.zsh.in create mode 100644 cmake/modules/Info.plist.in diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c9750eb355..1ffd6e3148 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -96,7 +96,7 @@ jobs: compiler: xcode compiler_version: "15.4" python: None - cmake_config: -DMATERIALX_BUILD_IOS=ON -DCMAKE_OSX_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path` -DCMAKE_OSX_ARCHITECTURES=arm64 + cmake_config: -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path` -DCMAKE_OSX_ARCHITECTURES=arm64 - name: Windows_VS2019_Win32_Python37 os: windows-2019 diff --git a/CMakeLists.txt b/CMakeLists.txt index f0d21e6f0b..59afaca01e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,10 +59,27 @@ option(MATERIALX_COVERAGE_ANALYSIS "Build MaterialX libraries with coverage anal 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." OFF) -option(MATERIALX_BUILD_IOS "Build MaterialX for iOS." OFF) +option(MATERIALX_BUILD_IOS "Build MaterialX for iOS. (Deprecated. Set CMAKE_SYSTEM_NAME instead)" OFF) +set(MATERIALX_BUILD_APPLE_EMBEDDED OFF) if (MATERIALX_BUILD_IOS) + MESSAGE(WARNING "The MATERIALX_BUILD_IOS is deprecated. Set the CMAKE_SYSTEM_NAME to the platform instead") set(CMAKE_SYSTEM_NAME iOS) - add_definitions(-DTARGET_OS_IOS=1) +endif() + +# Cross Compilation detection as defined in CMake docs +# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos +# Note: All these SDKs may not be supported by MaterialX +set(__build_apple_framework OFF) +if (CMAKE_SYSTEM_NAME MATCHES "iOS" + OR CMAKE_SYSTEM_NAME MATCHES "tvOS" + OR CMAKE_SYSTEM_NAME MATCHES "visionOS" + OR CMAKE_SYSTEM_NAME MATCHES "watchOS") + set(MATERIALX_BUILD_APPLE_EMBEDDED ON) + set(__build_apple_framework ${MATERIALX_BUILD_SHARED_LIBS}) + # TARGET_OS_IPHONE refers to all IPHONE derived platforms + # https://chaosinmotion.com/2021/08/02/things-to-remember-compiler-conditionals-for-macos-ios-etc/ + # This should be auto-defined, but leaving it in here because it was historically defined + add_definitions(-DTARGET_OS_IPHONE=1) set(MATERIALX_BUILD_MONOLITHIC ON) set(MATERIALX_BUILD_PYTHON OFF) set(MATERIALX_BUILD_VIEWER OFF) @@ -73,6 +90,18 @@ if (MATERIALX_BUILD_IOS) set(MATERIALX_BUILD_TESTS OFF) endif() +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" CACHE STRING "The Codesigning identity needed to sign compiled objects") +option(MATERIALX_BUILD_APPLE_FRAMEWORK "Build MaterialX as an Apple Framework" ${__build_apple_framework}) +if (MATERIALX_BUILD_APPLE_FRAMEWORK) + add_definitions(-DBUILD_APPLE_FRAMEWORK) + set(MATERIALX_BUILD_MONOLITHIC ON) + set(MATERIALX_BUILD_PYTHON OFF) + set(MATERIALX_BUILD_VIEWER OFF) + set(MATERIALX_BUILD_GRAPH_EDITOR OFF) + set(MATERIALX_BUILD_TESTS OFF) + set(MATERIALX_BUILD_SHARED_LIBS ON) +endif() + if (MATERIALX_BUILD_JS) set(MATERIALX_BUILD_RENDER OFF) set(MATERIALX_BUILD_TESTS OFF) @@ -163,6 +192,7 @@ mark_as_advanced(MATERIALX_INSTALL_STDLIB_PATH) mark_as_advanced(MATERIALX_BUILD_JS) mark_as_advanced(MATERIALX_EMSDK_PATH) mark_as_advanced(MATERIALX_BUILD_IOS) +mark_as_advanced(MATERIALX_BUILD_APPLE_FRAMEWORK) if (MATERIALX_BUILD_GEN_MDL) mark_as_advanced(MATERIALX_MDLC_EXECUTABLE) mark_as_advanced(MATERIALX_MDL_RENDER_EXECUTABLE) @@ -496,6 +526,24 @@ if (MATERIALX_BUILD_MONOLITHIC) # Note : we don't install the headers etc. here, and rely on each separate modules CMakeLists.txt # to do that installation, thus we respect the build options configuration, and only install # the headers for the modules we've built in to the monolithic build. + + # Finally do the framework build if requested + # This uses a zsh script since zsh is guaranteed to exist on systems + if(MATERIALX_BUILD_APPLE_FRAMEWORK) + # Conform cmake formats to zsh expected formats + set(__embedded_build "false") + if (MATERIALX_BUILD_APPLE_EMBEDDED) + set(__embedded_build "true") + endif() + + # Install the Info.plist and shell script + math(EXPR CFBUNDLEVERSION "${MATERIALX_MAJOR_VERSION} * 10000 + ${MATERIALX_MINOR_VERSION} * 100 + ${MATERIALX_BUILD_VERSION}") + configure_file(cmake/modules/Info.plist.in "${PROJECT_BINARY_DIR}/Info.plist" @ONLY) + configure_file(cmake/modules/AppleFrameworkBuild.zsh.in "${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh" @ONLY) + + # Run the shell script for the primary configuration + install(CODE "execute_process(COMMAND zsh ${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh )") + endif() endif() endif() diff --git a/cmake/modules/AppleFrameworkBuild.zsh.in b/cmake/modules/AppleFrameworkBuild.zsh.in new file mode 100644 index 0000000000..75b0dba0eb --- /dev/null +++ b/cmake/modules/AppleFrameworkBuild.zsh.in @@ -0,0 +1,113 @@ +#!/bin/zsh + +# Creates an Apple framework for the given platform type +# documentation: https://developer.apple.com/documentation/bundleresources/placing_content_in_a_bundle +# https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html +echo "⌛️ Creating MaterialX.framework ..." + +# Variables are substituted by CMake +CMAKE_INSTALL_PREFIX="@CMAKE_INSTALL_PREFIX@" +PROJECT_BINARY_DIR="@PROJECT_BINARY_DIR@" + +FRAMEWORK_NAME="MaterialX" +FRAMEWORK_DIR="${CMAKE_INSTALL_PREFIX}/frameworks/${FRAMEWORK_NAME}.framework" +FRAMEWORK_LIBRARIES_DIR="${FRAMEWORK_DIR}/Libraries" +FRAMEWORK_ROOT_LIBRARY_NAME="libMaterialX.@MATERIALX_LIBRARY_VERSION@.dylib" +EMBEDDED_BUILD=@__embedded_build@ +FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}" +MATERIALX_SOURCE_LIBRARIES="${CMAKE_INSTALL_PREFIX}/libraries/" +BUNDLE_IDENTIFIER="org.aswf.materialx" +CODESIGN_ID="@CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY@" +OLD_RC_PATH="${CMAKE_INSTALL_PREFIX}/lib" + +function fix_linkage() { + readonly file=${1:?"A file path must be specified."} + readonly prepend="${FRAMEWORK_NAME}.framework/Libraries" + filename=$(basename ${file}) + # First, change the install name. This corresponds to LC_ID_DYLIB. + install_name_tool -id "@rpath/${prepend}/${filename}" ${file} + + parts=("${(@f)$(otool -l ${file})}") + for line in ${parts}; do + dylib_name="" + [[ $line =~ ' *name @rpath/(.*\.dylib)' ]] && dylib_name=$match[1] + if [ -n "${dylib_name}" ]; then + install_name_tool -change "@rpath/${dylib_name}" "@rpath/${prepend}/${dylib_name}" "${file}" + fi + if [[ $line == *"${OLD_RC_PATH}"* ]]; then + install_name_tool -delete_rpath ${OLD_RC_PATH} ${file} + fi + done + + codesign -f -s ${CODESIGN_ID} ${file} +} + +# Remove the existing directory if it exists +if [ -d ${FRAMEWORK_DIR} ]; then + echo "Removing existing framework"; + rm -Rf ${FRAMEWORK_DIR}; +fi + +# Create the parent directory +echo "Creating Framework Directory: ${FRAMEWORK_DIR}" +mkdir -p ${FRAMEWORK_DIR} + +if [ "$EMBEDDED_BUILD" = true ];then + FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}/Resources" + FRAMEWORK_PLIST_LOCATION="${FRAMEWORK_DIR}/Info.plist" + FRAMEWORK_HEADERS_DIR="${FRAMEWORK_DIR}/Headers" + FRAMEWORK_LIB_PATH=""${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"" +else + FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}/Versions/A/Resources/" + FRAMEWORK_PLIST_LOCATION="${FRAMEWORK_DIR}/Versions/A/Resources/Info.plist" + FRAMEWORK_HEADERS_DIR="${FRAMEWORK_DIR}/Versions/A/Headers" + FRAMEWORK_LIB_PATH="${FRAMEWORK_DIR}/Versions/A/${FRAMEWORK_NAME}" +fi + +echo "Creating Resources Root: ${FRAMEWORK_RESOURCES_DIR}" +mkdir -p ${FRAMEWORK_RESOURCES_DIR} + +echo "Creating Headers Root: ${FRAMEWORK_HEADERS_DIR}" +mkdir -p ${FRAMEWORK_HEADERS_DIR} + +# Copy the plist over +echo "Copying files into ${FRAMEWORK_DIR}" +ditto "${PROJECT_BINARY_DIR}/Info.plist" "${FRAMEWORK_PLIST_LOCATION}" + +# Copy the primary directories over +ditto "${CMAKE_INSTALL_PREFIX}/include/" ${FRAMEWORK_HEADERS_DIR} +ditto "${CMAKE_INSTALL_PREFIX}/libraries/" "${FRAMEWORK_RESOURCES_DIR}/libraries" +ditto "${CMAKE_INSTALL_PREFIX}/resources" "${FRAMEWORK_RESOURCES_DIR}/render" + +cp "${CMAKE_INSTALL_PREFIX}/lib/${FRAMEWORK_ROOT_LIBRARY_NAME}" "${FRAMEWORK_LIB_PATH}" + +# Setup symlinks +if [ "$EMBEDDED_BUILD" = false ];then + (cd "${FRAMEWORK_DIR}/Versions" && ln -s "A" "Current") + (cd ${FRAMEWORK_DIR} && ln -s "Versions/Current/Resources" "Resources") + (cd ${FRAMEWORK_DIR} && ln -s "Versions/Current/Headers" "Headers") + (cd ${FRAMEWORK_DIR} && ln -s "Versions/Current/${FRAMEWORK_NAME}" ${FRAMEWORK_NAME}) +fi + +# Fix the linkage on the primary dylib +fix_linkage "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" +install_name_tool -id "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" +install_name_tool -change "@rpath/${FRAMEWORK_NAME}.framework/Libraries/${FRAMEWORK_NAME}" "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" + +# Frameworks require all includes to use the framework name as the prefix for automatic discovery +echo "Modifying headers..." +HEADER_SET="" +for i in $(cd $FRAMEWORK_HEADERS_DIR && ls -d */ | cut -f1 -d'/');do + HEADER_SET+="${i}|" +done; +# Sed on macOS is POSIX compliant and so uses different args than GNU +# Things to be aware of are [[:<:]] and [[:>:]] are for word boundaries and spaces are explicit literals +INCLUDE_PATTERN="^# *include [\"|<]([[:<:]](${HEADER_SET::-1})[[:>:]].*)[\"|>].*$" +find ${FRAMEWORK_HEADERS_DIR} -type f -name "*.h*" -print0 | xargs -0 sed -i "" -E "s,${INCLUDE_PATTERN},#include <${FRAMEWORK_NAME}/\1>,g" + +# Sign the final framework +echo "Codesigning the framework..." +set -e +codesign --force --sign ${CODESIGN_ID} --generate-entitlement-der --identifier ${BUNDLE_IDENTIFIER} --verbose ${FRAMEWORK_DIR} + +echo "✅ Finished creating framework at ${FRAMEWORK_DIR}" diff --git a/cmake/modules/Info.plist.in b/cmake/modules/Info.plist.in new file mode 100644 index 0000000000..1293cdcbbf --- /dev/null +++ b/cmake/modules/Info.plist.in @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + MaterialX + CFBundleIdentifier + org.aswf.materialx + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + MaterialX + CFBundlePackageType + FMWK + CFBundleShortVersionString + @MATERIALX_LIBRARY_VERSION@ + CFBundleVersion + @CFBUNDLEVERSION@ + CSResourcesFileMapped + + + diff --git a/source/MaterialXFormat/Util.cpp b/source/MaterialXFormat/Util.cpp index 48ded1d6b1..3fc64e3819 100644 --- a/source/MaterialXFormat/Util.cpp +++ b/source/MaterialXFormat/Util.cpp @@ -9,6 +9,10 @@ #include #include +#if defined(__APPLE__) && defined(BUILD_APPLE_FRAMEWORK) + #include +#endif + MATERIALX_NAMESPACE_BEGIN string readFile(const FilePath& filePath) @@ -226,15 +230,33 @@ FileSearchPath getDefaultDataSearchPath() { const FilePath REQUIRED_LIBRARY_FOLDER("libraries/targets"); FilePath currentPath = FilePath::getModulePath(); + + FileSearchPath searchPath; + #if defined(BUILD_APPLE_FRAMEWORK) + const FilePath FRAMEWORK_RESOURCES("Resources"); + + Dl_info info; + if (dladdr(reinterpret_cast(&getDefaultDataSearchPath), &info)) + { + FilePath path = FilePath(info.dli_fname); + if (!path.isEmpty()) + { + path = path.getParentPath(); + searchPath.append(path / FRAMEWORK_RESOURCES); + } + } + #endif + while (!currentPath.isEmpty()) { if ((currentPath / REQUIRED_LIBRARY_FOLDER).exists()) { - return FileSearchPath(currentPath); + searchPath.append(FileSearchPath(currentPath)); + break; } currentPath = currentPath.getParentPath(); } - return FileSearchPath(); + return searchPath; } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXRenderHw/CMakeLists.txt b/source/MaterialXRenderHw/CMakeLists.txt index a8a806d1b6..d3adfb5b8f 100644 --- a/source/MaterialXRenderHw/CMakeLists.txt +++ b/source/MaterialXRenderHw/CMakeLists.txt @@ -3,7 +3,7 @@ file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") if(APPLE) - if (NOT MATERIALX_BUILD_IOS) + if (NOT MATERIALX_BUILD_APPLE_EMBEDDED) find_library(COCOA_FRAMEWORK Cocoa) endif() elseif(UNIX) @@ -31,7 +31,7 @@ if(APPLE) PUBLIC "-framework Foundation" "-framework Metal") - if (NOT MATERIALX_BUILD_IOS) + if (NOT MATERIALX_BUILD_APPLE_EMBEDDED) target_link_libraries(${TARGET_NAME} PUBLIC "-framework Cocoa" diff --git a/source/MaterialXRenderHw/SimpleWindowIOS.cpp b/source/MaterialXRenderHw/SimpleWindowIOS.cpp index 1d4189b2ab..4efcebfa64 100644 --- a/source/MaterialXRenderHw/SimpleWindowIOS.cpp +++ b/source/MaterialXRenderHw/SimpleWindowIOS.cpp @@ -5,7 +5,7 @@ #if defined(__APPLE__) -#ifdef TARGET_OS_IOS +#ifdef TARGET_OS_IPHONE #include diff --git a/source/MaterialXRenderHw/SimpleWindowMac.cpp b/source/MaterialXRenderHw/SimpleWindowMac.cpp index a04d1f49ae..d7035f8191 100644 --- a/source/MaterialXRenderHw/SimpleWindowMac.cpp +++ b/source/MaterialXRenderHw/SimpleWindowMac.cpp @@ -5,7 +5,7 @@ #if defined(__APPLE__) -#ifndef TARGET_OS_IOS +#ifndef TARGET_OS_IPHONE #include #include diff --git a/source/MaterialXRenderHw/WindowCocoaWrappers.m b/source/MaterialXRenderHw/WindowCocoaWrappers.m index a012966a8f..3283008300 100644 --- a/source/MaterialXRenderHw/WindowCocoaWrappers.m +++ b/source/MaterialXRenderHw/WindowCocoaWrappers.m @@ -5,7 +5,7 @@ #if defined (__APPLE__) -#ifndef TARGET_OS_IOS +#ifndef TARGET_OS_IPHONE #import #import diff --git a/source/MaterialXRenderHw/WindowWrapper.cpp b/source/MaterialXRenderHw/WindowWrapper.cpp index 654498d5cd..e2c059799c 100644 --- a/source/MaterialXRenderHw/WindowWrapper.cpp +++ b/source/MaterialXRenderHw/WindowWrapper.cpp @@ -84,7 +84,7 @@ WindowWrapper::WindowWrapper(ExternalWindowHandle externalHandle, DisplayHandle display) { _externalHandle = externalHandle; -#ifndef TARGET_OS_IOS +#ifndef TARGET_OS_IPHONE // Cache a pointer to the window. _internalHandle = NSUtilGetView(externalHandle); #else diff --git a/source/MaterialXRenderMsl/CMakeLists.txt b/source/MaterialXRenderMsl/CMakeLists.txt index 014c99eaae..741ce9d62a 100644 --- a/source/MaterialXRenderMsl/CMakeLists.txt +++ b/source/MaterialXRenderMsl/CMakeLists.txt @@ -6,7 +6,7 @@ if(POLICY CMP0072) endif() if(APPLE) - if(NOT MATERIALX_BUILD_IOS) + if(NOT MATERIALX_BUILD_APPLE_EMBEDDED) find_library(COCOA_FRAMEWORK Cocoa) find_package(OpenGL REQUIRED) endif() @@ -50,7 +50,7 @@ if(MSVC) PUBLIC Opengl32) elseif(APPLE) - if(NOT MATERIALX_BUILD_IOS) + if(NOT MATERIALX_BUILD_APPLE_EMBEDDED) target_link_libraries(${TARGET_NAME} PUBLIC "-framework Cocoa" From 8fef28d8cddc1b8aab1676e2f0a8703a8461b2fe Mon Sep 17 00:00:00 2001 From: Ashwin Bhat <1727158+ashwinbhat@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:14:07 -0700 Subject: [PATCH 063/137] Improvements to benchmark tests (#2030) - Update shaderGenPerformanceTest to use improved MaterialX API workflows. - Add a readme update to cover Benchmark tests. --- .../MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp | 8 ++++---- source/MaterialXTest/README.md | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 848348066c..6dc24fc15c 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -316,8 +316,7 @@ void testUniqueNames(mx::GenContext& context, const std::string& stage) void shaderGenPerformanceTest(mx::GenContext& context) { mx::DocumentPtr nodeLibrary = mx::createDocument(); - mx::FilePath currentPath = mx::FilePath::getCurrentPath(); - const mx::FileSearchPath libSearchPath(currentPath); + const mx::FileSearchPath libSearchPath(mx::getDefaultDataSearchPath()); // Load the standard libraries. loadLibraries({ "libraries" }, libSearchPath, nodeLibrary); @@ -351,8 +350,9 @@ void shaderGenPerformanceTest(mx::GenContext& context) } // Read mtlx documents + mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); mx::FilePathVec testRootPaths; - testRootPaths.push_back("resources/Materials/Examples/StandardSurface"); + testRootPaths.push_back(searchPath.find("resources/Materials/Examples/StandardSurface")); std::vector loadedDocuments; mx::StringVec documentsPaths; @@ -367,7 +367,7 @@ void shaderGenPerformanceTest(mx::GenContext& context) REQUIRE(loadedDocuments.size() > 0); REQUIRE(loadedDocuments.size() == documentsPaths.size()); - // Shuffle the order of documents and perform document library import validatation and shadergen + // Shuffle the order of documents and perform document library import validation and shadergen std::mt19937 rng(0); std::shuffle(loadedDocuments.begin(), loadedDocuments.end(), rng); for (const auto& doc : loadedDocuments) diff --git a/source/MaterialXTest/README.md b/source/MaterialXTest/README.md index 8cd732f2cf..6de3064ec8 100644 --- a/source/MaterialXTest/README.md +++ b/source/MaterialXTest/README.md @@ -82,3 +82,13 @@ When rendering tests are enabled through the `MATERIALX_TEST_RENDER` option, the #### HTML Render Comparisons - A `tests_to_html` Python script is provided in the [`python/MaterialXTest`](../../python/MaterialXTest) folder, which can be run to generate an HTML file comparing the rendered results in each shading language. - Example render comparisons may be found in [commits to the MaterialX repository](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1164), and we encourage developers to post their own results when making changes that have the potential to impact generated shaders. + +#### Benchmark Tests + +Processing MaterialX documents and generating shaders is an integral part of many pipelines. MaterialX benchmark testing using [Catch2 benchmark framework](https://github.com/catchorg/Catch2/blob/devel/docs/benchmarks.md) and can be enabled using `MATERIALX_BUILD_BENCHMARK_TESTS` CMake macro. + +Here is an example of how to run the benchmark test + + `MaterialXTest.exe "GenShader: GLSL Performance Test" --benchmark-samples 10` + +This will iterate and gather 10 samples of the test case and report low, mean and high timing results. From 70cb28de8b313371462eb9f0f3e4ec31e903e4a7 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 27 Sep 2024 15:45:40 -0700 Subject: [PATCH 064/137] Lock version of deploy action (#2033) This changelist updates our GitHub CI to lock the version of the web deployment action, as the head revision of this action is currently broken. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1ffd6e3148..d6baf5dc10 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -332,7 +332,7 @@ jobs: - name: Deploy Web Viewer if: matrix.build_javascript == 'ON' && github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@v4 + uses: JamesIves/github-pages-deploy-action@v4.6.4 with: branch: gh-pages folder: javascript/MaterialXView/dist From c3f4e5a2881cb7d1e67cbfceba1b67236d2dd30a Mon Sep 17 00:00:00 2001 From: Juan de Joya Date: Sat, 28 Sep 2024 19:21:34 +0200 Subject: [PATCH 065/137] Add keyboard shortcuts documentation to Viewer (#2026) Addressing issue #2011 with the creation of a popup button for helpful information and keyboard shortcuts. Help tooltips also included for all buttons except for selected geometry. Markdown doc also updated. --- source/MaterialXView/Viewer.cpp | 177 ++++++++++++++++++++++++-------- source/MaterialXView/Viewer.h | 2 +- 2 files changed, 134 insertions(+), 45 deletions(-) diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 71cccf36c8..c0d90d30a7 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -566,6 +566,7 @@ void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) { ng::Button* meshButton = new ng::Button(parent, label); meshButton->set_icon(FA_FOLDER); + meshButton->set_tooltip("Load a new geometry in the OBJ or glTF format."); meshButton->set_callback([this]() { m_process_events = false; @@ -593,6 +594,7 @@ void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& lab { ng::Button* materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_FOLDER); + materialButton->set_tooltip("Load a material document in the MTLX format."); materialButton->set_callback([this]() { m_process_events = false; @@ -610,6 +612,7 @@ void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& l { ng::Button* envButton = new ng::Button(parent, label); envButton->set_icon(FA_FOLDER); + envButton->set_tooltip("Load a lat-long environment light in the HDR format."); envButton->set_callback([this]() { m_process_events = false; @@ -635,6 +638,7 @@ void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& lab { ng::Button* materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_SAVE); + materialButton->set_tooltip("Save a material document in the MTLX format."); materialButton->set_callback([this]() { m_process_events = false; @@ -664,6 +668,7 @@ void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& la { ng::Button* editorButton = new ng::Button(parent, label); editorButton->set_flags(ng::Button::ToggleButton); + editorButton->set_tooltip("View or edit properties of the current material."); editorButton->set_change_callback([this](bool state) { _propertyEditor.setVisible(state); @@ -671,56 +676,138 @@ void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& la }); } +void Viewer::createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel) +{ + ng::GridLayout* documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, + ng::Alignment::Minimum, 13, 5); + documentationLayout->set_row_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); + + ng::Widget* documentationGroup = new ng::Widget(parent); + documentationGroup->set_layout(documentationLayout); + ng::Label* documentationLabel = new ng::Label(documentationGroup, "Documentation"); + documentationLabel->set_font_size(20); + documentationLabel->set_font("sans-bold"); + + ng::Button* shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); + shortcutsButton->set_flags(ng::Button::ToggleButton); + shortcutsButton->set_icon(FA_CARET_RIGHT); + shortcutsButton->set_fixed_width(230); + + ng::Widget* shortcutsTable = new ng::Widget(documentationGroup); + shortcutsTable->set_layout(new ng::GroupLayout(13)); + shortcutsTable->set_visible(false); + + // recompute layout when showing/hiding shortcuts. + shortcutsButton->set_change_callback([this, scrollPanel, shortcutsButton, + shortcutsTable](bool state) + { + shortcutsTable->set_visible(state); + shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); + scrollPanel->set_scroll(state ? 0.73f : 1.0f); + perform_layout(); + }); + + // 2 cell layout for (key, description) pair. + ng::GridLayout* gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, + ng::Alignment::Minimum, 2, 2); + gridLayout2->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); + + const std::vector> KEYBOARD_SHORTCUTS = + { + std::make_pair("R", "Reload the current material from file. " + "Hold SHIFT to reload all standard libraries as well."), + std::make_pair("G", "Save the current GLSL shader source to file."), + std::make_pair("O", "Save the current OSL shader source to file."), + std::make_pair("M", "Save the current MDL shader source to file."), + std::make_pair("L", "Load GLSL shader source from file. " + "Editing the source files before loading provides a way " + "to debug and experiment with shader source code."), + std::make_pair("D", "Save each node graph in the current material as a DOT file. " + "See www.graphviz.org for more details on this format."), + std::make_pair("F", "Capture the current frame and save to file."), + std::make_pair("W", "Create a wedge rendering and save to file. " + "See Advanced Settings for additional controls."), + std::make_pair("T", "Translate the current material to a different shading model. " + "See Advanced Settings for additional controls."), + std::make_pair("B", "Bake the current material to textures. " + "See Advanced Settings for additional controls."), + std::make_pair("UP","Select the previous geometry."), + std::make_pair("DOWN","Select the next geometry."), + std::make_pair("RIGHT", "Switch to the next material."), + std::make_pair("LEFT", "Switch to the previous material."), + std::make_pair("+", "Zoom in with the camera."), + std::make_pair("-", "Zoom out with the camera.") + }; + + for (const auto& shortcut : KEYBOARD_SHORTCUTS) + { + ng::Widget* twoColumns = new ng::Widget(shortcutsTable); + twoColumns->set_layout(gridLayout2); + + ng::Label* keyLabel = new ng::Label(twoColumns, shortcut.first); + keyLabel->set_font("sans-bold"); + keyLabel->set_font_size(16); + keyLabel->set_fixed_width(40); + + ng::Label* descriptionLabel = new ng::Label(twoColumns, shortcut.second); + descriptionLabel->set_font_size(16); + descriptionLabel->set_fixed_width(160); + } +} + void Viewer::createAdvancedSettings(Widget* parent) { ng::PopupButton* advancedButton = new ng::PopupButton(parent, "Advanced Settings"); advancedButton->set_icon(FA_TOOLS); advancedButton->set_chevron_icon(-1); + advancedButton->set_tooltip("Asset and rendering options."); ng::Popup* advancedPopupParent = advancedButton->popup(); advancedPopupParent->set_layout(new ng::GroupLayout()); ng::VScrollPanel* scrollPanel = new ng::VScrollPanel(advancedPopupParent); scrollPanel->set_fixed_height(500); ng::Widget* advancedPopup = new ng::Widget(scrollPanel); - advancedPopup->set_layout(new ng::GroupLayout(13)); + advancedPopup->set_layout(new ng::BoxLayout(ng::Orientation::Vertical)); - ng::Label* viewLabel = new ng::Label(advancedPopup, "Viewing Options"); + ng::Widget* settingsGroup = new ng::Widget(advancedPopup); + settingsGroup->set_layout(new ng::GroupLayout(13)); + ng::Label* viewLabel = new ng::Label(settingsGroup, "Viewing Options"); viewLabel->set_font_size(20); viewLabel->set_font("sans-bold"); - ng::CheckBox* drawEnvironmentBox = new ng::CheckBox(advancedPopup, "Draw Environment"); + ng::CheckBox* drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); drawEnvironmentBox->set_checked(_drawEnvironment); drawEnvironmentBox->set_callback([this](bool enable) { _drawEnvironment = enable; }); - ng::CheckBox* outlineSelectedGeometryBox = new ng::CheckBox(advancedPopup, "Outline Selected Geometry"); + ng::CheckBox* outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); outlineSelectedGeometryBox->set_checked(_outlineSelection); outlineSelectedGeometryBox->set_callback([this](bool enable) { _outlineSelection = enable; }); - ng::Label* renderLabel = new ng::Label(advancedPopup, "Render Options"); + ng::Label* renderLabel = new ng::Label(settingsGroup, "Render Options"); renderLabel->set_font_size(20); renderLabel->set_font("sans-bold"); - ng::CheckBox* transparencyBox = new ng::CheckBox(advancedPopup, "Render Transparency"); + ng::CheckBox* transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); transparencyBox->set_checked(_renderTransparency); transparencyBox->set_callback([this](bool enable) { _renderTransparency = enable; }); - ng::CheckBox* doubleSidedBox = new ng::CheckBox(advancedPopup, "Render Double-Sided"); + ng::CheckBox* doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); doubleSidedBox->set_checked(_renderDoubleSided); doubleSidedBox->set_callback([this](bool enable) { _renderDoubleSided = enable; }); - ng::CheckBox* importanceSampleBox = new ng::CheckBox(advancedPopup, "Environment FIS"); + ng::CheckBox* importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); importanceSampleBox->set_checked(_genContext.getOptions().hwSpecularEnvironmentMethod == mx::SPECULAR_ENVIRONMENT_FIS); _lightHandler->setUsePrefilteredMap(_genContext.getOptions().hwSpecularEnvironmentMethod != mx::SPECULAR_ENVIRONMENT_FIS); importanceSampleBox->set_callback([this](bool enable) @@ -733,7 +820,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionBox = new ng::CheckBox(advancedPopup, "Transmission Refraction"); + ng::CheckBox* refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); refractionBox->set_checked(_genContext.getOptions().hwTransmissionRenderMethod == mx::TRANSMISSION_REFRACTION); refractionBox->set_callback([this](bool enable) { @@ -744,14 +831,14 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionSidedBox = new ng::CheckBox(advancedPopup, "Refraction Two-Sided"); + ng::CheckBox* refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); refractionSidedBox->set_checked(_lightHandler->getRefractionTwoSided()); refractionSidedBox->set_callback([this](bool enable) { _lightHandler->setRefractionTwoSided(enable); }); - ng::CheckBox* shaderInterfaceBox = new ng::CheckBox(advancedPopup, "Reduce Shader Interface"); + ng::CheckBox* shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); shaderInterfaceBox->set_checked(_genContext.getOptions().shaderInterfaceType == mx::SHADER_INTERFACE_REDUCED); shaderInterfaceBox->set_callback([this](bool enable) { @@ -759,7 +846,7 @@ void Viewer::createAdvancedSettings(Widget* parent) setShaderInterfaceType(interfaceType); }); - Widget* albedoGroup = new Widget(advancedPopup); + Widget* albedoGroup = new Widget(settingsGroup); albedoGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(albedoGroup, "Albedo Method:"); mx::StringVec albedoOptions = { "Analytic", "Table", "MC" }; @@ -790,7 +877,7 @@ void Viewer::createAdvancedSettings(Widget* parent) } }); - Widget* sampleGroup = new Widget(advancedPopup); + Widget* sampleGroup = new Widget(settingsGroup); sampleGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(sampleGroup, "Environment Samples:"); mx::StringVec sampleOptions; @@ -808,25 +895,25 @@ void Viewer::createAdvancedSettings(Widget* parent) _lightHandler->setEnvSampleCount(MIN_ENV_SAMPLE_COUNT * (int) std::pow(4, index)); }); - ng::Label* lightingLabel = new ng::Label(advancedPopup, "Lighting Options"); + ng::Label* lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); lightingLabel->set_font_size(20); lightingLabel->set_font("sans-bold"); - ng::CheckBox* directLightingBox = new ng::CheckBox(advancedPopup, "Direct Lighting"); + ng::CheckBox* directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); directLightingBox->set_checked(_lightHandler->getDirectLighting()); directLightingBox->set_callback([this](bool enable) { _lightHandler->setDirectLighting(enable); }); - ng::CheckBox* indirectLightingBox = new ng::CheckBox(advancedPopup, "Indirect Lighting"); + ng::CheckBox* indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); indirectLightingBox->set_checked(_lightHandler->getIndirectLighting()); indirectLightingBox->set_callback([this](bool enable) { _lightHandler->setIndirectLighting(enable); }); - ng::Widget* lightRotationRow = new ng::Widget(advancedPopup); + ng::Widget* lightRotationRow = new ng::Widget(settingsGroup); lightRotationRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties ui; ui.uiMin = mx::Value::createValue(0.0f); @@ -839,11 +926,11 @@ void Viewer::createAdvancedSettings(Widget* parent) }); lightRotationBox->set_editable(true); - ng::Label* shadowingLabel = new ng::Label(advancedPopup, "Shadowing Options"); + ng::Label* shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); shadowingLabel->set_font_size(20); shadowingLabel->set_font("sans-bold"); - ng::CheckBox* shadowMapBox = new ng::CheckBox(advancedPopup, "Shadow Map"); + ng::CheckBox* shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); shadowMapBox->set_checked(_genContext.getOptions().hwShadowMap); shadowMapBox->set_callback([this](bool enable) { @@ -851,7 +938,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* ambientOcclusionBox = new ng::CheckBox(advancedPopup, "Ambient Occlusion"); + ng::CheckBox* ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); ambientOcclusionBox->set_checked(_genContext.getOptions().hwAmbientOcclusion); ambientOcclusionBox->set_callback([this](bool enable) { @@ -859,7 +946,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::Widget* ambientOcclusionGainRow = new ng::Widget(advancedPopup); + ng::Widget* ambientOcclusionGainRow = new ng::Widget(settingsGroup); ambientOcclusionGainRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); ng::FloatBox* ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", _ambientOcclusionGain, nullptr, [this](float value) @@ -868,11 +955,11 @@ void Viewer::createAdvancedSettings(Widget* parent) }); ambientOcclusionGainBox->set_editable(true); - ng::Label* sceneLabel = new ng::Label(advancedPopup, "Scene Options"); + ng::Label* sceneLabel = new ng::Label(settingsGroup, "Scene Options"); sceneLabel->set_font_size(20); sceneLabel->set_font("sans-bold"); - Widget* unitGroup = new Widget(advancedPopup); + Widget* unitGroup = new Widget(settingsGroup); unitGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(unitGroup, "Distance Unit:"); ng::ComboBox* distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); @@ -899,65 +986,65 @@ void Viewer::createAdvancedSettings(Widget* parent) m_process_events = true; }); - ng::Label* meshLoading = new ng::Label(advancedPopup, "Mesh Loading Options"); + ng::Label* meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); meshLoading->set_font_size(20); meshLoading->set_font("sans-bold"); - ng::CheckBox* splitUdimsBox = new ng::CheckBox(advancedPopup, "Split By UDIMs"); + ng::CheckBox* splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); splitUdimsBox->set_checked(_splitByUdims); splitUdimsBox->set_callback([this](bool enable) { _splitByUdims = enable; }); - ng::Label* materialLoading = new ng::Label(advancedPopup, "Material Loading Options"); + ng::Label* materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); materialLoading->set_font_size(20); materialLoading->set_font("sans-bold"); - ng::CheckBox* mergeMaterialsBox = new ng::CheckBox(advancedPopup, "Merge Materials"); + ng::CheckBox* mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); mergeMaterialsBox->set_checked(_mergeMaterials); mergeMaterialsBox->set_callback([this](bool enable) { _mergeMaterials = enable; }); - ng::CheckBox* showInputsBox = new ng::CheckBox(advancedPopup, "Show All Inputs"); + ng::CheckBox* showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); showInputsBox->set_checked(_showAllInputs); showInputsBox->set_callback([this](bool enable) { _showAllInputs = enable; }); - ng::CheckBox* flattenBox = new ng::CheckBox(advancedPopup, "Flatten Subgraphs"); + ng::CheckBox* flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); flattenBox->set_checked(_flattenSubgraphs); flattenBox->set_callback([this](bool enable) { _flattenSubgraphs = enable; }); - ng::Label* envLoading = new ng::Label(advancedPopup, "Environment Loading Options"); + ng::Label* envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); envLoading->set_font_size(20); envLoading->set_font("sans-bold"); - ng::CheckBox* normalizeEnvBox = new ng::CheckBox(advancedPopup, "Normalize Environment"); + ng::CheckBox* normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); normalizeEnvBox->set_checked(_normalizeEnvironment); normalizeEnvBox->set_callback([this](bool enable) { _normalizeEnvironment = enable; }); - ng::CheckBox* splitDirectLightBox = new ng::CheckBox(advancedPopup, "Split Direct Light"); + ng::CheckBox* splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); splitDirectLightBox->set_checked(_splitDirectLight); splitDirectLightBox->set_callback([this](bool enable) { _splitDirectLight = enable; }); - ng::Label* translationLabel = new ng::Label(advancedPopup, "Translation Options (T)"); + ng::Label* translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); translationLabel->set_font_size(20); translationLabel->set_font("sans-bold"); - ng::Widget* targetShaderGroup = new ng::Widget(advancedPopup); + ng::Widget* targetShaderGroup = new ng::Widget(settingsGroup); targetShaderGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(targetShaderGroup, "Target Shader"); ng::TextBox* targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); @@ -969,43 +1056,43 @@ void Viewer::createAdvancedSettings(Widget* parent) targetShaderBox->set_font_size(16); targetShaderBox->set_editable(true); - ng::Label* textureLabel = new ng::Label(advancedPopup, "Texture Baking Options (B)"); + ng::Label* textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); textureLabel->set_font_size(20); textureLabel->set_font("sans-bold"); - ng::CheckBox* bakeHdrBox = new ng::CheckBox(advancedPopup, "Bake HDR Textures"); + ng::CheckBox* bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); bakeHdrBox->set_checked(_bakeHdr); bakeHdrBox->set_callback([this](bool enable) { _bakeHdr = enable; }); - ng::CheckBox* bakeAverageBox = new ng::CheckBox(advancedPopup, "Bake Averaged Textures"); + ng::CheckBox* bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); bakeAverageBox->set_checked(_bakeAverage); bakeAverageBox->set_callback([this](bool enable) { _bakeAverage = enable; }); - ng::CheckBox* bakeOptimized = new ng::CheckBox(advancedPopup, "Optimize Baked Constants"); + ng::CheckBox* bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); bakeOptimized->set_checked(_bakeOptimize); bakeOptimized->set_callback([this](bool enable) { _bakeOptimize = enable; }); - ng::CheckBox* bakeDocumentPerMaterial= new ng::CheckBox(advancedPopup, "Bake Document Per Material"); + ng::CheckBox* bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); bakeDocumentPerMaterial->set_checked(_bakeDocumentPerMaterial); bakeDocumentPerMaterial->set_callback([this](bool enable) { _bakeDocumentPerMaterial = enable; }); - ng::Label* wedgeLabel = new ng::Label(advancedPopup, "Wedge Render Options (W)"); + ng::Label* wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); wedgeLabel->set_font_size(20); wedgeLabel->set_font("sans-bold"); - ng::Widget* wedgeNameGroup = new ng::Widget(advancedPopup); + ng::Widget* wedgeNameGroup = new ng::Widget(settingsGroup); wedgeNameGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(wedgeNameGroup, "Property Name"); ng::TextBox* wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); @@ -1017,7 +1104,7 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeNameBox->set_font_size(16); wedgeNameBox->set_editable(true); - ng::Widget* wedgeMinGroup = new ng::Widget(advancedPopup); + ng::Widget* wedgeMinGroup = new ng::Widget(settingsGroup); wedgeMinGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeProp; wedgeProp.uiSoftMin = mx::Value::createValue(0.0f); @@ -1030,7 +1117,7 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMinBox->set_value(0.0); wedgeMinBox->set_editable(true); - ng::Widget* wedgeMaxGroup = new ng::Widget(advancedPopup); + ng::Widget* wedgeMaxGroup = new ng::Widget(settingsGroup); wedgeMaxGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); ng::FloatBox* wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", _wedgePropertyMax, &wedgeProp, [this](float value) @@ -1040,7 +1127,7 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMaxBox->set_value(1.0); wedgeMaxBox->set_editable(true); - ng::Widget* wedgeCountGroup = new ng::Widget(advancedPopup); + ng::Widget* wedgeCountGroup = new ng::Widget(settingsGroup); wedgeCountGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeCountProp; wedgeCountProp.uiMin = mx::Value::createValue(1); @@ -1053,6 +1140,8 @@ void Viewer::createAdvancedSettings(Widget* parent) }); wedgeCountBox->set_value(8); wedgeCountBox->set_editable(true); + + createDocumentationInterface(advancedPopup, scrollPanel); } void Viewer::updateGeometrySelections() diff --git a/source/MaterialXView/Viewer.h b/source/MaterialXView/Viewer.h index c3f4bb48da..08712f3c78 100644 --- a/source/MaterialXView/Viewer.h +++ b/source/MaterialXView/Viewer.h @@ -16,7 +16,6 @@ #include #include - #include namespace mx = MaterialX; @@ -290,6 +289,7 @@ class Viewer : public ng::Screen void createSaveMaterialsInterface(Widget* parent, const std::string& label); void createPropertyEditorInterface(Widget* parent, const std::string& label); void createAdvancedSettings(Widget* parent); + void createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel); // Return the ambient occlusion image, if any, associated with the given material. mx::ImagePtr getAmbientOcclusionImage(mx::MaterialPtr material); From 76bef700bb61f2582de19ca7d6c608066bcb07ac Mon Sep 17 00:00:00 2001 From: LeaRe Date: Sat, 28 Sep 2024 11:06:08 -0700 Subject: [PATCH 066/137] Fix Graph Editor unintentional camera orbit in render view (#2032) This fixes the logic that detects whether the cursor is in the render view. Previously, there were three known issues that are fixed with this change: - The camera would orbit when grabbing the scrollbar located next to the render view. - The camera would orbit when clicking a menu option in the menu dropdown overlapping the render view. - The previous logic to detect the cursor in the render view did not consider that the render view moves up when scrolling. As a result, the camera would still orbit when clicking parts of the Node Property Editor that were previously occupied by the render view. --- source/MaterialXGraphEditor/Graph.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 45d74fd2f1..d09961d42f 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -3240,6 +3240,15 @@ void Graph::graphButtons() ImGui::BeginChild("Selection", ImVec2(paneWidth, 0), false, windowFlags); ImVec2 windowPos = ImGui::GetWindowPos(); + // Update cursorInRenderView to account for other windows overlapping the Render View (e.g. Menu dropdown). + cursorInRenderView &= ImGui::IsWindowHovered(ImGuiHoveredFlags_None); + + // Update cursorInRenderView to account for visible scrollbar and scroll amount. + ImGuiContext* context = ImGui::GetCurrentContext(); + bool hasScrollbar = context->CurrentWindow->ScrollbarY; + cursorInRenderView &= hasScrollbar ? mousePos.x < (tempWindowPos.x + screenSize.x - ImGui::GetStyle().ScrollbarSize) : true; + cursorInRenderView &= hasScrollbar ? mousePos.y < (tempWindowPos.y + screenSize.y - ImGui::GetScrollY()) : true; + // RenderView window ImVec2 wsize = ImVec2((float) _renderer->getViewWidth(), (float) _renderer->getViewHeight()); _renderer->setViewWidth((int) screenSize[0]); From 210266bc6f85816ae5723633206759bf4f336c42 Mon Sep 17 00:00:00 2001 From: Charlotte Manning Date: Sat, 28 Sep 2024 20:08:15 -0700 Subject: [PATCH 067/137] Support transmission in translation from Standard Surface to glTF PBR (#2027) This corrects the translation of transmission parameters from Standard Surface to glTF PBR. Issue: https://github.com/AcademySoftwareFoundation/MaterialX/issues/1599 --- .../standard_surface_to_gltf_pbr.mtlx | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx b/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx index 461e918400..51dfc6c634 100644 --- a/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx @@ -76,12 +76,24 @@ - + + + + + + + + + + + + + @@ -96,9 +108,18 @@ - - - + + + + + + + + + + + + From 923ffd9ec9edfe109e7437be675f7693f460af08 Mon Sep 17 00:00:00 2001 From: Stefan Habel <19556655+StefanHabel@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:13:55 -0700 Subject: [PATCH 068/137] Updated markdown documentation files (#2037) Changes: - Replaced relative image sources with absolute image URLs so that images load when viewed at https://pypi.org/project/MaterialX/ and when integrating the contents into the new Python API documentation - Streamlined headline levels: page title (if any) uses `#`, first level uses `##`, second level uses `###`, etc. - Updated the approach for formatting image galleries - Streamlined figure captions to format colons in **bold** - Used HTML comment syntax for comments in XML blocks - Other minor formatting changes, e.g. formatting the `MaterialXView` executable in a code font --- README.md | 44 +++++++++------ documents/DeveloperGuide/GraphEditor.md | 35 ++++++------ documents/DeveloperGuide/MainPage.md | 30 +++++----- documents/DeveloperGuide/ShaderGeneration.md | 42 +++++++------- documents/DeveloperGuide/Viewer.md | 58 ++++++++++++-------- 5 files changed, 117 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index 41e7d5aeca..fdd06680a4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/LICENSE) @@ -7,18 +7,18 @@ [![Build Status](https://github.com/AcademySoftwareFoundation/MaterialX/workflows/main/badge.svg?branch=main)](https://github.com/AcademySoftwareFoundation/MaterialX/actions?query=branch%3Amain) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/6025/badge)](https://bestpractices.coreinfrastructure.org/projects/6025) -### Introduction +## Introduction MaterialX is an open standard for representing rich material and look-development content in computer graphics, enabling its platform-independent description and exchange across applications and renderers. Launched at [Industrial Light & Magic](https://www.ilm.com/) in 2012, MaterialX has been a key technology in their feature films and real-time experiences since _Star Wars: The Force Awakens_ and _Millennium Falcon: Smugglers Run_. The project was released as open source in 2017, with companies including Sony Pictures Imageworks, Pixar, Autodesk, Adobe, and SideFX contributing to its ongoing development. In 2021, MaterialX became the seventh hosted project of the [Academy Software Foundation](https://www.aswf.io/). -### Quick Start for Developers +## Quick Start for Developers - Download the latest version of the [CMake](https://cmake.org/) build system. - Point CMake to the root of the MaterialX library and generate C++ projects for your platform and compiler. - Select the `MATERIALX_BUILD_PYTHON` option to build Python bindings. - Select the `MATERIALX_BUILD_VIEWER` option to build the MaterialX viewer. -### Supported Platforms +## Supported Platforms The MaterialX codebase requires a compiler with support for C++17, and can be built with any of the following: @@ -28,35 +28,47 @@ The MaterialX codebase requires a compiler with support for C++17, and can be bu The Python bindings for MaterialX are based on [PyBind11](https://github.com/pybind/pybind11), and support Python versions 3.6 and greater. -### MaterialX Viewer +## MaterialX Viewer The [MaterialX Viewer](documents/DeveloperGuide/Viewer.md) leverages shader generation to build GLSL shaders from MaterialX graphs, rendering the results using the NanoGUI framework. **Figure 1:** Procedural and uniform materials in the MaterialX viewer

- - - - + + + +

**Figure 2:** Textured, color-space-managed materials in the MaterialX viewer

- - + +

-### Open Chess Set +## Open Chess Set The Open Chess Set is an open reference asset, consisting of a [MaterialX file](resources/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx) in the Standard Surface shading model and a [geometry file](resources/Geometry) in the glTF format. It was authored by Moeen Sayed and Mujtaba Sayed, and was contributed to the MaterialX project by Side Effects. **Figure 3:** The Open Chess Set, rendered in Arnold for Maya - +![The Open Chess Set rendered in Arnold for Maya](https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/documents/Images/OpenChessSet_Arnold_01.png) **Figure 4:** The Open Chess Set, rendered in Karma XPU for Houdini - +![The Open Chess Set rendered in Karma XPU for Houdini](https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/documents/Images/OpenChessSet_Karma_01.png) -### Pre-Built Binaries +## Pre-Built Binaries The following packages contain pre-built binaries for the latest release, including the MaterialX viewer, Python libraries, and example assets: @@ -64,7 +76,7 @@ The following packages contain pre-built binaries for the latest release, includ - [MacOS (Xcode 15, Python 3.12)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_MacOS_Xcode_15_Python312.zip) - [Linux (GCC 14, Python 3.12)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Linux_GCC_14_Python312.zip) -### Additional Resources +## Additional Resources - The [Developer Guide](http://www.materialx.org/docs/api/index.html) contains a developer-oriented overview of MaterialX with API documentation. - The [Python Scripts](python/Scripts) folder contains standalone examples of MaterialX Python code. diff --git a/documents/DeveloperGuide/GraphEditor.md b/documents/DeveloperGuide/GraphEditor.md index aaac7b75a2..394754c309 100644 --- a/documents/DeveloperGuide/GraphEditor.md +++ b/documents/DeveloperGuide/GraphEditor.md @@ -2,29 +2,30 @@ The MaterialX Graph Editor is an example application for visualizing, creating, and editing MaterialX graphs. It utilizes the ImGui framework as well as additional ImGui extensions such as the Node Editor. -### Example Images +## Example Images **Figure 1:** MaterialX Graph Editor with procedural marble example - -## Building The MaterialX Graph Editor +![MaterialX Graph Editor with procedural marble example](https://github.com/AcademySoftwareFoundation/MaterialX/raw/main/documents/Images/MaterialXGraphEditor_Marble.png) + +## Building the MaterialX Graph Editor Select the `MATERIALX_BUILD_GRAPH_EDITOR` option in CMake to build the MaterialX Graph Editor. Installation will copy the **MaterialXGraphEditor** executable to a `/bin` directory within the selected install folder. -### Summary of Graph Editor Features +## Summary of Graph Editor Features -1. **Load Material**: Load a material document in the MTLX format. -2. **Save Material**: Save out a graph as a mterial document in MTLX format. -3. **New Material**: Clear all information to set up for the creation of a new material -4. **Node Property Editor**: View or edit properties of the selected node. -5. **Render View**: View the rendered material. +1. **`Load Material`**: Load a material document in the MTLX format. +2. **`Save Material`**: Save out a graph as a mterial document in MTLX format. +3. **`New Material`**: Clear all information to set up for the creation of a new material +4. **`Node Property Editor`**: View or edit properties of the selected node. +5. **`Render View`**: View the rendered material. -### Buttons +## Buttons -To display a new material and graph, click the `Load Material` button and and navigate to the [Example Materials](../../resources/Materials/Examples) folder, which contains a selection of materials in the MTLX format, and select a document to load. The Graph Editor will display the graph hierarchy of the selected document for visualization and editing. +To display a new material and graph, click the `Load Material` button and and navigate to the [Materials/Examples](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples) folder, which contains a selection of materials in the MTLX format, and select a document to load. The Graph Editor will display the graph hierarchy of the selected document for visualization and editing. To save out changes to the graphs as MTLX files click the `Save Material` button. This will save the position of the nodes in the graph for future use as well. -### Editor Window +## Editor Window The MaterialX document is displayed as nodes in the Editor window. When a file is intially loaded the material node, surface shader node, and any enclosing nodegraphs will be displayed. Double-clicking on a nodegraph, or any node defined as a subgraph, will display the contents of that graph. @@ -40,19 +41,19 @@ Another type of node present in the `Add Node` pop-up is the group, or backgroun To search the editor window for a specific node use `CTRL` + `F` to bring up the search bar. -### Node Property Editor +## Node Property Editor When a node is selected in the graph, its information is displayed on the left-hand column in the `Node Property Editor`. This editor displays the name of the node, its category, its inputs, the input name, types and values. Inputs that are connected to other nodes will not display a value. This is where a node's properties such as its name and input values can be adjusted. When an input value is changed the material is automatically updated to reflect that change. The node info button displays the `doc` string for the selected node and its inputs if they exist. This `doc` string is currently read only. The show All Inputs checkbox displays all possible inputs for a node. With the box unchecked only inputs that have a connection or have had a value set will be shown. Only these inputs will be saved out when the graph is saved. -### Render View +## Render View Above the `Node Property Editor`, the `Render View` displays the current material on the Arnold Shader Ball. If inside a subgraph it will display the material associated with that subgraph; otherwise it will display the output of the selected node. It automatically updates when any changes are made to the graph. To adjust the relative sizes of the Node Property Editor and Render View windows, drag the separator between these windows in the application. The render view window camera can be changed using the left or right mouse buttons to manipulate the shader ball. -### Keyboard Shortcuts +## Keyboard Shortcuts - `TAB`: Add Node Popup - `Right Click`: pan along the editor @@ -66,7 +67,7 @@ To adjust the relative sizes of the Node Property Editor and Render View windows - `+` : Zoom in with the camera when mouse is over the Render View Window. - `-` : Zoom out with the camera when mouse is over the Render View Window. -### Command-Line Options +## Command-Line Options The following are common command-line options for MaterialXGraphEditor, and a complete list can be displayed with the `--help` option. - `--material [FILENAME]` : Specify the filename of the MTLX document to be displayed in the graph editor @@ -75,7 +76,7 @@ The following are common command-line options for MaterialXGraphEditor, and a co - `--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. - `--captureFilename [FILENAME]` : Specify the filename to which the first rendered frame should be written -### Known Limitations +## Known Limitations - Creating new connections using the `channels` attribute of an input is not yet supported, though existing `channels` connections will be displayed in graphs. - Assigning a new `colorspace` attribute to an input is not yet supported, though existing `colorspace` attributes on inputs will be respected by the render view. diff --git a/documents/DeveloperGuide/MainPage.md b/documents/DeveloperGuide/MainPage.md index 9cf0a0d8e0..155c58eb4d 100644 --- a/documents/DeveloperGuide/MainPage.md +++ b/documents/DeveloperGuide/MainPage.md @@ -2,14 +2,14 @@ MaterialX is an open standard for representing rich material and look-development content in computer graphics, enabling its platform-independent description and exchange across applications and renderers. Launched at [Industrial Light & Magic](https://www.ilm.com/) in 2012, MaterialX has been a key technology in their feature films and real-time experiences since _Star Wars: The Force Awakens_ and _Millennium Falcon: Smugglers Run_. The project was released as open source in 2017, with companies including Sony Pictures Imageworks, Pixar, Autodesk, Adobe, and SideFX contributing to its ongoing development. In 2021, MaterialX became the seventh hosted project of the [Academy Software Foundation](https://www.aswf.io/). -### Quick Start for Developers +## Quick Start for Developers - Download the latest version of the [CMake](https://cmake.org/) build system. - Point CMake to the root of the MaterialX library and generate C++ projects for your platform and compiler. - Select the `MATERIALX_BUILD_PYTHON` option to build Python bindings. - Select the `MATERIALX_BUILD_VIEWER` option to build the MaterialX viewer. -### Supported Platforms +## Supported Platforms The MaterialX codebase requires a compiler with support for C++17, and can be built with any of the following: @@ -19,9 +19,9 @@ The MaterialX codebase requires a compiler with support for C++17, and can be bu The Python bindings for MaterialX are based on [PyBind11](https://github.com/pybind/pybind11), and support Python versions 3.6 and greater. -### Building MaterialX +## Building MaterialX -#### Building MaterialX C++ +### Building MaterialX C++ The MaterialX C++ libraries are automatically included when building MaterialX through CMake. @@ -32,7 +32,7 @@ To enable OpenImageIO support in MaterialX builds, the following additional opti See the [MaterialX Unit Tests](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/source/MaterialXTest) page for documentation on shader generation and render testing in GLSL, OSL, and MDL. -#### Building MaterialX Python +### Building MaterialX Python By default, the `MATERIALX_BUILD_PYTHON` option will use the active version of Python in the developer's path. To select a specific version of Python, use one or more of the following advanced options: @@ -44,32 +44,32 @@ Additional options for the generation of MaterialX Python include the following: - `MATERIALX_PYTHON_OCIO_DIR`: Path to a folder containing the default OCIO configuration to be packaged with MaterialX Python. The recommended OpenColorIO configuration for MaterialX is [ACES 1.2](https://github.com/colour-science/OpenColorIO-Configs/tree/feature/aces-1.2-config/aces_1.2). - `MATERIALX_PYTHON_PYBIND11_DIR`: Path to a folder containing the PyBind11 source to be used in building MaterialX Python. Defaults to the included PyBind11 source. -#### Building The MaterialX Viewer +### Building The MaterialX Viewer -Select the `MATERIALX_BUILD_VIEWER` option to build the MaterialX Viewer. Installation will copy the **MaterialXView** executable to a `bin/` directory within the selected install folder. +Select the `MATERIALX_BUILD_VIEWER` option to build the MaterialX Viewer. Installation will copy the `MaterialXView` executable to a `bin/` directory within the selected install folder. -#### Building API Documentation +### Building API Documentation To generate HTML documentation for the MaterialX C++ API, make sure a version of [Doxygen](https://www.doxygen.org/) is on your path, and select the advanced option `MATERIALX_BUILD_DOCS` in CMake. This option will add a target named `MaterialXDocs` to your project, which can be built as an independent step from your development environment. -### Installing MaterialX +## Installing MaterialX Building the `install` target of your project will install the MaterialX C++ and Python libraries to the folder specified by the `CMAKE_INSTALL_PREFIX` setting, and will install MaterialX Python as a third-party library in your Python environment. Installation of MaterialX Python as a third-party library can be disabled by setting `MATERIALX_INSTALL_PYTHON` to `OFF`. -### MaterialX Versioning +## MaterialX Versioning -The MaterialX codebase uses a modified semantic versioning system where the *major* and *minor* versions match that of the corresponding MaterialX [specification](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/documents/Specification/MaterialX.Specification.md), and the *build* version represents engineering advances within that specification version. MaterialX documents are similarly marked with the specification version they were authored in, and they are valid to load into any MaterialX codebase with an equal or higher specification version. +The MaterialX codebase uses a modified semantic versioning system where the *major* and *minor* versions match that of the corresponding [MaterialX Specification](https://materialx.org/Specification.html), and the *build* version represents engineering advances within that specification version. MaterialX documents are similarly marked with the specification version they were authored in, and they are valid to load into any MaterialX codebase with an equal or higher specification version. -Upgrading of MaterialX documents from earlier versions is handled at import time by the `Document::upgradeVersion` method, which applies the syntax and node interface upgrades that have occurred in previous specification revisions. This allows the syntax conventions of MaterialX and the names and interfaces of nodes to evolve over time, without invalidating documents from earlier versions. +Upgrading of MaterialX documents from earlier versions is handled at import time by the `Document::upgradeVersion()` method, which applies the syntax and node interface upgrades that have occurred in previous specification revisions. This allows the syntax conventions of MaterialX and the names and interfaces of nodes to evolve over time, without invalidating documents from earlier versions. -#### MaterialX API Changes +### MaterialX API Changes The following rules describe the categories of changes to the [MaterialX API](https://materialx.org/docs/api/classes.html) that are allowed in version upgrades: - In *build* version upgrades, only non-breaking changes to the MaterialX API are allowed. For any API call that is modified in a build version upgrade, backwards compatibility should be maintained using deprecated C++ and Python wrappers for the original API call. - In *minor* and *major* version upgrades, breaking changes to the MaterialX API are allowed, though their benefit should be carefully weighed against their cost. Any breaking changes to API calls should be highlighted in the release notes for the new version. -#### MaterialX Data Library Changes +### MaterialX Data Library Changes The following rules describe the categories of changes to the [MaterialX Data Libraries](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/libraries) that are allowed in version upgrades: @@ -77,7 +77,7 @@ The following rules describe the categories of changes to the [MaterialX Data Li - In *minor* version upgrades, changes to the names and interfaces of MaterialX nodes are allowed, with the requirement that version upgrade logic be used to maintain the validity and visual interpretation of documents from earlier versions. - In *major* version upgrades, changes to the syntax rules of MaterialX documents are allowed, with the requirement that version upgrade logic be used to maintain the validity and visual interpretation of documents from earlier versions. These changes usually require synchronized updates to both the MaterialX API and data libraries. -### Additional Links +## Additional Links - The main [MaterialX website](http://www.materialx.org) provides background on the project's history, industry collaborations, and recent presentations. - The [Python Scripts](https://github.com/materialx/MaterialX/tree/main/python/Scripts) folder contains standalone examples of MaterialX Python code. diff --git a/documents/DeveloperGuide/ShaderGeneration.md b/documents/DeveloperGuide/ShaderGeneration.md index 01bd823ec4..594715fb39 100644 --- a/documents/DeveloperGuide/ShaderGeneration.md +++ b/documents/DeveloperGuide/ShaderGeneration.md @@ -1,13 +1,13 @@ # Shader Generation ## 1.1 Scope -A shader generation framework is implemented as part of MaterialX. This can help applications to transform the agnostic MaterialX data description into executable shader code for a specific renderer. A library module named MaterialXGenShader contains the core shader generation features, and support for specific languages resides in separate libraries, e.g. [MaterialXGenGlsl](/source/MaterialXGenGlsl), [MaterialXGenOsl](/source/MaterialXGenOsl). +A shader generation framework is implemented as part of MaterialX. This can help applications to transform the agnostic MaterialX data description into executable shader code for a specific renderer. A library module named MaterialXGenShader contains the core shader generation features, and support for specific languages resides in separate libraries, e.g. [MaterialXGenGlsl](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/source/MaterialXGenGlsl), [MaterialXGenOsl](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/source/MaterialXGenOsl). Note that this system has no runtime and the output produced is source code, not binary executable code. The source code produced needs to be compiled by a shading language compiler before being executed by the renderer. See Figure 1 for a high level overview of the system. -![Shader generation with multiple shader generators](/documents/Images/shadergen.png) +![Shader generation with multiple shader generators](https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/documents/Images/shadergen.png) -**Figure 1**: Shader generation with multiple shader generators. +**Figure 1:** Shader generation with multiple shader generators. ## 1.2 Languages and Shader Generators The MaterialX description is free from device specific details and all implementation details needs to be taken care of by shader generators. There is one shader generator for each supported shading language. However for each language there can also be variations needed for different renderers. For example; OpenGL renderers supporting GLSL can use forward rendering or deferred rendering, each with very different requirements for how the shaders are constructed. Another example is different renderers supporting OSL but with different sets of closures or closure parameters. Hence a separate shader generator can be defined for each language/target combination. @@ -28,11 +28,11 @@ In the following sub-sections each of these methods are explained. For all metho ### 1.3.1 Inline Expression Provided code generators support a very simple expression language for inlining code. This is useful for simple nodes where the operation can be expressed as a single line of code. Inlining will reduce the number of function calls and produce more compact code. The syntax to use is the same as the target shading language, with the addition of using the node’s input ports as variables wrapped in double curly brackets: `{{input}}`. The code generator will replace these variables with values assigned or connected to the respective inputs. Figure 2 gives an example. -Connecting the expression to the nodedef is done using an `` element as seen in +Connecting the expression to the `nodedef` is done using an `` element as seen in Figure 2. The first option is to keep inline code in a file. The file extension is used to differentiate inline expressions from source code functions, using `filename.inline`. The second option is to directly embed the inlined code using `sourcecode`. This is the recommended approach for inlining if there the logic can fit on one line of code. ```xml -// Nodedef elements for node + @@ -43,14 +43,14 @@ Figure 2. The first option is to keep inline code in a file. The file extension -<... more types ...> + -// Implementation elements for node + -<... more types ...> + -// Nodedef elements for node + @@ -63,26 +63,26 @@ Figure 2. The first option is to keep inline code in a file. The file extension -<... more types ...> + -// Implementation elements for node + -<... more types ...> + ``` ```c++ // File 'mx_add.inline' contains: {{in1}} + {{in2}} ``` -**Figure 2**: Inline expressions for implementing nodes `` and ``. The code for `` is stored in an additional file, while the code for `` is specified as part of the +**Figure 2:** Inline expressions for implementing nodes `` and ``. The code for `` is stored in an additional file, while the code for `` is specified as part of the `` declaration. ### 1.3.2 Shading Language Function -For nodes that can’t be implemented by inline expressions a function definition can be used instead. The function signature should match the nodedefs interface with inputs and outputs. See Figure 3 for an example. Connecting the source code to the nodedef is done using an `` element, see the [MaterialX specification](../Specification/MaterialX.v1.36.Spec.pdf) for more information. +For nodes that can’t be implemented by inline expressions a function definition can be used instead. The function signature should match the nodedefs interface with inputs and outputs. See Figure 3 for an example. Connecting the source code to the nodedef is done using an `` element, see the [MaterialX Specification](https://materialx.org/Specification.html) for more information. ```xml -// Nodedef element + @@ -97,7 +97,7 @@ For nodes that can’t be implemented by inline expressions a function definitio -// Implementation element + ``` ```c++ @@ -115,7 +115,7 @@ void mx_image_color3(string file, string layer, color defaultvalue, "wrap", uaddressmode); } ``` -**Figure 3**: Shading language function's implementation for node `` in OSL. +**Figure 3:** Shading language function's implementation for node `` in OSL. ### 1.3.3 Node Graph Implementation As an alternative to defining source code, there is also an option to reference a nodegraph as the implementation of a nodedef. The only requirement is that the nodegraph and nodedef have matching inputs and outputs. @@ -147,7 +147,7 @@ This is useful for creating a compound for a set of nodes performing some common
``` -**Figure 4**: Checker node implementation using a nodegraph. +**Figure 4:** Checker node implementation using a nodegraph. ### 1.3.4 Dynamic Code Generation In some situations static source code is not enough to implement a node. The code might need to be customized depending on parameters set on the node. Or for a hardware render target vertex streams or uniform inputs might need to be created in order to supply the data needed for the node implementation. @@ -192,7 +192,7 @@ OslShaderGenerator::OslShaderGenerator() : ... } ``` -**Figure 5**: C++ class for dynamic code generation. +**Figure 5:** C++ class for dynamic code generation. ## 1.4 Shader Generation Steps This section outlines the steps taken in general to produce a shader from the MaterialX description. The `ShaderGenerator` base class and its supporting classes will handle this for you, but it’s good to know the steps involved if custom changes are needed to support a new target. @@ -305,7 +305,7 @@ class TexCoordGlsl : public ShaderNodeImpl } }; ``` -**Figure 6**: Implementation of node `texcoord` in GLSL. Using a `ShaderNodeImpl` sub-class in order to control shader variable creation and code generation into separate shader stages. +**Figure 6:** Implementation of node `texcoord` in GLSL. Using a `ShaderNodeImpl` sub-class in order to control shader variable creation and code generation into separate shader stages. ### 1.6.2 Variable Naming Convention @@ -353,4 +353,4 @@ Uniform variables | u_lightData[] | struct | Array of struct LightData holding parameters for active light sources. The `LightData` struct is built dynamically depending on requirements for bound light shaders. | | u_\UnitTarget[] | integer | An attribute indicating the target unit for a given unit type definition (\). | -**Figure 7** : Listing of predefined variables with their binding rules. +**Figure 7:** Listing of predefined variables with their binding rules. diff --git a/documents/DeveloperGuide/Viewer.md b/documents/DeveloperGuide/Viewer.md index 1d3a1d7dcf..388132ff47 100644 --- a/documents/DeveloperGuide/Viewer.md +++ b/documents/DeveloperGuide/Viewer.md @@ -2,60 +2,72 @@ The MaterialX Viewer leverages shader generation to build GLSL shaders from MaterialX graphs, rendering the results using the NanoGUI framework. The standard set of pattern and physically based shading nodes is supported, and libraries of custom nodes can be included as additional library paths. -### Example Images +## Example Images **Figure 1:** Procedural and uniform materials in the MaterialX viewer

- - - - + + + +

**Figure 2:** Textured, color-space-managed materials in the MaterialX viewer

- - + +

## Building The MaterialX Viewer Select the `MATERIALX_BUILD_VIEWER` option in CMake to build the MaterialX Viewer. Installation will copy the **MaterialXView** executable to a `/bin` directory within the selected install folder. -### Summary of Viewer Options +## Summary of Viewer Options -1. **Load Mesh**: Load a new geometry in the OBJ or glTF format. -2. **Load Material**: Load a material document in the MTLX format. -3. **Load Environment**: Load a lat-long environment light in the HDR format. -4. **Property Editor**: View or edit properties of the current material. -5. **Advanced Settings** : Asset and rendering options. +1. **`Load Mesh`**: Load a new geometry in the OBJ or glTF format. +2. **`Load Material`**: Load a material document in the MTLX format. +3. **`Load Environment`**: Load a lat-long environment light in the HDR format. +4. **`Property Editor`**: View or edit properties of the current material. +5. **`Advanced Settings`** : Asset and rendering options. -### Geometry +## Geometry -The default display geometry for the MaterialX viewer is the Arnold Shader Ball, which was contributed to the MaterialX project by the Solid Angle team at Autodesk. To change the display geometry, click `Load Mesh` and navigate to the [Geometry](../../resources/Geometry) folder for additional models in the OBJ format. +The default display geometry for the MaterialX viewer is the Arnold Shader Ball, which was contributed to the MaterialX project by the Solid Angle team at Autodesk. To change the display geometry, click `Load Mesh` and navigate to the [Geometry](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Geometry) folder for additional models in the OBJ format. If a loaded geometry contains more than one geometric group, then a `Select Geometry` drop-down box will appear, allowing the user to select which group is active. The active geometric group will be used for subsequent actions such as material assignment and rendering property changes. -### Materials +## Materials -To change the displayed material, click `Load Material` and navigate to the [Materials/Examples/StandardSurface](../../resources/Materials/Examples/StandardSurface) or [Materials/Examples/UsdPreviewSurface](../../resources/Materials/Examples/UsdPreviewSurface) folders, which contain a selection of example materials in the MTLX format. +To change the displayed material, click `Load Material` and navigate to the [Materials/Examples/StandardSurface](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples/StandardSurface) or [Materials/Examples/UsdPreviewSurface](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples/UsdPreviewSurface) folders, which contain a selection of example materials in the MTLX format. Once a material is loaded into the viewer, its parameters may be inspected and adjusted by clicking the `Property Editor` and scrolling through the list of parameters. An edited material may be saved to the file system by clicking `Save Material`. Multiple material documents can be combined in a single session by navigating to `Advanced Settings` and enabling `Merge Materials`. Loading new materials with this setting enabled will add them to the current material list, where they can be assigned to geometry via the `Assigned Material` drop-down box. Alternatively the `LEFT` and `RIGHT` arrows can be used to cycle through the list of available materials. -If a material document containing `look` elements is loaded into the viewer, then any material assignments within the look will be applied to geometric groups that match the specified geometry strings. See [standard_surface_look_brass_tiled.mtlx](../../resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx) for an example of a material document containing look elements. +If a material document containing `look` elements is loaded into the viewer, then any material assignments within the look will be applied to geometric groups that match the specified geometry strings. See [standard_surface_look_brass_tiled.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx) for an example of a material document containing look elements. -### Lighting +## Lighting -The default lighting environment for the viewer is the San Giuseppe Bridge environment from HDRI Haven. To load another environment into the viewer, click `Load Environment` and navigate to the [Lights](../../resources/Lights) folder, or load any HDR environment in the latitude-longitude format. If the HDR file on disk has a companion MaterialX document with a matching name, then this document will be loaded as the direct lighting rig for the environment; otherwise only indirect lighting will be rendered. If the HDR file on disk has a companion image in an `irradiance` subfolder, then this image will be loaded as the diffuse convolution of the environment; otherwise, a diffuse convolution will be generated at load-time using spherical harmonics. +The default lighting environment for the viewer is the San Giuseppe Bridge environment from HDRI Haven. To load another environment into the viewer, click `Load Environment` and navigate to the [Lights](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Lights) folder, or load any HDR environment in the latitude-longitude format. If the HDR file on disk has a companion MaterialX document with a matching name, then this document will be loaded as the direct lighting rig for the environment; otherwise only indirect lighting will be rendered. If the HDR file on disk has a companion image in an `irradiance` subfolder, then this image will be loaded as the diffuse convolution of the environment; otherwise, a diffuse convolution will be generated at load-time using spherical harmonics. Shadow maps from the primary directional light may be enabled with the `Shadow Map` option under `Advanced Settings`. Ambient occlusion, if available for the given geometry, may be enabled with the `Ambient Occlusion` option. The fidelity of environment lighting may be improved by increasing the value of `Environment Samples`, though this requires additional GPU resources and can affect the interactivity of the viewer. -### Images +## Images By default, the MaterialX viewer loads and saves image files using `stb_image`, which supports commmon 8-bit formats such as JPEG, PNG, TGA, and BMP, as well as the HDR format for high-dynamic-range images. If you need access to additional image formats such as EXR and TIFF, then the MaterialX viewer can be built with support for `OpenImageIO`. To build MaterialX with OpenImageIO, check the `MATERIALX_BUILD_OIIO` option in CMake, and specify the location of your OpenImageIO installation with the `MATERIALX_OIIO_DIR` option. -### Keyboard Shortcuts +## Keyboard Shortcuts - `R`: Reload the current material from file. Hold `SHIFT` to reload all standard libraries as well. - `G`: Save the current GLSL shader source to file. @@ -74,7 +86,7 @@ By default, the MaterialX viewer loads and saves image files using `stb_image`, - `+` : Zoom in with the camera. - `-` : Zoom out with the camera. -### Command-Line Options +## Command-Line Options The following are common command-line options for MaterialXView, and a complete list can be displayed with the `--help` option. - `--material [FILENAME]` : Specify the filename of the MTLX document to be displayed in the viewer From 29477f743575688cfd0ec4a937dafb1c7a1319ac Mon Sep 17 00:00:00 2001 From: Hridiza Roy <52705197+hridizaroy@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:32:42 -0400 Subject: [PATCH 069/137] Fix memory leaks in viewer property editor (#2043) Fixed memory leaks in Viewer by making sure that _gridLayout3 in PropertyEditor gets connected to the top-level NanoGUI parent --- source/MaterialXView/Editor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/MaterialXView/Editor.cpp b/source/MaterialXView/Editor.cpp index 090937d6e5..abba9ce10e 100644 --- a/source/MaterialXView/Editor.cpp +++ b/source/MaterialXView/Editor.cpp @@ -631,6 +631,8 @@ void PropertyEditor::updateContents(Viewer* viewer) { ng::Widget* twoColumns = new ng::Widget(_container); twoColumns->set_layout(_gridLayout2); + ng::Widget* threeColumns = new ng::Widget(_container); + threeColumns->set_layout(_gridLayout3); ng::Label* modelLabel = new ng::Label(twoColumns, "Shading Model"); modelLabel->set_font_size(20); modelLabel->set_font("sans-bold"); From 0653e1da3753291616aa7be048738cd4aa9d9ddf Mon Sep 17 00:00:00 2001 From: rherrera-ilm Date: Wed, 2 Oct 2024 13:41:57 -0700 Subject: [PATCH 070/137] Added attribute strings to Element class in Python API (#2047) This change fixes #1545 --- source/PyMaterialX/PyMaterialXCore/PyElement.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp index 6e846c120e..9f35770e8b 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp @@ -103,6 +103,15 @@ void bindPyElement(py::module& mod) py::arg("geom") = mx::EMPTY_STRING) .def("asString", &mx::Element::asString) .def("__str__", &mx::Element::asString) + .def_readonly_static("NAME_ATTRIBUTE", &mx::Element::NAME_ATTRIBUTE) + .def_readonly_static("FILE_PREFIX_ATTRIBUTE", &mx::Element::FILE_PREFIX_ATTRIBUTE) + .def_readonly_static("GEOM_PREFIX_ATTRIBUTE", &mx::Element::GEOM_PREFIX_ATTRIBUTE) + .def_readonly_static("COLOR_SPACE_ATTRIBUTE", &mx::Element::COLOR_SPACE_ATTRIBUTE) + .def_readonly_static("INHERIT_ATTRIBUTE", &mx::Element::INHERIT_ATTRIBUTE) + .def_readonly_static("NAMESPACE_ATTRIBUTE", &mx::Element::NAMESPACE_ATTRIBUTE) + .def_readonly_static("DOC_ATTRIBUTE", &mx::Element::DOC_ATTRIBUTE) + .def_readonly_static("XPOS_ATTRIBUTE", &mx::Element::XPOS_ATTRIBUTE) + .def_readonly_static("YPOS_ATTRIBUTE", &mx::Element::YPOS_ATTRIBUTE) BIND_ELEMENT_FUNC_INSTANCE(Collection) BIND_ELEMENT_FUNC_INSTANCE(Document) BIND_ELEMENT_FUNC_INSTANCE(GeomInfo) From 860b8d476ec73f4f939bb59c5f3f57ecf8e9442d Mon Sep 17 00:00:00 2001 From: Ethan Dobrowolski <67444514+edobrowo@users.noreply.github.com> Date: Thu, 3 Oct 2024 11:23:49 -0400 Subject: [PATCH 071/137] Add support for viewdirection space in hardware shading (#2036) This addresses issue #1656. Previously, attribute `space` in node `viewdirection_vector3` was unused by GLSL and MSL implementations. This change correctly transforms the view direction from world space to the specified space. --- .../Nodes/HwViewDirectionNode.cpp | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/source/MaterialXGenShader/Nodes/HwViewDirectionNode.cpp b/source/MaterialXGenShader/Nodes/HwViewDirectionNode.cpp index 819ac93029..9c92897be4 100644 --- a/source/MaterialXGenShader/Nodes/HwViewDirectionNode.cpp +++ b/source/MaterialXGenShader/Nodes/HwViewDirectionNode.cpp @@ -14,20 +14,31 @@ ShaderNodeImplPtr HwViewDirectionNode::create() return std::make_shared(); } -void HwViewDirectionNode::createVariables(const ShaderNode&, GenContext&, Shader& shader) const +void HwViewDirectionNode::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const { ShaderStage& vs = shader.getStage(Stage::VERTEX); ShaderStage& ps = shader.getStage(Stage::PIXEL); addStageInput(HW::VERTEX_INPUTS, Type::VECTOR3, HW::T_IN_POSITION, vs); - addStageConnector(HW::VERTEX_DATA, Type::VECTOR3, HW::T_POSITION_WORLD, vs, ps); + + const ShaderInput* spaceInput = node.getInput(SPACE); + const int space = spaceInput ? spaceInput->getValue()->asA() : OBJECT_SPACE; + addStageUniform(HW::PRIVATE_UNIFORMS, Type::VECTOR3, HW::T_VIEW_POSITION, ps); + addStageConnector(HW::VERTEX_DATA, Type::VECTOR3, HW::T_POSITION_WORLD, vs, ps); + if (space == OBJECT_SPACE || space == MODEL_SPACE) + { + addStageUniform(HW::PRIVATE_UNIFORMS, Type::MATRIX44, HW::T_WORLD_INVERSE_TRANSPOSE_MATRIX, ps); + } } void HwViewDirectionNode::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const { const HwShaderGenerator& shadergen = static_cast(context.getShaderGenerator()); + const ShaderInput* spaceInput = node.getInput(SPACE); + const int space = spaceInput ? spaceInput->getValue()->asA() : OBJECT_SPACE; + DEFINE_SHADER_STAGE(stage, Stage::VERTEX) { VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA); @@ -44,10 +55,17 @@ void HwViewDirectionNode::emitFunctionCall(const ShaderNode& node, GenContext& c { VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA); const string prefix = shadergen.getVertexDataPrefix(vertexData); - ShaderPort* position = vertexData[HW::T_POSITION_WORLD]; shadergen.emitLineBegin(stage); shadergen.emitOutput(node.getOutput(), true, false, context, stage); - shadergen.emitString(" = normalize(" + prefix + position->getVariable() + " - " + HW::T_VIEW_POSITION + ")", stage); + ShaderPort* position = vertexData[HW::T_POSITION_WORLD]; + if (space == WORLD_SPACE) + { + shadergen.emitString(" = normalize(" + prefix + position->getVariable() + " - " + HW::T_VIEW_POSITION + ")", stage); + } + else + { + shadergen.emitString(" = normalize((" + HW::T_WORLD_INVERSE_TRANSPOSE_MATRIX + " * vec4(" + prefix + position->getVariable() + " - " + HW::T_VIEW_POSITION + ", 0.0)).xyz)", stage); + } shadergen.emitLineEnd(stage); } } From a11792ae92fb4ba0c6fe4410e0a9b0673c0dc74c Mon Sep 17 00:00:00 2001 From: Stefan Habel <19556655+StefanHabel@users.noreply.github.com> Date: Thu, 3 Oct 2024 08:33:40 -0700 Subject: [PATCH 072/137] Improvements to PyMaterialX docstrings (#2039) This PR tweaks the docstrings of all PyMaterialX* modules to be more descriptive. --- source/PyMaterialX/PyMaterialXCore/PyModule.cpp | 2 +- source/PyMaterialX/PyMaterialXFormat/PyModule.cpp | 2 +- source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp | 2 +- source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp | 2 +- source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp | 2 +- source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp | 2 +- source/PyMaterialX/PyMaterialXGenShader/PyModule.cpp | 2 +- source/PyMaterialX/PyMaterialXRender/PyModule.cpp | 2 +- source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp | 2 +- source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm | 2 +- source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/PyMaterialX/PyMaterialXCore/PyModule.cpp b/source/PyMaterialX/PyMaterialXCore/PyModule.cpp index e2e8a0080f..c22b7de841 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyModule.cpp @@ -26,7 +26,7 @@ void bindPyVariant(py::module& mod); PYBIND11_MODULE(PyMaterialXCore, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXCore library"; + mod.doc() = "Core MaterialX elements and graph traversal."; bindPyElement(mod); bindPyTraversal(mod); diff --git a/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp b/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp index 3965f48753..469ec43590 100644 --- a/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp @@ -13,7 +13,7 @@ void bindPyUtil(py::module& mod); PYBIND11_MODULE(PyMaterialXFormat, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXFormat library"; + mod.doc() = "Cross-platform support for document serialization and file utilities."; // PyMaterialXFormat depends on types defined in PyMaterialXCore PYMATERIALX_IMPORT_MODULE(PyMaterialXCore); diff --git a/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp index 9ab46e514d..448e1f4321 100644 --- a/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp @@ -14,7 +14,7 @@ void bindPyVkShaderGenerator(py::module& mod); PYBIND11_MODULE(PyMaterialXGenGlsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenGlsl library"; + mod.doc() = "Shader generation using the OpenGL Shading Language."; // PyMaterialXGenGlsl depends on types defined in PyMaterialXGenShader PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); diff --git a/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp index a34b28a729..f656f9a395 100644 --- a/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp @@ -11,7 +11,7 @@ void bindPyMdlShaderGenerator(py::module& mod); PYBIND11_MODULE(PyMaterialXGenMdl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenMdl library"; + mod.doc() = "Shader generation using the Material Definition Language."; // PyMaterialXGenMdl depends on types defined in PyMaterialXGenShader PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); diff --git a/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp index b3dcdb10a8..454f04c9ee 100644 --- a/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp @@ -12,7 +12,7 @@ void bindPyMslResourceBindingContext(py::module &mod); PYBIND11_MODULE(PyMaterialXGenMsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenMsl library"; + mod.doc() = "Shader generation using the Metal Shading Language."; // PyMaterialXGenMsl depends on types defined in PyMaterialXGenShader PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); diff --git a/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp index 54d7d2439a..a503bacab5 100644 --- a/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp @@ -11,7 +11,7 @@ void bindPyOslShaderGenerator(py::module& mod); PYBIND11_MODULE(PyMaterialXGenOsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenOsl library"; + mod.doc() = "Shader generation using Open Shading Language."; // PyMaterialXGenOsl depends on types defined in PyMaterialXGenShader PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyModule.cpp index f3dc613bff..a3f9911f33 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyModule.cpp @@ -24,7 +24,7 @@ void bindPyUnitSystem(py::module& mod); PYBIND11_MODULE(PyMaterialXGenShader, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenShader library"; + mod.doc() = "Core shader generation support for MaterialX."; bindPyColorManagement(mod); bindPyShaderPort(mod); diff --git a/source/PyMaterialX/PyMaterialXRender/PyModule.cpp b/source/PyMaterialX/PyMaterialXRender/PyModule.cpp index bbf9688403..450b1dda69 100644 --- a/source/PyMaterialX/PyMaterialXRender/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXRender/PyModule.cpp @@ -23,7 +23,7 @@ void bindPyCgltfLoader(py::module& mod); PYBIND11_MODULE(PyMaterialXRender, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXRender library"; + mod.doc() = "Core rendering support for MaterialX."; // PyMaterialXRender depends on types defined in PyMaterialXCore PYMATERIALX_IMPORT_MODULE(PyMaterialXCore); diff --git a/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp index d0ef04158d..69f5b3d353 100644 --- a/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp @@ -14,7 +14,7 @@ void bindPyTextureBaker(py::module& mod); PYBIND11_MODULE(PyMaterialXRenderGlsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXRenderGlsl library"; + mod.doc() = "Rendering support for the OpenGL Shading Language."; // PyMaterialXRenderGlsl depends on types defined in PyMaterialXRender PYMATERIALX_IMPORT_MODULE(PyMaterialXRender); diff --git a/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm b/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm index f4d0dbeaeb..63bd933591 100644 --- a/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm +++ b/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm @@ -14,7 +14,7 @@ PYBIND11_MODULE(PyMaterialXRenderMsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXRenderMsl library"; + mod.doc() = "Rendering support for the Metal Shading Language."; // PyMaterialXRenderMsl depends on types defined in PyMaterialXRender PYMATERIALX_IMPORT_MODULE(PyMaterialXRender); diff --git a/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp index 4019d364ab..c013afef89 100644 --- a/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp @@ -11,7 +11,7 @@ void bindPyOslRenderer(py::module& mod); PYBIND11_MODULE(PyMaterialXRenderOsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXRenderOsl library"; + mod.doc() = "Rendering support for Open Shading Language."; // PyMaterialXRenderOsl depends on types defined in PyMaterialXRender PYMATERIALX_IMPORT_MODULE(PyMaterialXRender); From 8357e1402bd875c8204ad8e8ac970ff6c1638cd6 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 5 Oct 2024 17:08:57 -0700 Subject: [PATCH 073/137] Updates to GitHub CI (#2050) - Move static analysis testing to MacOS 14, which is a more optimized environment and has a more recent version of cppcheck. - Upgrade to MacOS 13, as the MacOS 12 environment is now considered deprecated in GitHub CI. --- .github/workflows/main.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d6baf5dc10..dc73409606 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,8 +37,6 @@ jobs: compiler: gcc compiler_version: "14" python: 3.12 - static_analysis: ON - cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: Linux_GCC_CoverageAnalysis os: ubuntu-24.04 @@ -63,10 +61,10 @@ jobs: test_render: ON clang_format: ON - - name: MacOS_Xcode_13_Python39 - os: macos-12 + - name: MacOS_Xcode_14_Python39 + os: macos-13 compiler: xcode - compiler_version: "13.1" + compiler_version: "14.1" cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON python: 3.9 @@ -75,6 +73,8 @@ jobs: compiler: xcode compiler_version: "14.3" python: 3.11 + static_analysis: ON + cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: MacOS_Xcode_15_Python312 os: macos-14 @@ -245,10 +245,14 @@ jobs: working-directory: build - name: Static Analysis Tests - if: matrix.static_analysis == 'ON' && runner.os == 'Linux' + if: matrix.static_analysis == 'ON' run: | - sudo apt-get install cppcheck - cppcheck --project=build/compile_commands.json --error-exitcode=1 --suppress=*:*/External/* --suppress=*:*/NanoGUI/* + if [ "${{ runner.os }}" = "Linux" ]; then + sudo apt-get install cppcheck + else + brew install cppcheck + fi + cppcheck --project=build/compile_commands.json --error-exitcode=1 --suppress=normalCheckLevelMaxBranches --suppress=*:*/External/* --suppress=*:*/NanoGUI/* - name: Initialize Virtual Framebuffer if: matrix.test_render == 'ON' && runner.os == 'Linux' From 19d69283f52e4d207ae412936371730011240bb1 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 6 Oct 2024 20:30:13 -0700 Subject: [PATCH 074/137] Update JavaScript packages (#2052) This changelist updates all referenced JavaScript packages to their latest version via 'npm audit'. --- javascript/MaterialXTest/package-lock.json | 1487 ++++++++++---------- javascript/MaterialXTest/package.json | 12 +- javascript/MaterialXView/package-lock.json | 412 +++--- javascript/MaterialXView/package.json | 2 +- 4 files changed, 930 insertions(+), 983 deletions(-) diff --git a/javascript/MaterialXTest/package-lock.json b/javascript/MaterialXTest/package-lock.json index 4bd40a8468..d40a804991 100644 --- a/javascript/MaterialXTest/package-lock.json +++ b/javascript/MaterialXTest/package-lock.json @@ -9,17 +9,17 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "@babel/core": "^7.24.7", - "@babel/preset-env": "^7.24.7", - "@babel/register": "^7.24.6", - "chai": "^4.4.1", + "@babel/core": "^7.25.7", + "@babel/preset-env": "^7.25.7", + "@babel/register": "^7.25.7", + "chai": "^4.5.0", "copyfiles": "^2.4.1", - "karma": "^6.4.3", + "karma": "^6.4.4", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.2.0", "karma-mocha": "^2.0.1", "karma-mocha-reporter": "^2.2.5", - "mocha": "^10.4.0", + "mocha": "^10.7.3", "rimraf": "^3.0.2" } }, @@ -38,13 +38,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/highlight": "^7.25.7", "picocolors": "^1.0.0" }, "engines": { @@ -52,9 +52,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.7.tgz", + "integrity": "sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==", "dev": true, "license": "MIT", "engines": { @@ -62,22 +62,22 @@ } }, "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz", + "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helpers": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -93,58 +93,58 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7", + "@babel/types": "^7.25.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz", + "integrity": "sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", + "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -153,20 +153,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", - "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz", + "integrity": "sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/traverse": "^7.25.7", "semver": "^6.3.1" }, "engines": { @@ -177,14 +175,14 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz", + "integrity": "sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.7", + "regexpu-core": "^6.1.1", "semver": "^6.3.1" }, "engines": { @@ -211,86 +209,45 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", - "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz", + "integrity": "sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", + "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -300,22 +257,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz", + "integrity": "sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", - "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", + "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", "dev": true, "license": "MIT", "engines": { @@ -323,15 +280,15 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz", + "integrity": "sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-wrap-function": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -341,15 +298,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz", + "integrity": "sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -359,50 +316,37 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", + "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz", + "integrity": "sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", "dev": true, "license": "MIT", "engines": { @@ -410,9 +354,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", "dev": true, "license": "MIT", "engines": { @@ -420,9 +364,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", "dev": true, "license": "MIT", "engines": { @@ -430,43 +374,42 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz", + "integrity": "sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", + "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -476,11 +419,14 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz", + "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.7" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -489,14 +435,30 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz", + "integrity": "sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz", + "integrity": "sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -506,13 +468,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz", + "integrity": "sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -522,15 +484,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz", + "integrity": "sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/plugin-transform-optional-chaining": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -540,14 +502,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz", + "integrity": "sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -638,13 +600,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz", + "integrity": "sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -654,13 +616,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", + "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -823,13 +785,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz", + "integrity": "sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -839,16 +801,16 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.7.tgz", + "integrity": "sha512-4B6OhTrwYKHYYgcwErvZjbmH9X5TxQBsaBHdzEIB4l71gR5jh/tuHGlb9in47udL2+wVUcOz5XXhhfhVJwEpEg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-remap-async-to-generator": "^7.25.7", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -858,15 +820,15 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", - "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.7.tgz", + "integrity": "sha512-ZUCjAavsh5CESCmi/xCpX1qcCaAglzs/7tmuvoFnJgA1dM7gQplsguljoTg+Ru8WENpX89cQyAtWoaE0I3X3Pg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-remap-async-to-generator": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -876,13 +838,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz", + "integrity": "sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -892,13 +854,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz", + "integrity": "sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -908,14 +870,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", - "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz", + "integrity": "sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -925,14 +887,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.7.tgz", + "integrity": "sha512-rvUUtoVlkDWtDWxGAiiQj0aNktTPn3eFynBcMC2IhsXweehwgdI9ODe+XjWw515kEmv22sSOTp/rxIRuTiB7zg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -943,19 +905,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.7.tgz", - "integrity": "sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz", + "integrity": "sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/traverse": "^7.25.7", "globals": "^11.1.0" }, "engines": { @@ -966,14 +926,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz", + "integrity": "sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/template": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -983,13 +943,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.7.tgz", - "integrity": "sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz", + "integrity": "sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -999,14 +959,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz", + "integrity": "sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1016,13 +976,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz", + "integrity": "sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1031,14 +991,31 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", - "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.7.tgz", + "integrity": "sha512-UvcLuual4h7/GfylKm2IAA3aph9rwvAM2XBA0uPKU3lca+Maai4jBjjEVUS568ld6kJcgbouuumCBhMd/Yz17w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -1049,14 +1026,14 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz", + "integrity": "sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1066,13 +1043,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", - "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.7.tgz", + "integrity": "sha512-h3MDAP5l34NQkkNulsTNyjdaR+OiB0Im67VU//sFupouP8Q6m9Spy7l66DcaAQxtmCqGdanPByLsnwFttxKISQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -1083,14 +1060,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz", + "integrity": "sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1100,15 +1077,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz", + "integrity": "sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1118,13 +1095,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.7.tgz", + "integrity": "sha512-Ot43PrL9TEAiCe8C/2erAjXMeVSnE/BLEx6eyrKLNFCCw5jvhTHKyHxdI1pA0kz5njZRYAnMO2KObGqOCRDYSA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -1135,13 +1112,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz", + "integrity": "sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1151,13 +1128,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.7.tgz", + "integrity": "sha512-iImzbA55BjiovLyG2bggWS+V+OLkaBorNvc/yJoeeDQGztknRnDdYfp2d/UPmunZYEnZi6Lg8QcTmNMHOB0lGA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -1168,13 +1145,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz", + "integrity": "sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1184,14 +1161,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz", + "integrity": "sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1201,15 +1178,15 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", - "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz", + "integrity": "sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1219,16 +1196,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz", + "integrity": "sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1238,14 +1215,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz", + "integrity": "sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1255,14 +1232,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1272,13 +1249,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz", + "integrity": "sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1288,13 +1265,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.7.tgz", + "integrity": "sha512-FbuJ63/4LEL32mIxrxwYaqjJxpbzxPVQj5a+Ebrc8JICV6YX8nE53jY+K0RZT3um56GoNWgkS2BQ/uLGTjtwfw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -1305,13 +1282,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.7.tgz", + "integrity": "sha512-8CbutzSSh4hmD+jJHIA8vdTNk15kAzOnFLVVgBSMGr28rt85ouT01/rezMecks9pkU939wDInImwCKv4ahU4IA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -1322,16 +1299,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.7.tgz", + "integrity": "sha512-1JdVKPhD7Y5PvgfFy0Mv2brdrolzpzSoUq2pr6xsR+m+3viGGeHEokFKsCgOkbeFOQxfB1Vt2F0cPJLRpFI4Zg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" + "@babel/plugin-transform-parameters": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1341,14 +1318,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz", + "integrity": "sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1358,13 +1335,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.7.tgz", + "integrity": "sha512-m9obYBA39mDPN7lJzD5WkGGb0GO54PPLXsbcnj1Hyeu8mSRz7Gb4b1A6zxNX32ZuUySDK4G6it8SDFWD1nCnqg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -1375,14 +1352,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.7.tgz", - "integrity": "sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.7.tgz", + "integrity": "sha512-h39agClImgPWg4H8mYVAbD1qP9vClFbEjqoJmt87Zen8pjqK8FTPUwrOXAvqu5soytwxrLMd2fx2KSCp2CHcNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -1393,13 +1370,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz", + "integrity": "sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1409,14 +1386,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", - "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz", + "integrity": "sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1426,15 +1403,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.7.tgz", + "integrity": "sha512-LzA5ESzBy7tqj00Yjey9yWfs3FKy4EmJyKOSWld144OxkTji81WWnUT8nkLUn+imN/zHL8ZQlOu/MTUAhHaX3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -1445,13 +1422,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz", + "integrity": "sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1461,13 +1438,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz", + "integrity": "sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "regenerator-transform": "^0.15.2" }, "engines": { @@ -1478,13 +1455,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz", + "integrity": "sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1494,13 +1471,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz", + "integrity": "sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1510,14 +1487,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz", + "integrity": "sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1527,13 +1504,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz", + "integrity": "sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1543,13 +1520,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz", + "integrity": "sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1559,13 +1536,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.7.tgz", - "integrity": "sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz", + "integrity": "sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1575,13 +1552,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz", + "integrity": "sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1591,14 +1568,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz", + "integrity": "sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1608,14 +1585,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz", + "integrity": "sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1625,14 +1602,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", - "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz", + "integrity": "sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1642,28 +1619,29 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.7.tgz", - "integrity": "sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.7.tgz", + "integrity": "sha512-Gibz4OUdyNqqLj+7OAvBZxOD7CklCtMA5/j0JgUEwOnaRULsPDXmic2iKxL2DX2vQduPR5wH2hjZas/Vr/Oc0g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/compat-data": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.7", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-assertions": "^7.25.7", + "@babel/plugin-syntax-import-attributes": "^7.25.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", @@ -1675,59 +1653,60 @@ "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", - "@babel/plugin-transform-class-properties": "^7.24.7", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.7", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.7", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.7", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/plugin-transform-arrow-functions": "^7.25.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.7", + "@babel/plugin-transform-async-to-generator": "^7.25.7", + "@babel/plugin-transform-block-scoped-functions": "^7.25.7", + "@babel/plugin-transform-block-scoping": "^7.25.7", + "@babel/plugin-transform-class-properties": "^7.25.7", + "@babel/plugin-transform-class-static-block": "^7.25.7", + "@babel/plugin-transform-classes": "^7.25.7", + "@babel/plugin-transform-computed-properties": "^7.25.7", + "@babel/plugin-transform-destructuring": "^7.25.7", + "@babel/plugin-transform-dotall-regex": "^7.25.7", + "@babel/plugin-transform-duplicate-keys": "^7.25.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-dynamic-import": "^7.25.7", + "@babel/plugin-transform-exponentiation-operator": "^7.25.7", + "@babel/plugin-transform-export-namespace-from": "^7.25.7", + "@babel/plugin-transform-for-of": "^7.25.7", + "@babel/plugin-transform-function-name": "^7.25.7", + "@babel/plugin-transform-json-strings": "^7.25.7", + "@babel/plugin-transform-literals": "^7.25.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.7", + "@babel/plugin-transform-member-expression-literals": "^7.25.7", + "@babel/plugin-transform-modules-amd": "^7.25.7", + "@babel/plugin-transform-modules-commonjs": "^7.25.7", + "@babel/plugin-transform-modules-systemjs": "^7.25.7", + "@babel/plugin-transform-modules-umd": "^7.25.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-new-target": "^7.25.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.7", + "@babel/plugin-transform-numeric-separator": "^7.25.7", + "@babel/plugin-transform-object-rest-spread": "^7.25.7", + "@babel/plugin-transform-object-super": "^7.25.7", + "@babel/plugin-transform-optional-catch-binding": "^7.25.7", + "@babel/plugin-transform-optional-chaining": "^7.25.7", + "@babel/plugin-transform-parameters": "^7.25.7", + "@babel/plugin-transform-private-methods": "^7.25.7", + "@babel/plugin-transform-private-property-in-object": "^7.25.7", + "@babel/plugin-transform-property-literals": "^7.25.7", + "@babel/plugin-transform-regenerator": "^7.25.7", + "@babel/plugin-transform-reserved-words": "^7.25.7", + "@babel/plugin-transform-shorthand-properties": "^7.25.7", + "@babel/plugin-transform-spread": "^7.25.7", + "@babel/plugin-transform-sticky-regex": "^7.25.7", + "@babel/plugin-transform-template-literals": "^7.25.7", + "@babel/plugin-transform-typeof-symbol": "^7.25.7", + "@babel/plugin-transform-unicode-escapes": "^7.25.7", + "@babel/plugin-transform-unicode-property-regex": "^7.25.7", + "@babel/plugin-transform-unicode-regex": "^7.25.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.7", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", + "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "engines": { @@ -1753,9 +1732,9 @@ } }, "node_modules/@babel/register": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.24.6.tgz", - "integrity": "sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.25.7.tgz", + "integrity": "sha512-qHTd2Rhn/rKhSUwdY6+n98FmwXN+N+zxSVx3zWqRe9INyvTpv+aQ5gDV2+43ACd3VtMBzPPljbb0gZb8u5ma6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1772,17 +1751,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true, - "license": "MIT" - }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", "dev": true, "license": "MIT", "dependencies": { @@ -1793,35 +1765,32 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1830,14 +1799,14 @@ } }, "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz", + "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1890,9 +1859,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, "license": "MIT" }, @@ -1932,13 +1901,13 @@ } }, "node_modules/@types/node": { - "version": "20.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", - "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==", + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/accepts": { @@ -1956,9 +1925,9 @@ } }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "license": "MIT", "engines": { @@ -2035,14 +2004,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", - "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -2092,9 +2061,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { @@ -2106,7 +2075,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -2165,9 +2134,9 @@ "license": "ISC" }, "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -2185,10 +2154,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -2248,9 +2217,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001636", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", - "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", + "version": "1.0.30001667", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", + "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", "dev": true, "funding": [ { @@ -2269,9 +2238,9 @@ "license": "CC-BY-4.0" }, "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", "dev": true, "license": "MIT", "dependencies": { @@ -2281,7 +2250,7 @@ "get-func-name": "^2.0.2", "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "type-detect": "^4.1.0" }, "engines": { "node": ">=4" @@ -2502,13 +2471,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.0" + "browserslist": "^4.23.3" }, "funding": { "type": "opencollective", @@ -2554,13 +2523,13 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2644,9 +2613,9 @@ "license": "MIT" }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -2674,9 +2643,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.806", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz", - "integrity": "sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg==", + "version": "1.5.32", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz", + "integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==", "dev": true, "license": "ISC" }, @@ -2698,9 +2667,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.1.tgz", + "integrity": "sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og==", "dev": true, "license": "MIT", "dependencies": { @@ -2720,9 +2689,9 @@ } }, "node_modules/engine.io-parser": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", - "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "dev": true, "license": "MIT", "engines": { @@ -2730,11 +2699,17 @@ } }, "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.1.tgz", + "integrity": "sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/es-define-property": { "version": "1.0.0", @@ -2760,9 +2735,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -2922,9 +2897,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "dev": true, "funding": [ { @@ -3264,13 +3239,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3413,16 +3391,16 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json5": { @@ -3449,9 +3427,9 @@ } }, "node_modules/karma": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", - "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", + "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", "dependencies": { @@ -3743,32 +3721,32 @@ } }, "node_modules/mocha": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", - "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -3834,34 +3812,6 @@ "node": ">=8" } }, - "node_modules/mocha/node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/mocha/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3882,31 +3832,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" - }, "node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3969,9 +3894,9 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "license": "ISC", "dependencies": { @@ -3981,13 +3906,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -4005,9 +3923,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -4022,9 +3940,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true, "license": "MIT" }, @@ -4060,11 +3978,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4182,9 +4103,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "dev": true, "license": "ISC" }, @@ -4307,6 +4228,13 @@ "dev": true, "license": "MIT" }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, "node_modules/qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", @@ -4318,13 +4246,13 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -4403,9 +4331,9 @@ "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, "license": "MIT", "dependencies": { @@ -4433,16 +4361,16 @@ } }, "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -4450,28 +4378,26 @@ "node": ">=4" } }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.1.tgz", + "integrity": "sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -4570,9 +4496,9 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -4637,9 +4563,9 @@ } }, "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz", + "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==", "dev": true, "license": "MIT", "dependencies": { @@ -4647,7 +4573,7 @@ "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.5.2", + "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, @@ -4918,9 +4844,9 @@ } }, "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, "license": "MIT", "engines": { @@ -4942,9 +4868,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.38", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.38.tgz", - "integrity": "sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==", + "version": "0.7.39", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.39.tgz", + "integrity": "sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==", "dev": true, "funding": [ { @@ -4961,21 +4887,24 @@ } ], "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, "engines": { "node": "*" } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "license": "MIT", "engines": { @@ -4997,9 +4926,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, "license": "MIT", "engines": { @@ -5047,9 +4976,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -5067,8 +4996,8 @@ ], "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -5128,9 +5057,9 @@ } }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true, "license": "Apache-2.0" }, @@ -5287,9 +5216,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "license": "ISC", "engines": { diff --git a/javascript/MaterialXTest/package.json b/javascript/MaterialXTest/package.json index 02f42e430f..08578ceb32 100644 --- a/javascript/MaterialXTest/package.json +++ b/javascript/MaterialXTest/package.json @@ -16,17 +16,17 @@ "author": "", "license": "ISC", "devDependencies": { - "@babel/core": "^7.24.7", - "@babel/preset-env": "^7.24.7", - "@babel/register": "^7.24.6", - "chai": "^4.4.1", + "@babel/core": "^7.25.7", + "@babel/preset-env": "^7.25.7", + "@babel/register": "^7.25.7", + "chai": "^4.5.0", "copyfiles": "^2.4.1", - "karma": "^6.4.3", + "karma": "^6.4.4", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.2.0", "karma-mocha": "^2.0.1", "karma-mocha-reporter": "^2.2.5", - "mocha": "^10.4.0", + "mocha": "^10.7.3", "rimraf": "^3.0.2" } } diff --git a/javascript/MaterialXView/package-lock.json b/javascript/MaterialXView/package-lock.json index cf4b120c32..298f6d7f72 100644 --- a/javascript/MaterialXView/package-lock.json +++ b/javascript/MaterialXView/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "lil-gui": "^0.19.2", "three": "^0.152.2", - "webpack": "^5.92.1" + "webpack": "^5.95.0" }, "devDependencies": { "copy-webpack-plugin": "^8.1.1", @@ -73,9 +73,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -175,30 +175,10 @@ "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "license": "MIT" }, "node_modules/@types/express": { @@ -215,9 +195,22 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz", + "integrity": "sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", "dev": true, "license": "MIT", "dependencies": { @@ -242,9 +235,9 @@ "license": "MIT" }, "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -265,12 +258,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", - "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==", + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/node-forge": { @@ -284,9 +277,9 @@ } }, "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", "dev": true, "license": "MIT" }, @@ -348,9 +341,9 @@ } }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -569,9 +562,9 @@ } }, "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -624,16 +617,16 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -738,9 +731,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { @@ -752,7 +745,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -815,9 +808,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "funding": [ { "type": "opencollective", @@ -834,10 +827,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -894,9 +887,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001636", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", - "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", + "version": "1.0.30001667", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", + "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", "funding": [ { "type": "opencollective", @@ -1359,15 +1352,15 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.806", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz", - "integrity": "sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg==", + "version": "1.5.32", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz", + "integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==", "license": "ISC" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { @@ -1375,9 +1368,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -1398,9 +1391,9 @@ } }, "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", "dev": true, "license": "MIT", "bin": { @@ -1434,15 +1427,15 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz", - "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", "license": "MIT" }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" @@ -1549,38 +1542,38 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1620,6 +1613,13 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.2.tgz", + "integrity": "sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row==", + "dev": true, + "license": "MIT" + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -1667,14 +1667,14 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1710,9 +1710,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "dev": true, "funding": [ { @@ -2166,9 +2166,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, "license": "MIT", "dependencies": { @@ -2214,9 +2214,9 @@ } }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -2224,9 +2224,9 @@ } }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "license": "MIT", "dependencies": { @@ -2296,13 +2296,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2470,9 +2473,9 @@ } }, "node_modules/launch-editor": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", - "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "dev": true, "license": "MIT", "dependencies": { @@ -2549,11 +2552,14 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -2582,9 +2588,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { @@ -2718,9 +2724,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "license": "MIT" }, "node_modules/normalize-path": { @@ -2760,11 +2766,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2982,9 +2991,9 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "dev": true, "license": "MIT" }, @@ -2999,9 +3008,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "license": "ISC" }, "node_modules/picomatch": { @@ -3082,13 +3091,13 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -3415,9 +3424,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "license": "MIT", "dependencies": { @@ -3439,6 +3448,16 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3526,16 +3545,16 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -3712,13 +3731,13 @@ } }, "node_modules/spdy-transport/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3730,20 +3749,20 @@ } }, "node_modules/spdy-transport/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, "node_modules/spdy/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3755,9 +3774,9 @@ } }, "node_modules/spdy/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -3842,9 +3861,9 @@ } }, "node_modules/terser": { - "version": "5.31.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", - "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", + "version": "5.34.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz", + "integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -3945,9 +3964,9 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "dev": true, "license": "0BSD" }, @@ -3966,9 +3985,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "license": "MIT" }, "node_modules/unpipe": { @@ -3982,9 +4001,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -4001,8 +4020,8 @@ ], "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -4065,9 +4084,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -4088,12 +4107,11 @@ } }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "version": "5.95.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", + "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", @@ -4102,7 +4120,7 @@ "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -4217,16 +4235,16 @@ } }, "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -4334,16 +4352,16 @@ } }, "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -4470,9 +4488,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "license": "MIT", "engines": { diff --git a/javascript/MaterialXView/package.json b/javascript/MaterialXView/package.json index df27cebb57..74dd12bd85 100644 --- a/javascript/MaterialXView/package.json +++ b/javascript/MaterialXView/package.json @@ -12,7 +12,7 @@ "dependencies": { "lil-gui": "^0.19.2", "three": "^0.152.2", - "webpack": "^5.92.1" + "webpack": "^5.95.0" }, "devDependencies": { "copy-webpack-plugin": "^8.1.1", From a5073ac08f3d527841691ac5535637b14f1d9016 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Mon, 7 Oct 2024 13:35:42 -0400 Subject: [PATCH 075/137] Add Element Equivalence Interfaces (#2003) - Adds a new `isEquivalent` method to `Element`. - Adds a new `isAttributeEquivalent` method for `Element` and override for `ValueElement` to allow for value vs string comparisons on the latter. - Adds equivalence options class: `ElementEquivalanceOptions` which can be passed in as an argument to `isEquivalent` - Adds an optional results / feedback class: `ElementEquivalenceResult` which can be passed in as an argument to `isEquivalent` and `isAttributeEquivalent`. --- source/MaterialXCore/Element.cpp | 174 ++++++++++++++ source/MaterialXCore/Element.h | 110 +++++++++ .../MaterialXTest/MaterialXCore/Document.cpp | 212 ++++++++++++++++++ .../PyMaterialX/PyMaterialXCore/PyElement.cpp | 25 +++ 4 files changed, 521 insertions(+) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 94836245a7..149b7bc757 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -39,6 +39,12 @@ const string ValueElement::UI_ADVANCED_ATTRIBUTE = "uiadvanced"; const string ValueElement::UNIT_ATTRIBUTE = "unit"; const string ValueElement::UNITTYPE_ATTRIBUTE = "unittype"; const string ValueElement::UNIFORM_ATTRIBUTE = "uniform"; +const string ElementEquivalenceResult::ATTRIBUTE = "attribute"; +const string ElementEquivalenceResult::ATTRIBUTE_NAMES = "attribute names"; +const string ElementEquivalenceResult::CHILD_COUNT = "child count"; +const string ElementEquivalenceResult::CHILD_NAME = "child name"; +const string ElementEquivalenceResult::NAME = "name"; +const string ElementEquivalenceResult::CATEGORY = "category"; Element::CreatorMap Element::_creatorMap; @@ -334,6 +340,108 @@ bool Element::hasInheritanceCycle() const return false; } +bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, + ElementEquivalenceResultVec* results) const +{ + if (getName() != rhs->getName()) + { + if (results) + results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::NAME)); + return false; + } + if (getCategory() != rhs->getCategory()) + { + if (results) + results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::CATEGORY)); + return false; + } + + // Compare attribute names. + StringVec attributeNames = getAttributeNames(); + StringVec rhsAttributeNames = rhs->getAttributeNames(); + + // Filter out any attributes specified in the options. + const StringSet& skipAttributes = options.skipAttributes; + if (!skipAttributes.empty()) + { + attributeNames.erase(std::remove_if(attributeNames.begin(), attributeNames.end(), + [&skipAttributes](const string& attr) { return skipAttributes.find(attr) != skipAttributes.end(); }), + attributeNames.end()); + rhsAttributeNames.erase(std::remove_if(rhsAttributeNames.begin(), rhsAttributeNames.end(), + [&skipAttributes](const string& attr) { return skipAttributes.find(attr) != skipAttributes.end(); }), + rhsAttributeNames.end()); + } + + // Ignore attribute ordering by sorting names + std::sort(attributeNames.begin(), attributeNames.end()); + std::sort(rhsAttributeNames.begin(), rhsAttributeNames.end()); + + if (attributeNames != rhsAttributeNames) + { + if (results) + results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE_NAMES)); + return false; + } + + for (const string& attr : rhsAttributeNames) + { + if (!isAttributeEquivalent(rhs, attr, options, results)) + { + return false; + } + } + + // Compare children. + const vector& children = getChildren(); + const vector& rhsChildren = rhs->getChildren(); + if (children.size() != rhsChildren.size()) + { + if (results) + results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::CHILD_COUNT)); + return false; + } + for (size_t i = 0; i < children.size(); i++) + { + ElementPtr rhsElement = rhsChildren[i]; + // Handle unordered children if parent is a compound graph (NodeGraph, Document). + // (Functional graphs have a "nodedef" reference and define node interfaces + // so require strict interface ordering.) + ConstGraphElementPtr graph = this->getSelf()->asA(); + if (graph) + { + ConstNodeGraphPtr nodeGraph = graph->asA(); + ConstDocumentPtr document = graph->asA(); + if (document || (nodeGraph && !nodeGraph->getNodeDef())) + { + const string& childName = children[i]->getName(); + rhsElement = rhs->getChild(childName); + if (!rhsElement) + { + if (results) + results->push_back(ElementEquivalenceResult(children[i]->getNamePath(), "", + ElementEquivalenceResult::CHILD_NAME, childName)); + return false; + } + } + } + if (!children[i]->isEquivalent(rhsElement, options, results)) + return false; + } + return true; +} + +bool Element::isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, + const ElementEquivalenceOptions& /*options*/, ElementEquivalenceResultVec* results) const +{ + if (getAttribute(attributeName) != rhs->getAttribute(attributeName)) + { + if (results) + results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE, attributeName)); + return false; + } + return true; +} + TreeIterator Element::traverseTree() const { return TreeIterator(getSelfNonConst()); @@ -534,6 +642,72 @@ const string& ValueElement::getActiveUnit() const return EMPTY_STRING; } +bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, + const ElementEquivalenceOptions& options, ElementEquivalenceResultVec* results) const +{ + // Perform value comparisons + bool performedValueComparison = false; + if (!options.skipValueComparisons) + { + const StringSet uiAttributes = + { + ValueElement::UI_MIN_ATTRIBUTE, ValueElement::UI_MAX_ATTRIBUTE, + ValueElement::UI_SOFT_MIN_ATTRIBUTE, ValueElement::UI_SOFT_MAX_ATTRIBUTE, + ValueElement::UI_STEP_ATTRIBUTE + }; + + // Get precision and format options + ScopedFloatFormatting fmt(options.format, options.precision); + + ConstValueElementPtr rhsValueElement = rhs->asA(); + + // Check value equality + if (attributeName == ValueElement::VALUE_ATTRIBUTE) + { + ValuePtr thisValue = getValue(); + ValuePtr rhsValue = rhsValueElement->getValue(); + if (thisValue && rhsValue) + { + if (thisValue->getValueString() != rhsValue->getValueString()) + { + if (results) + results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE, attributeName)); + return false; + } + } + performedValueComparison = true; + } + + // Check ui attribute value equality + else if (uiAttributes.find(attributeName) != uiAttributes.end()) + { + const string& uiAttribute = getAttribute(attributeName); + const string& rhsUiAttribute = getAttribute(attributeName); + ValuePtr uiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(uiAttribute, getType()) : nullptr; + ValuePtr rhsUiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(rhsUiAttribute, getType()) : nullptr; + if (uiValue && rhsUiValue) + { + if (uiValue->getValueString() != rhsUiValue->getValueString()) + { + if (results) + results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE, attributeName)); + return false; + } + } + + performedValueComparison = true; + } + } + + // If did not peform a value comparison, perform the default comparison + if (!performedValueComparison) + { + return Element::isAttributeEquivalent(rhs, attributeName, options, results); + } + + return true; +} + bool ValueElement::validate(string* message) const { bool res = true; diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index d1abcdfdca..2b92dd8094 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -71,6 +71,10 @@ using ElementMap = std::unordered_map; /// A standard function taking an ElementPtr and returning a boolean. using ElementPredicate = std::function; +class ElementEquivalenceOptions; +class ElementEquivalenceResult; +using ElementEquivalenceResultVec = vector; + /// @class Element /// The base class for MaterialX elements. /// @@ -612,6 +616,31 @@ class MX_CORE_API Element : public std::enable_shared_from_this return nullptr; } + /// @} + /// @name Functional Equivalence + /// @{ + + /// Return true if the given element tree, including all descendents, + /// is considered to be equivalent to this one based on the equivalence + /// criteria provided. + /// @param rhs Element to compare against + /// @param options Equivalence criteria + /// @param results Results of comparison if argument is specified. + /// @return True if the elements are equivalent. False otherwise. + bool isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, + ElementEquivalenceResultVec* results = nullptr) const; + + /// Return true if the attribute on a given element is equivalent + /// based on the equivalence criteria provided. + /// @param rhs Element to compare against + /// @param attributeName Name of attribute to compare + /// @param options Equivalence criteria + /// @param results Results of comparison if argument is specified. + /// @return True if the attribute on the elements are equivalent. False otherwise. + virtual bool isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, + const ElementEquivalenceOptions& options, + ElementEquivalenceResultVec* results = nullptr) const; + /// @} /// @name Traversal /// @{ @@ -1114,6 +1143,21 @@ class MX_CORE_API ValueElement : public TypedElement return getTypedAttribute(UNIFORM_ATTRIBUTE); } + /// @} + /// @name Functional Equivalence + /// @{ + + /// Return true if the attribute on a given element is equivalent + /// based on the equivalence criteria provided. + /// @param rhs Element to compare against + /// @param attributeName Name of attribute to compare + /// @param options Equivalence criteria + /// @param results Results of comparison if argument is specified. + /// @return True if the attribute on the elements are equivalent. False otherwise. + bool isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, + const ElementEquivalenceOptions& options, + ElementEquivalenceResultVec* results = nullptr) const override; + /// @} /// @name Validation /// @{ @@ -1336,6 +1380,72 @@ class MX_CORE_API StringResolver StringMap _geomNameMap; }; +/// @class ElementEquivalenceResult +/// A comparison result for the functional equivalence of two elements. +class MX_CORE_API ElementEquivalenceResult +{ + public: + ElementEquivalenceResult(const string& p1, const string& p2, const string& type, + const string& attrName = EMPTY_STRING) + { + path1 = p1; + path2 = p2; + differenceType = type; + attributeName = attrName; + } + ElementEquivalenceResult() = delete; + ~ElementEquivalenceResult() = default; + + string path1; + string path2; + string differenceType; + string attributeName; + + static const string ATTRIBUTE; + static const string ATTRIBUTE_NAMES; + static const string CHILD_COUNT; + static const string CHILD_NAME; + static const string NAME; + static const string CATEGORY; +}; + +/// @class ElementEquivalenceOptions +/// A set of options for comparing the functional equivalence of elements. +class MX_CORE_API ElementEquivalenceOptions +{ + public: + ElementEquivalenceOptions() + { + format = Value::getFloatFormat(); + precision = Value::getFloatPrecision(); + skipAttributes = {}; + skipValueComparisons = false; + }; + ~ElementEquivalenceOptions() { } + + /// Floating point format option for floating point value comparisons + Value::FloatFormat format; + + /// Floating point precision option for floating point value comparisons + int precision; + + /// Attribute filtering options. By default all attributes are considered. + /// Name, category attributes cannot be skipped. + /// + /// For example UI attribute comparision be skipped by setting: + /// skipAttributes = { + /// ValueElement::UI_MIN_ATTRIBUTE, ValueElement::UI_MAX_ATTRIBUTE, + /// ValueElement::UI_SOFT_MIN_ATTRIBUTE, ValueElement::UI_SOFT_MAX_ATTRIBUTE, + /// ValueElement::UI_STEP_ATTRIBUTE, Element::XPOS_ATTRIBUTE, + /// Element::YPOS_ATTRIBUTE }; + StringSet skipAttributes; + + /// Do not perform any value comparisions. Instead perform exact string comparisons for attributes + /// Default is false. The operator==() method can be used instead as it always performs + /// a strict comparison. Default is false. + bool skipValueComparisons; +}; + /// @class ExceptionOrphanedElement /// An exception that is thrown when an ElementPtr is used after its owning /// Document has gone out of scope. diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index fb35e58ccb..1b02966fb8 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -10,6 +10,8 @@ #include #include +#include + namespace mx = MaterialX; TEST_CASE("Document", "[document]") @@ -116,3 +118,213 @@ TEST_CASE("Document", "[document]") // Validate the combined document. REQUIRE(doc->validate()); } + +void printDifferences(const mx::ElementEquivalenceResultVec& results, const std::string& label) +{ + for (const mx::ElementEquivalenceResult& result : results) + { + std::cout << label << ": " << "Element: " << result.path1 << + ", Element: " << result.path2 << ", Difference Type: " << result.differenceType + << ", Value: " << result.attributeName << std::endl; + } +} + +TEST_CASE("Document equivalence", "[document]") +{ + mx::DocumentPtr doc = mx::createDocument(); + std::unordered_multimap inputMap; + + inputMap.insert({ "color3", " 1.0, +2.0, 3.0 " }); + inputMap.insert({ "color4", "1.0, 2.00, 0.3000, -4" }); + inputMap.insert({ "integer", " 12 " }); + inputMap.insert({ "matrix33", + "01.0, 2.0, 0000.2310, " + " 01.0, 2.0, 0000.2310, " + "01.0, 2.0, 0000.2310 " }); + inputMap.insert({ "matrix44", + "01.0, 2.0, 0000.2310, 0.100, " + "01.0, 2.0, 0000.2310, 0.100, " + "01.0, 2.0, 0000.2310, 0.100, " + "01.0, 2.0, 0000.2310, 0.100" }); + inputMap.insert({ "vector2", "1.0, 0.012345608" }); // For precision check + inputMap.insert({ "vector3", " 1.0, +2.0, 3.0 " }); + inputMap.insert({ "vector4", "1.0, 2.00, 0.3000, -4" }); + inputMap.insert({ "string", "mystring" }); + inputMap.insert({ "boolean", "false" }); + inputMap.insert({ "filename", "filename1" }); + inputMap.insert({ "float", " 1.2e-10 " }); + inputMap.insert({ "float", " 00.1000 " }); + + unsigned int index = 0; + mx::ElementPtr child = doc->addNodeGraph("mygraph"); + mx::NodeGraphPtr graph = child->asA(); + for (auto it = inputMap.begin(); it != inputMap.end(); ++it) + { + const std::string inputType = (*it).first; + mx::InputPtr input = graph->addInput("input_" + std::to_string(index), inputType); + if (inputType == "float") + { + input->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, " 0.0100 "); + input->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, " 01.0100 "); + index++; + } + else + { + input->setName("input_" + inputType); // Set by name for difference in order test + } + input->setValueString((*it).second); + } + + mx::DocumentPtr doc2 = mx::createDocument(); + std::unordered_multimap inputMap2; + inputMap2.insert({ "color4", "1, 2, 0.3, -4" }); + inputMap2.insert({ "integer", "12" }); + inputMap2.insert({ "matrix33", "1, 2, 0.231, 1, 2, 0.231, 1, 2, 0.231, 1, 2, 0.231" }); + inputMap2.insert({ "matrix44", "1, 2, 0.231, 0.1, 1, 2, 0.231, 0.1, 1, 2, 0.231, 0.1, 1, 2, 0.231, 0.1" }); + inputMap2.insert({ "vector2", "1, 0.012345611" }); // For precision check + inputMap2.insert({ "string", "mystring" }); + inputMap2.insert({ "boolean", "false" }); + inputMap2.insert({ "color3", "1, 2, 3" }); + inputMap2.insert({ "vector3", "1, 2, 3" }); + inputMap2.insert({ "vector4", "1, 2, 0.3, -4" }); + inputMap2.insert({ "filename", "filename1" }); + inputMap2.insert({ "float", "1.2e-10" }); + inputMap2.insert({ "float", "0.1" }); + + index = 0; + child = doc2->addNodeGraph("mygraph"); + graph = child->asA(); + std::vector floatInputs; + for (auto it = inputMap2.begin(); it != inputMap2.end(); ++it) + { + const std::string inputType = (*it).first; + mx::InputPtr input = graph->addInput("input_" + std::to_string(index), inputType); + // Note: order of value and ui attributes is different for ordering comparison + input->setValueString((*it).second); + if (inputType == "float") + { + input->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, " 0.01"); + input->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, " 1.01"); + floatInputs.push_back(input); + index++; + } + else + { + input->setName("input_" + inputType); + } + } + + mx::ElementEquivalenceOptions options; + mx::ElementEquivalenceResultVec results; + + // Check skipping all value compares + options.skipValueComparisons = true; + bool equivalent = doc->isEquivalent(doc2, options, &results); + if (equivalent) + { + std::cout << "Unexpected skip value equivalence:" << std::endl; + std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; + std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; + } + else + { + printDifferences(results, "Expected value differences"); + } + REQUIRE(!equivalent); + + // Check attibute values + options.skipValueComparisons = false; + results.clear(); + equivalent = doc->isEquivalent(doc2, options, &results); + if (!equivalent) + { + printDifferences(results, "Unexpected value difference"); + std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; + std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; + } + REQUIRE(equivalent); + + unsigned int currentPrecision = mx::Value::getFloatPrecision(); + // This will compare 0.012345608 versus: 1, 0.012345611 for input10 + options.precision = 8; + equivalent = doc->isEquivalent(doc2, options); + if (equivalent) + { + std::cout << "Unexpected precision equivalence:" << std::endl; + std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; + std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; + } + else + { + printDifferences(results, "Expected precision difference"); + } + REQUIRE(!equivalent); + options.precision = currentPrecision; + + // Check attribute filtering of inputs + results.clear(); + options.skipAttributes = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; + for (mx::InputPtr floatInput : floatInputs) + { + floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, "0.9"); + floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, "100.0"); + } + equivalent = doc->isEquivalent(doc2, options, &results); + if (!equivalent) + { + printDifferences(results, "Unexpected filtering differences"); + std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; + std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; + } + REQUIRE(equivalent); + for (mx::InputPtr floatInput : floatInputs) + { + floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, " 0.01"); + floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, " 1.01"); + } + + // Check for child name mismatch + mx::ElementPtr mismatchElement = doc->getDescendant("mygraph/input_color4"); + std::string previousName = mismatchElement->getName(); + mismatchElement->setName("mismatch_color4"); + results.clear(); + equivalent = doc->isEquivalent(doc2, options, &results); + if (!equivalent) + { + printDifferences(results, "Expected name mismatch differences"); + } + else + { + std::cout << "Unexpected name match equivalence:" << std::endl; + std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; + std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; + } + REQUIRE(!equivalent); + mismatchElement->setName(previousName); + results.clear(); + equivalent = doc->isEquivalent(doc2, options, &results); + REQUIRE(equivalent); + + // Check for functional nodegraphs + mx::NodeGraphPtr nodeGraph = doc->getNodeGraph("mygraph"); + REQUIRE(nodeGraph); + doc->addNodeDef("ND_mygraph"); + nodeGraph->setNodeDefString("ND_mygraph"); + mx::NodeGraphPtr nodeGraph2 = doc2->getNodeGraph("mygraph"); + REQUIRE(nodeGraph2); + doc2->addNodeDef("ND_mygraph"); + nodeGraph2->setNodeDefString("ND_mygraph"); + results.clear(); + equivalent = doc->isEquivalent(doc2, options, &results); + if (!equivalent) + { + printDifferences(results, "Expected functional graph differences"); + } + else + { + std::cout << "Unexpected functional graph equivalence:" << std::endl; + std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; + std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; + } + REQUIRE(!equivalent); +} diff --git a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp index 9f35770e8b..cb70d04704 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp @@ -29,6 +29,12 @@ void bindPyElement(py::module& mod) py::class_(mod, "Element") .def(py::self == py::self) .def(py::self != py::self) + .def("isEquivalent", [](const mx::Element& elem, mx::ConstElementPtr& rhs, const mx::ElementEquivalenceOptions& options) + { + mx::ElementEquivalenceResultVec results; + bool res = elem.isEquivalent(rhs, options, &results); + return std::pair(res, results); + }) .def("setCategory", &mx::Element::setCategory) .def("getCategory", &mx::Element::getCategory) .def("setName", &mx::Element::setName) @@ -205,6 +211,25 @@ void bindPyElement(py::module& mod) py::class_(mod, "GenericElement") .def_readonly_static("CATEGORY", &mx::GenericElement::CATEGORY); + py::class_(mod, "ElementEquivalenceResult") + .def_readonly_static("ATTRIBUTE", &mx::ElementEquivalenceResult::ATTRIBUTE) + .def_readonly_static("ATTRIBUTE_NAMES", &mx::ElementEquivalenceResult::ATTRIBUTE_NAMES) + .def_readonly_static("CHILD_COUNT", &mx::ElementEquivalenceResult::CHILD_COUNT) + .def_readonly_static("CHILD_NAME", &mx::ElementEquivalenceResult::CHILD_NAME) + .def_readonly_static("NAME", &mx::ElementEquivalenceResult::NAME) + .def_readonly_static("CATEGORY", &mx::ElementEquivalenceResult::CATEGORY) + .def_readwrite("path1", &mx::ElementEquivalenceResult::path1) + .def_readwrite("path2", &mx::ElementEquivalenceResult::path2) + .def_readwrite("differenceType", &mx::ElementEquivalenceResult::differenceType) + .def_readwrite("attributeName", &mx::ElementEquivalenceResult::attributeName); + + py::class_(mod, "ElementEquivalenceOptions") + .def_readwrite("format", &mx::ElementEquivalenceOptions::format) + .def_readwrite("precision", &mx::ElementEquivalenceOptions::precision) + .def_readwrite("skipAttributes", &mx::ElementEquivalenceOptions::skipAttributes) + .def_readwrite("skipValueComparisons", &mx::ElementEquivalenceOptions::skipValueComparisons) + .def(py::init<>()); + py::class_(mod, "StringResolver") .def("setFilePrefix", &mx::StringResolver::setFilePrefix) .def("getFilePrefix", &mx::StringResolver::getFilePrefix) From 610ce0ce4ae33fafddd3909efb3e06cb5aa62b2b Mon Sep 17 00:00:00 2001 From: Dhruv Govil Date: Wed, 9 Oct 2024 07:47:03 -0700 Subject: [PATCH 076/137] Fix issue with framework builds on latest Xcode with embedded platforms (#2053) I discovered an issue with my [previous frameworks PR](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2020) that was showing up on recent Xcode versions where the `Resources` folder was acting as a reserved name on iOS, but is a required name on macOS. I also took the opportunity to clean up the linker code here. --- cmake/modules/AppleFrameworkBuild.zsh.in | 31 ++++-------------------- source/MaterialXFormat/Util.cpp | 5 +++- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/cmake/modules/AppleFrameworkBuild.zsh.in b/cmake/modules/AppleFrameworkBuild.zsh.in index 75b0dba0eb..e6e630cc19 100644 --- a/cmake/modules/AppleFrameworkBuild.zsh.in +++ b/cmake/modules/AppleFrameworkBuild.zsh.in @@ -20,28 +20,6 @@ BUNDLE_IDENTIFIER="org.aswf.materialx" CODESIGN_ID="@CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY@" OLD_RC_PATH="${CMAKE_INSTALL_PREFIX}/lib" -function fix_linkage() { - readonly file=${1:?"A file path must be specified."} - readonly prepend="${FRAMEWORK_NAME}.framework/Libraries" - filename=$(basename ${file}) - # First, change the install name. This corresponds to LC_ID_DYLIB. - install_name_tool -id "@rpath/${prepend}/${filename}" ${file} - - parts=("${(@f)$(otool -l ${file})}") - for line in ${parts}; do - dylib_name="" - [[ $line =~ ' *name @rpath/(.*\.dylib)' ]] && dylib_name=$match[1] - if [ -n "${dylib_name}" ]; then - install_name_tool -change "@rpath/${dylib_name}" "@rpath/${prepend}/${dylib_name}" "${file}" - fi - if [[ $line == *"${OLD_RC_PATH}"* ]]; then - install_name_tool -delete_rpath ${OLD_RC_PATH} ${file} - fi - done - - codesign -f -s ${CODESIGN_ID} ${file} -} - # Remove the existing directory if it exists if [ -d ${FRAMEWORK_DIR} ]; then echo "Removing existing framework"; @@ -53,15 +31,17 @@ echo "Creating Framework Directory: ${FRAMEWORK_DIR}" mkdir -p ${FRAMEWORK_DIR} if [ "$EMBEDDED_BUILD" = true ];then - FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}/Resources" + FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}/Assets" FRAMEWORK_PLIST_LOCATION="${FRAMEWORK_DIR}/Info.plist" FRAMEWORK_HEADERS_DIR="${FRAMEWORK_DIR}/Headers" FRAMEWORK_LIB_PATH=""${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"" + FRAMEWORK_LINKER_PATH="@rpath/Frameworks/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" else FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}/Versions/A/Resources/" FRAMEWORK_PLIST_LOCATION="${FRAMEWORK_DIR}/Versions/A/Resources/Info.plist" FRAMEWORK_HEADERS_DIR="${FRAMEWORK_DIR}/Versions/A/Headers" FRAMEWORK_LIB_PATH="${FRAMEWORK_DIR}/Versions/A/${FRAMEWORK_NAME}" + FRAMEWORK_LINKER_PATH="@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" fi echo "Creating Resources Root: ${FRAMEWORK_RESOURCES_DIR}" @@ -90,9 +70,8 @@ if [ "$EMBEDDED_BUILD" = false ];then fi # Fix the linkage on the primary dylib -fix_linkage "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" -install_name_tool -id "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" -install_name_tool -change "@rpath/${FRAMEWORK_NAME}.framework/Libraries/${FRAMEWORK_NAME}" "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" +install_name_tool -id "${FRAMEWORK_LINKER_PATH}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" +install_name_tool -change "@rpath/libMaterialX.@MATERIALX_MAJOR_VERSION@.dylib" "${FRAMEWORK_LINKER_PATH}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" # Frameworks require all includes to use the framework name as the prefix for automatic discovery echo "Modifying headers..." diff --git a/source/MaterialXFormat/Util.cpp b/source/MaterialXFormat/Util.cpp index 3fc64e3819..ee4e4067f5 100644 --- a/source/MaterialXFormat/Util.cpp +++ b/source/MaterialXFormat/Util.cpp @@ -233,8 +233,11 @@ FileSearchPath getDefaultDataSearchPath() FileSearchPath searchPath; #if defined(BUILD_APPLE_FRAMEWORK) + #if defined(TARGET_OS_IPHONE) + const FilePath FRAMEWORK_RESOURCES("Assets"); + #else const FilePath FRAMEWORK_RESOURCES("Resources"); - + #endif Dl_info info; if (dladdr(reinterpret_cast(&getDefaultDataSearchPath), &info)) { From 5101013ac9a0e4a39971d44d91e7b3cc7c77ee5f Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 9 Oct 2024 14:05:01 -0700 Subject: [PATCH 077/137] Updates to GitHub CI (#2055) - Harmonize on ubuntu-22-04 for builds requiring wide coverage, as other Linux environments are more restricted in their latest releases. --- .github/workflows/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dc73409606..0967a6f9ab 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,10 +18,10 @@ jobs: fail-fast: false matrix: include: - - name: Linux_GCC_9_Python37 - os: ubuntu-20.04 + - name: Linux_GCC_10_Python37 + os: ubuntu-22.04 compiler: gcc - compiler_version: "9" + compiler_version: "10" python: 3.7 cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON -DMATERIALX_BUILD_MONOLITHIC=ON @@ -46,10 +46,10 @@ jobs: 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 + - name: Linux_Clang_13_Python37 + os: ubuntu-22.04 compiler: clang - compiler_version: "10" + compiler_version: "13" python: 3.7 cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON @@ -351,7 +351,7 @@ jobs: sdist: name: Python SDist - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.repository == 'AcademySoftwareFoundation/MaterialX' outputs: sdist_filename: ${{ steps.generate.outputs.filename }} @@ -387,7 +387,7 @@ jobs: fail-fast: false matrix: python-minor: ['7', '8', '9', '10', '11', '12'] - os: ['ubuntu-latest', 'windows-2022', 'macos-13'] + os: ['ubuntu-22.04', 'windows-2022', 'macos-13'] steps: - name: Sync Repository From 0f2438e35afda93870232beaa4535a42baece782 Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:42:37 -0700 Subject: [PATCH 078/137] Fix Chiang hair model for Metal Shading language (#2057) The current approach for converting GLSL code to MSL doesn't work for the recent Chiang hair PR #1968. --- libraries/pbrlib/genglsl/mx_hair_bsdf.glsl | 13 ++++++++-- source/MaterialXGenMsl/MslShaderGenerator.cpp | 24 ++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl b/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl index e3a9ac20d5..ec1acf91b3 100644 --- a/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl @@ -240,12 +240,21 @@ vec3 mx_chiang_hair_bsdf( float alpha = cuticle_angle * M_PI - (M_PI / 2.0); // remap [0, 1] to [-PI/2, PI/2] mx_hair_alpha_angles(alpha, sinThetaI, cosThetaI, angles); - vec3 tint[4] = vec3[](tint_R, tint_TT, tint_TRT, tint_TRT); + vec3 tint[4]; + tint[0] = tint_R; + tint[1] = tint_TT; + tint[2] = tint_TRT; + tint[3] = tint_TRT; roughness_R = clamp(roughness_R, 0.001, 1.0); roughness_TT = clamp(roughness_TT, 0.001, 1.0); roughness_TRT = clamp(roughness_TRT, 0.001, 1.0); - vec2 vs[4] = vec2[](roughness_R, roughness_TT, roughness_TRT, roughness_TRT); + + vec2 vs[4]; + vs[0] = roughness_R; + vs[1] = roughness_TT; + vs[2] = roughness_TRT; + vs[3] = roughness_TRT; // R, TT, TRT, TRRT+ vec3 F = vec3(0.0); diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index 8db763d7e1..5476b33c90 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -237,7 +237,29 @@ void MslShaderGenerator::MetalizeGeneratedShader(ShaderStage& shaderStage) const } size_t typename_end = pos; std::string typeName = sourceCode.substr(typename_beg, typename_end - typename_beg); - sourceCode.replace(beg, typename_end - beg, "thread " + typeName + "&"); + + while (std::isspace(sourceCode[pos])) + { + ++pos; + } + size_t varname_beg = pos; + while (!std::isspace(sourceCode[pos]) && sourceCode[pos] != '\n' && sourceCode[pos] != ',' && sourceCode[pos] != ')' ) + { + ++pos; + } + size_t varname_end = pos; + std::string varName = sourceCode.substr(varname_beg, varname_end - varname_beg); + + if (varName.find('[') != std::string::npos) + { + // if the variable is an array then we don't need to declare it as a reference, + // we will effectively just be passing the pointer to the array + sourceCode.replace(beg, typename_end - beg, "thread " + typeName); + } + else + { + sourceCode.replace(beg, typename_end - beg, "thread " + typeName + "&"); + } } pos = sourceCode.find(keyword, pos); } From cb04ef7b2388592125fe61b5dae7782523847a5b Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:43:22 -0700 Subject: [PATCH 079/137] Refactor mx_math files to remove GLSL guard (#2014) Refactor mx_math.glsl and mx_math.metal to remove the `__DECL_GL_MATH_FUNCTIONS__` guard, and prefix any necessary functions to ensure isolation from other shader generators, such as HdStorm. --- .../lib/mx_generate_prefilter_env.glsl | 6 +- .../pbrlib/genglsl/lib/mx_microfacet.glsl | 8 +- .../genglsl/lib/mx_microfacet_diffuse.glsl | 8 +- .../genglsl/lib/mx_microfacet_specular.glsl | 20 +-- libraries/stdlib/genglsl/lib/mx_math.glsl | 113 +++++++++++++++- .../stdlib/genglsl/mx_rotate_vector2.glsl | 6 +- .../stdlib/genglsl/mx_rotate_vector3.glsl | 6 +- .../stdlib/genglsl/stdlib_genglsl_impl.mtlx | 48 +++---- libraries/stdlib/genmsl/lib/mx_math.metal | 126 +++++++++++++++--- .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 52 ++++---- 10 files changed, 296 insertions(+), 97 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl b/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl index 7a80d0d3ec..7bc202bfeb 100644 --- a/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl @@ -13,9 +13,9 @@ vec3 mx_latlong_map_projection_inverse(vec2 uv) float latitude = (uv.y - 0.5) * M_PI; float longitude = (uv.x - 0.5) * M_PI * 2.0; - float x = -cos(latitude) * sin(longitude); - float y = -sin(latitude); - float z = cos(latitude) * cos(longitude); + float x = -mx_cos(latitude) * mx_sin(longitude); + float y = -mx_sin(latitude); + float z = mx_cos(latitude) * mx_cos(longitude); return vec3(x, y, z); } diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl index f0e6f55c13..05c12e907c 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl @@ -77,8 +77,8 @@ vec3 mx_uniform_sample_hemisphere(vec2 Xi) float phi = 2.0 * M_PI * Xi.x; float cosTheta = 1.0 - Xi.y; float sinTheta = sqrt(1.0 - mx_square(cosTheta)); - return vec3(cos(phi) * sinTheta, - sin(phi) * sinTheta, + return vec3(mx_cos(phi) * sinTheta, + mx_sin(phi) * sinTheta, cosTheta); } @@ -88,8 +88,8 @@ vec3 mx_cosine_sample_hemisphere(vec2 Xi) float phi = 2.0 * M_PI * Xi.x; float cosTheta = sqrt(Xi.y); float sinTheta = sqrt(1.0 - Xi.y); - return vec3(cos(phi) * sinTheta, - sin(phi) * sinTheta, + return vec3(mx_cos(phi) * sinTheta, + mx_sin(phi) * sinTheta, cosTheta); } diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl index 622db85012..f26c15df37 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl @@ -89,7 +89,7 @@ float mx_oren_nayar_fujii_diffuse_dir_albedo(float cosTheta, float roughness) float A = 1.0 / (1.0 + FUJII_CONSTANT_1 * roughness); float B = roughness * A; float Si = sqrt(max(0.0, 1.0 - mx_square(cosTheta))); - float G = Si * (acos(clamp(cosTheta, -1.0, 1.0)) - Si * cosTheta) + + float G = Si * (mx_acos(clamp(cosTheta, -1.0, 1.0)) - Si * cosTheta) + 2.0 * ((Si / cosTheta) * (1.0 - Si * Si * Si) - Si) / 3.0; return A + (B * G * M_PI_INV); } @@ -169,7 +169,7 @@ vec3 mx_burley_diffusion_profile(float dist, vec3 shape) // Inspired by Eric Penner's presentation in http://advances.realtimerendering.com/s2011/ vec3 mx_integrate_burley_diffusion(vec3 N, vec3 L, float radius, vec3 mfp) { - float theta = acos(dot(N, L)); + float theta = mx_acos(dot(N, L)); // Estimate the Burley diffusion shape from mean free path. vec3 shape = vec3(1.0) / max(mfp, 0.1); @@ -182,9 +182,9 @@ vec3 mx_integrate_burley_diffusion(vec3 N, vec3 L, float radius, vec3 mfp) for (int i = 0; i < SAMPLE_COUNT; i++) { float x = -M_PI + (float(i) + 0.5) * SAMPLE_WIDTH; - float dist = radius * abs(2.0 * sin(x * 0.5)); + float dist = radius * abs(2.0 * mx_sin(x * 0.5)); vec3 R = mx_burley_diffusion_profile(dist, shape); - sumD += R * max(cos(theta + x), 0.0); + sumD += R * max(mx_cos(theta + x), 0.0); sumR += R; } diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index 0e77e545e9..fd52bd7435 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -48,8 +48,8 @@ vec3 mx_ggx_importance_sample_VNDF(vec2 Xi, vec3 V, vec2 alpha) float phi = 2.0 * M_PI * Xi.x; float z = (1.0 - Xi.y) * (1.0 + V.z) - V.z; float sinTheta = sqrt(clamp(1.0 - z * z, 0.0, 1.0)); - float x = sinTheta * cos(phi); - float y = sinTheta * sin(phi); + float x = sinTheta * mx_cos(phi); + float y = sinTheta * mx_sin(phi); vec3 c = vec3(x, y, z); // Compute the microfacet normal. @@ -286,9 +286,9 @@ void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, vec3 U = sqrt((A+B)/2.0); vec3 V = max(vec3(0.0), sqrt((B-A)/2.0)); - phiS = atan(2.0*eta1*V*cosTheta, U*U + V*V - mx_square(eta1*cosTheta)); - phiP = atan(2.0*eta1*eta2*eta2*cosTheta * (2.0*k2*U - (vec3(1.0)-k2*k2) * V), - mx_square(eta2*eta2*(vec3(1.0)+k2*k2)*cosTheta) - eta1*eta1*(U*U+V*V)); + phiS = mx_atan(2.0*eta1*V*cosTheta, U*U + V*V - mx_square(eta1*cosTheta)); + phiP = mx_atan(2.0*eta1*eta2*eta2*cosTheta * (2.0*k2*U - (vec3(1.0)-k2*k2) * V), + mx_square(eta2*eta2*(vec3(1.0)+k2*k2)*cosTheta) - eta1*eta1*(U*U+V*V)); } // https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html @@ -299,8 +299,8 @@ vec3 mx_eval_sensitivity(float opd, vec3 shift) vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13); vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06); vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09); - vec3 xyz = val * sqrt(2.0*M_PI * var) * cos(pos * phase + shift) * exp(- var * phase*phase); - xyz.x += 9.7470e-14 * sqrt(2.0*M_PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift[0]) * exp(- 4.5282e+09 * phase*phase); + vec3 xyz = val * sqrt(2.0*M_PI * var) * mx_cos(pos * phase + shift) * exp(- var * phase*phase); + xyz.x += 9.7470e-14 * sqrt(2.0*M_PI * 4.5282e+09) * mx_cos(2.2399e+06 * phase + shift[0]) * exp(- 4.5282e+09 * phase*phase); return xyz / 1.0685e-7; } @@ -341,7 +341,7 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) } // Phase shift - float cosB = cos(atan(eta2 / eta1)); + float cosB = mx_cos(mx_atan(eta2 / eta1)); vec2 phi21 = vec2(cosTheta < cosB ? 0.0 : M_PI, M_PI); vec3 phi23p, phi23s; if (fd.model == FRESNEL_MODEL_SCHLICK) @@ -486,8 +486,8 @@ vec3 mx_refraction_solid_sphere(vec3 R, vec3 N, float ior) vec2 mx_latlong_projection(vec3 dir) { - float latitude = -asin(dir.y) * M_PI_INV + 0.5; - float longitude = atan(dir.x, -dir.z) * M_PI_INV * 0.5 + 0.5; + float latitude = -mx_asin(dir.y) * M_PI_INV + 0.5; + float longitude = mx_atan(dir.x, -dir.z) * M_PI_INV * 0.5 + 0.5; return vec2(longitude, latitude); } diff --git a/libraries/stdlib/genglsl/lib/mx_math.glsl b/libraries/stdlib/genglsl/lib/mx_math.glsl index cff7835a4c..838fe1f3dd 100644 --- a/libraries/stdlib/genglsl/lib/mx_math.glsl +++ b/libraries/stdlib/genglsl/lib/mx_math.glsl @@ -4,12 +4,10 @@ float mx_square(float x) { return x*x; } - vec2 mx_square(vec2 x) { return x*x; } - vec3 mx_square(vec3 x) { return x*x; @@ -27,3 +25,114 @@ float mx_inversesqrt(float x) { return inversesqrt(x); } + +float mx_radians(float degree) +{ + return radians(degree); +} + +float mx_sin(float x) +{ + return sin(x); +} +vec2 mx_sin(vec2 x) +{ + return sin(x); +} +vec3 mx_sin(vec3 x) +{ + return sin(x); +} +vec4 mx_sin(vec4 x) +{ + return sin(x); +} + +float mx_cos(float x) +{ + return cos(x); +} +vec2 mx_cos(vec2 x) +{ + return cos(x); +} +vec3 mx_cos(vec3 x) +{ + return cos(x); +} +vec4 mx_cos(vec4 x) +{ + return cos(x); +} + +float mx_tan(float x) +{ + return tan(x); +} +vec2 mx_tan(vec2 x) +{ + return tan(x); +} +vec3 mx_tan(vec3 x) +{ + return tan(x); +} +vec4 mx_tan(vec4 x) +{ + return tan(x); +} + +float mx_asin(float x) +{ + return asin(x); +} +vec2 mx_asin(vec2 x) +{ + return asin(x); +} +vec3 mx_asin(vec3 x) +{ + return asin(x); +} +vec4 mx_asin(vec4 x) +{ + return asin(x); +} + +float mx_acos(float x) +{ + return acos(x); +} +vec2 mx_acos(vec2 x) +{ + return acos(x); +} +vec3 mx_acos(vec3 x) +{ + return acos(x); +} +vec4 mx_acos(vec4 x) +{ + return acos(x); +} + +float mx_atan(float y_over_x) +{ + return atan(y_over_x); +} +float mx_atan(float y, float x) +{ + return atan(y, x); +} +vec2 mx_atan(vec2 y, vec2 x) +{ + return atan(y, x); +} +vec3 mx_atan(vec3 y, vec3 x) +{ + return atan(y, x); +} +vec4 mx_atan(vec4 y, vec4 x) +{ + return atan(y, x); +} diff --git a/libraries/stdlib/genglsl/mx_rotate_vector2.glsl b/libraries/stdlib/genglsl/mx_rotate_vector2.glsl index a66c17d0ab..d01270d8ce 100644 --- a/libraries/stdlib/genglsl/mx_rotate_vector2.glsl +++ b/libraries/stdlib/genglsl/mx_rotate_vector2.glsl @@ -1,7 +1,7 @@ void mx_rotate_vector2(vec2 _in, float amount, out vec2 result) { - float rotationRadians = radians(amount); - float sa = sin(rotationRadians); - float ca = cos(rotationRadians); + float rotationRadians = mx_radians(amount); + float sa = mx_sin(rotationRadians); + float ca = mx_cos(rotationRadians); result = vec2(ca*_in.x + sa*_in.y, -sa*_in.x + ca*_in.y); } diff --git a/libraries/stdlib/genglsl/mx_rotate_vector3.glsl b/libraries/stdlib/genglsl/mx_rotate_vector3.glsl index fb06e120ec..fda1188379 100644 --- a/libraries/stdlib/genglsl/mx_rotate_vector3.glsl +++ b/libraries/stdlib/genglsl/mx_rotate_vector3.glsl @@ -1,8 +1,8 @@ mat4 mx_rotationMatrix(vec3 axis, float angle) { axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); + float s = mx_sin(angle); + float c = mx_cos(angle); float oc = 1.0 - c; return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, @@ -13,7 +13,7 @@ mat4 mx_rotationMatrix(vec3 axis, float angle) void mx_rotate_vector3(vec3 _in, float amount, vec3 axis, out vec3 result) { - float rotationRadians = radians(amount); + float rotationRadians = mx_radians(amount); mat4 m = mx_rotationMatrix(axis, rotationRadians); result = (m * vec4(_in, 1.0)).xyz; } diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index c3ee147e13..765c48c77b 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -326,30 +326,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libraries/stdlib/genmsl/lib/mx_math.metal b/libraries/stdlib/genmsl/lib/mx_math.metal index 46a8c5d57e..cda4e867e4 100644 --- a/libraries/stdlib/genmsl/lib/mx_math.metal +++ b/libraries/stdlib/genmsl/lib/mx_math.metal @@ -4,12 +4,10 @@ float mx_square(float x) { return x*x; } - vec2 mx_square(vec2 x) { return x*x; } - vec3 mx_square(vec3 x) { return x*x; @@ -26,11 +24,12 @@ float mx_inversesqrt(float x) return ::rsqrt(x); } -#ifdef __DECL_GL_MATH_FUNCTIONS__ - -float radians(float degree) { return (degree * M_PI_F / 180.0f); } +float mx_radians(float degree) +{ + return (degree * M_PI_F / 180.0f); +} -float3x3 inverse(float3x3 m) +float3x3 mx_inverse(float3x3 m) { float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0]; float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1]; @@ -56,7 +55,7 @@ float3x3 inverse(float3x3 m) return ret; } -float4x4 inverse(float4x4 m) +float4x4 mx_inverse(float4x4 m) { float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0], n14 = m[3][0]; float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1], n24 = m[3][1]; @@ -96,17 +95,108 @@ float4x4 inverse(float4x4 m) return ret; } -template -T atan(T y_over_x) { return ::atan(y_over_x); } +float mx_sin(float x) +{ + return sin(x); +} +vec2 mx_sin(vec2 x) +{ + return sin(x); +} +vec3 mx_sin(vec3 x) +{ + return sin(x); +} +vec4 mx_sin(vec4 x) +{ + return sin(x); +} -template -T atan(T y, T x) { return ::atan2(y, x); } +float mx_cos(float x) +{ + return cos(x); +} +vec2 mx_cos(vec2 x) +{ + return cos(x); +} +vec3 mx_cos(vec3 x) +{ + return cos(x); +} +vec4 mx_cos(vec4 x) +{ + return cos(x); +} -#define lessThan(a, b) ((a) < (b)) -#define lessThanEqual(a, b) ((a) <= (b)) -#define greaterThan(a, b) ((a) > (b)) -#define greaterThanEqual(a, b) ((a) >= (b)) -#define equal(a, b) ((a) == (b)) -#define notEqual(a, b) ((a) != (b)) +float mx_tan(float x) +{ + return tan(x); +} +vec2 mx_tan(vec2 x) +{ + return tan(x); +} +vec3 mx_tan(vec3 x) +{ + return tan(x); +} +vec4 mx_tan(vec4 x) +{ + return tan(x); +} -#endif +float mx_asin(float x) +{ + return asin(x); +} +vec2 mx_asin(vec2 x) +{ + return asin(x); +} +vec3 mx_asin(vec3 x) +{ + return asin(x); +} +vec4 mx_asin(vec4 x) +{ + return asin(x); +} + +float mx_acos(float x) +{ + return acos(x); +} +vec2 mx_acos(vec2 x) +{ + return acos(x); +} +vec3 mx_acos(vec3 x) +{ + return acos(x); +} +vec4 mx_acos(vec4 x) +{ + return acos(x); +} + +float mx_atan(float y_over_x) +{ + return ::atan(y_over_x); +} +float mx_atan(float y, float x) +{ + return ::atan2(y, x); +} +vec2 mx_atan(vec2 y, vec2 x) +{ + return ::atan2(y, x); +} +vec3 mx_atan(vec3 y, vec3 x) +{ + return ::atan2(y, x); +} +vec4 mx_atan(vec4 y, vec4 x) +{ + return ::atan2(y, x); +} diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index 2f69a1bb90..ab4461cad4 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -327,30 +327,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -459,8 +459,8 @@ - - + + From 4f380f3b47041b1b2768acf484564906547a8d1c Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 12 Oct 2024 09:09:43 -0700 Subject: [PATCH 080/137] Simplify mx_math files (#2058) This changelist simplifies mx_math.glsl and mx_math.metal to reduce code repetition and clarify the differences between dedicated helper functions and simple keyword replacement. Additionally it addresses an omitted update from atan to mx_atan in the implementation of chiang_hair_bsdf, and adds an update step to Linux CI for robustness. --- .github/workflows/main.yml | 1 + libraries/pbrlib/genglsl/mx_hair_bsdf.glsl | 2 +- libraries/stdlib/genglsl/lib/mx_math.glsl | 127 ++------------------- libraries/stdlib/genmsl/lib/mx_math.metal | 113 ++++-------------- 4 files changed, 33 insertions(+), 210 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0967a6f9ab..95516bd4e5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -127,6 +127,7 @@ jobs: - name: Install Dependencies (Linux) if: runner.os == 'Linux' run: | + sudo apt-get update sudo apt-get install xorg-dev if [ "${{ matrix.compiler_version }}" != 'None' ]; then if [ "${{ matrix.compiler }}" = "gcc" ]; then diff --git a/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl b/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl index ec1acf91b3..8ac6222714 100644 --- a/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl @@ -213,7 +213,7 @@ vec3 mx_chiang_hair_bsdf( float x1 = dot(L, Y); float y2 = dot(V, N); float x2 = dot(V, Y); - float phi = atan(y1 * x2 - y2 * x1, x1 * x2 + y1 * y2); + float phi = mx_atan(y1 * x2 - y2 * x1, x1 * x2 + y1 * y2); vec3 k1_p = normalize(V - X * dot(V, X)); float cosGammaO = dot(N, k1_p); diff --git a/libraries/stdlib/genglsl/lib/mx_math.glsl b/libraries/stdlib/genglsl/lib/mx_math.glsl index 838fe1f3dd..f87e5653da 100644 --- a/libraries/stdlib/genglsl/lib/mx_math.glsl +++ b/libraries/stdlib/genglsl/lib/mx_math.glsl @@ -1,13 +1,24 @@ #define M_FLOAT_EPS 1e-8 +#define mx_inversesqrt inversesqrt +#define mx_sin sin +#define mx_cos cos +#define mx_tan tan +#define mx_asin asin +#define mx_acos acos +#define mx_atan atan +#define mx_radians radians + float mx_square(float x) { return x*x; } + vec2 mx_square(vec2 x) { return x*x; } + vec3 mx_square(vec3 x) { return x*x; @@ -20,119 +31,3 @@ vec3 mx_srgb_encode(vec3 color) vec3 powSeg = 1.055 * pow(max(color, vec3(0.0)), vec3(1.0 / 2.4)) - 0.055; return mix(linSeg, powSeg, isAbove); } - -float mx_inversesqrt(float x) -{ - return inversesqrt(x); -} - -float mx_radians(float degree) -{ - return radians(degree); -} - -float mx_sin(float x) -{ - return sin(x); -} -vec2 mx_sin(vec2 x) -{ - return sin(x); -} -vec3 mx_sin(vec3 x) -{ - return sin(x); -} -vec4 mx_sin(vec4 x) -{ - return sin(x); -} - -float mx_cos(float x) -{ - return cos(x); -} -vec2 mx_cos(vec2 x) -{ - return cos(x); -} -vec3 mx_cos(vec3 x) -{ - return cos(x); -} -vec4 mx_cos(vec4 x) -{ - return cos(x); -} - -float mx_tan(float x) -{ - return tan(x); -} -vec2 mx_tan(vec2 x) -{ - return tan(x); -} -vec3 mx_tan(vec3 x) -{ - return tan(x); -} -vec4 mx_tan(vec4 x) -{ - return tan(x); -} - -float mx_asin(float x) -{ - return asin(x); -} -vec2 mx_asin(vec2 x) -{ - return asin(x); -} -vec3 mx_asin(vec3 x) -{ - return asin(x); -} -vec4 mx_asin(vec4 x) -{ - return asin(x); -} - -float mx_acos(float x) -{ - return acos(x); -} -vec2 mx_acos(vec2 x) -{ - return acos(x); -} -vec3 mx_acos(vec3 x) -{ - return acos(x); -} -vec4 mx_acos(vec4 x) -{ - return acos(x); -} - -float mx_atan(float y_over_x) -{ - return atan(y_over_x); -} -float mx_atan(float y, float x) -{ - return atan(y, x); -} -vec2 mx_atan(vec2 y, vec2 x) -{ - return atan(y, x); -} -vec3 mx_atan(vec3 y, vec3 x) -{ - return atan(y, x); -} -vec4 mx_atan(vec4 y, vec4 x) -{ - return atan(y, x); -} diff --git a/libraries/stdlib/genmsl/lib/mx_math.metal b/libraries/stdlib/genmsl/lib/mx_math.metal index cda4e867e4..afd8fb4a7e 100644 --- a/libraries/stdlib/genmsl/lib/mx_math.metal +++ b/libraries/stdlib/genmsl/lib/mx_math.metal @@ -1,32 +1,35 @@ #define M_FLOAT_EPS 1e-8 +#define mx_sin sin +#define mx_cos cos +#define mx_tan tan +#define mx_asin asin +#define mx_acos acos + float mx_square(float x) { return x*x; } + vec2 mx_square(vec2 x) { return x*x; } + vec3 mx_square(vec3 x) { return x*x; } -template -T1 mx_mod(T1 x, T2 y) -{ - return x - y * floor(x/y); -} - float mx_inversesqrt(float x) { return ::rsqrt(x); } -float mx_radians(float degree) +template +T1 mx_mod(T1 x, T2 y) { - return (degree * M_PI_F / 180.0f); + return x - y * floor(x/y); } float3x3 mx_inverse(float3x3 m) @@ -95,108 +98,32 @@ float4x4 mx_inverse(float4x4 m) return ret; } -float mx_sin(float x) -{ - return sin(x); -} -vec2 mx_sin(vec2 x) -{ - return sin(x); -} -vec3 mx_sin(vec3 x) -{ - return sin(x); -} -vec4 mx_sin(vec4 x) -{ - return sin(x); -} - -float mx_cos(float x) -{ - return cos(x); -} -vec2 mx_cos(vec2 x) -{ - return cos(x); -} -vec3 mx_cos(vec3 x) -{ - return cos(x); -} -vec4 mx_cos(vec4 x) -{ - return cos(x); -} - -float mx_tan(float x) -{ - return tan(x); -} -vec2 mx_tan(vec2 x) -{ - return tan(x); -} -vec3 mx_tan(vec3 x) -{ - return tan(x); -} -vec4 mx_tan(vec4 x) -{ - return tan(x); -} - -float mx_asin(float x) -{ - return asin(x); -} -vec2 mx_asin(vec2 x) -{ - return asin(x); -} -vec3 mx_asin(vec3 x) -{ - return asin(x); -} -vec4 mx_asin(vec4 x) -{ - return asin(x); -} - -float mx_acos(float x) -{ - return acos(x); -} -vec2 mx_acos(vec2 x) -{ - return acos(x); -} -vec3 mx_acos(vec3 x) -{ - return acos(x); -} -vec4 mx_acos(vec4 x) -{ - return acos(x); -} - float mx_atan(float y_over_x) { return ::atan(y_over_x); } + float mx_atan(float y, float x) { return ::atan2(y, x); } + vec2 mx_atan(vec2 y, vec2 x) { return ::atan2(y, x); } + vec3 mx_atan(vec3 y, vec3 x) { return ::atan2(y, x); } + vec4 mx_atan(vec4 y, vec4 x) { return ::atan2(y, x); } + +float mx_radians(float degree) +{ + return (degree * M_PI_F / 180.0f); +} From 0ba2ad0d712283cdf9cf33ab16cd1656a18e6276 Mon Sep 17 00:00:00 2001 From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com> Date: Sat, 12 Oct 2024 17:41:16 -0700 Subject: [PATCH 081/137] Add hair nodes to MDL backend (#2059) This PR introduces support for hair nodes to the MDL backend. Nodes to add: - `` - `` - `` - `` --- .../pbrlib/genmdl/pbrlib_genmdl_impl.mtlx | 12 +++ .../mdl/materialx/pbrlib_1_6.mdl | 90 +++++++++++++++++++ .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 6 +- source/MaterialXTest/MaterialXGenMdl/GenMdl.h | 3 - 4 files changed, 103 insertions(+), 8 deletions(-) diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index 86b19eaa71..754594620b 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -25,6 +25,9 @@ + + + @@ -90,4 +93,13 @@ + + + + + + + + + diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl index ef2e090a49..b69d59e8b0 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl @@ -428,6 +428,35 @@ export material mx_thin_film_bsdf( volume: mxp_base.volume ); +export material mx_chiang_hair_bsdf( + // TODO: MDL's chiang_hair BSDF has no support tinting each lobes + color mxp_tint_R = color(1.0), + color mxp_tint_TT = color(1.0), + color mxp_tint_TRT = color(1.0), + float mxp_ior = 1.55, + float2 mxp_roughness_R = float2(0.1, 0.1), + float2 mxp_roughness_TT = float2(0.05, 0.05), + float2 mxp_roughness_TRT = float2(0.2, 0.2), + float mxp_cuticle_angle = 0.5, + float3 mxp_absorption_coefficient = float3(0.0), + // TODO: MDL's chiang_hair BSDF has no support user tangent vector + float3 mxp_curve_direction = state::texture_tangent_u(0) +) [[ + anno::usage( "materialx:bsdf") +]] += material( + hair: df::chiang_hair_bsdf( + diffuse_reflection_weight: 0.0, + diffuse_reflection_tint: color(0.0), + roughness_R: mxp_roughness_R, + roughness_TT: mxp_roughness_TT, + roughness_TRT: mxp_roughness_TRT, + cuticle_angle: mxp_cuticle_angle, + absorption_coefficient: mxp_absorption_coefficient, + ior: mxp_ior + ) +); + // EDF Nodes export material mx_uniform_edf( @@ -980,3 +1009,64 @@ export mx_artistic_ior__result mx_artistic_ior( color k = math::sqrt(k2); return mx_artistic_ior__result(n,k); } + +export float3 mx_dion_hair_absorption_from_melanin( + float mxp_melanin_concentration = 0.25, + float mxp_melanin_redness = 0.5, + color mxp_eumelanin_color = color(0.657704, 0.498077, 0.254107), + color mxp_pheomelanin_color = color(0.829444, 0.67032, 0.349938) +) { + float melanin = -math::log(math::max(1.0 - mxp_melanin_concentration, 0.0001)); + float eumelanin = melanin * (1.0 = mxp_melanin_redness); + float pheomelanin = melanin * mxp_melanin_redness; + return math::max( + eumelanin * -math::log(mxp_eumelanin_color) + pheomelanin * -math::log(mxp_pheomelanin_color), + float3(0.0) + ); +} + +export float3 mx_chiang_hair_absorption_from_color( + color mxp_color = color(1.0, 1.0, 1.0), + float mxp_azimuthal_roughness = 0.2 +) { + float r2 = mxp_azimuthal_roughness * mxp_azimuthal_roughness; + float r4 = r2 * r2; + float r_fac = + 5.969 - + (0.215 * mxp_azimuthal_roughness) + + (2.532 * r2) - + (10.73 * r2 * mxp_azimuthal_roughness) + + (5.574 * r4) + + (0.245 * r4 * mxp_azimuthal_roughness); + float3 sigma = math::log(math::min(math::max(mxp_color, 0.001), float3(1.0))) / r_fac; + return (sigma * sigma); +} + +// Supportive struct type for the three outputs of mx_chiang_hair_roughness +export struct mx_chiang_hair_roughness__result { + float2 mxp_roughness_R; + float2 mxp_roughness_TT; + float2 mxp_roughness_TRT; +}; + +export mx_chiang_hair_roughness__result mx_chiang_hair_roughness( + float mxp_longitudinal = 0.1, + float mxp_azimuthal = 0.2, + float mxp_scale_TT = 0.5, + float mxp_scale_TRT = 2.0 +) { + float lr = math::clamp(mxp_longitudinal, 0.001, 1.0); + float ar = math::clamp(mxp_azimuthal, 0.001, 1.0); + + // longitudinal variance + float v = 0.726 * lr + 0.812 * lr * lr + 3.7 * math::pow(lr, 20); + v = v * v; + + float s = 0.265 * ar + 1.194 * ar * ar + 5.372 * math::pow(ar, 22); + + float2 roughness_R = float2(v, s); + float2 roughness_TT = float2(v * mxp_scale_TT * mxp_scale_TT, s); + float2 roughness_TRT = float2(v * mxp_scale_TRT * mxp_scale_TRT, s); + + return mx_chiang_hair_roughness__result(roughness_R, roughness_TT, roughness_TRT); +} diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index 12a1f33868..e1a23cf7d4 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -93,12 +93,8 @@ TEST_CASE("GenShader: MDL Implementation Check", "[genmdl]") generatorSkipNodeTypes.insert("light"); mx::StringSet generatorSkipNodeDefs; - generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); - generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); - generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); - generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 35); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31); } diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h index 1e617f73fb..ab92a5dacf 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h @@ -50,9 +50,6 @@ class MdlShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester _skipFiles.insert("heighttonormal_in_nodegraph.mtlx"); } - _skipFiles.insert("hair_bsdf.mtlx"); - _skipFiles.insert("hair_surfaceshader.mtlx"); - ShaderGeneratorTester::addSkipFiles(); } From 3f6c60578b9924f45ea8a7ca08b3ea7a6bec8ce7 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 13 Oct 2024 12:47:11 -0700 Subject: [PATCH 082/137] Refinements to chiang_hair_bsdf (#2060) - Fix MSL and ESSL compatibility issues in the implementation of chiang_hair_bsdf, including integer-to-float conversions and computations of boolean arrays. - Move the GLSL implementation of chiang_hair_bsdf to mx_chiang_hair_bsdf.glsl for consistency with other nodes. - Remove a stray reference to the GLSL implementation in MDL. --- .../{mx_hair_bsdf.glsl => mx_chiang_hair_bsdf.glsl} | 11 +++++------ libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx | 8 ++++---- libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) rename libraries/pbrlib/genglsl/{mx_hair_bsdf.glsl => mx_chiang_hair_bsdf.glsl} (97%) diff --git a/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl b/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl similarity index 97% rename from libraries/pbrlib/genglsl/mx_hair_bsdf.glsl rename to libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl index 8ac6222714..22b2226ab3 100644 --- a/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl @@ -49,10 +49,10 @@ void mx_chiang_hair_roughness( float ar = clamp(azimuthal, 0.001, 1.0); // longitudinal variance - float v = 0.726 * lr + 0.812 * lr * lr + 3.7 * pow(lr, 20); + float v = 0.726 * lr + 0.812 * lr * lr + 3.7 * pow(lr, 20.0); v = v * v; - float s = 0.265 * ar + 1.194 * ar * ar + 5.372 * pow(ar, 22); + float s = 0.265 * ar + 1.194 * ar * ar + 5.372 * pow(ar, 22.0); roughness_R = vec2(v, s); roughness_TT = vec2(v * scale_TT * scale_TT, s); @@ -111,7 +111,8 @@ float mx_hair_trimmed_logistic(float x, float s, float a, float b) float mx_hair_phi(int p, float gammaO, float gammaT) { - return 2.0 * p * gammaT - 2.0 * gammaO + p * M_PI; + float fP = float(p); + return 2.0 * fP * gammaT - 2.0 * gammaO + fP * M_PI; } float mx_hair_longitudinal_scattering( // Mp @@ -260,9 +261,7 @@ vec3 mx_chiang_hair_bsdf( vec3 F = vec3(0.0); for (int i = 0; i <= 3; ++i) { - if (all(lessThanEqual(tint[i], vec3(0.0)))) - continue; - + tint[i] = max(tint[i], vec3(0.0)); float Mp = mx_hair_longitudinal_scattering(angles[i].x, angles[i].y, sinThetaO, cosThetaO, vs[i].x); float Np = (i == 3) ? (1.0 / 2.0 * M_PI) : mx_hair_azimuthal_scattering(phi, i, vs[i].y, gammaO, gammaT); F += Mp * Np * tint[i] * Ap[i]; diff --git a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx index 1c495cb4bd..4b3be10faf 100644 --- a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx +++ b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx @@ -26,7 +26,7 @@ - + @@ -78,12 +78,12 @@ - + - + - + diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index 754594620b..0737ca82ab 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -100,6 +100,6 @@ - + From ede65733dc1884fff0c07be04ac7938cf50d128f Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 13 Oct 2024 15:31:13 -0700 Subject: [PATCH 083/137] Extend shader validation tests (#2062) --- .github/workflows/main.yml | 6 +++--- python/Scripts/generateshader.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 95516bd4e5..6821002b6d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -229,13 +229,13 @@ jobs: run: | vcpkg/vcpkg install glslang --triplet=x64-windows glslangValidator.exe -v - python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --target glsl --validator glslangValidator.exe --vulkanGlsl True --validatorArgs="-V --aml" - python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --target essl --validator glslangValidator.exe + python python/Scripts/generateshader.py resources/Materials/Examples --target glsl --validator glslangValidator.exe --vulkanGlsl True --validatorArgs="-V --aml" + python python/Scripts/generateshader.py resources/Materials/Examples --target essl --validator glslangValidator.exe - name: Shader Validation Tests (MacOS) if: matrix.test_shaders == 'ON' && runner.os == 'macOS' run: | - python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --target msl --validator "xcrun metal --language=metal" --validatorArgs="-w" + python python/Scripts/generateshader.py resources/Materials/Examples --target msl --validator "xcrun metal --language=metal" --validatorArgs="-w" - name: Coverage Analysis Tests if: matrix.coverage_analysis == 'ON' diff --git a/python/Scripts/generateshader.py b/python/Scripts/generateshader.py index f6158d270a..cd158f2143 100644 --- a/python/Scripts/generateshader.py +++ b/python/Scripts/generateshader.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ''' -Utility to generate the shader for materials found in a MaterialX document. One file will be generated -for each material / shader found. The currently supported target languages are GLSL, OSL, MDL and ESSL. +Generate shader code for each renderable element in a MaterialX document or folder. +The currently supported target languages are GLSL, ESSL, MSL, OSL, and MDL. ''' import sys, os, argparse, subprocess @@ -43,7 +43,7 @@ def getMaterialXFiles(rootPath): return filelist def main(): - parser = argparse.ArgumentParser(description='Generate shader code for each material / shader in a document.') + parser = argparse.ArgumentParser(description='Generate shader code for each renderable element in a MaterialX document or folder.') parser.add_argument('--path', dest='paths', action='append', nargs='+', help='An additional absolute search path location (e.g. "/projects/MaterialX")') parser.add_argument('--library', dest='libraries', action='append', nargs='+', help='An additional relative path to a custom data library folder (e.g. "libraries/custom")') parser.add_argument('--target', dest='target', default='glsl', help='Target shader generator to use (e.g. "glsl, osl, mdl, essl, vulkan"). Default is glsl.') From b058d9cbba16d06ed858c53f39f2af7b9e41b550 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 14 Oct 2024 09:37:36 -0700 Subject: [PATCH 084/137] Improvements to shader validation (#2067) This changelist makes a handful of improvements to the GitHub CI for shader validation, increasing the level of coverage for future changes. - Add MSL validation for the stdlib test suite. - Replace a non-working Vulkan GLSL test with standard GLSL. - Fix an edge case in generateshader.py. - Remove unneeded tests from the stdlib test suite. --- .github/workflows/main.yml | 3 +- python/Scripts/generateshader.py | 27 +++--- .../TestSuite/stdlib/convert/convert.mtlx | 84 ------------------- 3 files changed, 12 insertions(+), 102 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6821002b6d..c11603dd70 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -229,13 +229,14 @@ jobs: run: | vcpkg/vcpkg install glslang --triplet=x64-windows glslangValidator.exe -v - python python/Scripts/generateshader.py resources/Materials/Examples --target glsl --validator glslangValidator.exe --vulkanGlsl True --validatorArgs="-V --aml" + python python/Scripts/generateshader.py resources/Materials/Examples --target glsl --validator glslangValidator.exe python python/Scripts/generateshader.py resources/Materials/Examples --target essl --validator glslangValidator.exe - name: Shader Validation Tests (MacOS) if: matrix.test_shaders == 'ON' && runner.os == 'macOS' run: | python python/Scripts/generateshader.py resources/Materials/Examples --target msl --validator "xcrun metal --language=metal" --validatorArgs="-w" + python python/Scripts/generateshader.py resources/Materials/TestSuite/stdlib --target msl --validator "xcrun metal --language=metal" --validatorArgs="-w" - name: Coverage Analysis Tests if: matrix.coverage_analysis == 'ON' diff --git a/python/Scripts/generateshader.py b/python/Scripts/generateshader.py index cd158f2143..259812f6f1 100644 --- a/python/Scripts/generateshader.py +++ b/python/Scripts/generateshader.py @@ -139,13 +139,6 @@ def main(): shadergen.setUnitSystem(unitsystem) genoptions.targetDistanceUnit = 'meter' - # Look for renderable nodes - nodes = mx_gen_shader.findRenderableElements(doc) - if not nodes: - nodes = doc.getMaterialNodes() - if not nodes: - nodes = doc.getNodesOfType(mx.SURFACE_SHADER_TYPE_STRING) - pathPrefix = '' if opts.outputPath and os.path.exists(opts.outputPath): pathPrefix = opts.outputPath + os.path.sep @@ -154,11 +147,11 @@ def main(): print('- Shader output path: ' + pathPrefix) failedShaders = "" - for node in nodes: - nodeName = node.getName() - print('-- Generate code for node: ' + nodeName) - nodeName = mx.createValidName(nodeName) - shader = shadergen.generate(nodeName, node, context) + for elem in mx_gen_shader.findRenderableElements(doc): + elemName = elem.getName() + print('-- Generate code for element: ' + elemName) + elemName = mx.createValidName(elemName) + shader = shadergen.generate(elemName, elem, context) if shader: # Use extension of .vert and .frag as it's type is # recognized by glslangValidator @@ -189,17 +182,17 @@ def main(): errors = validateCode(filename, opts.validator, opts.validatorArgs) if errors != "": - print("--- Validation failed for node: ", nodeName) + print("--- Validation failed for element: ", elemName) print("----------------------------") print('--- Error log: ', errors) print("----------------------------") - failedShaders += (nodeName + ' ') + failedShaders += (elemName + ' ') else: - print("--- Validation passed for node:", nodeName) + print("--- Validation passed for element:", elemName) else: - print("--- Validation failed for node:", nodeName) - failedShaders += (nodeName + ' ') + print("--- Validation failed for element:", elemName) + failedShaders += (elemName + ' ') if failedShaders != "": sys.exit(-1) diff --git a/resources/Materials/TestSuite/stdlib/convert/convert.mtlx b/resources/Materials/TestSuite/stdlib/convert/convert.mtlx index 377cb015df..f29b1eaab4 100644 --- a/resources/Materials/TestSuite/stdlib/convert/convert.mtlx +++ b/resources/Materials/TestSuite/stdlib/convert/convert.mtlx @@ -1,8 +1,5 @@ - @@ -30,85 +27,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From afa175675212c5e9014d4f948095b1d1200c5587 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 14 Oct 2024 14:46:16 -0700 Subject: [PATCH 085/137] Reduce duplication in MSL implementations (#2068) This changelist removes a number of MSL implementations that duplicate their counterparts in GLSL, instead using the inheritance relationship between these two shader generators to handle code sharing. --- .../pbrlib/genmsl/pbrlib_genmsl_impl.mtlx | 46 -- .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 545 ------------------ 2 files changed, 591 deletions(-) diff --git a/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx b/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx index e88a47a1dc..30dd6e937d 100644 --- a/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx +++ b/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx @@ -1,33 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -46,29 +19,10 @@ - - - - - - - - - - - - - - - - - - - diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index ab4461cad4..be55f772be 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -49,92 +49,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -186,72 +104,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -265,176 +117,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -444,88 +126,21 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -536,141 +151,14 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -685,18 +173,6 @@ - - - - - - - - - - - - @@ -716,29 +192,8 @@ - - - - - - - - - - - - - - - - - - - - - From da60312f485fef948b1f38578a8aa13f397e102d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 14 Oct 2024 17:19:57 -0700 Subject: [PATCH 086/137] Move templated accessors to Element.cpp (#2069) This changelist moves the templated accessors `getChildOfType` and `getChildrenOfType` from Element.h to Element.cpp, allowing upcoming features to be implemented in a more straightforward fashion. --- source/MaterialXCore/Element.cpp | 29 ++++++++++++++++++++++++++--- source/MaterialXCore/Element.h | 21 ++------------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 149b7bc757..1a48142962 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -284,6 +284,27 @@ ElementPtr Element::changeChildCategory(ElementPtr child, const string& category return newChild; } +template shared_ptr Element::getChildOfType(const string& name) const +{ + ElementPtr child = getChild(name); + return child ? child->asA() : shared_ptr(); +} + +template vector> Element::getChildrenOfType(const string& category) const +{ + vector> children; + for (ElementPtr child : _childOrder) + { + shared_ptr instance = child->asA(); + if (!instance) + continue; + if (!category.empty() && child->getCategory() != category) + continue; + children.push_back(instance); + } + return children; +} + ElementPtr Element::getRoot() { ElementPtr root = _root.lock(); @@ -866,9 +887,11 @@ template class ElementRegistry // Template instantiations // -#define INSTANTIATE_SUBCLASS(T) \ - template MX_CORE_API shared_ptr Element::asA(); \ - template MX_CORE_API shared_ptr Element::asA() const; +#define INSTANTIATE_SUBCLASS(T) \ + template MX_CORE_API shared_ptr Element::asA(); \ + template MX_CORE_API shared_ptr Element::asA() const; \ + template MX_CORE_API shared_ptr Element::getChildOfType(const string& name) const; \ + template MX_CORE_API vector> Element::getChildrenOfType(const string& category) const; INSTANTIATE_SUBCLASS(Element) INSTANTIATE_SUBCLASS(GeomElement) diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 2b92dd8094..a80bc3a49f 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -439,11 +439,7 @@ class MX_CORE_API Element : public std::enable_shared_from_this /// Return the child element, if any, with the given name and subclass. /// If a child with the given name exists, but belongs to a different /// subclass, then an empty shared pointer is returned. - template shared_ptr getChildOfType(const string& name) const - { - ElementPtr child = getChild(name); - return child ? child->asA() : shared_ptr(); - } + template shared_ptr getChildOfType(const string& name) const; /// Return a constant vector of all child elements. /// The returned vector maintains the order in which children were added. @@ -455,20 +451,7 @@ class MX_CORE_API Element : public std::enable_shared_from_this /// Return a vector of all child elements that are instances of the given /// subclass, optionally filtered by the given category string. The returned /// vector maintains the order in which children were added. - template vector> getChildrenOfType(const string& category = EMPTY_STRING) const - { - vector> children; - for (ElementPtr child : _childOrder) - { - shared_ptr instance = child->asA(); - if (!instance) - continue; - if (!category.empty() && child->getCategory() != category) - continue; - children.push_back(instance); - } - return children; - } + template vector> getChildrenOfType(const string& category = EMPTY_STRING) const; /// Set the index of the child, if any, with the given name. /// If the given index is out of bounds, then an exception is thrown. From 8af07e1e4e867aa00817440eca730c4588a12a95 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 15 Oct 2024 13:07:20 -0700 Subject: [PATCH 087/137] Harmonize MSL and GLSL implementations (#2070) This changelist addresses a handful of remaining cases where our MSL and GLSL code diverged, harmonizing on shading code that works in both contexts. --- libraries/stdlib/genglsl/mx_burn_color3.glsl | 7 ++++--- libraries/stdlib/genglsl/mx_burn_color4.glsl | 9 +++++---- libraries/stdlib/genglsl/mx_dodge_color3.glsl | 7 ++++--- libraries/stdlib/genglsl/mx_dodge_color4.glsl | 9 +++++---- libraries/stdlib/genglsl/mx_normalmap.glsl | 8 ++++---- libraries/stdlib/genmsl/mx_burn_color3.metal | 9 --------- libraries/stdlib/genmsl/mx_burn_color4.metal | 10 ---------- libraries/stdlib/genmsl/mx_burn_float.metal | 9 --------- libraries/stdlib/genmsl/mx_dodge_color3.metal | 9 --------- libraries/stdlib/genmsl/mx_dodge_color4.metal | 10 ---------- libraries/stdlib/genmsl/mx_dodge_float.metal | 9 --------- libraries/stdlib/genmsl/mx_normalmap.metal | 13 ------------- .../stdlib/genmsl/mx_smoothstep_float.metal | 9 --------- libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx | 17 ----------------- 14 files changed, 22 insertions(+), 113 deletions(-) delete mode 100644 libraries/stdlib/genmsl/mx_burn_color3.metal delete mode 100644 libraries/stdlib/genmsl/mx_burn_color4.metal delete mode 100644 libraries/stdlib/genmsl/mx_burn_float.metal delete mode 100644 libraries/stdlib/genmsl/mx_dodge_color3.metal delete mode 100644 libraries/stdlib/genmsl/mx_dodge_color4.metal delete mode 100644 libraries/stdlib/genmsl/mx_dodge_float.metal delete mode 100644 libraries/stdlib/genmsl/mx_normalmap.metal delete mode 100644 libraries/stdlib/genmsl/mx_smoothstep_float.metal diff --git a/libraries/stdlib/genglsl/mx_burn_color3.glsl b/libraries/stdlib/genglsl/mx_burn_color3.glsl index 10f4008f1a..8e60f857d6 100644 --- a/libraries/stdlib/genglsl/mx_burn_color3.glsl +++ b/libraries/stdlib/genglsl/mx_burn_color3.glsl @@ -2,7 +2,8 @@ void mx_burn_color3(vec3 fg, vec3 bg, float mixval, out vec3 result) { - mx_burn_float(fg.x, bg.x, mixval, result.x); - mx_burn_float(fg.y, bg.y, mixval, result.y); - mx_burn_float(fg.z, bg.z, mixval, result.z); + float f; + mx_burn_float(fg.x, bg.x, mixval, f); result.x = f; + mx_burn_float(fg.y, bg.y, mixval, f); result.y = f; + mx_burn_float(fg.z, bg.z, mixval, f); result.z = f; } diff --git a/libraries/stdlib/genglsl/mx_burn_color4.glsl b/libraries/stdlib/genglsl/mx_burn_color4.glsl index df6802a646..a1add5a372 100644 --- a/libraries/stdlib/genglsl/mx_burn_color4.glsl +++ b/libraries/stdlib/genglsl/mx_burn_color4.glsl @@ -2,8 +2,9 @@ void mx_burn_color4(vec4 fg, vec4 bg, float mixval, out vec4 result) { - mx_burn_float(fg.x, bg.x, mixval, result.x); - mx_burn_float(fg.y, bg.y, mixval, result.y); - mx_burn_float(fg.z, bg.z, mixval, result.z); - mx_burn_float(fg.w, bg.w, mixval, result.w); + float f; + mx_burn_float(fg.x, bg.x, mixval, f); result.x = f; + mx_burn_float(fg.y, bg.y, mixval, f); result.y = f; + mx_burn_float(fg.z, bg.z, mixval, f); result.z = f; + mx_burn_float(fg.w, bg.w, mixval, f); result.w = f; } diff --git a/libraries/stdlib/genglsl/mx_dodge_color3.glsl b/libraries/stdlib/genglsl/mx_dodge_color3.glsl index a8cfd1dff7..aa9cf023a6 100644 --- a/libraries/stdlib/genglsl/mx_dodge_color3.glsl +++ b/libraries/stdlib/genglsl/mx_dodge_color3.glsl @@ -2,7 +2,8 @@ void mx_dodge_color3(vec3 fg, vec3 bg, float mixval, out vec3 result) { - mx_dodge_float(fg.x, bg.x, mixval, result.x); - mx_dodge_float(fg.y, bg.y, mixval, result.y); - mx_dodge_float(fg.z, bg.z, mixval, result.z); + float f; + mx_dodge_float(fg.x, bg.x, mixval, f); result.x = f; + mx_dodge_float(fg.y, bg.y, mixval, f); result.y = f; + mx_dodge_float(fg.z, bg.z, mixval, f); result.z = f; } diff --git a/libraries/stdlib/genglsl/mx_dodge_color4.glsl b/libraries/stdlib/genglsl/mx_dodge_color4.glsl index c492043ceb..25888219b6 100644 --- a/libraries/stdlib/genglsl/mx_dodge_color4.glsl +++ b/libraries/stdlib/genglsl/mx_dodge_color4.glsl @@ -2,8 +2,9 @@ void mx_dodge_color4(vec4 fg , vec4 bg , float mixval, out vec4 result) { - mx_dodge_float(fg.x, bg.x, mixval, result.x); - mx_dodge_float(fg.y, bg.y, mixval, result.y); - mx_dodge_float(fg.z, bg.z, mixval, result.z); - mx_dodge_float(fg.w, bg.w, mixval, result.w); + float f; + mx_dodge_float(fg.x, bg.x, mixval, f); result.x = f; + mx_dodge_float(fg.y, bg.y, mixval, f); result.y = f; + mx_dodge_float(fg.z, bg.z, mixval, f); result.z = f; + mx_dodge_float(fg.w, bg.w, mixval, f); result.w = f; } diff --git a/libraries/stdlib/genglsl/mx_normalmap.glsl b/libraries/stdlib/genglsl/mx_normalmap.glsl index 9fe8c66920..66c50f31f5 100644 --- a/libraries/stdlib/genglsl/mx_normalmap.glsl +++ b/libraries/stdlib/genglsl/mx_normalmap.glsl @@ -1,9 +1,9 @@ void mx_normalmap_vector2(vec3 value, vec2 normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) { - value = (value == vec3(0.0)) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; - - value = T * value.x * normal_scale.x + B * value.y * normal_scale.y + N * value.z; - + value = (dot(value, value) == 0.0) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; + value = T * value.x * normal_scale.x + + B * value.y * normal_scale.y + + N * value.z; result = normalize(value); } diff --git a/libraries/stdlib/genmsl/mx_burn_color3.metal b/libraries/stdlib/genmsl/mx_burn_color3.metal deleted file mode 100644 index 856d79c929..0000000000 --- a/libraries/stdlib/genmsl/mx_burn_color3.metal +++ /dev/null @@ -1,9 +0,0 @@ -#include "mx_burn_float.metal" - -void mx_burn_color3(vec3 fg, vec3 bg, float mixval, out vec3 result) -{ - float f; - mx_burn_float(fg.x, bg.x, mixval, f); result.x = f; - mx_burn_float(fg.y, bg.y, mixval, f); result.y = f; - mx_burn_float(fg.z, bg.z, mixval, f); result.z = f; -} diff --git a/libraries/stdlib/genmsl/mx_burn_color4.metal b/libraries/stdlib/genmsl/mx_burn_color4.metal deleted file mode 100644 index 48dc6bfa47..0000000000 --- a/libraries/stdlib/genmsl/mx_burn_color4.metal +++ /dev/null @@ -1,10 +0,0 @@ -#include "mx_burn_float.metal" - -void mx_burn_color4(vec4 fg, vec4 bg, float mixval, out vec4 result) -{ - float f; - mx_burn_float(fg.x, bg.x, mixval, f); result.x = f; - mx_burn_float(fg.y, bg.y, mixval, f); result.y = f; - mx_burn_float(fg.z, bg.z, mixval, f); result.z = f; - mx_burn_float(fg.w, bg.w, mixval, f); result.w = f; -} diff --git a/libraries/stdlib/genmsl/mx_burn_float.metal b/libraries/stdlib/genmsl/mx_burn_float.metal deleted file mode 100644 index 31d981ddb9..0000000000 --- a/libraries/stdlib/genmsl/mx_burn_float.metal +++ /dev/null @@ -1,9 +0,0 @@ -void mx_burn_float(float fg, float bg, float mixval, out float result) -{ - if (abs(fg) < M_FLOAT_EPS) - { - result = 0.0; - return; - } - result = mixval*(1.0 - ((1.0 - bg) / fg)) + ((1.0-mixval)*bg); -} diff --git a/libraries/stdlib/genmsl/mx_dodge_color3.metal b/libraries/stdlib/genmsl/mx_dodge_color3.metal deleted file mode 100644 index 864a6a2529..0000000000 --- a/libraries/stdlib/genmsl/mx_dodge_color3.metal +++ /dev/null @@ -1,9 +0,0 @@ -#include "mx_dodge_float.metal" - -void mx_dodge_color3(vec3 fg, vec3 bg, float mixval, out vec3 result) -{ - float f; - mx_dodge_float(fg.x, bg.x, mixval, f); result.x = f; - mx_dodge_float(fg.y, bg.y, mixval, f); result.y = f; - mx_dodge_float(fg.z, bg.z, mixval, f); result.z = f; -} diff --git a/libraries/stdlib/genmsl/mx_dodge_color4.metal b/libraries/stdlib/genmsl/mx_dodge_color4.metal deleted file mode 100644 index dc226b4271..0000000000 --- a/libraries/stdlib/genmsl/mx_dodge_color4.metal +++ /dev/null @@ -1,10 +0,0 @@ -#include "mx_dodge_float.metal" - -void mx_dodge_color4(vec4 fg , vec4 bg , float mixval, out vec4 result) -{ - float f; - mx_dodge_float(fg.x, bg.x, mixval, f); result.x = f; - mx_dodge_float(fg.y, bg.y, mixval, f); result.y = f; - mx_dodge_float(fg.z, bg.z, mixval, f); result.z = f; - mx_dodge_float(fg.w, bg.w, mixval, f); result.w = f; -} diff --git a/libraries/stdlib/genmsl/mx_dodge_float.metal b/libraries/stdlib/genmsl/mx_dodge_float.metal deleted file mode 100644 index f138354138..0000000000 --- a/libraries/stdlib/genmsl/mx_dodge_float.metal +++ /dev/null @@ -1,9 +0,0 @@ -void mx_dodge_float(float fg, float bg, float mixval, out float result) -{ - if (abs(1.0 - fg) < M_FLOAT_EPS) - { - result = 0.0; - return; - } - result = mixval*(bg / (1.0 - fg)) + ((1.0-mixval)*bg); -} diff --git a/libraries/stdlib/genmsl/mx_normalmap.metal b/libraries/stdlib/genmsl/mx_normalmap.metal deleted file mode 100644 index 3674756d8b..0000000000 --- a/libraries/stdlib/genmsl/mx_normalmap.metal +++ /dev/null @@ -1,13 +0,0 @@ -void mx_normalmap_vector2(vec3 value, vec2 normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) -{ - value = all(value == vec3(0.0)) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; - - value = T * value.x * normal_scale.x + B * value.y * normal_scale.y + N * value.z; - - result = normalize(value); -} - -void mx_normalmap_float(vec3 value, float normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) -{ - mx_normalmap_vector2(value, vec2(normal_scale), N, T, B, result); -} diff --git a/libraries/stdlib/genmsl/mx_smoothstep_float.metal b/libraries/stdlib/genmsl/mx_smoothstep_float.metal deleted file mode 100644 index 1bca2e4d9b..0000000000 --- a/libraries/stdlib/genmsl/mx_smoothstep_float.metal +++ /dev/null @@ -1,9 +0,0 @@ -void mx_smoothstep_float(float val, float low, float high, out float result) -{ - if (val <= low) - result = 0.0; - else if (val >= high) - result = 1.0; - else - result = smoothstep(low, high, val); -} diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index be55f772be..1920d04b70 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -41,10 +41,6 @@ - - - - @@ -134,23 +130,10 @@ - - - - - - - - - - - - - From 4057541945b580be4ad385ea6c9892b4ac0efc50 Mon Sep 17 00:00:00 2001 From: Ashwin Bhat <1727158+ashwinbhat@users.noreply.github.com> Date: Wed, 16 Oct 2024 08:44:29 -0700 Subject: [PATCH 088/137] Add support for data library referencing (#2054) ### Background MaterialX documents are required to be complete self contained with all required node definitions. This is done by using the `mx::importLibrary` API. While processing large number of documents the Import and Merge workflows can cause performance and memory challenges. ### Proposal Since the MaterialX library or the Data library hosts definitions, we propose that these definitions could be referenced by a document instead of importing them. This concept of referencing the Data library may have some workflow impact such as, do new definitions to into Data library or the document or can a document have local definitions? The answer depends on the specific artist or studio workflow. To maintain compatibility with existing usage patterns, we have introduced a new set of methods **that allow registration of data library for a document by setting a document reference to it**. 1. setDataLibrary(ConstDocumentPtr dataLibrary); 2. getDataLibrary() 3. hasDataLibrary() ### Using this new Data library registration, two usage patterns are possible **Build library and import** This is the current usage pattern - use `importlibrary `to build your datalibrary - use `importLibrary `to import the datalibrary to the working document. **Build library and register** Proposed usage pattern - use `importlibrary` to build your datalibrary - use `setDataLibrary `to assign the datalibrary to the working document. This can be extended were 3rd party defs can be imported into the datalibrary **Other changes include** - Updates to `getChildOfType` and `getChildrenOfType` to support Data Library. - Updates to redirect _Document::get*_ calls to process local document content and Data Library. --- .../JsMaterialXCore/JsDocument.cpp | 3 ++ source/MaterialXCore/Document.cpp | 26 ++++++++----- source/MaterialXCore/Document.h | 38 ++++++++++++++++--- source/MaterialXCore/Element.cpp | 16 +++++++- .../MaterialXTest/MaterialXCore/Document.cpp | 6 ++- source/MaterialXTest/MaterialXCore/Node.cpp | 2 +- .../MaterialXGenShader/GenShader.cpp | 8 ++-- .../MaterialXGenShader/GenShaderUtil.cpp | 8 ++-- .../MaterialXRender/RenderUtil.cpp | 2 +- source/MaterialXView/Viewer.cpp | 4 +- .../PyMaterialXCore/PyDocument.cpp | 3 ++ 11 files changed, 86 insertions(+), 30 deletions(-) diff --git a/source/JsMaterialX/JsMaterialXCore/JsDocument.cpp b/source/JsMaterialX/JsMaterialXCore/JsDocument.cpp index ec4881732d..18750666b7 100644 --- a/source/JsMaterialX/JsMaterialXCore/JsDocument.cpp +++ b/source/JsMaterialX/JsMaterialXCore/JsDocument.cpp @@ -23,6 +23,9 @@ EMSCRIPTEN_BINDINGS(document) .class_function("createDocument", &mx::Document::createDocument) .function("initialize", &mx::Document::initialize) .function("copy", &mx::Document::copy) + .function("setDataLibrary", &mx::Document::setDataLibrary) + .function("getDataLibrary", &mx::Document::getDataLibrary) + .function("hasDataLibrary", &mx::Document::hasDataLibrary) .function("importLibrary", &mx::Document::importLibrary) .function("getReferencedSourceUris", ems::optional_override([](mx::Document &self) { mx::StringSet set = self.getReferencedSourceUris(); diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 7ebdab0aa7..1cd031d87c 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -357,34 +357,40 @@ vector Document::getMaterialOutputs() const vector Document::getMatchingNodeDefs(const string& nodeName) const { + // Recurse to data library if present. + vector matchingNodeDefs = hasDataLibrary() ? + getDataLibrary()->getMatchingNodeDefs(nodeName) : + vector(); + // Refresh the cache. _cache->refresh(); // Return all nodedefs matching the given node name. if (_cache->nodeDefMap.count(nodeName)) { - return _cache->nodeDefMap.at(nodeName); - } - else - { - return vector(); + matchingNodeDefs.insert(matchingNodeDefs.end(), _cache->nodeDefMap.at(nodeName).begin(), _cache->nodeDefMap.at(nodeName).end()); } + + return matchingNodeDefs; } vector Document::getMatchingImplementations(const string& nodeDef) const { + // Recurse to data library if present. + vector matchingImplementations = hasDataLibrary() ? + getDataLibrary()->getMatchingImplementations(nodeDef) : + vector(); + // Refresh the cache. _cache->refresh(); // Return all implementations matching the given nodedef string. if (_cache->implementationMap.count(nodeDef)) { - return _cache->implementationMap.at(nodeDef); - } - else - { - return vector(); + matchingImplementations.insert(matchingImplementations.end(), _cache->implementationMap.at(nodeDef).begin(), _cache->implementationMap.at(nodeDef).end()); } + + return matchingImplementations; } bool Document::validate(string* message) const diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index a14a5edf7b..ab01bbbc11 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -50,18 +50,41 @@ class MX_CORE_API Document : public GraphElement { DocumentPtr doc = createDocument(); doc->copyContentFrom(getSelf()); + doc->setDataLibrary(getDataLibrary()); return doc; } - /// Import the given document as a library within this document. - /// The contents of the library document are copied into this one, and + /// Get a list of source URIs referenced by the document + StringSet getReferencedSourceUris() const; + + /// @name Data Libraries + /// @{ + + /// Store a reference to a data library in this document. + void setDataLibrary(ConstDocumentPtr dataLibrary) + { + _dataLibrary = dataLibrary; + } + + /// Return true if this document has a data library. + bool hasDataLibrary() const + { + return (_dataLibrary != nullptr); + } + + /// Return the data library, if any, referenced by this document. + ConstDocumentPtr getDataLibrary() const + { + return _dataLibrary; + } + + /// Import the given data library into this document. + /// The contents of the data library are copied into this one, and /// are assigned the source URI of the library. - /// @param library The library document to be imported. + /// @param library The data library to be imported. void importLibrary(const ConstDocumentPtr& library); - /// Get a list of source URI's referenced by the document - StringSet getReferencedSourceUris() const; - + /// @} /// @name NodeGraph Elements /// @{ @@ -679,6 +702,9 @@ class MX_CORE_API Document : public GraphElement private: class Cache; + + private: + ConstDocumentPtr _dataLibrary; std::unique_ptr _cache; }; diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 1a48142962..af47a6a2ba 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -286,13 +286,27 @@ ElementPtr Element::changeChildCategory(ElementPtr child, const string& category template shared_ptr Element::getChildOfType(const string& name) const { - ElementPtr child = getChild(name); + ElementPtr child; + ConstDocumentPtr doc = asA(); + if (doc && doc->hasDataLibrary()) + { + child = doc->getDataLibrary()->getChild(name); + } + if (!child) + { + child = getChild(name); + } return child ? child->asA() : shared_ptr(); } template vector> Element::getChildrenOfType(const string& category) const { vector> children; + ConstDocumentPtr doc = asA(); + if (doc && doc->hasDataLibrary()) + { + children = doc->getDataLibrary()->getChildrenOfType(category); + } for (ElementPtr child : _childOrder) { shared_ptr instance = child->asA(); diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index 1b02966fb8..94f8b98708 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -106,7 +106,11 @@ TEST_CASE("Document", "[document]") REQUIRE(customLibrary->validate()); // Import the custom library. - doc->importLibrary(customLibrary); + mx::DocumentPtr customDatalibrary = mx::createDocument(); + customDatalibrary->importLibrary(customLibrary); + + // Set data library + doc->setDataLibrary(customDatalibrary); mx::NodeGraphPtr importedNodeGraph = doc->getNodeGraph("custom:NG_custom"); mx::NodeDefPtr importedNodeDef = doc->getNodeDef("custom:ND_simpleSrf"); mx::ImplementationPtr importedImpl = doc->getImplementation("custom:IM_custom"); diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp index b72cd65328..58ee125bad 100644 --- a/source/MaterialXTest/MaterialXCore/Node.cpp +++ b/source/MaterialXTest/MaterialXCore/Node.cpp @@ -672,7 +672,7 @@ TEST_CASE("Node Definition Creation", "[nodedef]") mx::DocumentPtr doc = mx::createDocument(); mx::readFromXmlFile(doc, "resources/Materials/TestSuite/stdlib/definition/definition_from_nodegraph.mtlx", searchPath); - doc->importLibrary(stdlib); + doc->setDataLibrary(stdlib); mx::NodeGraphPtr graph = doc->getNodeGraph("test_colorcorrect"); REQUIRE(graph); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShader.cpp b/source/MaterialXTest/MaterialXGenShader/GenShader.cpp index 22afffbff4..a959283aad 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShader.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShader.cpp @@ -161,7 +161,7 @@ TEST_CASE("GenShader: Transparency Regression Check", "[genshader]") bool testValue = transparencyTest[i]; mx::DocumentPtr testDoc = mx::createDocument(); - testDoc->importLibrary(libraries); + testDoc->setDataLibrary(libraries); try { @@ -207,7 +207,7 @@ void testDeterministicGeneration(mx::DocumentPtr libraries, mx::GenContext& cont { mx::DocumentPtr testDoc = mx::createDocument(); mx::readFromXmlFile(testDoc, testFile); - testDoc->importLibrary(libraries); + testDoc->setDataLibrary(libraries); // Keep the document alive to make sure // new memory is allocated for each run @@ -272,7 +272,7 @@ void checkPixelDependencies(mx::DocumentPtr libraries, mx::GenContext& context) mx::DocumentPtr testDoc = mx::createDocument(); mx::readFromXmlFile(testDoc, testFile); - testDoc->importLibrary(libraries); + testDoc->setDataLibrary(libraries); mx::ElementPtr element = testDoc->getChild(testElement); CHECK(element); @@ -385,7 +385,7 @@ TEST_CASE("GenShader: Track Application Variables", "[genshader]") mx::DocumentPtr testDoc = mx::createDocument(); mx::readFromXmlString(testDoc, testDocumentString); - testDoc->importLibrary(libraries); + testDoc->setDataLibrary(libraries); mx::ElementPtr element = testDoc->getChild(testElement); CHECK(element); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 6dc24fc15c..4a8e61645a 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -372,7 +372,7 @@ void shaderGenPerformanceTest(mx::GenContext& context) std::shuffle(loadedDocuments.begin(), loadedDocuments.end(), rng); for (const auto& doc : loadedDocuments) { - doc->importLibrary(nodeLibrary); + doc->setDataLibrary(nodeLibrary); std::vector elements = mx::findRenderableElements(doc); REQUIRE(elements.size() > 0); @@ -721,7 +721,7 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons bool importedLibrary = false; try { - doc->importLibrary(_dependLib); + doc->setDataLibrary(_dependLib); importedLibrary = true; } catch (mx::Exception& e) @@ -734,8 +734,8 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons } // Find and register lights - findLights(doc, _lights); - registerLights(doc, _lights, context); + findLights(_dependLib, _lights); + registerLights(_dependLib, _lights, context); // Find elements to render in the document std::vector elements; diff --git a/source/MaterialXTest/MaterialXRender/RenderUtil.cpp b/source/MaterialXTest/MaterialXRender/RenderUtil.cpp index d8265a4050..e3e5e8033e 100644 --- a/source/MaterialXTest/MaterialXRender/RenderUtil.cpp +++ b/source/MaterialXTest/MaterialXRender/RenderUtil.cpp @@ -223,7 +223,7 @@ bool ShaderRenderTester::validate(const mx::FilePath optionsFilePath) // colliding with implementations in previous test cases. context.clearNodeImplementations(); - doc->importLibrary(dependLib); + doc->setDataLibrary(dependLib); ioTimer.endTimer(); validateTimer.startTimer(); diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index c0d90d30a7..24aea1eb42 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -1316,8 +1316,8 @@ void Viewer::loadDocument(const mx::FilePath& filename, mx::DocumentPtr librarie mx::readFromXmlFile(doc, filename, _searchPath, &readOptions); _materialSearchPath = mx::getSourceSearchPath(doc); - // Import libraries. - doc->importLibrary(libraries); + // Store data library reference. + doc->setDataLibrary(libraries); // Apply direct lights. applyDirectLights(doc); diff --git a/source/PyMaterialX/PyMaterialXCore/PyDocument.cpp b/source/PyMaterialX/PyMaterialXCore/PyDocument.cpp index 3f4403c673..e021bc92de 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyDocument.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyDocument.cpp @@ -29,6 +29,9 @@ void bindPyDocument(py::module& mod) py::class_(mod, "Document") .def("initialize", &mx::Document::initialize) .def("copy", &mx::Document::copy) + .def("setDataLibrary", &mx::Document::setDataLibrary) + .def("getDataLibrary", &mx::Document::getDataLibrary) + .def("hasDataLibrary", &mx::Document::hasDataLibrary) .def("importLibrary", &mx::Document::importLibrary) .def("getReferencedSourceUris", &mx::Document::getReferencedSourceUris) .def("addNodeGraph", &mx::Document::addNodeGraph, From eaebfc34e0a29a18ee6c0d6f4178748a5e0bdc36 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 16 Oct 2024 15:45:58 -0700 Subject: [PATCH 089/137] Update generateshader for data library referencing (#2071) This changelist updates the generateshader.py script to take advantage of data library referencing. i.e. `Document::setDataLibrary`. In this context, the use of data library referencing should be noticeably more efficient than data library importing when multiple documents are being processed. --- python/Scripts/generateshader.py | 45 +++++++++++++++----------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/python/Scripts/generateshader.py b/python/Scripts/generateshader.py index 259812f6f1..b00311eb2e 100644 --- a/python/Scripts/generateshader.py +++ b/python/Scripts/generateshader.py @@ -55,38 +55,33 @@ def main(): parser.add_argument(dest='inputFilename', help='Path to input document or folder containing input documents.') opts = parser.parse_args() - filelist = getMaterialXFiles(opts.inputFilename) - - for inputFilename in filelist: + # Load standard and custom data libraries. + stdlib = mx.createDocument() + searchPath = mx.getDefaultDataSearchPath() + libraryFolders = [] + if opts.paths: + for pathList in opts.paths: + for path in pathList: + searchPath.append(path) + if opts.libraries: + for libraryList in opts.libraries: + for library in libraryList: + libraryFolders.append(library) + libraryFolders.extend(mx.getDefaultDataLibraryFolders()) + mx.loadLibraries(libraryFolders, searchPath, stdlib) + + # Generate shaders for each input document. + for inputFilename in getMaterialXFiles(opts.inputFilename): doc = mx.createDocument() try: mx.readFromXmlFile(doc, inputFilename) + doc.setDataLibrary(stdlib) except mx.ExceptionFileMissing as err: print('Generation failed: "', err, '"') sys.exit(-1) print('---------- Generate code for file: ', inputFilename, '--------------------') - stdlib = mx.createDocument() - searchPath = mx.getDefaultDataSearchPath() - searchPath.append(os.path.dirname(inputFilename)) - libraryFolders = [] - if opts.paths: - for pathList in opts.paths: - for path in pathList: - searchPath.append(path) - if opts.libraries: - for libraryList in opts.libraries: - for library in libraryList: - libraryFolders.append(library) - libraryFolders.extend(mx.getDefaultDataLibraryFolders()) - try: - mx.loadLibraries(libraryFolders, searchPath, stdlib) - doc.importLibrary(stdlib) - except Exception as err: - print('Generation failed: "', err, '"') - sys.exit(-1) - valid, msg = doc.validate() if not valid: print('Validation warnings for input document:') @@ -108,8 +103,10 @@ def main(): else: shadergen = mx_gen_glsl.GlslShaderGenerator.create() + codeSearchPath = searchPath + codeSearchPath.append(os.path.dirname(inputFilename)) context = mx_gen_shader.GenContext(shadergen) - context.registerSourceCodeSearchPath(searchPath) + context.registerSourceCodeSearchPath(codeSearchPath) # If we're generating Vulkan-compliant GLSL then set the binding context if opts.vulkanCompliantGlsl: From ea4cea0a1df19a1fe0a36c6cc9a584962cf71e44 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 16 Oct 2024 17:51:13 -0700 Subject: [PATCH 090/137] Update translateshader for data library referencing (#2073) This changelist updates the translateshader.py script to take advantage of data library referencing. i.e. `Document::setDataLibrary`. --- python/Scripts/translateshader.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/python/Scripts/translateshader.py b/python/Scripts/translateshader.py index f7c5686211..fca1e2ab07 100644 --- a/python/Scripts/translateshader.py +++ b/python/Scripts/translateshader.py @@ -24,19 +24,12 @@ def main(): parser.add_argument('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to seprate MaterialX documents. Default is True') if platform == "darwin": parser.add_argument("--glsl", dest="useGlslBackend", default=False, type=bool, help="Set to True to use GLSL backend (default = Metal).") - parser.add_argument(dest="inputFilename", help="Filename of the input document.") parser.add_argument(dest="outputFilename", help="Filename of the output document.") parser.add_argument(dest="destShader", help="Destination shader for translation") opts = parser.parse_args() - doc = mx.createDocument() - try: - mx.readFromXmlFile(doc, opts.inputFilename) - except mx.ExceptionFileMissing as err: - print(err) - sys.exit(0) - + # Load standard and custom data libraries. stdlib = mx.createDocument() searchPath = mx.getDefaultDataSearchPath() searchPath.append(os.path.dirname(opts.inputFilename)) @@ -51,8 +44,15 @@ def main(): libraryFolders.append(library) libraryFolders.extend(mx.getDefaultDataLibraryFolders()) mx.loadLibraries(libraryFolders, searchPath, stdlib) - doc.importLibrary(stdlib) + # Read and validate the source document. + doc = mx.createDocument() + try: + mx.readFromXmlFile(doc, opts.inputFilename) + doc.setDataLibrary(stdlib) + except mx.ExceptionFileMissing as err: + print(err) + sys.exit(0) valid, msg = doc.validate() if not valid: print("Validation warnings for input document:") From 12cf23489d9881ad4c4c5aa4b45bd972c2140f2d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 16 Oct 2024 21:58:16 -0700 Subject: [PATCH 091/137] Update baketextures for data library referencing (#2074) This changelist updates the baketextures.py script to take advantage of data library referencing. i.e. `Document::setDataLibrary`. --- python/Scripts/baketextures.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/python/Scripts/baketextures.py b/python/Scripts/baketextures.py index ce132036a6..7856dca749 100644 --- a/python/Scripts/baketextures.py +++ b/python/Scripts/baketextures.py @@ -27,13 +27,7 @@ def main(): parser.add_argument(dest="outputFilename", help="Filename of the output document.") opts = parser.parse_args() - doc = mx.createDocument() - try: - mx.readFromXmlFile(doc, opts.inputFilename) - except mx.ExceptionFileMissing as err: - print(err) - sys.exit(0) - + # Load standard and custom data libraries. stdlib = mx.createDocument() searchPath = mx.getDefaultDataSearchPath() searchPath.append(os.path.dirname(opts.inputFilename)) @@ -48,21 +42,28 @@ def main(): libraryFolders.append(library) libraryFolders.extend(mx.getDefaultDataLibraryFolders()) mx.loadLibraries(libraryFolders, searchPath, stdlib) - doc.importLibrary(stdlib) + # Read and validate the source document. + doc = mx.createDocument() + try: + mx.readFromXmlFile(doc, opts.inputFilename) + doc.setDataLibrary(stdlib) + except mx.ExceptionFileMissing as err: + print(err) + sys.exit(0) valid, msg = doc.validate() if not valid: print("Validation warnings for input document:") print(msg) + # Construct the texture baker. baseType = mx_render.BaseType.FLOAT if opts.hdr else mx_render.BaseType.UINT8 - - if platform == "darwin" and not opts.useGlslBackend: baker = mx_render_msl.TextureBaker.create(opts.width, opts.height, baseType) else: baker = mx_render_glsl.TextureBaker.create(opts.width, opts.height, baseType) + # Bake materials to textures. if opts.average: baker.setAverageImages(True) baker.writeDocumentPerMaterial(opts.writeDocumentPerMaterial) From 9f9a57aead130b8879ce7bbea3aced8f204a95ff Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 17 Oct 2024 15:51:32 -0700 Subject: [PATCH 092/137] Update mxvalidate for data library referencing (#2075) This changelist updates the mxvalidate.py script to take advantage of data library referencing. i.e. `Document::setDataLibrary`. --- python/Scripts/mxvalidate.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/python/Scripts/mxvalidate.py b/python/Scripts/mxvalidate.py index 8b5271e9ed..8cc1ee78fd 100755 --- a/python/Scripts/mxvalidate.py +++ b/python/Scripts/mxvalidate.py @@ -16,13 +16,7 @@ def main(): parser.add_argument(dest="inputFilename", help="Filename of the input document.") opts = parser.parse_args() - doc = mx.createDocument() - try: - mx.readFromXmlFile(doc, opts.inputFilename) - except mx.ExceptionFileMissing as err: - print(err) - sys.exit(0) - + # Load standard libraries if requested. if opts.stdlib: stdlib = mx.createDocument() try: @@ -30,15 +24,23 @@ def main(): except Exception as err: print(err) sys.exit(0) - doc.importLibrary(stdlib) - (valid, message) = doc.validate() + # Read and validate the source document. + doc = mx.createDocument() + try: + mx.readFromXmlFile(doc, opts.inputFilename) + doc.setDataLibrary(stdlib) + except mx.ExceptionFileMissing as err: + print(err) + sys.exit(0) + valid, message = doc.validate() if (valid): print("%s is a valid MaterialX document in v%s" % (opts.inputFilename, mx.getVersionString())) else: print("%s is not a valid MaterialX document in v%s" % (opts.inputFilename, mx.getVersionString())) print(message) + # Generate verbose output if requested. if opts.verbose: nodegraphs = doc.getNodeGraphs() materials = doc.getMaterialNodes() From d18af703f1205f207297452906569195c9f7787e Mon Sep 17 00:00:00 2001 From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com> Date: Thu, 17 Oct 2024 16:44:46 -0700 Subject: [PATCH 093/137] Add support `closest` texture lookup mode in MDL backend (#2072) Add support `closest` texture lookup mode in MDL backend. This change affects in all type of `image` nodes. --- .../mdl/materialx/stdlib_1_6.mdl | 90 ++++++++++++------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl index 601a10fda2..f5d661b17e 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl @@ -88,6 +88,24 @@ export material mx_surface_unlit( } } +// Helper function provides texture lookup coordinate with `closest` lookup type support +float2 tex_lookup_coord(float2 st, int tex_width, int tex_height, core::mx_filterlookup_type lookup_type, bool flip_v) +{ + float2 coord = st; + + // `closest` lookup + if (lookup_type == core::mx_filterlookup_type_closest) + { + int2 tex_size(tex_width, tex_height); + coord = (math::floor(coord * tex_size) + float2(0.5)) / tex_size; + } + + // `linear` and `cubic` uses the original coord + coord = flip_v ? float2(coord.x, 1.0 - coord.y) : coord; + + return coord; +} + // NOTE: need to map MaterialX return type overloads to different function names // or we require the mx_default to be always set explicitly @@ -121,8 +139,7 @@ export float mx_image_float( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -160,9 +177,12 @@ export float mx_image_float( return mxp_default; float returnValue = ::tex::lookup_float(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -198,8 +218,7 @@ export color mx_image_color3( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -237,9 +256,12 @@ export color mx_image_color3( return mxp_default; color returnValue = ::tex::lookup_color(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -275,8 +297,7 @@ export core::color4 mx_image_color4( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -314,9 +335,12 @@ export core::color4 mx_image_color4( return mxp_default; core::color4 returnValue = core::mk_color4(::tex::lookup_float4(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode))); return returnValue; @@ -352,8 +376,7 @@ export float2 mx_image_vector2( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -391,9 +414,12 @@ export float2 mx_image_vector2( return mxp_default; float2 returnValue = ::tex::lookup_float2(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -429,8 +455,7 @@ export float3 mx_image_vector3( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -468,9 +493,12 @@ export float3 mx_image_vector3( return mxp_default; float3 returnValue = ::tex::lookup_float3(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -506,8 +534,7 @@ export float4 mx_image_vector4( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -545,9 +572,12 @@ export float4 mx_image_vector4( return mxp_default; float4 returnValue = ::tex::lookup_float4(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; From 2a61e63f445fc547b56d479141b10191e4eb31e1 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 18 Oct 2024 17:27:04 -0700 Subject: [PATCH 094/137] CMake updates for Apple builds (#2077) - Mark the CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY flag as Apple-specific, removing it from CMake interfaces on other platforms. - Simplify comment blocks to highlight key points. - Reorder the order of option declarations for clarity. --- CMakeLists.txt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59afaca01e..31db83e8fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,25 +60,21 @@ option(MATERIALX_DYNAMIC_ANALYSIS "Build MaterialX libraries with dynamic analys option(MATERIALX_OSL_LEGACY_CLOSURES "Build OSL shader generation supporting the legacy OSL closures." OFF) option(MATERIALX_BUILD_IOS "Build MaterialX for iOS. (Deprecated. Set CMAKE_SYSTEM_NAME instead)" OFF) -set(MATERIALX_BUILD_APPLE_EMBEDDED OFF) +option(MATERIALX_BUILD_APPLE_FRAMEWORK "Build MaterialX as an Apple Framework" ${__build_apple_framework}) if (MATERIALX_BUILD_IOS) MESSAGE(WARNING "The MATERIALX_BUILD_IOS is deprecated. Set the CMAKE_SYSTEM_NAME to the platform instead") set(CMAKE_SYSTEM_NAME iOS) endif() -# Cross Compilation detection as defined in CMake docs +# Apple ecosystem cross-compilation # https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos -# Note: All these SDKs may not be supported by MaterialX +set(MATERIALX_BUILD_APPLE_EMBEDDED OFF) set(__build_apple_framework OFF) -if (CMAKE_SYSTEM_NAME MATCHES "iOS" - OR CMAKE_SYSTEM_NAME MATCHES "tvOS" - OR CMAKE_SYSTEM_NAME MATCHES "visionOS" - OR CMAKE_SYSTEM_NAME MATCHES "watchOS") +if (CMAKE_SYSTEM_NAME MATCHES "iOS" OR CMAKE_SYSTEM_NAME MATCHES "tvOS" OR CMAKE_SYSTEM_NAME MATCHES "visionOS" OR CMAKE_SYSTEM_NAME MATCHES "watchOS") set(MATERIALX_BUILD_APPLE_EMBEDDED ON) set(__build_apple_framework ${MATERIALX_BUILD_SHARED_LIBS}) # TARGET_OS_IPHONE refers to all IPHONE derived platforms # https://chaosinmotion.com/2021/08/02/things-to-remember-compiler-conditionals-for-macos-ios-etc/ - # This should be auto-defined, but leaving it in here because it was historically defined add_definitions(-DTARGET_OS_IPHONE=1) set(MATERIALX_BUILD_MONOLITHIC ON) set(MATERIALX_BUILD_PYTHON OFF) @@ -90,8 +86,10 @@ if (CMAKE_SYSTEM_NAME MATCHES "iOS" set(MATERIALX_BUILD_TESTS OFF) endif() -set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" CACHE STRING "The Codesigning identity needed to sign compiled objects") -option(MATERIALX_BUILD_APPLE_FRAMEWORK "Build MaterialX as an Apple Framework" ${__build_apple_framework}) +# Apple framework handling +if(APPLE) + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" CACHE STRING "The Codesigning identity needed to sign compiled objects") +endif() if (MATERIALX_BUILD_APPLE_FRAMEWORK) add_definitions(-DBUILD_APPLE_FRAMEWORK) set(MATERIALX_BUILD_MONOLITHIC ON) From 4cb8ef9ed38975dfc01656493b66b62ef63a715d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 18 Oct 2024 21:05:18 -0700 Subject: [PATCH 095/137] Simplify material test suite (#2078) - Split adjustment.mtlx into separate documents for each node. - Remove test materials for nodes with graph definitions. --- .../stdlib/adjustment/adjustment.mtlx | 383 ------------------ .../stdlib/adjustment/luminance.mtlx | 15 + .../TestSuite/stdlib/adjustment/remap.mtlx | 113 ++++++ .../TestSuite/stdlib/channel/channel.mtlx | 56 --- .../conditional/conditional_switch.mtlx | 199 --------- .../TestSuite/stdlib/convert/convert.mtlx | 30 -- 6 files changed, 128 insertions(+), 668 deletions(-) delete mode 100644 resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx create mode 100644 resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx create mode 100644 resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx delete mode 100644 resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx delete mode 100644 resources/Materials/TestSuite/stdlib/convert/convert.mtlx diff --git a/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx deleted file mode 100644 index 83c4b95e9b..0000000000 --- a/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx new file mode 100644 index 0000000000..6260df8c57 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx new file mode 100644 index 0000000000..9175411a5d --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx b/resources/Materials/TestSuite/stdlib/channel/channel.mtlx index 59dbd160eb..57e90acf45 100644 --- a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx +++ b/resources/Materials/TestSuite/stdlib/channel/channel.mtlx @@ -97,60 +97,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx b/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx deleted file mode 100644 index 38f36a7290..0000000000 --- a/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/convert/convert.mtlx b/resources/Materials/TestSuite/stdlib/convert/convert.mtlx deleted file mode 100644 index f29b1eaab4..0000000000 --- a/resources/Materials/TestSuite/stdlib/convert/convert.mtlx +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From bec073ba952dcd1ca79279ebc7e2698cbd0a94c3 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 19 Oct 2024 11:54:31 -0700 Subject: [PATCH 096/137] Additional refinements to GLSL and MSL (#2079) - Provide mx_mod and mx_inverse in both GLSL and MSL. - Remove a legacy preprocessor definition in MSL. --- libraries/stdlib/genglsl/lib/mx_math.glsl | 2 ++ .../stdlib/genglsl/stdlib_genglsl_impl.mtlx | 26 +++++++++---------- .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 17 ------------ source/MaterialXGenMsl/MslShaderGenerator.cpp | 1 - 4 files changed, 15 insertions(+), 31 deletions(-) diff --git a/libraries/stdlib/genglsl/lib/mx_math.glsl b/libraries/stdlib/genglsl/lib/mx_math.glsl index f87e5653da..d196615e70 100644 --- a/libraries/stdlib/genglsl/lib/mx_math.glsl +++ b/libraries/stdlib/genglsl/lib/mx_math.glsl @@ -1,5 +1,7 @@ #define M_FLOAT_EPS 1e-8 +#define mx_mod mod +#define mx_inverse inverse #define mx_inversesqrt inversesqrt #define mx_sin sin #define mx_cos cos diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index 765c48c77b..69f8f9a7f8 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -252,17 +252,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -458,8 +458,8 @@ - - + + diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index 1920d04b70..afdfb2cfbb 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -100,19 +100,6 @@ - - - - - - - - - - - - - @@ -122,10 +109,6 @@ - - - - diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index 5476b33c90..9511fac7ba 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -944,7 +944,6 @@ void MslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& co emitLine("{}", stage, false); // Add common math functions - emitLine("#define __DECL_GL_MATH_FUNCTIONS__", stage, false); emitLibraryInclude("stdlib/genmsl/lib/mx_math.metal", context, stage); emitLineBreak(stage); From f6355a66b635d11d20e75d0f2705fba728fb38ad Mon Sep 17 00:00:00 2001 From: Jonathan Feldstein Date: Sat, 19 Oct 2024 14:57:43 -0400 Subject: [PATCH 097/137] Add defaultgeomprop support for nodegraph inputs (#2076) This PR makes it so that defaultgeomprop values can be used with nodegraph inputs as opposed to solely used on nodedef inputs. Includes a test file that is a nodegraph version of a checkerboard nodegraph implementation. The nodegraph exposes a defaultgeomprop value on the nodegraph's texcoord input of "UV0". --- .../defaultgeomprop/defaultgeomprop.mtlx | 41 +++++++++++++++++++ source/MaterialXCore/Interface.cpp | 2 +- source/MaterialXGenShader/ShaderGraph.cpp | 18 +++++++- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx diff --git a/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx b/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx new file mode 100644 index 0000000000..86bddc9650 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index 24d3ccfe0d..1c12e38ded 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -295,7 +295,7 @@ bool Input::validate(string* message) const if (hasDefaultGeomPropString()) { - validateRequire(parent->isA(), res, message, "Invalid defaultgeomprop on non-definition input"); + validateRequire(parent->isA() || parent->isA(), res, message, "Invalid defaultgeomprop on non-definition and non-nodegraph input"); validateRequire(getDefaultGeomProp() != nullptr, res, message, "Invalid defaultgeomprop string"); } if (parent->isA()) diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index 0f39b46c32..e9a3b50b79 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -81,7 +81,7 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, ElementPtr connectingElement, GenContext& context) { - // Create the node if it doesn't exists + // Create the node if it doesn't exist. NodePtr upstreamNode = upstreamElement->asA(); if (!upstreamNode) { @@ -95,6 +95,22 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, newNode = createNode(upstreamNode, context); } + // Handle interface inputs with default geometric properties. + for (InputPtr activeInput : upstreamNode->getActiveInputs()) + { + if (!activeInput->hasInterfaceName() || activeInput->getConnectedNode()) + { + continue; + } + + InputPtr graphInput = activeInput->getInterfaceInput(); + if (graphInput && graphInput->hasDefaultGeomPropString()) + { + ShaderInput* shaderInput = getNode(upstreamNode->getName())->getInput(activeInput->getName()); + addDefaultGeomNode(shaderInput, *graphInput->getDefaultGeomProp(), context); + } + } + // // Make connections // From a578d8a9758f0a6eefc5a1a5c7ab10727ee11b2d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 20 Oct 2024 12:31:54 -0700 Subject: [PATCH 098/137] Simplify material test suite (#2080) - Split channel.mtlx into separate documents for each node. - Remove test materials for nodes with graph definitions. - Reduce coupling of unit tests with material examples. --- libraries/stdlib/stdlib_ng.mtlx | 1 - .../channel/{channel.mtlx => combine.mtlx} | 35 ----------------- .../TestSuite/stdlib/channel/extract.mtlx | 38 +++++++++++++++++++ .../stdlib/compositing/compositing.mtlx | 25 ------------ .../{tokenGraph.mtlx => token_graph.mtlx} | 0 source/MaterialXTest/MaterialXCore/Node.cpp | 37 ------------------ 6 files changed, 38 insertions(+), 98 deletions(-) rename resources/Materials/TestSuite/stdlib/channel/{channel.mtlx => combine.mtlx} (65%) create mode 100644 resources/Materials/TestSuite/stdlib/channel/extract.mtlx rename resources/Materials/TestSuite/stdlib/texture/{tokenGraph.mtlx => token_graph.mtlx} (100%) diff --git a/libraries/stdlib/stdlib_ng.mtlx b/libraries/stdlib/stdlib_ng.mtlx index 893e084b68..ef7f5ebc90 100644 --- a/libraries/stdlib/stdlib_ng.mtlx +++ b/libraries/stdlib/stdlib_ng.mtlx @@ -4386,7 +4386,6 @@ - diff --git a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx b/resources/Materials/TestSuite/stdlib/channel/combine.mtlx similarity index 65% rename from resources/Materials/TestSuite/stdlib/channel/channel.mtlx rename to resources/Materials/TestSuite/stdlib/channel/combine.mtlx index 57e90acf45..403b344226 100644 --- a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx +++ b/resources/Materials/TestSuite/stdlib/channel/combine.mtlx @@ -62,39 +62,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/channel/extract.mtlx b/resources/Materials/TestSuite/stdlib/channel/extract.mtlx new file mode 100644 index 0000000000..467707a47f --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/channel/extract.mtlx @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx b/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx index 4a2d032be6..b60b9803a9 100644 --- a/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx +++ b/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx @@ -8,7 +8,6 @@ - burn - dodge - screen - - overlay - disjointover - mask - matte @@ -181,30 +180,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx b/resources/Materials/TestSuite/stdlib/texture/token_graph.mtlx similarity index 100% rename from resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx rename to resources/Materials/TestSuite/stdlib/texture/token_graph.mtlx diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp index 58ee125bad..ef746bfe05 100644 --- a/source/MaterialXTest/MaterialXCore/Node.cpp +++ b/source/MaterialXTest/MaterialXCore/Node.cpp @@ -627,43 +627,6 @@ TEST_CASE("Organization", "[nodegraph]") CHECK(nodeGraph->getBackdrops().empty()); } -TEST_CASE("Tokens", "[nodegraph]") -{ - mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); - mx::DocumentPtr stdlib = mx::createDocument(); - mx::loadLibraries({ "libraries" }, searchPath, stdlib); - - mx::DocumentPtr doc = mx::createDocument(); - mx::readFromXmlFile(doc, "resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx", searchPath); - - mx::StringVec graphNames = { "Tokenized_Image_2k_png", "Tokenized_Image_4k_jpg" }; - mx::StringVec resolutionStrings = { "2k", "4k" }; - mx::StringVec extensionStrings = { "png", "jpg" }; - for (size_t i=0; igetNodeGraph(graphNames[i]); - REQUIRE(graph); - std::vector tokens = graph->getActiveTokens(); - - mx::NodePtr imagePtr = graph->getNode("tiledimage"); - REQUIRE(imagePtr); - - mx::InputPtr input = imagePtr->getInput("file"); - REQUIRE(input); - - // Test file name substitution creation. - mx::StringResolverPtr resolver = input->createStringResolver(); - const mx::StringMap& substitutions = resolver->getFilenameSubstitutions(); - const std::string DELIMITER_PREFIX("["); - const std::string DELIMITER_POSTFIX("]"); - for (auto token : tokens) - { - const std::string tokenString = DELIMITER_PREFIX + token->getName() + DELIMITER_POSTFIX; - REQUIRE(substitutions.count(tokenString)); - } - } -} - TEST_CASE("Node Definition Creation", "[nodedef]") { mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); From 5d6aa6ec30a7966fae51dc75c6b37d0656300a71 Mon Sep 17 00:00:00 2001 From: Karen Lucknavalai <34335343+klucknav@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:12:08 -0700 Subject: [PATCH 099/137] Update UsdPreviewSurface Nodegraph This PR fixes the cutout issue described in gitIssue #2044. It also updates the nodegraph to reflect the recently updated PreviewSurface v2.6 which removes specular highlights for fully transparent materials. --- libraries/bxdf/usd_preview_surface.mtlx | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index 7106da779b..d99fab3a8c 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -6,7 +6,7 @@ - + @@ -152,10 +152,16 @@ + + + + + + - + @@ -170,8 +176,12 @@ + + + + - + @@ -213,8 +223,12 @@ + + + + - + From 5cdb375e81d172048bf881d35d8b22a6c1af5049 Mon Sep 17 00:00:00 2001 From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com> Date: Wed, 23 Oct 2024 18:58:43 -0700 Subject: [PATCH 100/137] Fix hair nodes in MDL backend (#2085) Fix the issue where the generated MDL code with hair nodes does not compile. Also address warnings for unused parameters. --- libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx | 2 +- .../SimpleHair/simple_hair_default.mtlx | 1 + .../mdl/materialx/pbrlib_1_6.mdl | 17 +++++++++-------- .../mdl/materialx/pbrlib_1_7.mdl | 5 +++++ .../mdl/materialx/stdlib_1_6.mdl | 1 + 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index 0737ca82ab..c8f23958ae 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -26,7 +26,7 @@ - + diff --git a/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx index 056c79b554..b3dbd80f9a 100644 --- a/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx +++ b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx @@ -45,6 +45,7 @@ + diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl index b69d59e8b0..e70f849920 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl @@ -430,9 +430,9 @@ export material mx_thin_film_bsdf( export material mx_chiang_hair_bsdf( // TODO: MDL's chiang_hair BSDF has no support tinting each lobes - color mxp_tint_R = color(1.0), - color mxp_tint_TT = color(1.0), - color mxp_tint_TRT = color(1.0), + color mxp_tint_R = color(1.0) [[ anno::unused() ]], + color mxp_tint_TT = color(1.0) [[ anno::unused() ]], + color mxp_tint_TRT = color(1.0) [[ anno::unused() ]], float mxp_ior = 1.55, float2 mxp_roughness_R = float2(0.1, 0.1), float2 mxp_roughness_TT = float2(0.05, 0.05), @@ -452,7 +452,7 @@ export material mx_chiang_hair_bsdf( roughness_TT: mxp_roughness_TT, roughness_TRT: mxp_roughness_TRT, cuticle_angle: mxp_cuticle_angle, - absorption_coefficient: mxp_absorption_coefficient, + absorption_coefficient: color(mxp_absorption_coefficient), ior: mxp_ior ) ); @@ -590,6 +590,7 @@ export material mx_surface( scattering: bsdf_node, emission: edf_node ), + hair: mxp_bsdf.hair, ior: mxp_transmission_ior > 0.0 ? color(mxp_transmission_ior) : mxp_bsdf.ior, volume: bsdf_volume, geometry: material_geometry( @@ -1010,17 +1011,17 @@ export mx_artistic_ior__result mx_artistic_ior( return mx_artistic_ior__result(n,k); } -export float3 mx_dion_hair_absorption_from_melanin( +export float3 mx_deon_hair_absorption_from_melanin( float mxp_melanin_concentration = 0.25, float mxp_melanin_redness = 0.5, color mxp_eumelanin_color = color(0.657704, 0.498077, 0.254107), color mxp_pheomelanin_color = color(0.829444, 0.67032, 0.349938) ) { float melanin = -math::log(math::max(1.0 - mxp_melanin_concentration, 0.0001)); - float eumelanin = melanin * (1.0 = mxp_melanin_redness); + float eumelanin = melanin * (1.0 - mxp_melanin_redness); float pheomelanin = melanin * mxp_melanin_redness; return math::max( - eumelanin * -math::log(mxp_eumelanin_color) + pheomelanin * -math::log(mxp_pheomelanin_color), + eumelanin * -math::log(float3(mxp_eumelanin_color)) + pheomelanin * -math::log(float3(mxp_pheomelanin_color)), float3(0.0) ); } @@ -1038,7 +1039,7 @@ export float3 mx_chiang_hair_absorption_from_color( (10.73 * r2 * mxp_azimuthal_roughness) + (5.574 * r4) + (0.245 * r4 * mxp_azimuthal_roughness); - float3 sigma = math::log(math::min(math::max(mxp_color, 0.001), float3(1.0))) / r_fac; + float3 sigma = math::log(math::min(math::max(float3(mxp_color), 0.001), float3(1.0))) / r_fac; return (sigma * sigma); } diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl index 2d288ee8f2..bea4e59bf6 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl @@ -48,6 +48,7 @@ export using .::pbrlib_1_6 import mx_conductor_bsdf; export using .::pbrlib_1_6 import mx_generalized_schlick_bsdf; export using .::pbrlib_1_6 import mx_subsurface_bsdf; export using .::pbrlib_1_6 import mx_thin_film_bsdf; +export using .::pbrlib_1_6 import mx_chiang_hair_bsdf; export using .::pbrlib_1_6 import mx_uniform_edf; export using .::pbrlib_1_6 import mx_conical_edf; export using .::pbrlib_1_6 import mx_measured_edf; @@ -72,6 +73,10 @@ export using .::pbrlib_1_6 import mx_roughness_dual; export using .::pbrlib_1_6 import mx_blackbody; export using .::pbrlib_1_6 import mx_artistic_ior__result ; export using .::pbrlib_1_6 import mx_artistic_ior; +export using .::pbrlib_1_6 import mx_deon_hair_absorption_from_melanin; +export using .::pbrlib_1_6 import mx_chiang_hair_absorption_from_color; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness__result; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness; diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl index f5d661b17e..3815d892a0 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl @@ -42,6 +42,7 @@ export material mx_surfacematerial( = material( thin_walled: mxp_surfaceshader.thin_walled || mxp_backsurfaceshader.thin_walled, surface: mxp_surfaceshader.surface, + hair: mxp_surfaceshader.hair, backface: mxp_backsurfaceshader.surface, geometry: material_geometry( cutout_opacity: mxp_surfaceshader.geometry.cutout_opacity, From 1734e6dd9d132ddc9abcdd3a095ccf9f37e8fcc5 Mon Sep 17 00:00:00 2001 From: Rui Yang Date: Wed, 23 Oct 2024 19:25:39 -0700 Subject: [PATCH 101/137] Add a combined version define in MaterialX C++ (#2031) PR for https://github.com/AcademySoftwareFoundation/MaterialX/issues/1609 Also added a simple test in source/MaterialXTest/MaterialXCore --- source/MaterialXCore/Library.h | 5 +++++ source/MaterialXTest/MaterialXCore/CoreUtil.cpp | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/source/MaterialXCore/Library.h b/source/MaterialXCore/Library.h index 1a92c634a7..571644c098 100644 --- a/source/MaterialXCore/Library.h +++ b/source/MaterialXCore/Library.h @@ -21,6 +21,11 @@ #include +#define MATERIALX_GENERATE_INDEX(major, minor, build) \ + ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(build))) +#define MATERIALX_VERSION_INDEX \ + MATERIALX_GENERATE_INDEX(MATERIALX_MAJOR_VERSION, MATERIALX_MINOR_VERSION, MATERIALX_BUILD_VERSION) + /// Platform-specific macros for declaring imported and exported symbols. #if defined(MATERIALX_BUILD_SHARED_LIBS) #if defined(_WIN32) diff --git a/source/MaterialXTest/MaterialXCore/CoreUtil.cpp b/source/MaterialXTest/MaterialXCore/CoreUtil.cpp index 11aa826d4f..4bc174a690 100644 --- a/source/MaterialXTest/MaterialXCore/CoreUtil.cpp +++ b/source/MaterialXTest/MaterialXCore/CoreUtil.cpp @@ -10,6 +10,12 @@ namespace mx = MaterialX; +TEST_CASE("Version comparison", "[coreutil]") +{ + // Test for version comparison + REQUIRE(MATERIALX_VERSION_INDEX > MATERIALX_GENERATE_INDEX(1, 38, 8)); +} + TEST_CASE("String utilities", "[coreutil]") { std::string invalidName("test.name"); From 593e175f3f17ccd00337cad29682d321643babaa Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 28 Oct 2024 17:14:33 -0700 Subject: [PATCH 102/137] Restore specular terms of UsdPreviewSurface (#2088) This changelist restores the interpretation of the reflective and transmissive specular terms of UsdPreviewSurface, reverting some unintended changes in PR #2081. --- libraries/bxdf/usd_preview_surface.mtlx | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index d99fab3a8c..a521c756bc 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -152,16 +152,10 @@ - - - - - - - + @@ -176,12 +170,8 @@ - - - - - + @@ -223,12 +213,8 @@ - - - - - + From 7af264b4039f06b78133b68e56c03e20b20449e6 Mon Sep 17 00:00:00 2001 From: JGamache-autodesk <56274617+JGamache-autodesk@users.noreply.github.com> Date: Mon, 28 Oct 2024 20:56:17 -0400 Subject: [PATCH 103/137] Coat layer should affect emission in USD translation (#2087) The standard_surface coat parameters are currently affecting the baseColor of UsdPreviewSurface. It should also affect emission color. --- libraries/bxdf/translation/standard_surface_to_usd.mtlx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/bxdf/translation/standard_surface_to_usd.mtlx b/libraries/bxdf/translation/standard_surface_to_usd.mtlx index 099465e369..51c7d5fc6e 100644 --- a/libraries/bxdf/translation/standard_surface_to_usd.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_usd.mtlx @@ -80,10 +80,14 @@ - + + + + + From 967d4c2f5c5d563f10c0b7fcd8fb7e19e6369768 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 29 Oct 2024 14:44:23 -0700 Subject: [PATCH 104/137] Reduce verbosity of unit tests (#2091) This changelist reduces the verbosity of our unit tests for element equivalence, focusing on REQUIRE statements to provide coverage. --- .../MaterialXTest/MaterialXCore/Document.cpp | 64 ------------------- 1 file changed, 64 deletions(-) diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index 94f8b98708..ae7623084e 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -10,8 +10,6 @@ #include #include -#include - namespace mx = MaterialX; TEST_CASE("Document", "[document]") @@ -123,16 +121,6 @@ TEST_CASE("Document", "[document]") REQUIRE(doc->validate()); } -void printDifferences(const mx::ElementEquivalenceResultVec& results, const std::string& label) -{ - for (const mx::ElementEquivalenceResult& result : results) - { - std::cout << label << ": " << "Element: " << result.path1 << - ", Element: " << result.path2 << ", Difference Type: " << result.differenceType - << ", Value: " << result.attributeName << std::endl; - } -} - TEST_CASE("Document equivalence", "[document]") { mx::DocumentPtr doc = mx::createDocument(); @@ -224,44 +212,18 @@ TEST_CASE("Document equivalence", "[document]") // Check skipping all value compares options.skipValueComparisons = true; bool equivalent = doc->isEquivalent(doc2, options, &results); - if (equivalent) - { - std::cout << "Unexpected skip value equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } - else - { - printDifferences(results, "Expected value differences"); - } REQUIRE(!equivalent); // Check attibute values options.skipValueComparisons = false; results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Unexpected value difference"); - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(equivalent); unsigned int currentPrecision = mx::Value::getFloatPrecision(); // This will compare 0.012345608 versus: 1, 0.012345611 for input10 options.precision = 8; equivalent = doc->isEquivalent(doc2, options); - if (equivalent) - { - std::cout << "Unexpected precision equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } - else - { - printDifferences(results, "Expected precision difference"); - } REQUIRE(!equivalent); options.precision = currentPrecision; @@ -274,12 +236,6 @@ TEST_CASE("Document equivalence", "[document]") floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, "100.0"); } equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Unexpected filtering differences"); - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(equivalent); for (mx::InputPtr floatInput : floatInputs) { @@ -293,16 +249,6 @@ TEST_CASE("Document equivalence", "[document]") mismatchElement->setName("mismatch_color4"); results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Expected name mismatch differences"); - } - else - { - std::cout << "Unexpected name match equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(!equivalent); mismatchElement->setName(previousName); results.clear(); @@ -320,15 +266,5 @@ TEST_CASE("Document equivalence", "[document]") nodeGraph2->setNodeDefString("ND_mygraph"); results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Expected functional graph differences"); - } - else - { - std::cout << "Unexpected functional graph equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(!equivalent); } From 9d875a817f17dac5d8b3ad2b388cdfdee5c6eb6a Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:10:33 -0700 Subject: [PATCH 105/137] Initial implementation of structs in MaterialX (#1831) This PR introduces support for custom structs types. Custom structs are defined using the `typedef` element. ``` ``` `member` elements are used to define the members of the custom struct. The `value` here is the default value used if no initializer is specified. --- .../JsMaterialX/JsMaterialXCore/JsValue.cpp | 2 +- source/MaterialXCore/Definition.cpp | 8 + source/MaterialXCore/Definition.h | 11 +- source/MaterialXCore/Element.cpp | 16 + source/MaterialXCore/Element.h | 14 +- source/MaterialXCore/Exception.h | 8 + source/MaterialXCore/Value.cpp | 73 ++++- source/MaterialXCore/Value.h | 81 ++++- source/MaterialXGenGlsl/GlslSyntax.cpp | 37 +++ source/MaterialXGenGlsl/GlslSyntax.h | 14 + .../mdl/materialx/stdlib_1_8.mdl | 20 ++ source/MaterialXGenOsl/OslShaderGenerator.cpp | 9 +- source/MaterialXGenShader/ShaderGenerator.cpp | 41 +++ source/MaterialXGenShader/ShaderGenerator.h | 6 + source/MaterialXGenShader/ShaderNode.cpp | 4 +- source/MaterialXGenShader/Syntax.cpp | 65 ++++ source/MaterialXGenShader/Syntax.h | 32 ++ source/MaterialXGenShader/TypeDesc.cpp | 129 +++++++- source/MaterialXGenShader/TypeDesc.h | 79 ++++- source/MaterialXGraphEditor/RenderView.cpp | 3 + source/MaterialXRender/Util.cpp | 2 +- source/MaterialXRenderGlsl/GlslMaterial.cpp | 2 +- source/MaterialXRenderGlsl/GlslProgram.cpp | 120 ++++--- source/MaterialXRenderGlsl/GlslProgram.h | 4 +- source/MaterialXRenderMsl/MslMaterial.mm | 2 +- .../MslPipelineStateObject.h | 4 +- .../MslPipelineStateObject.mm | 296 +++++++++++------- source/MaterialXTest/MaterialXCore/Node.cpp | 6 +- .../MaterialXGenShader/GenShaderUtil.cpp | 5 + source/MaterialXView/Viewer.cpp | 3 + .../PyMaterialX/PyMaterialXCore/PyValue.cpp | 6 +- .../PyShaderGenerator.cpp | 2 + 32 files changed, 903 insertions(+), 201 deletions(-) diff --git a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp index d0ddba7e17..5e45ef16cd 100644 --- a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp +++ b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp @@ -47,7 +47,7 @@ EMSCRIPTEN_BINDINGS(value) .function("copy", &mx::Value::copy, ems::pure_virtual()) .function("getTypeString", &mx::Value::getTypeString) .function("getValueString", &mx::Value::getValueString) - .class_function("createValueFromStrings", &mx::Value::createValueFromStrings) + BIND_CLASS_FUNC("createValueFromStrings", mx::Value, createValueFromStrings, 2, 3, stRef, stRef, mx::ConstTypeDefPtr) .class_function("setFloatFormat", &mx::Value::setFloatFormat) .class_function("setFloatPrecision", &mx::Value::setFloatPrecision) .class_function("getFloatFormat", &mx::Value::getFloatFormat) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 22c111f03c..da6c3ca3af 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -196,4 +196,12 @@ vector UnitTypeDef::getUnitDefs() const return unitDefs; } +ValuePtr AttributeDef::getValue() const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType())); +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXCore/Definition.h b/source/MaterialXCore/Definition.h index 6498f21c89..0ce7761b6d 100644 --- a/source/MaterialXCore/Definition.h +++ b/source/MaterialXCore/Definition.h @@ -423,11 +423,11 @@ class MX_CORE_API TargetDef : public TypedElement /// @class Member /// A member element within a TypeDef. -class MX_CORE_API Member : public TypedElement +class MX_CORE_API Member : public ValueElement { public: Member(ElementPtr parent, const string& name) : - TypedElement(parent, CATEGORY, name) + ValueElement(parent, CATEGORY, name) { } virtual ~Member() { } @@ -625,12 +625,7 @@ class MX_CORE_API AttributeDef : public TypedElement /// /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getValue() const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getValueString(), getType()); - } + ValuePtr getValue() const; /// @} /// @name Elements diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index af47a6a2ba..648d7df000 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -638,6 +638,22 @@ string ValueElement::getResolvedValueString(StringResolverPtr resolver) const return resolver->resolve(getValueString(), getType()); } +ValuePtr ValueElement::getValue() const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType())); +} + +ValuePtr ValueElement::getResolvedValue(StringResolverPtr resolver) const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getResolvedValueString(resolver), getType(), getDocument()->getTypeDef(getType())); +} + ValuePtr ValueElement::getDefaultValue() const { ConstElementPtr parent = getParent(); diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index a80bc3a49f..fb4bbe07ce 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -1037,12 +1037,7 @@ class MX_CORE_API ValueElement : public TypedElement /// /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getValue() const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getValueString(), getType()); - } + ValuePtr getValue() const; /// Return the resolved value of an element as a generic value object, which /// may be queried to access its data. @@ -1052,12 +1047,7 @@ class MX_CORE_API ValueElement : public TypedElement /// will be created at this scope and applied to the return value. /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getResolvedValueString(resolver), getType()); - } + ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const; /// Return the default value for this element as a generic value object, which /// may be queried to access its data. diff --git a/source/MaterialXCore/Exception.h b/source/MaterialXCore/Exception.h index 4fc0c728ec..4cf51f1cd5 100644 --- a/source/MaterialXCore/Exception.h +++ b/source/MaterialXCore/Exception.h @@ -50,6 +50,14 @@ class MX_CORE_API Exception : public std::exception string _msg; }; +/// @class ExceptionTypeError +/// An exception that is thrown when a type mismatch is encountered. +class MX_CORE_API ExceptionTypeError : public Exception +{ + public: + using Exception::Exception; +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXCore/Value.cpp b/source/MaterialXCore/Value.cpp index 68da4b5b9d..bb70aa04ae 100644 --- a/source/MaterialXCore/Value.cpp +++ b/source/MaterialXCore/Value.cpp @@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 // +#include +#include #include #include @@ -267,12 +269,18 @@ template ValuePtr TypedValue::createFromString(const string& value) // Value methods // -ValuePtr Value::createValueFromStrings(const string& value, const string& type) +ValuePtr Value::createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef) { CreatorMap::iterator it = _creatorMap.find(type); if (it != _creatorMap.end()) return it->second(value); + if (typeDef && !typeDef->getMembers().empty()) + { + // If we're given a TypeDef pointer that has child members, then we can create a new AggregateValue. + return AggregateValue::createAggregateValueFromString(value, type, typeDef); + } + return TypedValue::createFromString(value); } @@ -291,6 +299,69 @@ template const T& Value::asA() const return typedVal->getData(); } +template <> +MX_CORE_API bool Value::isA() const +{ + return dynamic_cast(this) != nullptr; +} + +template <> +MX_CORE_API const AggregateValue& Value::asA() const +{ + const AggregateValue* typedVal = dynamic_cast(this); + if (!typedVal) + { + throw ExceptionTypeError("Incorrect type specified for value"); + } + return *typedVal; +} + +string AggregateValue::getValueString() const +{ + if (_data.empty()) + return EMPTY_STRING; + + std::string result = "{"; + std::string separator = ""; + for (const auto& val : _data) + { + result += separator + val->getValueString(); + separator = ";"; + } + result += "}"; + + return result; +} + +AggregateValuePtr AggregateValue::createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDef) +{ + StringVec subValues = parseStructValueString(value); + + AggregateValuePtr result = AggregateValue::createAggregateValue(type); + const auto& members = typeDef->getMembers(); + + if (subValues.size() != members.size()) + { + std::stringstream ss; + ss << "Wrong number of initializers - expect " << members.size(); + throw Exception(ss.str()); + } + + auto doc = typeDef->getDocument(); + for (size_t i = 0; i < members.size(); ++i) + { + const auto& member = members[i]; + + // This will return nullptr if the type is not a listed typedef. + ConstTypeDefPtr subTypeDef = doc->getTypeDef(members[i]->getType()); + + // Calling Value::createValueFromStrings() here allows support for recursively nested structs. + result->appendValue(Value::createValueFromStrings(subValues[i], member->getType(), subTypeDef)); + } + + return result; +} + ScopedFloatFormatting::ScopedFloatFormatting(Value::FloatFormat format, int precision) : _format(Value::getFloatFormat()), _precision(Value::getFloatPrecision()) diff --git a/source/MaterialXCore/Value.h b/source/MaterialXCore/Value.h index 764a0ccc01..4dae4ab135 100644 --- a/source/MaterialXCore/Value.h +++ b/source/MaterialXCore/Value.h @@ -24,21 +24,22 @@ using BoolVec = vector; using FloatVec = vector; class Value; +class AggregateValue; /// A shared pointer to a Value using ValuePtr = shared_ptr; /// A shared pointer to a const Value using ConstValuePtr = shared_ptr; -template class TypedValue; +/// A shared pointer to an Aggregate Value +using AggregateValuePtr = shared_ptr; +/// A shared pointer to a const Aggregate Value +using ConstAggregateValuePtr = shared_ptr; -/// @class ExceptionTypeError -/// An exception that is thrown when a type mismatch is encountered. -class MX_CORE_API ExceptionTypeError : public Exception -{ - public: - using Exception::Exception; -}; +class TypeDef; +using ConstTypeDefPtr = shared_ptr; + +template class TypedValue; /// A generic, discriminated value, whose type may be queried dynamically. class MX_CORE_API Value @@ -73,7 +74,7 @@ class MX_CORE_API Value /// Create a new value instance from value and type strings. /// @return A shared pointer to a typed value, or an empty shared pointer /// if the conversion to the given data type cannot be performed. - static ValuePtr createValueFromStrings(const string& value, const string& type); + static ValuePtr createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef = nullptr); /// Create a deep copy of the value. virtual ValuePtr copy() const = 0; @@ -193,6 +194,68 @@ template class MX_CORE_API TypedValue : public Value T _data; }; +/// A subclass for aggregate values with multiple members +class MX_CORE_API AggregateValue : public Value +{ + public: + AggregateValue(const string& typeName) : + _typeName(typeName) + { + } + virtual ~AggregateValue() { } + + /// Create a deep copy of the value. + ValuePtr copy() const override + { + auto result = createAggregateValue(_typeName); + for (const auto& val : _data) + { + result->appendValue(val->copy()); + } + return result; + } + + /// Append a member value to the aggregate. + void appendValue(ConstValuePtr valuePtr) + { + _data.emplace_back(valuePtr); + } + + const vector& getMembers() const + { + return _data; + } + + /// Query an indexed member value from the aggregate. + ConstValuePtr getMemberValue(size_t index) const + { + return _data[index]; + } + + /// Return type string. + const string& getTypeString() const override { return _typeName; } + + /// Return value string. + string getValueString() const override; + + // + // Static helper methods + // + + /// Create a new value from an object of any valid MaterialX type. + static AggregateValuePtr createAggregateValue(const string& typeName) + { + return std::make_shared(typeName); + } + + static AggregateValuePtr createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDefPtr); + + private: + const string _typeName; + + vector _data; +}; + /// @class ScopedFloatFormatting /// An RAII class for controlling the float formatting of values. class MX_CORE_API ScopedFloatFormatting diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp index f91305f1a6..651a4ab5ff 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.cpp +++ b/source/MaterialXGenGlsl/GlslSyntax.cpp @@ -375,4 +375,41 @@ bool GlslSyntax::remapEnumeration(const string& value, TypeDesc type, const stri return true; } +StructTypeSyntaxPtr GlslSyntax::createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const +{ + return std::make_shared( + this, + structTypeName, + defaultValue, + uniformDefaultValue, + typeAlias, + typeDefinition); +} + +string GlslStructTypeSyntax::getValue(const Value& value, bool /* uniform */) const +{ + const AggregateValue& aggValue = static_cast(value); + + string result = aggValue.getTypeString() + "("; + + string separator = ""; + for (const auto& memberValue : aggValue.getMembers()) + { + result += separator; + separator = ","; + + auto memberTypeName = memberValue->getTypeString(); + auto memberTypeDesc = TypeDesc::get(memberTypeName); + + // Recursively use the syntax to generate the output, so we can supported nested structs. + result += _parentSyntax->getValue(memberTypeDesc, *memberValue, true); + } + + result += ")"; + + return result; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/GlslSyntax.h b/source/MaterialXGenGlsl/GlslSyntax.h index 8408534e7e..1e82e354bd 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.h +++ b/source/MaterialXGenGlsl/GlslSyntax.h @@ -45,6 +45,20 @@ class MX_GENGLSL_API GlslSyntax : public Syntax static const StringVec VEC2_MEMBERS; static const StringVec VEC3_MEMBERS; static const StringVec VEC4_MEMBERS; + + protected: + StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const override; +}; + +/// Specialization of TypeSyntax for aggregate types. +class MX_GENGLSL_API GlslStructTypeSyntax : public StructTypeSyntax +{ + public: + using StructTypeSyntax::StructTypeSyntax; + + string getValue(const Value& value, bool uniform) const override; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl index bef1e430d4..bb6eaf157a 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl @@ -441,3 +441,23 @@ export float3 mx_viewdirection_vector3( ::state::coordinate_object, internal_space_direction)); } + + +export float3 mx_extractGroup( + uniform texcoordGroup_struct in = {{0.1,0.1},{0.2,0.2},{0.3,0.3}}, + uniform int index = 0 +) + [[ + anno::description("Node Group: experimental") + ]] +{ + result = in.st_0.ss; + + if (index == 1) + result = in.st_1.ss; + else if (index == 2) + result = in.st_2.ss; + + return result; +} + diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index f29719a39b..d0d9d96cba 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -510,10 +511,10 @@ void OslShaderGenerator::emitMetadata(const ShaderPort* port, ShaderStage& stage { static const std::unordered_map UI_WIDGET_METADATA = { - { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("filename", Type::STRING.getName())) }, - { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("checkBox", Type::STRING.getName())) } + { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("filename")) }, + { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("checkBox")) } }; static const std::set METADATA_TYPE_BLACKLIST = diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index 6c23382f81..398232bf39 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -344,6 +344,47 @@ ShaderNodeImplPtr ShaderGenerator::getImplementation(const NodeDef& nodedef, Gen return impl; } +/// Load any struct type definitions from the document in to the type cache. +void ShaderGenerator::loadStructTypeDefs(const DocumentPtr& doc) +{ + for (const auto& mxTypeDef : doc->getTypeDefs()) + { + const auto& typeDefName = mxTypeDef->getName(); + const auto& members = mxTypeDef->getMembers(); + + // If we don't have any member children then we're not going to consider ourselves a struct. + if (members.empty()) + continue; + + StructTypeDesc newStructTypeDesc; + for (const auto& member : members) + { + auto memberName = member->getName(); + auto memberTypeName = member->getType(); + auto memberType = TypeDesc::get(memberTypeName); + auto memberDefaultValue = member->getValueString(); + + newStructTypeDesc.addMember(memberName, memberType, memberDefaultValue); + } + + auto structIndex = StructTypeDesc::emplace_back(newStructTypeDesc); + + TypeDesc structTypeDesc(typeDefName, TypeDesc::BASETYPE_STRUCT, TypeDesc::SEMANTIC_NONE, 1, structIndex); + + TypeDescRegistry(structTypeDesc, typeDefName); + + StructTypeDesc::get(structIndex).setTypeDesc(TypeDesc::get(typeDefName)); + } + + _syntax->registerStructTypeDescSyntax(); +} + +/// Clear any struct type definitions loaded +void ShaderGenerator::clearStructTypeDefs() +{ + StructTypeDesc::clear(); +} + namespace { diff --git a/source/MaterialXGenShader/ShaderGenerator.h b/source/MaterialXGenShader/ShaderGenerator.h index fa60a4d63e..a2f54fec2e 100644 --- a/source/MaterialXGenShader/ShaderGenerator.h +++ b/source/MaterialXGenShader/ShaderGenerator.h @@ -191,6 +191,12 @@ class MX_GENSHADER_API ShaderGenerator return _tokenSubstitutions; } + /// Load any struct type definitions from the document in to the type cache. + void loadStructTypeDefs(const DocumentPtr& doc); + + /// Clear any struct type definitions loaded + void clearStructTypeDefs(); + /// Register metadata that should be exported to the generated shaders. /// Supported metadata includes standard UI attributes like "uiname", "uifolder", /// "uimin", "uimax", etc. diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index 4e90fcbb2d..d52810ffc4 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -437,7 +437,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) const string& attrValue = nodeDef.getAttribute(nodedefAttr); if (!attrValue.empty()) { - ValuePtr value = Value::createValueFromStrings(attrValue, metadataEntry->type.getName()); + ValuePtr value = metadataEntry->type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; @@ -472,7 +472,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) if (!attrValue.empty()) { const TypeDesc type = metadataEntry->type != Type::NONE ? metadataEntry->type : input->getType(); - ValuePtr value = Value::createValueFromStrings(attrValue, type.getName()); + ValuePtr value = type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index 661aa41660..b8eed3e9b8 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -190,6 +190,36 @@ bool Syntax::remapEnumeration(const string&, TypeDesc, const string&, std::pair< return false; } +void Syntax::registerStructTypeDescSyntax() +{ + for (const auto& typeName : StructTypeDesc::getStructTypeNames()) + { + const auto& typeDesc = TypeDesc::get(typeName); + const auto& structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); + + string structTypeName = typeName; + string defaultValue = typeName + "( "; + string uniformDefaultValue = EMPTY_STRING; + string typeAlias = EMPTY_STRING; + string typeDefinition = "struct " + structTypeName + " { "; + + for (const auto& x : structTypeDesc.getMembers()) + { + string memberName = x._name; + string memberType = x._typeDesc.getName(); + string memberDefaultValue = x._defaultValueStr; + + defaultValue += memberDefaultValue + ", "; + typeDefinition += memberType + " " + memberName + "; "; + } + + typeDefinition += " };"; + defaultValue += " )"; + + registerTypeSyntax(typeDesc, createStructSyntax(structTypeName, defaultValue, uniformDefaultValue, typeAlias, typeDefinition)); + } +} + const StringVec TypeSyntax::EMPTY_MEMBERS; TypeSyntax::TypeSyntax(const string& name, const string& defaultValue, const string& uniformDefaultValue, @@ -246,4 +276,39 @@ string AggregateTypeSyntax::getValue(const Value& value, bool /*uniform*/) const return valueString.empty() ? valueString : getName() + "(" + valueString + ")"; } +StructTypeSyntax::StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias, const string& typeDefinition, const StringVec& members) : + TypeSyntax(name, defaultValue, uniformDefaultValue, typeAlias, typeDefinition, members), _parentSyntax(parentSyntax) +{ +} + +string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const +{ + const AggregateValue& aggValue = static_cast(value); + + auto typeDesc = TypeDesc::get(aggValue.getTypeString()); + auto structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); + + string result = "{"; + + string separator = ""; + for (const auto& memberValue : aggValue.getMembers()) + { + result += separator; + separator = ";"; + + auto memberTypeName = memberValue->getTypeString(); + auto memberTypeDesc = TypeDesc::get(memberTypeName); + + // Recursively use the syntax to generate the output, so we can support nested structs. + const string valueStr = _parentSyntax->getValue(memberTypeDesc, *memberValue, true); + + result += valueStr; + } + + result += "}"; + + return result; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/Syntax.h b/source/MaterialXGenShader/Syntax.h index a4bb7e49b5..6f16633b59 100644 --- a/source/MaterialXGenShader/Syntax.h +++ b/source/MaterialXGenShader/Syntax.h @@ -20,6 +20,7 @@ MATERIALX_NAMESPACE_BEGIN class Syntax; class TypeSyntax; +class StructTypeSyntax; class TypeDesc; class ShaderPort; @@ -29,6 +30,8 @@ using SyntaxPtr = shared_ptr; using ConstSyntaxPtr = shared_ptr; /// Shared pointer to a TypeSyntax using TypeSyntaxPtr = shared_ptr; +/// Shared pointer to a StructTypeSyntax +using StructTypeSyntaxPtr = shared_ptr; /// Map holding identifier names and a counter for /// creating unique names from them. @@ -67,6 +70,8 @@ class MX_GENSHADER_API Syntax /// Multiple calls will add to the internal set of tokens. void registerInvalidTokens(const StringMap& tokens); + virtual void registerStructTypeDescSyntax(); + /// Returns a set of names that are reserved words for this language syntax. const StringSet& getReservedWords() const { return _reservedWords; } @@ -199,6 +204,19 @@ class MX_GENSHADER_API Syntax /// Protected constructor Syntax(); + virtual StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const + { + return std::make_shared( + this, + structTypeName, + defaultValue, + uniformDefaultValue, + typeAlias, + typeDefinition); + } + vector _typeSyntaxes; std::unordered_map _typeSyntaxIndexByType; @@ -292,6 +310,20 @@ class MX_GENSHADER_API AggregateTypeSyntax : public TypeSyntax string getValue(const Value& value, bool uniform) const override; }; +/// Specialization of TypeSyntax for aggregate types. +class MX_GENSHADER_API StructTypeSyntax : public TypeSyntax +{ + public: + StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias = EMPTY_STRING, const string& typeDefinition = EMPTY_STRING, + const StringVec& members = EMPTY_MEMBERS); + + string getValue(const Value& value, bool uniform) const override; + + protected: + const Syntax* _parentSyntax; +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp index 1267caf14d..5d51680211 100644 --- a/source/MaterialXGenShader/TypeDesc.cpp +++ b/source/MaterialXGenShader/TypeDesc.cpp @@ -5,7 +5,7 @@ #include -#include +#include MATERIALX_NAMESPACE_BEGIN @@ -28,6 +28,16 @@ TypeDescNameMap& typeNameMap() return map; } +using StructTypeDescStorage = vector; +StructTypeDescStorage& structTypeStorage() +{ + // TODO: Our use of the singleton pattern for TypeDescMap and StructTypeDestStorage + // is not thread-safe, and we should consider replacing this with thread-local + // data in the GenContext object. + static StructTypeDescStorage storage; + return storage; +} + } // anonymous namespace const string TypeDesc::NONE_TYPE_NAME = "none"; @@ -46,7 +56,52 @@ TypeDesc TypeDesc::get(const string& name) return it != types.end() ? it->second : Type::NONE; } -TypeDescRegistry::TypeDescRegistry(TypeDesc type, const std::string& name) +void TypeDesc::remove(const string& name) +{ + TypeDescNameMap& typenames = typeNameMap(); + + TypeDescMap& types = typeMap(); + + auto it = types.find(name); + if (it == types.end()) + return; + + typenames.erase(it->second.typeId()); + types.erase(it); +} + +ValuePtr TypeDesc::createValueFromStrings(const string& value) const +{ + ValuePtr newValue = Value::createValueFromStrings(value, getName()); + if (!isStruct()) + return newValue; + + // Value::createValueFromStrings() can only create a valid Value for a struct if it is passed + // the optional TypeDef argument, otherwise it just returns a "string" typed Value. + // So if this is a struct type we need to create a new AggregateValue. + + StringVec subValues = parseStructValueString(value); + + AggregateValuePtr result = AggregateValue::createAggregateValue(getName()); + auto structTypeDesc = StructTypeDesc::get(getStructIndex()); + const auto& members = structTypeDesc.getMembers(); + + if (subValues.size() != members.size()) + { + std::stringstream ss; + ss << "Wrong number of initializers - expect " << members.size(); + throw ExceptionShaderGenError(ss.str()); + } + + for (size_t i = 0; i < members.size(); ++i) + { + result->appendValue( members[i]._typeDesc.createValueFromStrings(subValues[i])); + } + + return result; +} + +TypeDescRegistry::TypeDescRegistry(TypeDesc type, const string& name) { TypeDescMap& types = typeMap(); TypeDescNameMap& typenames = typeNameMap(); @@ -86,4 +141,74 @@ TYPEDESC_REGISTER_TYPE(MATERIAL, "material") } // namespace Type +// +// StructTypeDesc methods +// + +void StructTypeDesc::addMember(const string& name, TypeDesc type, string defaultValueStr) +{ + _members.emplace_back(StructTypeDesc::StructMemberTypeDesc(name, type, defaultValueStr)); +} + +vector StructTypeDesc::getStructTypeNames() +{ + StructTypeDescStorage& structs = structTypeStorage(); + vector structNames; + for (const auto& x : structs) + { + structNames.emplace_back(x.typeDesc().getName()); + } + return structNames; +} + +StructTypeDesc& StructTypeDesc::get(unsigned int index) +{ + StructTypeDescStorage& structs = structTypeStorage(); + return structs[index]; +} + +uint16_t StructTypeDesc::emplace_back(StructTypeDesc structTypeDesc) +{ + StructTypeDescStorage& structs = structTypeStorage(); + if (structs.size() >= std::numeric_limits::max()) + { + throw ExceptionShaderGenError("Maximum number of custom struct types has been exceeded."); + } + uint16_t index = static_cast(structs.size()); + structs.emplace_back(structTypeDesc); + return index; +} + +void StructTypeDesc::clear() +{ + StructTypeDescStorage& structs = structTypeStorage(); + for (const auto& structType: structs) + { + // Need to add typeID to structTypeDesc - and use it here to reference back to typeDesc obj and remove it. + TypeDesc::remove(structType.typeDesc().getName()); + } + structs.clear(); +} + +const string& StructTypeDesc::getName() const +{ + return _typedesc.getName(); +} + +const vector& StructTypeDesc::getMembers() const +{ + return _members; +} + +TypeDesc createStructTypeDesc(std::string_view name) +{ + return {name, TypeDesc::BASETYPE_STRUCT}; +} + +void registerStructTypeDesc(std::string_view name) +{ + auto structTypeDesc = createStructTypeDesc(name); + TypeDescRegistry register_struct(structTypeDesc, string(name)); +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index 1a537b7e58..95d2851915 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -10,6 +10,7 @@ /// Type descriptor for a MaterialX data type. #include +#include #include @@ -61,14 +62,21 @@ class MX_GENSHADER_API TypeDesc /// Empty constructor. constexpr TypeDesc() noexcept : - _id(0), _basetype(BASETYPE_NONE), _semantic(SEMANTIC_NONE), _size(0) { } + _id(0), + _basetype(BASETYPE_NONE), + _semantic(SEMANTIC_NONE), + _size(0), + _structIndex(0) + { + } /// Constructor. - constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1) noexcept : + constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1, uint16_t structIndex = 0) noexcept : _id(constexpr_hash(name)), // Note: We only store the hash to keep the class size minimal. _basetype(basetype), _semantic(semantic), - _size(size) + _size(size), + _structIndex(structIndex) { } @@ -112,6 +120,12 @@ class MX_GENSHADER_API TypeDesc /// Return true if the type represents a closure. bool isClosure() const { return (_semantic == SEMANTIC_CLOSURE || _semantic == SEMANTIC_SHADER || _semantic == SEMANTIC_MATERIAL); } + /// Return true if the type represents a struct. + bool isStruct() const { return _basetype == BASETYPE_STRUCT; } + + /// Return the index for the struct member information in StructTypeDesc, the result is invalid if `isStruct()` returns false. + uint16_t getStructIndex() const { return _structIndex; } + /// Equality operator bool operator==(TypeDesc rhs) const { @@ -143,8 +157,14 @@ class MX_GENSHADER_API TypeDesc /// If no type is found Type::NONE is returned. static TypeDesc get(const string& name); + /// Remove a type description by name, if it exists. + static void remove(const string& name); + static const string NONE_TYPE_NAME; + /// Create a Value from a string for a given typeDesc + ValuePtr createValueFromStrings(const string& value) const; + private: /// Simple constexpr hash function, good enough for the small set of short strings that /// are used for our data type names. @@ -157,6 +177,7 @@ class MX_GENSHADER_API TypeDesc uint8_t _basetype; uint8_t _semantic; uint16_t _size; + uint16_t _structIndex; }; /// @class TypeDescRegistry @@ -208,6 +229,58 @@ TYPEDESC_DEFINE_TYPE(MATERIAL, "material", TypeDesc::BASETYPE_NONE, TypeDesc::SE } // namespace Type + +/// @class StructTypeDesc +/// A type descriptor for MaterialX struct types. +/// +/// All types need to have a type descriptor registered in order for shader generators +/// to know about the type. If the type represented is of basetype=BASETYPE_STRUCT then +/// the type also needs to have an associated StructTypeDesc that describes the members +/// of the struct. +/// +class MX_GENSHADER_API StructTypeDesc +{ + public: + struct StructMemberTypeDesc + { + StructMemberTypeDesc(string name, TypeDesc typeDesc, string defaultValueStr) : + _name(name), _typeDesc(typeDesc), _defaultValueStr(defaultValueStr) + { + } + string _name; + TypeDesc _typeDesc; + string _defaultValueStr; + }; + + /// Empty constructor. + StructTypeDesc() noexcept{} + + void addMember(const string& name, TypeDesc type, string defaultValueStr); + void setTypeDesc(TypeDesc typedesc) { _typedesc = typedesc; } + + /// Return a type description by index. + static StructTypeDesc& get(unsigned int index); + static vector getStructTypeNames(); + static uint16_t emplace_back(StructTypeDesc structTypeDesc); + static void clear(); + + TypeDesc typeDesc() const { return _typedesc; } + + const string& getName() const; + + const vector& getMembers() const; + + private: + TypeDesc _typedesc; + vector _members; +}; + +class MX_GENSHADER_API StructTypeDescRegistry +{ + public: + StructTypeDescRegistry(); +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index dbc9b4f980..92cd8f07c7 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -630,6 +630,9 @@ void RenderView::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Register struct type definitions + context.getShaderGenerator().loadStructTypeDefs(_document); } void RenderView::drawContents() diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index 881f1b7eea..00fdc65381 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -170,7 +170,7 @@ unsigned int getUIProperties(InputPtr input, const string& target, UIProperties& else { valueString += val; - uiProperties.enumerationValues.push_back(Value::createValueFromStrings(valueString, input->getType())); + uiProperties.enumerationValues.push_back(typeDesc.createValueFromStrings(valueString)); valueString.clear(); index = 0; } diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index 788af713b2..064ab898ff 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -360,7 +360,7 @@ void GlslMaterial::modifyUniform(const std::string& path, ConstValuePtr value, s { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index b2ca0aa66e..b63e1faecc 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -508,7 +508,7 @@ ImagePtr GlslProgram::bindTexture(unsigned int uniformType, int uniformLocation, return nullptr; } -MaterialX::ValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -946,47 +946,87 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - int glType = mapTypeToOpenGLType(v->getType()); - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - - // Ignore types which are unsupported in GLSL. - if (glType == Input::INVALID_OPENGL_TYPE) - { - continue; - } + const auto& variablePath = v->getPath(); + const auto& variableUnit = v->getUnit(); + const auto& variableColorspace = v->getColorSpace(); + const auto& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt != _uniformList.end()) + const auto populateUniformInput = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue) -> void { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->unit = v->getUnit(); - input->colorspace = v->getColorSpace(); - input->value = v->getValue(); - if (input->gltype == glType) - { - input->typeString = v->getType().getName(); - } - else + auto populateUniformInput_impl = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". Unit: \"" + (!v->getUnit().empty() ? v->getUnit() : "") - + "\". Colorspace: \"" + (!v->getColorSpace().empty() ? v->getColorSpace() : "") - + "\". GLType: " + std::to_string(mapTypeToOpenGLType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + if (!typedesc.isStruct()) + { + // Handle non-struct types + int glType = mapTypeToOpenGLType(typedesc); + + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } + + // Ignore types which are unsupported in GLSL. + if (glType == Input::INVALID_OPENGL_TYPE) + { + return; + } + + auto inputIt = _uniformList.find(variableName); + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->unit = variableUnit; + input->colorspace = variableColorspace; + input->value = variableValue; + if (input->gltype == glType) + { + input->typeString = typedesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + typedesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". Unit: \"" + (!variableUnit.empty() ? variableUnit : "") + + "\". Colorspace: \"" + (!variableColorspace.empty() ? variableColorspace : "") + + "\". GLType: " + std::to_string(glType)); + uniformTypeMismatchFound = true; + } + } + } + else + { + // If we're a struct - we need to loop over each member + auto structTypeDesc = StructTypeDesc::get(typedesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& member = members[i]; + auto memberTypeDesc = member._typeDesc; + auto memberVariableName = variableName + "." + member._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(memberTypeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(typedesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1100,12 +1140,12 @@ const GlslProgram::InputMap& GlslProgram::updateAttributesList() if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; diff --git a/source/MaterialXRenderGlsl/GlslProgram.h b/source/MaterialXRenderGlsl/GlslProgram.h index 7d58dbaca7..4addd7d54b 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.h +++ b/source/MaterialXRenderGlsl/GlslProgram.h @@ -102,7 +102,7 @@ class MX_RENDERGLSL_API GlslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) @@ -223,7 +223,7 @@ class MX_RENDERGLSL_API GlslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(unsigned int uniformType, int uniformLocation, const FilePath& filePath, diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm index 311d84acee..eb13ea7900 100644 --- a/source/MaterialXRenderMsl/MslMaterial.mm +++ b/source/MaterialXRenderMsl/MslMaterial.mm @@ -318,7 +318,7 @@ { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.h b/source/MaterialXRenderMsl/MslPipelineStateObject.h index b335e29af5..a823662f5f 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.h +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.h @@ -99,7 +99,7 @@ class MX_RENDERMSL_API MslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) @@ -256,7 +256,7 @@ class MX_RENDERMSL_API MslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(id renderCmdEncoder, diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm index 2d5685646f..470fa549b2 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm @@ -235,12 +235,12 @@ int GetStrideOfMetalType(MTLDataType type) if (_shader->hasAttribute(HW::ATTR_TRANSPARENT)) { - psoDesc.colorAttachments[0].blendingEnabled = YES; - psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + psoDesc.colorAttachments[0].blendingEnabled = YES; + psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; psoDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; _alphaBlendingEnabled = true; @@ -265,12 +265,12 @@ int GetStrideOfMetalType(MTLDataType type) if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; @@ -566,8 +566,8 @@ int GetStrideOfMetalType(MTLDataType type) return nullptr; } -MaterialX::ValuePtr MslProgram::findUniformValue(const string& uniformName, - const MslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr MslProgram::findUniformValue(const string& uniformName, + const MslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -925,31 +925,54 @@ int GetStrideOfMetalType(MTLDataType type) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { - for (MTLStructMember* member in arg.bufferStructType.members) - { - std::string uboObjectName = std::string(arg.name.UTF8String); - std::string memberName = member.name.UTF8String; - std::string uboDotMemberName = uboObjectName + "." + memberName; + const auto uboObjectName = string(arg.name.UTF8String); - InputPtr inputPtr = std::make_shared(arg.index, member.dataType, arg.bufferDataSize, EMPTY_STRING); - _uniformList[uboDotMemberName] = inputPtr; - _globalUniformNameList[memberName] = uboDotMemberName; - - if (MTLArrayType* arrayMember = member.arrayType) + const auto addUniformToList = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix) -> void + { + auto addUniformToList_impl = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix, auto& addUniformToList_ref) -> void { - for (int i = 0; i < arrayMember.arrayLength; ++i) + auto memberName = memberNamePrefix + member.name.UTF8String; + + if (MTLStructType* structMember = member.structType) { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + for (MTLStructMember* subMember in structMember.members) { - std::string memberNameDotSubmember = memberName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - std::string uboDotMemberNameDotSubmemberName = uboObjectName + "." + memberNameDotSubmember; + auto namePrefix = memberName + "."; + addUniformToList_ref(subMember, subMember.argumentIndex, subMember.offset, namePrefix, addUniformToList_ref); + } + } + else + { + auto uboDotMemberName = uboObjectName + "." + memberName; + + InputPtr inputPtr = std::make_shared(index, member.dataType, size, EMPTY_STRING); + this->_uniformList[uboDotMemberName] = inputPtr; + this->_globalUniformNameList[memberName] = uboDotMemberName; - InputPtr inputPtr = std::make_shared(ArrayOfStructMember.argumentIndex, ArrayOfStructMember.dataType, ArrayOfStructMember.offset, EMPTY_STRING); - _uniformList[uboDotMemberNameDotSubmemberName] = inputPtr; - _globalUniformNameList[memberNameDotSubmember] = uboDotMemberNameDotSubmemberName; + if (MTLArrayType* arrayMember = member.arrayType) + { + for (int i = 0; i < arrayMember.arrayLength; ++i) + { + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + auto namePrefix = memberName + "[" + std::to_string(i) + "]."; + addUniformToList_ref(ArrayOfStructMember, ArrayOfStructMember.argumentIndex, ArrayOfStructMember.offset, namePrefix, addUniformToList_ref); + } + } } } - } + }; + + return addUniformToList_impl(member, index, size, memberNamePrefix, addUniformToList_impl); + }; + + for (MTLStructMember* member in arg.bufferStructType.members) + { + addUniformToList(member, arg.index, arg.bufferDataSize, ""); } } @@ -1006,55 +1029,90 @@ int GetStrideOfMetalType(MTLDataType type) for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - MTLDataType resourceType = mapTypeToMetalType(v->getType()); - - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - // Ignore types which are unsupported in MSL. - if (resourceType == MTLDataTypeNone) - { - continue; - } + const string& variablePath = v->getPath(); + const string& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt == _uniformList.end()) + const auto populateUniformInput = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue) -> void { - if (v->getType() == Type::FILENAME) + auto populateUniformInput_impl = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - inputIt = _uniformList.find(TEXTURE_NAME(v->getVariable())); - } - else - { - inputIt = _uniformList.find(uniforms.getInstance() + "." + v->getVariable()); - } - } + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } - if (inputIt != _uniformList.end()) - { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->value = v->getValue(); - if (input->resourceType == resourceType) - { - input->typeString = v->getType().getName(); - } - else - { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". resourceType: " + std::to_string(mapTypeToMetalType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + MTLDataType resourceType = mapTypeToMetalType(variableTypeDesc); + // Ignore types which are unsupported in MSL. + if (resourceType == MTLDataTypeNone) + { + return; + } + + if (!variableTypeDesc.isStruct()) + { + auto inputIt = _uniformList.find(variableName); + + if (inputIt == _uniformList.end()) { + if(variableTypeDesc == Type::FILENAME) + { + inputIt = _uniformList.find(TEXTURE_NAME(variableName)); + } + else + { + inputIt = _uniformList.find(uniforms.getInstance() + "." + variableName); + } + } + + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->value = variableValue; + if (input->resourceType == resourceType) + { + input->typeString = variableTypeDesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + variableTypeDesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". resourceType: " + std::to_string(mapTypeToMetalType(variableTypeDesc)) + ); + uniformTypeMismatchFound = true; + } + } + } + else + { + auto structTypeDesc = StructTypeDesc::get(variableTypeDesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& structMember = members[i]; + auto memberVariableName = variableName+"."+structMember._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(structMember._typeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(variableTypeDesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1231,7 +1289,7 @@ int GetStrideOfMetalType(MTLDataType type) return false; }; - auto setValue = [](MaterialX::ValuePtr value, std::vector& data, size_t offset) + auto setValue = [](MaterialX::ConstValuePtr value, std::vector& data, size_t offset) { if (value->getTypeString() == "float") { @@ -1307,7 +1365,7 @@ throw ExceptionRenderError( { if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - MaterialX::ValuePtr value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; + auto value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; if (value) { setValue(value, uniformBufferData, member.offset); @@ -1332,39 +1390,60 @@ throw ExceptionRenderError( if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - auto uniformInfo = _uniformList.find(uniformName); - if (uniformInfo != _uniformList.end()) - { - MaterialX::ValuePtr value = uniformInfo->second->value; - if (value) - { - setValue(value, uniformBufferData, member.offset); - } - } - else - { - } - } - - if (MTLArrayType* arrayMember = member.arrayType) - { - for (int i = 0; i < arrayMember.arrayLength; ++i) + const auto setUniformValue = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset ) -> void { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + auto setUniformValue_impl = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset, auto &setUniformValue_ref ) -> void { - string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - - auto uniformInfo = _uniformList.find(uniformNameSubArray); - if (uniformInfo != _uniformList.end()) + if(MTLArrayType* arrayMember = member.arrayType) { - MaterialX::ValuePtr value = uniformInfo->second->value; - if (value) + for(int i = 0; i < arrayMember.arrayLength; ++i) { - setValue(value, uniformBufferData, member.offset + i * arrayMember.stride + ArrayOfStructMember.offset); + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; + auto uniformInfo = _uniformList.find(uniformNameSubArray); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset + i * arrayMember.stride + ArrayOfStructMember.offset); + } + } + } } } - } - } + else if (MTLStructType* structMember = member.structType) + { + // this code does not support struct recursion yet.... + for (MTLStructMember* subMember in structMember.members) + { + string subUniformName = uniformName+"."+subMember.name.UTF8String; + setUniformValue_ref(subMember, subUniformName, uniformBufferData, offset+subMember.offset, setUniformValue_ref); + } + } + else + { + auto uniformInfo = _uniformList.find(uniformName); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset); + } + } + } + }; + + return setUniformValue_impl(member, uniformName, uniformBufferData, offset, setUniformValue_impl); + }; + + setUniformValue(member, uniformName, uniformBufferData, member.offset); } } @@ -1415,14 +1494,15 @@ throw ExceptionRenderError( // A "filename" is not indicative of type, so just return a 2d sampler. return MTLDataTypeTexture; } - else if (type == Type::BSDF || - type == Type::MATERIAL || + else if (type == Type::BSDF || + type == Type::MATERIAL || type == Type::DISPLACEMENTSHADER || - type == Type::EDF || - type == Type::VDF || - type == Type::SURFACESHADER || - type == Type::LIGHTSHADER || - type == Type::VOLUMESHADER) + type == Type::EDF || + type == Type::VDF || + type == Type::SURFACESHADER || + type == Type::LIGHTSHADER || + type == Type::VOLUMESHADER || + type.isStruct()) return MTLDataTypeStruct; return MTLDataTypeNone; diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp index ef746bfe05..f3ce7d40de 100644 --- a/source/MaterialXTest/MaterialXCore/Node.cpp +++ b/source/MaterialXTest/MaterialXCore/Node.cpp @@ -159,12 +159,12 @@ TEST_CASE("Node", "[node]") REQUIRE(typeDef->getMembers().size() == scalarCount); // Reference the custom type. - std::string d65("400.0,82.75,500.0,109.35,600.0,90.01,700.0,71.61,800.0,59.45"); + std::string d65("{400;82.75;500;109.35;600;90.01;700;71.61;800;59.45}"); constant->setInputValue("value", d65, "spectrum"); REQUIRE(constant->getInput("value")->getType() == "spectrum"); REQUIRE(constant->getInput("value")->getValueString() == d65); - REQUIRE(constant->getInputValue("value")->isA()); - REQUIRE(constant->getInputValue("value")->asA() == d65); + REQUIRE(constant->getInputValue("value")->isA()); + REQUIRE(constant->getInputValue("value")->asA().getValueString() == d65); // Validate the document. REQUIRE(doc->validate()); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 4a8e61645a..78da7e50f3 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -649,6 +649,9 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons addColorManagement(); addUnitSystem(); + // Register struct typedefs from the library files. + _shaderGenerator->loadStructTypeDefs(_dependLib); + // Test suite setup addSkipFiles(); @@ -705,6 +708,8 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons preprocessDocument(doc); _shaderGenerator->registerShaderMetadata(doc, context); + _shaderGenerator->loadStructTypeDefs(doc); + // For each new file clear the implementation cache. // Since the new file might contain implementations with names // colliding with implementations in previous test cases. diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 24aea1eb42..c4c69bb812 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -1769,6 +1769,9 @@ void Viewer::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Initialize the struct typedefs from the stdlib + context.getShaderGenerator().loadStructTypeDefs(_stdLib); } void Viewer::loadStandardLibraries() diff --git a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp index 501f9d5f04..c36bd6c288 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp @@ -6,6 +6,7 @@ #include #include +#include #define BIND_TYPE_INSTANCE(NAME, T) \ py::class_, std::shared_ptr< mx::TypedValue >, mx::Value>(mod, "TypedValue_" #NAME) \ @@ -22,7 +23,10 @@ void bindPyValue(py::module& mod) py::class_(mod, "Value") .def("getValueString", &mx::Value::getValueString) .def("getTypeString", &mx::Value::getTypeString) - .def_static("createValueFromStrings", &mx::Value::createValueFromStrings); + .def_static("createValueFromStrings", &mx::Value::createValueFromStrings, + py::arg("value"), + py::arg("type"), + py::arg("typeDefPtr") = nullptr); BIND_TYPE_INSTANCE(integer, int) BIND_TYPE_INSTANCE(boolean, bool) diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp index b952bd4651..0c8a086e58 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp @@ -22,5 +22,7 @@ void bindPyShaderGenerator(py::module& mod) .def("setUnitSystem", &mx::ShaderGenerator::setUnitSystem) .def("getUnitSystem", &mx::ShaderGenerator::getUnitSystem) .def("getTokenSubstitutions", &mx::ShaderGenerator::getTokenSubstitutions) + .def("loadStructTypeDefs", &mx::ShaderGenerator::loadStructTypeDefs) + .def("clearStructTypeDefs", &mx::ShaderGenerator::clearStructTypeDefs) .def("registerShaderMetadata", &mx::ShaderGenerator::registerShaderMetadata); } From ed450e82de41a9a5d4273c49babfdb37b18b922e Mon Sep 17 00:00:00 2001 From: Chris Rydalch Date: Tue, 29 Oct 2024 18:12:58 -0500 Subject: [PATCH 106/137] Move unimplemented Worley noise features to proposals doc (#2090) The *period* and *metric* parameters are not yet implemented. --- documents/Specification/MaterialX.Proposals.md | 18 ++++++++++++++++++ .../Specification/MaterialX.Specification.md | 4 ---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/documents/Specification/MaterialX.Proposals.md b/documents/Specification/MaterialX.Proposals.md index b96c688f25..d387d28718 100644 --- a/documents/Specification/MaterialX.Proposals.md +++ b/documents/Specification/MaterialX.Proposals.md @@ -188,7 +188,25 @@ We have a standard 3d fractal noise, but a 2d variant would be useful as well. * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for input coordinate repeated at that step. Default is 0, meaning the noise is not periodic. * `in` (float): the 1D coordinate at which the noise is evaluated. + +Expanded 2D Worley noise to support different distance metrics and periodicity. + +* **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). + * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + + + +Expanded 3D Worley noise to support different distance metrics and periodicity. + +* **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). + * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + +#### Periodic Noises + +In #1201 it was decided that separate periodic versions of all of the noises is preferred to adding it to the existing noises. ### Shape Nodes diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 070587340c..65027694d8 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -887,16 +887,12 @@ Standard Noise nodes: * **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `texcoord` (vector2): the 2D position at which the noise is evaluated. Default is to use the first set of texture coordinates. * **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. From b330fd7ade12811aa4a39096bef3b986841d67bb Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:37:10 -0700 Subject: [PATCH 107/137] Removing MDL struct test function (#2099) Removing MDL struct test function incorrectly included in #1831. --- .../mdl/materialx/stdlib_1_8.mdl | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl index bb6eaf157a..bef1e430d4 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl @@ -441,23 +441,3 @@ export float3 mx_viewdirection_vector3( ::state::coordinate_object, internal_space_direction)); } - - -export float3 mx_extractGroup( - uniform texcoordGroup_struct in = {{0.1,0.1},{0.2,0.2},{0.3,0.3}}, - uniform int index = 0 -) - [[ - anno::description("Node Group: experimental") - ]] -{ - result = in.st_0.ss; - - if (index == 1) - result = in.st_1.ss; - else if (index == 2) - result = in.st_2.ss; - - return result; -} - From 1b2852e1db52fc52ba5f845b784a2c46d909ef2d Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Thu, 31 Oct 2024 09:33:36 -0700 Subject: [PATCH 108/137] Simplify the MetalTexture abstraction (#2095) `mx_texture.metal` is used to provide an abstraction to the texture code when being called from GLSL code. There are a few functions in the interface of this abstraction that do not appear to be used anywhere. This PR proposes removing them, as a precursor to other upcoming texture work. I'm proposing this as a separate PR to make things easier to review. All of the MSL unit tests pass. --- libraries/stdlib/genmsl/lib/mx_texture.metal | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/libraries/stdlib/genmsl/lib/mx_texture.metal b/libraries/stdlib/genmsl/lib/mx_texture.metal index 479a8836bf..7e90b60686 100644 --- a/libraries/stdlib/genmsl/lib/mx_texture.metal +++ b/libraries/stdlib/genmsl/lib/mx_texture.metal @@ -2,13 +2,8 @@ struct MetalTexture { texture2d tex; sampler s; - int get_width() { return tex.get_width(); } - int get_height() { return tex.get_height(); } - int get_num_mip_levels() { return tex.get_num_mip_levels(); } }; -int get_width(MetalTexture mtlTex) { return mtlTex.get_width(); } - float4 texture(MetalTexture mtlTex, float2 uv) { return mtlTex.tex.sample(mtlTex.s, uv); @@ -21,10 +16,5 @@ float4 textureLod(MetalTexture mtlTex, float2 uv, float lod) int2 textureSize(MetalTexture mtlTex, int mipLevel) { - return int2(mtlTex.get_width(), mtlTex.get_height()); -} - -int texture_mips(MetalTexture mtlTex) -{ - return mtlTex.tex.get_num_mip_levels(); + return int2(mtlTex.tex.get_width(), mtlTex.tex.get_height()); } From 65862ed56e9fd82dc2771bf3d371e16a1a1e30d3 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 31 Oct 2024 12:05:37 -0700 Subject: [PATCH 109/137] Clarifications to UsdPreviewSurface (#2100) - Set the shading model version to 2.5, reflecting the alignment of this graph definition with the 2.5 specification for UsdPreviewSurface (https://openusd.org/release/spec_usdpreviewsurface.html). - Add UI names for shading model inputs. - Update doc string letter case. --- libraries/bxdf/usd_preview_surface.mtlx | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index a521c756bc..4abdb91d9f 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -6,21 +6,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + From 4339aaa83480693c1bf4d5b54e1cf614654dd507 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 31 Oct 2024 17:12:44 -0700 Subject: [PATCH 110/137] Improvements to the MaterialX Viewer (#2101) - Replace raw pointers with NanoGUI references to improve application robustness. - Allow UI names to be displayed without a corresponding UI folder. --- source/MaterialXRender/Util.cpp | 2 +- source/MaterialXView/Editor.cpp | 103 ++++++++-------- source/MaterialXView/Editor.h | 20 ++-- source/MaterialXView/Viewer.cpp | 204 +++++++++++++++----------------- source/MaterialXView/Viewer.h | 36 +++--- 5 files changed, 179 insertions(+), 186 deletions(-) diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index 00fdc65381..c206514412 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -318,7 +318,7 @@ void createUIPropertyGroups(DocumentPtr doc, const VariableBlock& block, UIPrope // Prepend a parent label for unlabeled node inputs. ElementPtr parent = pair.first->getParent(); - if (item.ui.uiFolder.empty() && parent && parent->isA()) + if (item.ui.uiName.empty() && parent && parent->isA()) { item.label = parent->getName() + pathSeparator + item.label; } diff --git a/source/MaterialXView/Editor.cpp b/source/MaterialXView/Editor.cpp index abba9ce10e..6d64c55b30 100644 --- a/source/MaterialXView/Editor.cpp +++ b/source/MaterialXView/Editor.cpp @@ -18,11 +18,11 @@ namespace class EditorColorPicker : public ng::ColorPicker { public: - EditorColorPicker(ng::Widget* parent, const ng::Color& color) : + EditorColorPicker(ng::ref parent, const ng::Color& color) : ng::ColorPicker(parent, color) { - ng::Popup* popup = this->popup(); - ng::Widget* floatGroup = new ng::Widget(popup); + ng::ref popup = this->popup(); + ng::ref floatGroup = new ng::Widget(popup); auto layout = new ng::GridLayout(ng::Orientation::Horizontal, 2, ng::Alignment::Middle, 2, 2); layout->set_col_alignment({ ng::Alignment::Fill, ng::Alignment::Fill }); @@ -60,7 +60,7 @@ class EditorColorPicker : public ng::ColorPicker protected: // Additional numeric entry / feedback widgets - ng::FloatBox* _colorWidgets[4]; + ng::ref> _colorWidgets[4]; }; } // anonymous namespace @@ -70,10 +70,6 @@ class EditorColorPicker : public ng::ColorPicker // PropertyEditor::PropertyEditor() : - _window(nullptr), - _container(nullptr), - _gridLayout2(nullptr), - _gridLayout3(nullptr), _visible(false), _fileDialogsForImages(true) { @@ -81,7 +77,7 @@ PropertyEditor::PropertyEditor() : void PropertyEditor::create(Viewer& parent) { - ng::Window* parentWindow = parent.getWindow(); + ng::ref parentWindow = parent.getWindow(); // Remove the window associated with the form. // This is done by explicitly creating and owning the window @@ -110,7 +106,7 @@ void PropertyEditor::create(Viewer& parent) _window->set_position(previousPosition); _window->set_visible(_visible); - ng::VScrollPanel* scroll_panel = new ng::VScrollPanel(_window); + ng::ref scroll_panel = new ng::VScrollPanel(_window); scroll_panel->set_fixed_height(300); _container = new ng::Widget(scroll_panel); _container->set_layout(new ng::GroupLayout(1, 1, 1, 1)); @@ -127,7 +123,7 @@ void PropertyEditor::create(Viewer& parent) } void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable) + ng::ref container, Viewer* viewer, bool editable) { const mx::UIProperties& ui = item.ui; mx::ValuePtr value = item.variable->getValue(); @@ -148,9 +144,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!group.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); - ng::Label* groupLabel = new ng::Label(twoColumns, group); + ng::ref groupLabel = new ng::Label(twoColumns, group); groupLabel->set_font_size(20); groupLabel->set_font("sans-bold"); new ng::Label(twoColumns, ""); @@ -187,11 +183,11 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st const size_t valueIndex = indexInEnumeration(); if (INVALID_INDEX != valueIndex) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(static_cast(valueIndex)); @@ -215,7 +211,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st } else { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -252,9 +248,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Float widget else if (value->isA()) { - ng::Widget* threeColumns = new ng::Widget(container); + ng::ref threeColumns = new ng::Widget(container); threeColumns->set_layout(_gridLayout3); - ng::FloatBox* floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) + ng::ref> floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) { mx::MaterialPtr material = viewer->getSelectedMaterial(); if (material) @@ -269,12 +265,12 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Boolean widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); bool v = value->asA(); new ng::Label(twoColumns, label); - ng::CheckBox* boolVar = new ng::CheckBox(twoColumns, ""); + ng::ref boolVar = new ng::CheckBox(twoColumns, ""); boolVar->set_checked(v); boolVar->set_font_size(15); boolVar->set_callback([path, viewer](bool v) @@ -290,7 +286,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color3 input. Can map to a combo box if an enumeration else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); // Determine if there is an enumeration for this @@ -312,7 +308,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Create a combo box. The items are the enumerations in order. if (index >= 0) { - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(index); @@ -353,7 +349,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -376,7 +372,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 2 widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector2 v = value->asA(); @@ -415,7 +411,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 3 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector3 v = value->asA(); @@ -470,7 +466,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector4 v = value->asA(); @@ -542,16 +538,17 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st std::string v = value->asA(); if (!v.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); if (item.variable->getType() == mx::Type::FILENAME) { new ng::Label(twoColumns, label); - ng::Button* buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); + ng::ref buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); buttonVar->set_enabled(editable); buttonVar->set_font_size(15); - buttonVar->set_callback([buttonVar, path, viewer]() + auto buttonVarPtr = buttonVar.get(); + buttonVar->set_callback([buttonVarPtr, path, viewer]() { mx::MaterialPtr material = viewer->getSelectedMaterial(); mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; @@ -572,7 +569,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!filename.empty()) { uniform->setValue(mx::Value::createValue(filename)); - buttonVar->set_caption(mx::FilePath(filename).getBaseName()); + buttonVarPtr->set_caption(mx::FilePath(filename).getBaseName()); viewer->perform_layout(); } } @@ -583,7 +580,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st else { new ng::Label(twoColumns, label); - ng::TextBox* stringVar = new ng::TextBox(twoColumns, v); + ng::ref stringVar = new ng::TextBox(twoColumns, v); stringVar->set_fixed_size({ 100, 20 }); stringVar->set_font_size(15); stringVar->set_callback([path, viewer](const std::string& v) @@ -629,14 +626,12 @@ void PropertyEditor::updateContents(Viewer* viewer) } if (!shaderName.empty() && shaderName != "surface") { - ng::Widget* twoColumns = new ng::Widget(_container); + ng::ref twoColumns = new ng::Widget(_container); twoColumns->set_layout(_gridLayout2); - ng::Widget* threeColumns = new ng::Widget(_container); - threeColumns->set_layout(_gridLayout3); - ng::Label* modelLabel = new ng::Label(twoColumns, "Shading Model"); + ng::ref modelLabel = new ng::Label(twoColumns, "Shading Model"); modelLabel->set_font_size(20); modelLabel->set_font("sans-bold"); - ng::Label* nameLabel = new ng::Label(twoColumns, shaderName); + ng::ref nameLabel = new ng::Label(twoColumns, shaderName); nameLabel->set_font_size(20); } } @@ -688,15 +683,15 @@ void PropertyEditor::updateContents(Viewer* viewer) viewer->perform_layout(); } -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value(value); - ng::FloatBox* box = new ng::FloatBox(parent, value); + ng::ref> box = new ng::FloatBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -734,29 +729,31 @@ ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& la } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value(value); + boxPtr->set_value(value); callback(value); }); - box->set_callback([slider, callback](float value) + box->set_callback([sliderPtr, callback](float value) { - slider->set_value(value); + sliderPtr->set_value(value); callback(value); }); return box; } -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value((float) value); - ng::IntBox* box = new ng::IntBox(parent, value); + ng::ref> box = new ng::IntBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -794,14 +791,16 @@ ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, i } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value((int) value); + boxPtr->set_value((int) value); callback((int) value); }); - box->set_callback([slider, callback](int value) + box->set_callback([sliderPtr, callback](int value) { - slider->set_value((float) value); + sliderPtr->set_value((float) value); callback(value); }); diff --git a/source/MaterialXView/Editor.h b/source/MaterialXView/Editor.h index b1fb4a3ade..b99f1f160c 100644 --- a/source/MaterialXView/Editor.h +++ b/source/MaterialXView/Editor.h @@ -39,7 +39,7 @@ class PropertyEditor } } - ng::Window* getWindow() + ng::ref getWindow() { return _window; } @@ -47,19 +47,19 @@ class PropertyEditor protected: void create(Viewer& parent); void addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable); + ng::ref container, Viewer* viewer, bool editable); - ng::Window* _window; - ng::Widget* _container; - ng::GridLayout* _gridLayout2; - ng::GridLayout* _gridLayout3; + ng::ref _window; + ng::ref _container; + ng::ref _gridLayout2; + ng::ref _gridLayout3; bool _visible; bool _fileDialogsForImages; }; -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback = nullptr); -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback); +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback = nullptr); +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback); #endif // MATERIALXVIEW_EDITOR_H diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index c4c69bb812..46d03a1665 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -158,7 +158,6 @@ Viewer::Viewer(const std::string& materialFilename, const mx::Color3& screenColor) : ng::Screen(ng::Vector2i(screenWidth, screenHeight), "MaterialXView", true, false, true, true, USE_FLOAT_BUFFER, 4, 0), - _window(nullptr), _materialFilename(materialFilename), _meshFilename(meshFilename), _envRadianceFilename(envRadianceFilename), @@ -184,11 +183,7 @@ Viewer::Viewer(const std::string& materialFilename, _shadowSoftness(1), _ambientOcclusionGain(0.6f), _selectedGeom(0), - _geomLabel(nullptr), - _geometrySelectionBox(nullptr), _selectedMaterial(0), - _materialLabel(nullptr), - _materialSelectionBox(nullptr), _identityCamera(mx::Camera::create()), _viewCamera(mx::Camera::create()), _envCamera(mx::Camera::create()), @@ -232,9 +227,6 @@ Viewer::Viewer(const std::string& materialFilename, _bakeHeight(0), _bakeDocumentPerMaterial(false), _frameTiming(false), - _timingLabel(nullptr), - _timingPanel(nullptr), - _timingText(nullptr), _avgFrameTime(0.0) { // Resolve input filenames, taking both the provided search path and @@ -295,11 +287,11 @@ void Viewer::initialize() _imageHandler->setSearchPath(_searchPath); // Initialize user interfaces. - createLoadMeshInterface(_window, "Load Mesh"); - createLoadMaterialsInterface(_window, "Load Material"); - createLoadEnvironmentInterface(_window, "Load Environment"); - createPropertyEditorInterface(_window, "Property Editor"); - createAdvancedSettings(_window); + createLoadMeshInterface((ng::ref) _window, "Load Mesh"); + createLoadMaterialsInterface((ng::ref) _window, "Load Material"); + createLoadEnvironmentInterface((ng::ref) _window, "Load Environment"); + createPropertyEditorInterface((ng::ref) _window, "Property Editor"); + createAdvancedSettings((ng::ref) _window); // Create geometry selection box. _geomLabel = new ng::Label(_window, "Select Geometry"); @@ -562,9 +554,9 @@ mx::ElementPredicate Viewer::getElementPredicate() }; } -void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMeshInterface(ng::ref parent, const std::string& label) { - ng::Button* meshButton = new ng::Button(parent, label); + ng::ref meshButton = new ng::Button(parent, label); meshButton->set_icon(FA_FOLDER); meshButton->set_tooltip("Load a new geometry in the OBJ or glTF format."); meshButton->set_callback([this]() @@ -590,9 +582,9 @@ void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) }); } -void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_FOLDER); materialButton->set_tooltip("Load a material document in the MTLX format."); materialButton->set_callback([this]() @@ -608,9 +600,9 @@ void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& label) +void Viewer::createLoadEnvironmentInterface(ng::ref parent, const std::string& label) { - ng::Button* envButton = new ng::Button(parent, label); + ng::ref envButton = new ng::Button(parent, label); envButton->set_icon(FA_FOLDER); envButton->set_tooltip("Load a lat-long environment light in the HDR format."); envButton->set_callback([this]() @@ -634,9 +626,9 @@ void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& l }); } -void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createSaveMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_SAVE); materialButton->set_tooltip("Save a material document in the MTLX format."); materialButton->set_callback([this]() @@ -664,9 +656,9 @@ void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& label) +void Viewer::createPropertyEditorInterface(ng::ref parent, const std::string& label) { - ng::Button* editorButton = new ng::Button(parent, label); + ng::ref editorButton = new ng::Button(parent, label); editorButton->set_flags(ng::Button::ToggleButton); editorButton->set_tooltip("View or edit properties of the current material."); editorButton->set_change_callback([this](bool state) @@ -676,40 +668,38 @@ void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& la }); } -void Viewer::createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel) +void Viewer::createDocumentationInterface(ng::ref parent) { - ng::GridLayout* documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, - ng::Alignment::Minimum, 13, 5); + ng::ref documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, + ng::Alignment::Minimum, 13, 5); documentationLayout->set_row_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); - ng::Widget* documentationGroup = new ng::Widget(parent); + ng::ref documentationGroup = new ng::Widget(parent); documentationGroup->set_layout(documentationLayout); - ng::Label* documentationLabel = new ng::Label(documentationGroup, "Documentation"); + ng::ref documentationLabel = new ng::Label(documentationGroup, "Documentation"); documentationLabel->set_font_size(20); documentationLabel->set_font("sans-bold"); - ng::Button* shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); - shortcutsButton->set_flags(ng::Button::ToggleButton); - shortcutsButton->set_icon(FA_CARET_RIGHT); - shortcutsButton->set_fixed_width(230); + _shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); + _shortcutsButton->set_flags(ng::Button::ToggleButton); + _shortcutsButton->set_icon(FA_CARET_RIGHT); + _shortcutsButton->set_fixed_width(230); - ng::Widget* shortcutsTable = new ng::Widget(documentationGroup); - shortcutsTable->set_layout(new ng::GroupLayout(13)); - shortcutsTable->set_visible(false); + _shortcutsTable = new ng::Widget(documentationGroup); + _shortcutsTable->set_layout(new ng::GroupLayout(13)); + _shortcutsTable->set_visible(false); - // recompute layout when showing/hiding shortcuts. - shortcutsButton->set_change_callback([this, scrollPanel, shortcutsButton, - shortcutsTable](bool state) + // Recompute layout when showing/hiding shortcuts. + _shortcutsButton->set_change_callback([this](bool state) { - shortcutsTable->set_visible(state); - shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); - scrollPanel->set_scroll(state ? 0.73f : 1.0f); + _shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); + _shortcutsTable->set_visible(state); perform_layout(); }); // 2 cell layout for (key, description) pair. - ng::GridLayout* gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, - ng::Alignment::Minimum, 2, 2); + ng::ref gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, + ng::Alignment::Minimum, 2, 2); gridLayout2->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); const std::vector> KEYBOARD_SHORTCUTS = @@ -741,73 +731,73 @@ void Viewer::createDocumentationInterface(Widget* parent, ng::VScrollPanel* scro for (const auto& shortcut : KEYBOARD_SHORTCUTS) { - ng::Widget* twoColumns = new ng::Widget(shortcutsTable); + ng::ref twoColumns = new ng::Widget(_shortcutsTable); twoColumns->set_layout(gridLayout2); - ng::Label* keyLabel = new ng::Label(twoColumns, shortcut.first); + ng::ref keyLabel = new ng::Label(twoColumns, shortcut.first); keyLabel->set_font("sans-bold"); keyLabel->set_font_size(16); keyLabel->set_fixed_width(40); - ng::Label* descriptionLabel = new ng::Label(twoColumns, shortcut.second); + ng::ref descriptionLabel = new ng::Label(twoColumns, shortcut.second); descriptionLabel->set_font_size(16); descriptionLabel->set_fixed_width(160); } } -void Viewer::createAdvancedSettings(Widget* parent) +void Viewer::createAdvancedSettings(ng::ref parent) { - ng::PopupButton* advancedButton = new ng::PopupButton(parent, "Advanced Settings"); + ng::ref advancedButton = new ng::PopupButton(parent, "Advanced Settings"); advancedButton->set_icon(FA_TOOLS); advancedButton->set_chevron_icon(-1); advancedButton->set_tooltip("Asset and rendering options."); - ng::Popup* advancedPopupParent = advancedButton->popup(); + ng::ref advancedPopupParent = advancedButton->popup(); advancedPopupParent->set_layout(new ng::GroupLayout()); - ng::VScrollPanel* scrollPanel = new ng::VScrollPanel(advancedPopupParent); + ng::ref scrollPanel = new ng::VScrollPanel(advancedPopupParent); scrollPanel->set_fixed_height(500); - ng::Widget* advancedPopup = new ng::Widget(scrollPanel); + ng::ref advancedPopup = new ng::Widget(scrollPanel); advancedPopup->set_layout(new ng::BoxLayout(ng::Orientation::Vertical)); - ng::Widget* settingsGroup = new ng::Widget(advancedPopup); + ng::ref settingsGroup = new ng::Widget(advancedPopup); settingsGroup->set_layout(new ng::GroupLayout(13)); - ng::Label* viewLabel = new ng::Label(settingsGroup, "Viewing Options"); + ng::ref viewLabel = new ng::Label(settingsGroup, "Viewing Options"); viewLabel->set_font_size(20); viewLabel->set_font("sans-bold"); - ng::CheckBox* drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); + ng::ref drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); drawEnvironmentBox->set_checked(_drawEnvironment); drawEnvironmentBox->set_callback([this](bool enable) { _drawEnvironment = enable; }); - ng::CheckBox* outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); + ng::ref outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); outlineSelectedGeometryBox->set_checked(_outlineSelection); outlineSelectedGeometryBox->set_callback([this](bool enable) { _outlineSelection = enable; }); - ng::Label* renderLabel = new ng::Label(settingsGroup, "Render Options"); + ng::ref renderLabel = new ng::Label(settingsGroup, "Render Options"); renderLabel->set_font_size(20); renderLabel->set_font("sans-bold"); - ng::CheckBox* transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); + ng::ref transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); transparencyBox->set_checked(_renderTransparency); transparencyBox->set_callback([this](bool enable) { _renderTransparency = enable; }); - ng::CheckBox* doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); + ng::ref doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); doubleSidedBox->set_checked(_renderDoubleSided); doubleSidedBox->set_callback([this](bool enable) { _renderDoubleSided = enable; }); - ng::CheckBox* importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); + ng::ref importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); importanceSampleBox->set_checked(_genContext.getOptions().hwSpecularEnvironmentMethod == mx::SPECULAR_ENVIRONMENT_FIS); _lightHandler->setUsePrefilteredMap(_genContext.getOptions().hwSpecularEnvironmentMethod != mx::SPECULAR_ENVIRONMENT_FIS); importanceSampleBox->set_callback([this](bool enable) @@ -820,7 +810,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); + ng::ref refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); refractionBox->set_checked(_genContext.getOptions().hwTransmissionRenderMethod == mx::TRANSMISSION_REFRACTION); refractionBox->set_callback([this](bool enable) { @@ -831,14 +821,14 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); + ng::ref refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); refractionSidedBox->set_checked(_lightHandler->getRefractionTwoSided()); refractionSidedBox->set_callback([this](bool enable) { _lightHandler->setRefractionTwoSided(enable); }); - ng::CheckBox* shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); + ng::ref shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); shaderInterfaceBox->set_checked(_genContext.getOptions().shaderInterfaceType == mx::SHADER_INTERFACE_REDUCED); shaderInterfaceBox->set_callback([this](bool enable) { @@ -846,11 +836,11 @@ void Viewer::createAdvancedSettings(Widget* parent) setShaderInterfaceType(interfaceType); }); - Widget* albedoGroup = new Widget(settingsGroup); + ng::ref albedoGroup = new Widget(settingsGroup); albedoGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(albedoGroup, "Albedo Method:"); mx::StringVec albedoOptions = { "Analytic", "Table", "MC" }; - ng::ComboBox* albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); + ng::ref albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); albedoBox->set_chevron_icon(-1); albedoBox->set_selected_index((int) _genContext.getOptions().hwDirectionalAlbedoMethod ); albedoBox->set_callback([this](int index) @@ -877,7 +867,7 @@ void Viewer::createAdvancedSettings(Widget* parent) } }); - Widget* sampleGroup = new Widget(settingsGroup); + ng::ref sampleGroup = new Widget(settingsGroup); sampleGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(sampleGroup, "Environment Samples:"); mx::StringVec sampleOptions; @@ -887,7 +877,7 @@ void Viewer::createAdvancedSettings(Widget* parent) sampleOptions.push_back(std::to_string(i)); m_process_events = true; } - ng::ComboBox* sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); + ng::ref sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); sampleBox->set_chevron_icon(-1); sampleBox->set_selected_index((int)std::log2(_lightHandler->getEnvSampleCount() / MIN_ENV_SAMPLE_COUNT) / 2); sampleBox->set_callback([this](int index) @@ -895,30 +885,30 @@ void Viewer::createAdvancedSettings(Widget* parent) _lightHandler->setEnvSampleCount(MIN_ENV_SAMPLE_COUNT * (int) std::pow(4, index)); }); - ng::Label* lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); + ng::ref lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); lightingLabel->set_font_size(20); lightingLabel->set_font("sans-bold"); - ng::CheckBox* directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); + ng::ref directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); directLightingBox->set_checked(_lightHandler->getDirectLighting()); directLightingBox->set_callback([this](bool enable) { _lightHandler->setDirectLighting(enable); }); - ng::CheckBox* indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); + ng::ref indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); indirectLightingBox->set_checked(_lightHandler->getIndirectLighting()); indirectLightingBox->set_callback([this](bool enable) { _lightHandler->setIndirectLighting(enable); }); - ng::Widget* lightRotationRow = new ng::Widget(settingsGroup); + ng::ref lightRotationRow = new ng::Widget(settingsGroup); lightRotationRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties ui; ui.uiMin = mx::Value::createValue(0.0f); ui.uiMax = mx::Value::createValue(360.0f); - ng::FloatBox* lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", + ng::ref> lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", _lightRotation, &ui, [this](float value) { _lightRotation = value; @@ -926,11 +916,11 @@ void Viewer::createAdvancedSettings(Widget* parent) }); lightRotationBox->set_editable(true); - ng::Label* shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); + ng::ref shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); shadowingLabel->set_font_size(20); shadowingLabel->set_font("sans-bold"); - ng::CheckBox* shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); + ng::ref shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); shadowMapBox->set_checked(_genContext.getOptions().hwShadowMap); shadowMapBox->set_callback([this](bool enable) { @@ -938,7 +928,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); + ng::ref ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); ambientOcclusionBox->set_checked(_genContext.getOptions().hwAmbientOcclusion); ambientOcclusionBox->set_callback([this](bool enable) { @@ -946,23 +936,23 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::Widget* ambientOcclusionGainRow = new ng::Widget(settingsGroup); + ng::ref ambientOcclusionGainRow = new ng::Widget(settingsGroup); ambientOcclusionGainRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", + ng::ref> ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", _ambientOcclusionGain, nullptr, [this](float value) { _ambientOcclusionGain = value; }); ambientOcclusionGainBox->set_editable(true); - ng::Label* sceneLabel = new ng::Label(settingsGroup, "Scene Options"); + ng::ref sceneLabel = new ng::Label(settingsGroup, "Scene Options"); sceneLabel->set_font_size(20); sceneLabel->set_font("sans-bold"); - Widget* unitGroup = new Widget(settingsGroup); + ng::ref unitGroup = new Widget(settingsGroup); unitGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(unitGroup, "Distance Unit:"); - ng::ComboBox* distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); + ng::ref distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); distanceUnitBox->set_fixed_size(ng::Vector2i(100, 20)); distanceUnitBox->set_chevron_icon(-1); if (_distanceUnitConverter) @@ -986,68 +976,68 @@ void Viewer::createAdvancedSettings(Widget* parent) m_process_events = true; }); - ng::Label* meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); + ng::ref meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); meshLoading->set_font_size(20); meshLoading->set_font("sans-bold"); - ng::CheckBox* splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); + ng::ref splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); splitUdimsBox->set_checked(_splitByUdims); splitUdimsBox->set_callback([this](bool enable) { _splitByUdims = enable; }); - ng::Label* materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); + ng::ref materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); materialLoading->set_font_size(20); materialLoading->set_font("sans-bold"); - ng::CheckBox* mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); + ng::ref mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); mergeMaterialsBox->set_checked(_mergeMaterials); mergeMaterialsBox->set_callback([this](bool enable) { _mergeMaterials = enable; }); - ng::CheckBox* showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); + ng::ref showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); showInputsBox->set_checked(_showAllInputs); showInputsBox->set_callback([this](bool enable) { _showAllInputs = enable; }); - ng::CheckBox* flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); + ng::ref flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); flattenBox->set_checked(_flattenSubgraphs); flattenBox->set_callback([this](bool enable) { _flattenSubgraphs = enable; }); - ng::Label* envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); + ng::ref envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); envLoading->set_font_size(20); envLoading->set_font("sans-bold"); - ng::CheckBox* normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); + ng::ref normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); normalizeEnvBox->set_checked(_normalizeEnvironment); normalizeEnvBox->set_callback([this](bool enable) { _normalizeEnvironment = enable; }); - ng::CheckBox* splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); + ng::ref splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); splitDirectLightBox->set_checked(_splitDirectLight); splitDirectLightBox->set_callback([this](bool enable) { _splitDirectLight = enable; }); - ng::Label* translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); + ng::ref translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); translationLabel->set_font_size(20); translationLabel->set_font("sans-bold"); - ng::Widget* targetShaderGroup = new ng::Widget(settingsGroup); + ng::ref targetShaderGroup = new ng::Widget(settingsGroup); targetShaderGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(targetShaderGroup, "Target Shader"); - ng::TextBox* targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); + ng::ref targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); targetShaderBox->set_callback([this](const std::string& choice) { _targetShader = choice; @@ -1056,46 +1046,46 @@ void Viewer::createAdvancedSettings(Widget* parent) targetShaderBox->set_font_size(16); targetShaderBox->set_editable(true); - ng::Label* textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); + ng::ref textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); textureLabel->set_font_size(20); textureLabel->set_font("sans-bold"); - ng::CheckBox* bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); + ng::ref bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); bakeHdrBox->set_checked(_bakeHdr); bakeHdrBox->set_callback([this](bool enable) { _bakeHdr = enable; }); - ng::CheckBox* bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); + ng::ref bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); bakeAverageBox->set_checked(_bakeAverage); bakeAverageBox->set_callback([this](bool enable) { _bakeAverage = enable; }); - ng::CheckBox* bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); + ng::ref bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); bakeOptimized->set_checked(_bakeOptimize); bakeOptimized->set_callback([this](bool enable) { _bakeOptimize = enable; }); - ng::CheckBox* bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); + ng::ref bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); bakeDocumentPerMaterial->set_checked(_bakeDocumentPerMaterial); bakeDocumentPerMaterial->set_callback([this](bool enable) { _bakeDocumentPerMaterial = enable; }); - ng::Label* wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); + ng::ref wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); wedgeLabel->set_font_size(20); wedgeLabel->set_font("sans-bold"); - ng::Widget* wedgeNameGroup = new ng::Widget(settingsGroup); + ng::ref wedgeNameGroup = new ng::Widget(settingsGroup); wedgeNameGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(wedgeNameGroup, "Property Name"); - ng::TextBox* wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); + ng::ref wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); wedgeNameBox->set_callback([this](const std::string& choice) { _wedgePropertyName = choice; @@ -1104,12 +1094,12 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeNameBox->set_font_size(16); wedgeNameBox->set_editable(true); - ng::Widget* wedgeMinGroup = new ng::Widget(settingsGroup); + ng::ref wedgeMinGroup = new ng::Widget(settingsGroup); wedgeMinGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeProp; wedgeProp.uiSoftMin = mx::Value::createValue(0.0f); wedgeProp.uiSoftMax = mx::Value::createValue(1.0f); - ng::FloatBox* wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", + ng::ref> wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMin = value; @@ -1117,9 +1107,9 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMinBox->set_value(0.0); wedgeMinBox->set_editable(true); - ng::Widget* wedgeMaxGroup = new ng::Widget(settingsGroup); + ng::ref wedgeMaxGroup = new ng::Widget(settingsGroup); wedgeMaxGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", + ng::ref> wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMax = value; @@ -1127,13 +1117,13 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMaxBox->set_value(1.0); wedgeMaxBox->set_editable(true); - ng::Widget* wedgeCountGroup = new ng::Widget(settingsGroup); + ng::ref wedgeCountGroup = new ng::Widget(settingsGroup); wedgeCountGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeCountProp; wedgeCountProp.uiMin = mx::Value::createValue(1); wedgeCountProp.uiSoftMax = mx::Value::createValue(8); wedgeCountProp.uiStep = mx::Value::createValue(1); - ng::IntBox* wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", + ng::ref> wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", _wedgeImageCount, &wedgeCountProp, [this](int value) { _wedgeImageCount = value; @@ -1141,7 +1131,7 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeCountBox->set_value(8); wedgeCountBox->set_editable(true); - createDocumentationInterface(advancedPopup, scrollPanel); + createDocumentationInterface(advancedPopup); } void Viewer::updateGeometrySelections() @@ -2441,7 +2431,7 @@ void Viewer::updateCameras() void Viewer::updateDisplayedProperties() { _propertyEditor.updateContents(this); - createSaveMaterialsInterface(_propertyEditor.getWindow(), "Save Material"); + createSaveMaterialsInterface((ng::ref) _propertyEditor.getWindow(), "Save Material"); perform_layout(); } diff --git a/source/MaterialXView/Viewer.h b/source/MaterialXView/Viewer.h index 08712f3c78..8f0257e1e1 100644 --- a/source/MaterialXView/Viewer.h +++ b/source/MaterialXView/Viewer.h @@ -179,7 +179,7 @@ class Viewer : public ng::Screen } // Return the underlying NanoGUI window. - ng::Window* getWindow() const + ng::ref getWindow() const { return _window; } @@ -283,13 +283,13 @@ class Viewer : public ng::Screen void updateMaterialSelectionUI(); void updateDisplayedProperties(); - void createLoadMeshInterface(Widget* parent, const std::string& label); - void createLoadMaterialsInterface(Widget* parent, const std::string& label); - void createLoadEnvironmentInterface(Widget* parent, const std::string& label); - void createSaveMaterialsInterface(Widget* parent, const std::string& label); - void createPropertyEditorInterface(Widget* parent, const std::string& label); - void createAdvancedSettings(Widget* parent); - void createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel); + void createLoadMeshInterface(ng::ref parent, const std::string& label); + void createLoadMaterialsInterface(ng::ref parent, const std::string& label); + void createLoadEnvironmentInterface(ng::ref parent, const std::string& label); + void createSaveMaterialsInterface(ng::ref parent, const std::string& label); + void createPropertyEditorInterface(ng::ref parent, const std::string& label); + void createAdvancedSettings(ng::ref parent); + void createDocumentationInterface(ng::ref parent); // Return the ambient occlusion image, if any, associated with the given material. mx::ImagePtr getAmbientOcclusionImage(mx::MaterialPtr material); @@ -318,7 +318,7 @@ class Viewer : public ng::Screen void setShaderInterfaceType(mx::ShaderInterfaceType interfaceType); private: - ng::Window* _window; + ng::ref _window; RenderPipelinePtr _renderPipeline; mx::FilePath _materialFilename; @@ -380,15 +380,15 @@ class Viewer : public ng::Screen // Geometry selections std::vector _geometryList; size_t _selectedGeom; - ng::Label* _geomLabel; - ng::ComboBox* _geometrySelectionBox; + ng::ref _geomLabel; + ng::ref _geometrySelectionBox; // Material selections std::vector _materials; mx::MaterialPtr _wireMaterial; size_t _selectedMaterial; - ng::Label* _materialLabel; - ng::ComboBox* _materialSelectionBox; + ng::ref _materialLabel; + ng::ref _materialSelectionBox; PropertyEditor _propertyEditor; // Material assignments @@ -475,11 +475,15 @@ class Viewer : public ng::Screen // Frame timing bool _frameTiming; - ng::Label* _timingLabel; - ng::Widget* _timingPanel; - ng::TextBox* _timingText; + ng::ref _timingLabel; + ng::ref _timingPanel; + ng::ref _timingText; mx::ScopedTimer _frameTimer; double _avgFrameTime; + + // Documentation UI + ng::ref _shortcutsButton; + ng::ref _shortcutsTable; }; extern const mx::Vector3 DEFAULT_CAMERA_POSITION; From bef88b9f528cff361ecfcd2c52afb3359836aeb7 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 2 Nov 2024 14:59:16 -0700 Subject: [PATCH 111/137] Extend Chiang tests across languages (#2104) This changelist extends testing of Chiang Hair BSDF nodes across shading languages, allowing render comparisons to include the complete Examples and TestSuite folders. In order to avoid shader compilation errors, placeholder OSL implementations of these nodes have been added, and these should be replaced with accurate implementations once they are supported. --- libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl | 7 +++++++ libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx | 12 ++++++++++++ .../bsdf/{hair_bsdf.mtlx => chiang_hair_bsdf.mtlx} | 0 ...aceshader.mtlx => chiang_hair_surfaceshader.mtlx} | 0 source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp | 7 +------ source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 2 -- source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 6 +----- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 2 -- 8 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl rename resources/Materials/TestSuite/pbrlib/bsdf/{hair_bsdf.mtlx => chiang_hair_bsdf.mtlx} (100%) rename resources/Materials/TestSuite/pbrlib/surfaceshader/{hair_surfaceshader.mtlx => chiang_hair_surfaceshader.mtlx} (100%) diff --git a/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl new file mode 100644 index 0000000000..002bdc3044 --- /dev/null +++ b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl @@ -0,0 +1,7 @@ +void mx_chiang_hair_roughness(float longitudinal, float azimuthal, float scale_TT, float scale_TRT, output vector2 roughness_R, output vector2 roughness_TT, output vector2 roughness_TRT) +{ + // TODO: Write OSL implementation of this node. + roughness_R = vector2(0.0, 0.0); + roughness_TT = vector2(0.0, 0.0); + roughness_TRT = vector2(0.0, 0.0); +} diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx index d3849a5ddb..beac984518 100644 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx +++ b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx @@ -22,6 +22,9 @@ + + + @@ -71,4 +74,13 @@ + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx similarity index 100% rename from resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx rename to resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx similarity index 100% rename from resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx rename to resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp index 414bc3dd5d..b0309ea44d 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp @@ -84,12 +84,7 @@ TEST_CASE("GenShader: MSL Implementation Check", "[genmsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); - generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); - generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); - generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 34); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 30); } TEST_CASE("GenShader: MSL Unique Names", "[genmsl]") diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h index 692c283fda..7c96279d8b 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h @@ -43,8 +43,6 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester void addSkipFiles() override { - _skipFiles.insert("hair_bsdf.mtlx"); - _skipFiles.insert("hair_surfaceshader.mtlx"); } void setupDependentLibraries() override diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp index c89f9ab19d..612d134753 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp @@ -89,12 +89,8 @@ TEST_CASE("GenShader: OSL Implementation Check", "[genosl]") generatorSkipNodeTypes.insert("light"); mx::StringSet generatorSkipNodeDefs; - generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); - generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); - generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); - generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 35); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31); } TEST_CASE("GenShader: OSL Unique Names", "[genosl]") diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h index f02f750d26..959c12d48b 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h @@ -45,8 +45,6 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester void addSkipFiles() override { - _skipFiles.insert("hair_bsdf.mtlx"); - _skipFiles.insert("hair_surfaceshader.mtlx"); } // Ignore light shaders in the document for OSL From 20383ae3e721d93b6dce981b09475c4e2e524989 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 13 Nov 2024 17:05:33 -0800 Subject: [PATCH 112/137] Update deprecated Xcode in CI (#2114) This changelist updates a deprecated version of Xcode in our GitHub CI. --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c11603dd70..b2d5f182bf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,10 +68,10 @@ jobs: cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON python: 3.9 - - name: MacOS_Xcode_14_Python311 + - name: MacOS_Xcode_15_Python311 os: macos-14 compiler: xcode - compiler_version: "14.3" + compiler_version: "15.1" python: 3.11 static_analysis: ON cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON From 65dbd3937db8093011b825e9e5bf0b9ae9757abf Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Thu, 14 Nov 2024 10:31:09 -0500 Subject: [PATCH 113/137] Skip comments in functional equivalence tests (#2110) Skip `comment` blocks when checking for functional equivalency as they should not affect the comparison. --- source/MaterialXCore/Element.cpp | 22 ++++++++++++++++--- .../MaterialXTest/MaterialXCore/Document.cpp | 8 +++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 648d7df000..043d6f4092 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -426,9 +426,25 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& } } - // Compare children. - const vector& children = getChildren(); - const vector& rhsChildren = rhs->getChildren(); + // Compare all child elements that affect functional equivalence. + vector children; + for (ElementPtr child : getChildren()) + { + if (child->getCategory() == CommentElement::CATEGORY) + { + continue; + } + children.push_back(child); + } + vector rhsChildren; + for (ElementPtr child : rhs->getChildren()) + { + if (child->getCategory() == CommentElement::CATEGORY) + { + continue; + } + rhsChildren.push_back(child); + } if (children.size() != rhsChildren.size()) { if (results) diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index ae7623084e..f3a207fc84 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -150,6 +150,9 @@ TEST_CASE("Document equivalence", "[document]") unsigned int index = 0; mx::ElementPtr child = doc->addNodeGraph("mygraph"); mx::NodeGraphPtr graph = child->asA(); + // Add comment block at the start of the first doc to check skipping + mx::ElementPtr comment = doc->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 1"); for (auto it = inputMap.begin(); it != inputMap.end(); ++it) { const std::string inputType = (*it).first; @@ -205,6 +208,11 @@ TEST_CASE("Document equivalence", "[document]") input->setName("input_" + inputType); } } + // Add comment blocks at end of second doc to check value and count checks + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 2"); + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 3"); mx::ElementEquivalenceOptions options; mx::ElementEquivalenceResultVec results; From a368aac8ccc4f8cf7a9d1d5189826b040eced893 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Sat, 16 Nov 2024 18:27:38 -0500 Subject: [PATCH 114/137] Cleanup options for equivalence testing (#2115) User facing naming changes for the functional equivalence API. There are no logic changes. --- source/MaterialXCore/Element.cpp | 12 +++--- source/MaterialXCore/Element.h | 37 +++++++++---------- .../MaterialXTest/MaterialXCore/Document.cpp | 12 +++--- .../PyMaterialX/PyMaterialXCore/PyElement.cpp | 8 ++-- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 043d6f4092..3bede2fe74 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -396,14 +396,14 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& StringVec rhsAttributeNames = rhs->getAttributeNames(); // Filter out any attributes specified in the options. - const StringSet& skipAttributes = options.skipAttributes; - if (!skipAttributes.empty()) + const StringSet& attributeExclusionList = options.attributeExclusionList; + if (!attributeExclusionList.empty()) { attributeNames.erase(std::remove_if(attributeNames.begin(), attributeNames.end(), - [&skipAttributes](const string& attr) { return skipAttributes.find(attr) != skipAttributes.end(); }), + [&attributeExclusionList](const string& attr) { return attributeExclusionList.find(attr) != attributeExclusionList.end(); }), attributeNames.end()); rhsAttributeNames.erase(std::remove_if(rhsAttributeNames.begin(), rhsAttributeNames.end(), - [&skipAttributes](const string& attr) { return skipAttributes.find(attr) != skipAttributes.end(); }), + [&attributeExclusionList](const string& attr) { return attributeExclusionList.find(attr) != attributeExclusionList.end(); }), rhsAttributeNames.end()); } @@ -714,7 +714,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr { // Perform value comparisons bool performedValueComparison = false; - if (!options.skipValueComparisons) + if (options.performValueComparisons) { const StringSet uiAttributes = { @@ -724,7 +724,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr }; // Get precision and format options - ScopedFloatFormatting fmt(options.format, options.precision); + ScopedFloatFormatting fmt(options.floatFormat, options.floatPrecision); ConstValueElementPtr rhsValueElement = rhs->asA(); diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index fb4bbe07ce..05eb2235f3 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -1389,34 +1389,33 @@ class MX_CORE_API ElementEquivalenceOptions public: ElementEquivalenceOptions() { - format = Value::getFloatFormat(); - precision = Value::getFloatPrecision(); - skipAttributes = {}; - skipValueComparisons = false; + performValueComparisons = true; + floatFormat = Value::getFloatFormat(); + floatPrecision = Value::getFloatPrecision(); + attributeExclusionList = {}; }; ~ElementEquivalenceOptions() { } - /// Floating point format option for floating point value comparisons - Value::FloatFormat format; + /// Perform value comparisons as opposed to literal string comparisons. + /// Default is true. + bool performValueComparisons; - /// Floating point precision option for floating point value comparisons - int precision; + /// Floating point format to use for floating point value comparisons + Value::FloatFormat floatFormat; - /// Attribute filtering options. By default all attributes are considered. - /// Name, category attributes cannot be skipped. + /// Floating point precision to use for floating point value comparisons + int floatPrecision; + + /// Specifies the set of attributes that should be excluded when performing a comparison. + /// By default all attributes are considered. Name and category attributes cannot be excluded. /// - /// For example UI attribute comparision be skipped by setting: - /// skipAttributes = { + /// For example, to exclude UI and documentation attributes from consideration the follow may be set: + /// attributeExclusionList = { /// ValueElement::UI_MIN_ATTRIBUTE, ValueElement::UI_MAX_ATTRIBUTE, /// ValueElement::UI_SOFT_MIN_ATTRIBUTE, ValueElement::UI_SOFT_MAX_ATTRIBUTE, /// ValueElement::UI_STEP_ATTRIBUTE, Element::XPOS_ATTRIBUTE, - /// Element::YPOS_ATTRIBUTE }; - StringSet skipAttributes; - - /// Do not perform any value comparisions. Instead perform exact string comparisons for attributes - /// Default is false. The operator==() method can be used instead as it always performs - /// a strict comparison. Default is false. - bool skipValueComparisons; + /// Element::YPOS_ATTRIBUTE, Element::DOC_ATTRIBUTE }; + StringSet attributeExclusionList; }; /// @class ExceptionOrphanedElement diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index f3a207fc84..b593969ccb 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -217,27 +217,27 @@ TEST_CASE("Document equivalence", "[document]") mx::ElementEquivalenceOptions options; mx::ElementEquivalenceResultVec results; - // Check skipping all value compares - options.skipValueComparisons = true; + // Check that this fails when not performing value comparisons + options.performValueComparisons = false; bool equivalent = doc->isEquivalent(doc2, options, &results); REQUIRE(!equivalent); // Check attibute values - options.skipValueComparisons = false; + options.performValueComparisons = true; results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); REQUIRE(equivalent); unsigned int currentPrecision = mx::Value::getFloatPrecision(); // This will compare 0.012345608 versus: 1, 0.012345611 for input10 - options.precision = 8; + options.floatPrecision = 8; equivalent = doc->isEquivalent(doc2, options); REQUIRE(!equivalent); - options.precision = currentPrecision; + options.floatPrecision = currentPrecision; // Check attribute filtering of inputs results.clear(); - options.skipAttributes = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; + options.attributeExclusionList = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; for (mx::InputPtr floatInput : floatInputs) { floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, "0.9"); diff --git a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp index cb70d04704..004fa0a670 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp @@ -224,10 +224,10 @@ void bindPyElement(py::module& mod) .def_readwrite("attributeName", &mx::ElementEquivalenceResult::attributeName); py::class_(mod, "ElementEquivalenceOptions") - .def_readwrite("format", &mx::ElementEquivalenceOptions::format) - .def_readwrite("precision", &mx::ElementEquivalenceOptions::precision) - .def_readwrite("skipAttributes", &mx::ElementEquivalenceOptions::skipAttributes) - .def_readwrite("skipValueComparisons", &mx::ElementEquivalenceOptions::skipValueComparisons) + .def_readwrite("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) + .def_readwrite("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) + .def_readwrite("floatPrecision", &mx::ElementEquivalenceOptions::floatPrecision) + .def_readwrite("attributeExclusionList", &mx::ElementEquivalenceOptions::attributeExclusionList) .def(py::init<>()); py::class_(mod, "StringResolver") From a3a7744f3e7a290b4d029ea60452f4bab8a9496f Mon Sep 17 00:00:00 2001 From: krohmerNV <42233792+krohmerNV@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:48:00 +0100 Subject: [PATCH 115/137] MDL 1.9 updates (#2102) add new version to GenMDL and remove uniform restriction from material IOR Minor updates: - improve MDL printing by adding named parameters - handle 1-element mixes (basically scale) above layers - improve blur and height to normal to return something meaningful (before totally broken) - improve non-material outputs that can be rendered, e.g. float3x3 and float4x4 - preparations for MDL 1.10 - remove shader parameters from the public MDL material interface. backsurfaceshader and displacementshader showed up with default values only after recent upstream changes --- .../pbrlib/genmdl/pbrlib_genmdl_impl.mtlx | 6 +- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 2 +- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 89 +++- source/MaterialXGenMdl/MdlShaderGenerator.h | 9 +- .../Nodes/ClosureLayerNodeMdl.cpp | 45 ++ .../Nodes/ClosureLayerNodeMdl.h | 7 + .../MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp | 13 +- .../MaterialXGenMdl/mdl/materialx/pbrlib.mdl | 10 +- .../mdl/materialx/pbrlib_1_6.mdl | 34 +- .../mdl/materialx/pbrlib_1_9.mdl | 372 +++++++++++++++++ .../mdl/materialx/sampling.mdl | 19 +- .../MaterialXGenMdl/mdl/materialx/stdlib.mdl | 10 +- .../mdl/materialx/stdlib_1_9.mdl | 387 ++++++++++++++++++ .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 22 +- 14 files changed, 961 insertions(+), 64 deletions(-) create mode 100644 source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl create mode 100644 source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index c8f23958ae..45f83f164a 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -2,7 +2,7 @@ - + @@ -11,13 +11,13 @@ - + - + diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index 51566463aa..b190937c41 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -695,7 +695,7 @@ - + diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index 76cd7587fd..71db0d7cf4 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -52,9 +52,11 @@ const string IMPORT_ALL = " import *"; const string MDL_VERSION_1_6 = "1.6"; const string MDL_VERSION_1_7 = "1.7"; const string MDL_VERSION_1_8 = "1.8"; +const string MDL_VERSION_1_9 = "1.9"; const string MDL_VERSION_SUFFIX_1_6 = "1_6"; const string MDL_VERSION_SUFFIX_1_7 = "1_7"; const string MDL_VERSION_SUFFIX_1_8 = "1_8"; +const string MDL_VERSION_SUFFIX_1_9 = "1_9"; } // anonymous namespace @@ -191,6 +193,27 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G emitLineBreak(stage); } + // Emit shader inputs that have been filtered during printing of the public interface + const string uniformPrefix = _syntax->getUniformQualifier() + " "; + for (ShaderGraphInputSocket* inputSocket : graph.getInputSockets()) + { + if (inputSocket->getConnections().size() && + (inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL)) + { + const string& qualifier = inputSocket->isUniform() || inputSocket->getType() == Type::FILENAME + ? uniformPrefix + : EMPTY_STRING; + const string& type = _syntax->getTypeName(inputSocket->getType()); + + emitLineBegin(stage); + emitString(qualifier + type + " " + inputSocket->getVariable() + " = ", stage); + emitString(_syntax->getDefaultValue(inputSocket->getType(), true), stage); + emitLineEnd(stage, true); + } + } + // Emit all texturing nodes. These are inputs to any // closure/shader nodes and need to be emitted first. emitFunctionCalls(graph, context, stage, ShaderNode::Classification::TEXTURE); @@ -215,6 +238,7 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G const string result = getUpstreamResult(outputSocket, context); const TypeDesc outputType = outputSocket->getType(); + // Try to return some meaningful color in case the output is not a material if (graph.hasClassification(ShaderNode::Classification::TEXTURE)) { if (outputType == Type::DISPLACEMENTSHADER) @@ -229,7 +253,25 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G else { emitLine("float3 displacement__ = float3(0.0)", stage); - emitLine("color finalOutput__ = mk_color3(" + result + ")", stage); + std::string finalOutput = "mk_color3(0.0)"; + if (outputType == Type::BOOLEAN) + finalOutput = result + " ? mk_color3(0.0, 1.0, 0.0) : mk_color3(1.0, 0.0, 0.0)"; + else if (outputType == Type::INTEGER) + finalOutput = "mk_color3(" + result + " / 100)"; // arbitrary + else if (outputType == Type::FLOAT) + finalOutput = "mk_color3(" + result + ")"; + else if (outputType == Type::VECTOR2) + finalOutput = "mk_color3(" + result + ".x, " + result + ".y, 0.0)"; + else if (outputType == Type::VECTOR3) + finalOutput = "mk_color3(" + result + ")"; + else if (outputType == Type::COLOR3) + finalOutput = result; + else if (outputType == Type::COLOR4) + finalOutput = result + ".rgb"; + else if (outputType == Type::MATRIX33 || outputType == Type::MATRIX44) + finalOutput = "mk_color3(" + result + "[0][0], " + result + "[1][1], " + result + "[2][2])"; + + emitLine("color finalOutput__ = " + finalOutput, stage); } // End shader body @@ -527,6 +569,13 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen // and are editable by users. if (inputSocket->getConnections().size() && graph->isEditable(*inputSocket)) { + if (inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL) + { + continue; + } + inputs->add(inputSocket->getSelf()); } } @@ -537,7 +586,7 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen outputs->add(outputSocket->getSelf()); } - // MDL does not allow varying data connected to transmission IOR. + // MDL does not allow varying data connected to transmission IOR until MDL 1.9. // We must find all uses of transmission IOR and make sure we don't // have a varying connection to it. If a varying connection is found // we break that connection and revert to using default value on that @@ -552,8 +601,14 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen // this fix will disconnect the transmission IOR on the inside, but // still support the connection to reflection IOR. // - if (graph->hasClassification(ShaderNode::Classification::SHADER) || - graph->hasClassification(ShaderNode::Classification::CLOSURE)) + GenMdlOptions::MdlVersion version = getMdlVersion(context); + bool uniformIorRequired = + version == GenMdlOptions::MdlVersion::MDL_1_6 || + version == GenMdlOptions::MdlVersion::MDL_1_7 || + version == GenMdlOptions::MdlVersion::MDL_1_8; + if (uniformIorRequired && ( + graph->hasClassification(ShaderNode::Classification::SHADER) || + graph->hasClassification(ShaderNode::Classification::CLOSURE))) { // Find dependencies on transmission IOR. std::set graphsWithIorDependency; @@ -641,10 +696,15 @@ void MdlShaderGenerator::emitShaderInputs(const DocumentPtr doc, const VariableB } } -void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const +GenMdlOptions::MdlVersion MdlShaderGenerator::getMdlVersion(GenContext& context) const { GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); - GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; + return options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; +} + +void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const +{ + GenMdlOptions::MdlVersion version = getMdlVersion(context); emitLineBegin(stage); emitString("mdl ", stage); @@ -656,19 +716,22 @@ void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& case GenMdlOptions::MdlVersion::MDL_1_7: emitString(MDL_VERSION_1_7, stage); break; + case GenMdlOptions::MdlVersion::MDL_1_8: + emitString(MDL_VERSION_1_8, stage); + break; default: - // GenMdlOptions::MdlVersion::MDL_1_8 + // GenMdlOptions::MdlVersion::MDL_1_9 // GenMdlOptions::MdlVersion::MDL_LATEST - emitString(MDL_VERSION_1_8, stage); + emitString(MDL_VERSION_1_9, stage); break; } emitLineEnd(stage, true); } + const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& context) const { - GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); - GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; + GenMdlOptions::MdlVersion version = getMdlVersion(context); switch (version) { @@ -676,10 +739,12 @@ const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& contex return MDL_VERSION_SUFFIX_1_6; case GenMdlOptions::MdlVersion::MDL_1_7: return MDL_VERSION_SUFFIX_1_7; + case GenMdlOptions::MdlVersion::MDL_1_8: + return MDL_VERSION_SUFFIX_1_8; default: - // GenMdlOptions::MdlVersion::MDL_1_8 + // GenMdlOptions::MdlVersion::MDL_1_9 // GenMdlOptions::MdlVersion::MDL_LATEST - return MDL_VERSION_SUFFIX_1_8; + return MDL_VERSION_SUFFIX_1_9; } } diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.h b/source/MaterialXGenMdl/MdlShaderGenerator.h index 3a24bcf87d..ef88fbc453 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.h +++ b/source/MaterialXGenMdl/MdlShaderGenerator.h @@ -25,7 +25,8 @@ class MX_GENMDL_API GenMdlOptions : public GenUserData MDL_1_6, MDL_1_7, MDL_1_8, - MDL_LATEST = MDL_1_8 + MDL_1_9, + MDL_LATEST = MDL_1_9 }; /// Create MDL code generator options with default values. @@ -76,7 +77,11 @@ class MX_GENMDL_API MdlShaderGenerator : public ShaderGenerator /// Map of code snippets for geomprops in MDL. static const std::unordered_map GEOMPROP_DEFINITIONS; - /// Add the MDL file header containing the version number of the generated module.. + /// Get the selected MDL target language version number from the context option. + /// If not set, the latest version supported by GenMdl is returned. + GenMdlOptions::MdlVersion getMdlVersion(GenContext& context) const; + + /// Add the MDL file header containing the version number of the generated module. void emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const; /// Add the version number suffix appended to MDL modules that use versions. diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index e3484b0171..8949ae6cc0 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -16,6 +16,10 @@ MATERIALX_NAMESPACE_BEGIN const string StringConstantsMdl::TOP = "top"; const string StringConstantsMdl::BASE = "base"; +const string StringConstantsMdl::FG = "fg"; +const string StringConstantsMdl::BG = "bg"; +const string StringConstantsMdl::MIX = "mix"; +const string StringConstantsMdl::TOP_WEIGHT = "top_weight"; ShaderNodeImplPtr ClosureLayerNodeMdl::create() { @@ -101,6 +105,7 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // Transport the base bsdf further than one layer ShaderNode* baseReceiverNode = top; + ShaderNode* mixTopWeightNode = nullptr; while (true) { // If the top node is again a layer, we don't want to override the base @@ -111,6 +116,26 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& } else { + // TODO is there a more efficient way to check if the node is a mix_bsdf? + std::string name = top->getImplementation().getName(); + if (name == "IM_mix_bsdf_genmdl") + { + // handle one special case: the top node is a mix where either fg or bg is empty + // so basically a scale factor + ShaderOutput* fgOutput = top->getInput(StringConstantsMdl::FG)->getConnection(); + ShaderOutput* bgOutput = top->getInput(StringConstantsMdl::BG)->getConnection(); + ShaderOutput* mixOutput = top->getInput(StringConstantsMdl::MIX)->getConnection(); + ShaderNode* fg = fgOutput ? fgOutput->getNode() : nullptr; + ShaderNode* bg = bgOutput ? bgOutput->getNode() : nullptr; + ShaderNode* mix = mixOutput ? mixOutput->getNode() : nullptr; + if ((fg && !bg) || (!fg && bg)) + { + baseReceiverNode = fg ? fg : bg; // take the node that is valid + top = baseReceiverNode; + mixTopWeightNode = mix; + } + break; + } // we stop at elemental bsdfs // TODO handle mix, add, and multiply break; @@ -150,6 +175,11 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // base BSDF connection and output variable name from the // layer operator itself. topNodeBaseInput->makeConnection(base->getOutput()); + if (mixTopWeightNode) + { + ShaderInput* topNodeTopWeightInput = baseReceiverNode->getInput(StringConstantsMdl::TOP_WEIGHT); + topNodeTopWeightInput->makeConnection(mixTopWeightNode->getOutput()); + } ScopedSetVariableName setVariable(output->getVariable(), top->getOutput()); // Make the call. @@ -171,6 +201,21 @@ void LayerableNodeMdl::addInputs(ShaderNode& node, GenContext& /*context*/) cons { // Add the input to hold base layer BSDF. node.addInput(StringConstantsMdl::BASE, Type::BSDF); + + // Set the top level weight default to 1.0 + ShaderInput* topWeightNode = node.addInput(StringConstantsMdl::TOP_WEIGHT, Type::FLOAT); + ValuePtr value = TypedValue::createValue(1.0f); + topWeightNode->setValue(value); +} + +bool LayerableNodeMdl::isEditable(const ShaderInput& input) const +{ + if (input.getName() == StringConstantsMdl::BASE || + input.getName() == StringConstantsMdl::TOP_WEIGHT) + { + return false; + } + return BASE::isEditable(input); } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h index bced5cfac1..8b6f987287 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h @@ -23,6 +23,10 @@ class MX_GENMDL_API StringConstantsMdl /// String constants static const string TOP; ///< layer parameter name of the top component static const string BASE; ///< layer parameter name of the base component + static const string FG; ///< mix parameter name of the foreground + static const string BG; ///< mix parameter name of the background + static const string MIX; ///< mix parameter name of the amount + static const string TOP_WEIGHT; ///< mix amount forwarded into layer top component }; /// Closure layer node implementation for MDL. @@ -40,11 +44,14 @@ class MX_GENMDL_API ClosureLayerNodeMdl : public ShaderNodeImpl /// Note, not all elemental bsdfs support this kind of transformation. class MX_GENMDL_API LayerableNodeMdl : public SourceCodeNodeMdl { + using BASE = SourceCodeNodeMdl; + public: virtual ~LayerableNodeMdl() = default; static ShaderNodeImplPtr create(); void addInputs(ShaderNode& node, GenContext&) const override; + bool isEditable(const ShaderInput& input) const override; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp index 6477cd9ae8..dd0444d129 100644 --- a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp @@ -59,12 +59,17 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex // Emit calls for the closure dependencies upstream from this node. shadergen.emitDependentFunctionCalls(node, context, stage, ShaderNode::Classification::CLOSURE); - // Check if transmission IOR is used for this shader. + // Check if transmission IOR is used for this shader for MDL versions before 1.9. // MDL only supports a single transmission IOR per material and // it is given as an input on the 'material' constructor. // So if used we must forward this value/connection to the surface // constructor. It's set as an extra input below. - const ShaderInput* ior = findTransmissionIOR(node); + GenMdlOptions::MdlVersion version = shadergen.getMdlVersion(context); + bool uniformIorRequired = + version == GenMdlOptions::MdlVersion::MDL_1_6 || + version == GenMdlOptions::MdlVersion::MDL_1_7 || + version == GenMdlOptions::MdlVersion::MDL_1_8; + const ShaderInput* ior = uniformIorRequired ? findTransmissionIOR(node) : nullptr; shadergen.emitLineBegin(stage); @@ -79,6 +84,9 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex for (ShaderInput* input : node.getInputs()) { shadergen.emitString(delim, stage); + shadergen.emitString("mxp_", stage); + shadergen.emitString(input->getName(), stage); + shadergen.emitString(": ", stage); shadergen.emitInput(input, context, stage); delim = ", "; } @@ -87,6 +95,7 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex { // Emit the extra input for transmission IOR. shadergen.emitString(delim, stage); + shadergen.emitString("mxp_transmission_ior: ", stage); shadergen.emitInput(ior, context, stage); } diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl index 0c11ce3744..789b4cfa77 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl @@ -16,15 +16,15 @@ // MDL implementation of all types and nodes of // MaterialX Physically-Based Shading Nodes -// Document v1.37 REV2, July 16, 2019 (Revised October 17, 2019) +// Document version 1.39, June 29, 2024 // see www.materialx.org // in -// NVIDIA Material Definition Language 1.8 +// NVIDIA Material Definition Language 1.9 // Language Specification -// Document version 1.8.2, May 24, 2023 +// Document version 1.9.2, September 16, 2024 // www.nvidia.com/mdl -mdl 1.8; +mdl 1.9; // forward the latest version -export using .::pbrlib_1_8 import *; +export using .::pbrlib_1_9 import *; diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl index e70f849920..64102d6c27 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl @@ -82,7 +82,8 @@ export material mx_oren_nayar_diffuse_bsdf( float mxp_weight = 1.0, color mxp_color = color(0.18), float mxp_roughness = 0.0, - float3 mxp_normal = state::normal() + float3 mxp_normal = state::normal(), + uniform bool mxp_energy_compensation = false [[ anno::unused() ]] // MDL 1.10 ) [[ anno::usage( "materialx:bsdf") ]] @@ -152,7 +153,8 @@ export material mx_dielectric_bsdf( float3 mxp_tangent = state::texture_tangent_u(0), uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, - material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix float mxp_thinfilm_thickness = 0.0, float mxp_thinfilm_ior = 1.0 ) [[ @@ -174,8 +176,8 @@ export material mx_dielectric_bsdf( layer: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect), base: mxp_base.surface.scattering, @@ -186,8 +188,8 @@ export material mx_dielectric_bsdf( layer: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_transmit), normal: mxp_normal); @@ -200,8 +202,8 @@ export material mx_dielectric_bsdf( base: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect_transmit)), normal: mxp_normal); @@ -258,12 +260,13 @@ export material mx_conductor_bsdf( ) ); -// TODO MDL 1.8 +// MDL 1.8 // * will add support for thin film above a color_custom_curve_layer node until then, thin_film will have no effect // * thin_film(thickness: 0.0, ior: < 1.0) will be handled properly export material mx_generalized_schlick_bsdf( float mxp_weight = 1.0, color mxp_color0 = color(1.0), + color mxp_color82 = color(1.0), // MDL 1.10 color mxp_color90 = color(1.0), float mxp_exponent = 5.0, float2 mxp_roughness = float2(0.05), @@ -271,7 +274,8 @@ export material mx_generalized_schlick_bsdf( float3 mxp_tangent = state::texture_tangent_u(0), uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, - material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix float mxp_thinfilm_thickness = 0.0, float mxp_thinfilm_ior = 1.0 ) [[ @@ -283,8 +287,8 @@ export material mx_generalized_schlick_bsdf( bsdf ggx_model_R = df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: color(1.0), - multiscatter_tint: color(1.0), + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect); @@ -302,7 +306,7 @@ export material mx_generalized_schlick_bsdf( layer: mxp_scatter_mode == mx_scatter_mode_T ? df::color_custom_curve_layer( normal_reflectivity: mxp_color0, - grazing_reflectivity: mxp_color90, + grazing_reflectivity: mxp_color82 * mxp_color90, exponent: mxp_exponent, layer: bsdf(), base: ggx_model_T, @@ -312,7 +316,7 @@ export material mx_generalized_schlick_bsdf( ior: color(coatIor), base: df::color_custom_curve_layer( normal_reflectivity: mxp_color0, - grazing_reflectivity: mxp_color90, + grazing_reflectivity: mxp_color82 * mxp_color90, exponent: mxp_exponent, layer: ggx_model_R, base: mxp_scatter_mode == mx_scatter_mode_R @@ -440,7 +444,7 @@ export material mx_chiang_hair_bsdf( float mxp_cuticle_angle = 0.5, float3 mxp_absorption_coefficient = float3(0.0), // TODO: MDL's chiang_hair BSDF has no support user tangent vector - float3 mxp_curve_direction = state::texture_tangent_u(0) + float3 mxp_curve_direction = state::texture_tangent_u(0) [[ anno::unused() ]] ) [[ anno::usage( "materialx:bsdf") ]] diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl new file mode 100644 index 0000000000..e8654380d3 --- /dev/null +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// MDL implementation of all types and nodes of +// MaterialX Physically-Based Shading Nodes +// Document version 1.39, June 29, 2024 +// see www.materialx.org +// in +// NVIDIA Material Definition Language 1.9 +// Language Specification +// Document version 1.9.2, September 16, 2024 +// www.nvidia.com/mdl + +mdl 1.9; + +import ::anno::*; +import ::df::*; +import ::math::*; +import ::state::*; + +import .::core::*; + +// Changes since MDL 1.8 +// - lift the restriction of uniform IORs + +// forward unchanged definitions from the previous versions +export using .::pbrlib_1_6 import mx_scatter_mode; +export using .::pbrlib_1_6 import mx_map_scatter_mode; +export using .::pbrlib_1_6 import mx_oren_nayar_diffuse_bsdf; +export using .::pbrlib_1_6 import mx_burley_diffuse_bsdf; +export using .::pbrlib_1_6 import mx_translucent_bsdf; +export using .::pbrlib_1_6 import mx_subsurface_bsdf; +export using .::pbrlib_1_6 import mx_thin_film_bsdf; +export using .::pbrlib_1_6 import mx_chiang_hair_bsdf; +export using .::pbrlib_1_6 import mx_uniform_edf; +export using .::pbrlib_1_6 import mx_conical_edf; +export using .::pbrlib_1_6 import mx_measured_edf; +export using .::pbrlib_1_6 import mx_absorption_vdf; +export using .::pbrlib_1_6 import mx_anisotropic_vdf; +export using .::pbrlib_1_6 import mx_light; +export using .::pbrlib_1_6 import mx_displacement_float; +export using .::pbrlib_1_6 import mx_displacement_vector3; +export using .::pbrlib_1_6 import volume_mix_return; +export using .::pbrlib_1_6 import volume_mix; +export using .::pbrlib_1_6 import mx_multiply_bsdf_color3; +export using .::pbrlib_1_6 import mx_multiply_bsdf_float; +export using .::pbrlib_1_6 import mx_multiply_edf_color3; +export using .::pbrlib_1_6 import mx_multiply_edf_float; +export using .::pbrlib_1_6 import mx_multiply_vdf_color3; +export using .::pbrlib_1_6 import mx_multiply_vdf_float; +export using .::pbrlib_1_6 import mx_roughness_anisotropy; +export using .::pbrlib_1_6 import mx_roughness_dual; +export using .::pbrlib_1_6 import mx_blackbody; +export using .::pbrlib_1_6 import mx_artistic_ior__result; +export using .::pbrlib_1_6 import mx_artistic_ior; +export using .::pbrlib_1_6 import mx_deon_hair_absorption_from_melanin; +export using .::pbrlib_1_6 import mx_chiang_hair_absorption_from_color; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness__result; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness; + +export using .::pbrlib_1_7 import mx_sheen_bsdf; +export using .::pbrlib_1_7 import mx_add_bsdf; +export using .::pbrlib_1_7 import mx_add_edf; +export using .::pbrlib_1_7 import mx_mix_edf; +export using .::pbrlib_1_7 import mx_add_vdf; +export using .::pbrlib_1_7 import mx_generalized_schlick_edf; +export using .::pbrlib_1_7 import mx_volume; + +export material mx_mix_bsdf( + material mxp_fg = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_bg = material() [[ anno::usage( "materialx:bsdf") ]], + float mxp_mix = 0.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float mix = math::saturate(mxp_mix); + volume_mix_return v = volume_mix( + mxp_fg.volume.scattering_coefficient, mix, + mxp_bg.volume.scattering_coefficient, (1.0f - mix)); +} in material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mix, + layer: mxp_fg.surface.scattering, + base: mxp_bg.surface.scattering + ) + ), + // we need to carry volume properties along for SSS + ior: mix * mxp_fg.ior + (1.0f - mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component(v.mix_weight1, mxp_fg.volume.scattering), + df::vdf_component(1.0 - v.mix_weight1, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: v.scattering_coefficient + ) +); + +export material mx_mix_vdf( + material mxp_fg = material() [[ anno::usage( "materialx:vdf") ]], + material mxp_bg = material() [[ anno::usage( "materialx:vdf") ]], + float mxp_mix = 0.0 +) [[ + anno::usage( "materialx:vdf") +]] += let { + float mix = math::saturate(mxp_mix); + volume_mix_return v = volume_mix( + mxp_fg.volume.scattering_coefficient, mix, + mxp_bg.volume.scattering_coefficient, (1.0f - mix)); +} in material( + ior: mix * mxp_fg.ior + (1.0f - mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component( v.mix_weight1, mxp_fg.volume.scattering), + df::vdf_component( 1.0 - v.mix_weight1, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: v.scattering_coefficient + ) +); + +// helper to compute ior for generalized_schlick +color mx_f0_to_ior(color F0) +{ + float3 sqrtF0 = math::sqrt(math::clamp(float3(F0), 0.01, 0.99)); + return color((float3(1.0) + sqrtF0) / (float3(1.0) - sqrtF0)); +} + +export material mx_generalized_schlick_bsdf( + float mxp_weight = 1.0, + color mxp_color0 = color(1.0), + color mxp_color82 = color(1.0), // MDL 1.10 + color mxp_color90 = color(1.0), + float mxp_exponent = 5.0, + float2 mxp_roughness = float2(0.05), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + bsdf ggx_model_R = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect); + + bsdf ggx_model_T = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_transmit); + +} in material( + surface: material_surface( + scattering: df::unbounded_mix( + df::bsdf_component[]( + df::bsdf_component( + mxp_weight, + mxp_scatter_mode == mx_scatter_mode_T + ? df::color_custom_curve_layer( + normal_reflectivity: mxp_color0, + grazing_reflectivity: mxp_color82 * mxp_color90, + exponent: mxp_exponent, + layer: bsdf(), + base: ggx_model_T, + normal: mxp_normal) + : df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: df::color_custom_curve_layer( + normal_reflectivity: mxp_color0, + grazing_reflectivity: mxp_color82 * mxp_color90, + exponent: mxp_exponent, + layer: ggx_model_R, + base: mxp_scatter_mode == mx_scatter_mode_R + ? mxp_base.surface.scattering + : ggx_model_T, + normal: mxp_normal)) + ), + df::bsdf_component( + 1.0 - mxp_weight, + mxp_base.surface.scattering) + ) + ) + ), + ior: mx_f0_to_ior(mxp_color0), + // we need to carry volume properties along for SSS + volume: mxp_base.volume +); + + +// TODO MDL 1.8 +// * will add support for thin film above a color_custom_curve_layer node until then, thin_film will have no effect +// * thin_film(thickness: 0.0, ior: < 1.0) will be handled properly +export material mx_dielectric_bsdf( + float mxp_weight = 1.0, + color mxp_tint = color(1.0), + float mxp_ior = 1.5, + float2 mxp_roughness = float2(0.0), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + float grazing_refl = math::max((1.0 - math::average(mxp_roughness)), 0.0); + float root_r = (mxp_ior-1)/(mxp_ior+1); + bsdf bsdf_R = df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + // fresnel layer has issues if base is a diffuse transmission, use custom curve for now + // this will break thin_film but improves standard_surface with diffuse transmission + base: df::custom_curve_layer( + normal_reflectivity: root_r*root_r, + grazing_reflectivity: grazing_refl, + weight: mxp_weight, + layer: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect), + base: mxp_base.surface.scattering, + normal: mxp_normal)); + + bsdf bsdf_T = df::weighted_layer( + weight: mxp_weight, + layer: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_transmit), + normal: mxp_normal); + + bsdf bsdf_RT = df::weighted_layer( + weight: mxp_weight, + layer: df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect_transmit)), + normal: mxp_normal); + + bsdf bsdf_selected = (mxp_scatter_mode == mx_scatter_mode_R) ? bsdf_R : + ((mxp_scatter_mode == mx_scatter_mode_T) ? bsdf_T : bsdf_RT); +} in material( + surface: material_surface( + scattering: bsdf_selected + ), + // we need to carry volume properties along for SSS + ior: color(mxp_ior), + volume: mxp_base.volume +); + +export material mx_conductor_bsdf( + float mxp_weight = 1.0, + color mxp_ior = color(0.18, 0.42, 1.37), + color mxp_extinction = color(3.42, 2.35, 1.77), + float2 mxp_roughness = float2(0.0), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + bsdf ggx_model = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0), + multiscatter_tint: color(1.0), + tangent_u: mxp_tangent); + bsdf conductor = df::fresnel_factor( + ior: mxp_ior, + extinction_coefficient: mxp_extinction, + base: ggx_model); + bsdf thin_film_conductor = df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: conductor); +} in material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mxp_weight, + layer: thin_film_conductor, + normal: mxp_normal + ) + ), + ior: mxp_ior, +); + +// Shader Nodes + +// NOTE: The MDL material with thin_walled == false uses the same material_surface +// properties for the front- and backface, the material will not be black +// from the backside as mandated by the MaterialX spec. +export material mx_surface( + material mxp_bsdf = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_edf = material() [[ anno::usage( "materialx:edf") ]], + float mxp_opacity = 1.0, + uniform bool mxp_thin_walled = false, + float mxp_transmission_ior = 0.0 // extra parameter for setting transmission IOR +) [[ + anno::usage( "materialx:surfaceshader") +]] += let { + bsdf bsdf_node = mxp_bsdf.surface.scattering; + material_emission edf_node = mxp_edf.surface.emission; + // we need to carry volume properties along for SSS + material_volume bsdf_volume = mxp_bsdf.volume; +} in material( + thin_walled: mxp_thin_walled, + surface: material_surface( + scattering: bsdf_node, + emission: edf_node + ), + ior: mxp_transmission_ior > 0.0 ? color(mxp_transmission_ior) : mxp_bsdf.ior, + volume: bsdf_volume, + geometry: material_geometry( + cutout_opacity: mxp_opacity + ) +); diff --git a/source/MaterialXGenMdl/mdl/materialx/sampling.mdl b/source/MaterialXGenMdl/mdl/materialx/sampling.mdl index 1809503653..15228efeca 100644 --- a/source/MaterialXGenMdl/mdl/materialx/sampling.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/sampling.mdl @@ -5,7 +5,9 @@ mdl 1.6; +import ::anno::*; import ::math::*; +import ::state::*; import .::core::*; @@ -15,14 +17,14 @@ export const int MX_MAX_SAMPLE_COUNT = 49; export const int MX_WEIGHT_ARRAY_SIZE = 84; // This is not available in MDL so just use a "small" number -float2 dFdx(float2 uv) +float2 dFdx(float2 uv [[anno::unused()]]) { - return uv+0.0001; + return float2(0.001, 0); } -float2 dFdy(float2 uv) +float2 dFdy(float2 uv [[anno::unused()]]) { - return uv+0.0001; + return float2(0, 0.001); } // @@ -49,11 +51,10 @@ export float2 mx_compute_sample_size_uv(float2 uv, float filterSize, float filte // export float3 mx_normal_from_samples_sobel(float[9] S, float scale) { - float nx = S[0] - S[2] + (2.0*S[3]) - (2.0*S[5]) + S[6] - S[8]; - float ny = S[0] + (2.0*S[1]) + S[2] - S[6] - (2.0*S[7]) - S[8]; - float nz = scale * ::math::sqrt(1.0 - nx*nx - ny*ny); - float3 norm = ::math::normalize(float3(nx, ny, nz)); - return (norm + 1.0) * 0.5; + float nx = S[0] - S[2] + (2.0*S[3]) - (2.0*S[5]) + S[6] - S[8]; + float ny = S[0] + (2.0*S[1]) + S[2] - S[6] - (2.0*S[7]) - S[8]; + float3 norm = math::normalize(float3(nx * scale, ny * scale, 0.125)); + return (norm + 1.0) * 0.5; } // Kernel weights for box filter diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl index 79ed3dff4f..a23c0150ed 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl @@ -4,15 +4,15 @@ // // MDL implementation of all Standard Source Nodes of // MaterialX: An Open Standard for Network-Based CG Object Looks -// Document v1.37 REV2, January 19, 2020 +// Document version 1.39, September 15, 2024 // www.materialx.org // in -// NVIDIA Material Definition Language 1.7 +// NVIDIA Material Definition Language 1.9 // Language Specification -// Document version 1.7.2, January 17, 2022 +// Document version 1.9.2, September 16, 2024 // www.nvidia.com/mdl -mdl 1.8; +mdl 1.9; // forward the latest version -export using .::stdlib_1_8 import *; +export using .::stdlib_1_9 import *; diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl new file mode 100644 index 0000000000..549287c5b7 --- /dev/null +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl @@ -0,0 +1,387 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// +// MDL implementation of all Standard Source Nodes of +// MaterialX: An Open Standard for Network-Based CG Object Looks +// Document version 1.39, September 15, 2024 +// www.materialx.org +// in +// NVIDIA Material Definition Language 1.9 +// Language Specification +// Document version 1.9.2, September 16, 2024 +// www.nvidia.com/mdl + +mdl 1.9; + +import ::anno::*; +import ::df::*; +import ::math::*; +import ::scene::*; +import ::state::*; + +import .::core::*; +import .::noise::*; +import .::hsv::*; + +// Changes since MDL 1.8 +// - lift the restriction of uniform IORs + +// forward unchanged definitions from the previous version +export using .::stdlib_1_7 import mx_surfacematerial; +export using .::stdlib_1_7 import mx_surface_unlit; +export using .::stdlib_1_7 import mx_image_float; +export using .::stdlib_1_7 import mx_image_color3; +export using .::stdlib_1_7 import mx_image_color4; +export using .::stdlib_1_7 import mx_image_vector2; +export using .::stdlib_1_7 import mx_image_vector3; +export using .::stdlib_1_7 import mx_image_vector4; +export using .::stdlib_1_7 import mx_constant_float; +export using .::stdlib_1_7 import mx_constant_color3; +export using .::stdlib_1_7 import mx_constant_color4; +export using .::stdlib_1_7 import mx_constant_vector2; +export using .::stdlib_1_7 import mx_constant_vector3; +export using .::stdlib_1_7 import mx_constant_vector4; +export using .::stdlib_1_7 import mx_constant_boolean; +export using .::stdlib_1_7 import mx_constant_integer; +export using .::stdlib_1_7 import mx_constant_matrix33; +export using .::stdlib_1_7 import mx_constant_matrix44; +export using .::stdlib_1_7 import mx_constant_string; +export using .::stdlib_1_7 import mx_constant_filename; +export using .::stdlib_1_7 import mx_ramplr_float; +export using .::stdlib_1_7 import mx_ramplr_color3; +export using .::stdlib_1_7 import mx_ramplr_color4; +export using .::stdlib_1_7 import mx_ramplr_vector2; +export using .::stdlib_1_7 import mx_ramplr_vector3; +export using .::stdlib_1_7 import mx_ramplr_vector4; +export using .::stdlib_1_7 import mx_ramptb_float; +export using .::stdlib_1_7 import mx_ramptb_color3; +export using .::stdlib_1_7 import mx_ramptb_color4; +export using .::stdlib_1_7 import mx_ramptb_vector2; +export using .::stdlib_1_7 import mx_ramptb_vector3; +export using .::stdlib_1_7 import mx_ramptb_vector4; +export using .::stdlib_1_7 import mx_splitlr_float; +export using .::stdlib_1_7 import mx_splitlr_color3; +export using .::stdlib_1_7 import mx_splitlr_color4; +export using .::stdlib_1_7 import mx_splitlr_vector2; +export using .::stdlib_1_7 import mx_splitlr_vector3; +export using .::stdlib_1_7 import mx_splitlr_vector4; +export using .::stdlib_1_7 import mx_splittb_float; +export using .::stdlib_1_7 import mx_splittb_color3; +export using .::stdlib_1_7 import mx_splittb_color4; +export using .::stdlib_1_7 import mx_splittb_vector2; +export using .::stdlib_1_7 import mx_splittb_vector3; +export using .::stdlib_1_7 import mx_splittb_vector4; +export using .::stdlib_1_7 import mx_position_vector3; +export using .::stdlib_1_7 import mx_normal_vector3; +export using .::stdlib_1_7 import mx_tangent_vector3; +export using .::stdlib_1_7 import mx_bitangent_vector3; +export using .::stdlib_1_7 import mx_texcoord_vector2; +export using .::stdlib_1_7 import mx_texcoord_vector3; +export using .::stdlib_1_7 import mx_geomcolor_float; +export using .::stdlib_1_7 import mx_geomcolor_color3; +export using .::stdlib_1_7 import mx_geomcolor_color4; +export using .::stdlib_1_7 import mx_ambientocclusion_float; +export using .::stdlib_1_7 import mx_frame_float; +export using .::stdlib_1_7 import mx_time_float; +export using .::stdlib_1_7 import mx_modulo_color3; +export using .::stdlib_1_7 import mx_modulo_color4; +export using .::stdlib_1_7 import mx_modulo_color3FA; +export using .::stdlib_1_7 import mx_modulo_color4FA; +export using .::stdlib_1_7 import mx_invert_color4; +export using .::stdlib_1_7 import mx_invert_color4FA; +export using .::stdlib_1_7 import mx_absval_color4; +export using .::stdlib_1_7 import mx_floor_color3; +export using .::stdlib_1_7 import mx_floor_color4; +export using .::stdlib_1_7 import mx_ceil_color3; +export using .::stdlib_1_7 import mx_ceil_color4; +export using .::stdlib_1_7 import mx_round_color3; +export using .::stdlib_1_7 import mx_round_color4; +export using .::stdlib_1_7 import mx_power_color4; +export using .::stdlib_1_7 import mx_power_color4FA; +export using .::stdlib_1_7 import mx_sin_float; +export using .::stdlib_1_7 import mx_cos_float; +export using .::stdlib_1_7 import mx_tan_float; +export using .::stdlib_1_7 import mx_asin_float; +export using .::stdlib_1_7 import mx_acos_float; +export using .::stdlib_1_7 import mx_atan2_float; +export using .::stdlib_1_7 import mx_sin_vector2; +export using .::stdlib_1_7 import mx_cos_vector2; +export using .::stdlib_1_7 import mx_tan_vector2; +export using .::stdlib_1_7 import mx_asin_vector2; +export using .::stdlib_1_7 import mx_acos_vector2; +export using .::stdlib_1_7 import mx_atan2_vector2; +export using .::stdlib_1_7 import mx_sin_vector3; +export using .::stdlib_1_7 import mx_cos_vector3; +export using .::stdlib_1_7 import mx_tan_vector3; +export using .::stdlib_1_7 import mx_asin_vector3; +export using .::stdlib_1_7 import mx_acos_vector3; +export using .::stdlib_1_7 import mx_atan2_vector3; +export using .::stdlib_1_7 import mx_sin_vector4; +export using .::stdlib_1_7 import mx_cos_vector4; +export using .::stdlib_1_7 import mx_tan_vector4; +export using .::stdlib_1_7 import mx_asin_vector4; +export using .::stdlib_1_7 import mx_acos_vector4; +export using .::stdlib_1_7 import mx_atan2_vector4; +export using .::stdlib_1_7 import mx_sqrt_float; +export using .::stdlib_1_7 import mx_ln_float; +export using .::stdlib_1_7 import mx_exp_float; +export using .::stdlib_1_7 import mx_sqrt_vector2; +export using .::stdlib_1_7 import mx_ln_vector2; +export using .::stdlib_1_7 import mx_exp_vector2; +export using .::stdlib_1_7 import mx_sqrt_vector3; +export using .::stdlib_1_7 import mx_ln_vector3; +export using .::stdlib_1_7 import mx_exp_vector3; +export using .::stdlib_1_7 import mx_sqrt_vector4; +export using .::stdlib_1_7 import mx_ln_vector4; +export using .::stdlib_1_7 import mx_exp_vector4; +export using .::stdlib_1_7 import mx_sign_color3; +export using .::stdlib_1_7 import mx_sign_color4; +export using .::stdlib_1_7 import mx_clamp_color4; +export using .::stdlib_1_7 import mx_clamp_color4FA; +export using .::stdlib_1_7 import mx_min_color4; +export using .::stdlib_1_7 import mx_min_color4; +export using .::stdlib_1_7 import mx_max_color4; +export using .::stdlib_1_7 import mx_max_color4; +export using .::stdlib_1_7 import mx_transformpoint_vector3; +export using .::stdlib_1_7 import mx_transformvector_vector3; +export using .::stdlib_1_7 import mx_transformnormal_vector3; +export using .::stdlib_1_7 import mx_transformmatrix_vector2M3; +export using .::stdlib_1_7 import mx_transformmatrix_vector3; +export using .::stdlib_1_7 import mx_transformmatrix_vector3M4; +export using .::stdlib_1_7 import mx_transformmatrix_vector4; +export using .::stdlib_1_7 import mx_normalmap_float; +export using .::stdlib_1_7 import mx_normalmap_vector2; +export using .::stdlib_1_7 import mx_transpose_matrix33; +export using .::stdlib_1_7 import mx_transpose_matrix44; +export using .::stdlib_1_7 import mx_determinant_matrix33; +export using .::stdlib_1_7 import mx_determinant_matrix44; +export using .::stdlib_1_7 import mx_invertmatrix_matrix33; +export using .::stdlib_1_7 import mx_invertmatrix_matrix44; +export using .::stdlib_1_7 import mx_rotate2d_vector2; +export using .::stdlib_1_7 import mx_rotate3d_vector3; +export using .::stdlib_1_7 import mx_remap_float; +export using .::stdlib_1_7 import mx_remap_color3; +export using .::stdlib_1_7 import mx_remap_color4; +export using .::stdlib_1_7 import mx_remap_vector2; +export using .::stdlib_1_7 import mx_remap_vector3; +export using .::stdlib_1_7 import mx_remap_vector4; +export using .::stdlib_1_7 import mx_remap_color3FA; +export using .::stdlib_1_7 import mx_remap_color4FA; +export using .::stdlib_1_7 import mx_remap_vector2FA; +export using .::stdlib_1_7 import mx_remap_vector3FA; +export using .::stdlib_1_7 import mx_remap_vector4FA; +export using .::stdlib_1_7 import mx_smoothstep_float; +export using .::stdlib_1_7 import mx_smoothstep_color3; +export using .::stdlib_1_7 import mx_smoothstep_color4; +export using .::stdlib_1_7 import mx_smoothstep_vector2; +export using .::stdlib_1_7 import mx_smoothstep_vector3; +export using .::stdlib_1_7 import mx_smoothstep_vector4; +export using .::stdlib_1_7 import mx_smoothstep_color3FA; +export using .::stdlib_1_7 import mx_smoothstep_color4FA; +export using .::stdlib_1_7 import mx_smoothstep_vector2FA; +export using .::stdlib_1_7 import mx_smoothstep_vector3FA; +export using .::stdlib_1_7 import mx_smoothstep_vector4FA; +export using .::stdlib_1_7 import mx_curveadjust_float; +export using .::stdlib_1_7 import mx_curveadjust_color3; +export using .::stdlib_1_7 import mx_curveadjust_color4; +export using .::stdlib_1_7 import mx_curveadjust_vector2; +export using .::stdlib_1_7 import mx_curveadjust_vector3; +export using .::stdlib_1_7 import mx_curveadjust_vector4; +export using .::stdlib_1_7 import mx_luminance_color3; +export using .::stdlib_1_7 import mx_luminance_color4; +export using .::stdlib_1_7 import mx_rgbtohsv_color3; +export using .::stdlib_1_7 import mx_rgbtohsv_color4; +export using .::stdlib_1_7 import mx_hsvtorgb_color3; +export using .::stdlib_1_7 import mx_hsvtorgb_color4; +export using .::stdlib_1_7 import mx_premult_color4; +export using .::stdlib_1_7 import mx_unpremult_color4; +export using .::stdlib_1_7 import mx_plus_color4; +export using .::stdlib_1_7 import mx_minus_color4; +export using .::stdlib_1_7 import mx_difference_color4; +export using .::stdlib_1_7 import mx_burn_float; +export using .::stdlib_1_7 import mx_burn_color3; +export using .::stdlib_1_7 import mx_burn_color4; +export using .::stdlib_1_7 import mx_dodge_float; +export using .::stdlib_1_7 import mx_dodge_color3; +export using .::stdlib_1_7 import mx_dodge_color4; +export using .::stdlib_1_7 import mx_screen_color4; +export using .::stdlib_1_7 import mx_disjointover_color4; +export using .::stdlib_1_7 import mx_in_color4; +export using .::stdlib_1_7 import mx_mask_color4; +export using .::stdlib_1_7 import mx_matte_color4; +export using .::stdlib_1_7 import mx_out_color4; +export using .::stdlib_1_7 import mx_over_color4; +export using .::stdlib_1_7 import mx_mix_color4; +export using .::stdlib_1_7 import mx_mix_color4_color4; +export using .::stdlib_1_7 import mx_mix_volumeshader; +export using .::stdlib_1_7 import mx_mix_displacementshader; +export using .::stdlib_1_7 import mx_ifgreater_float; +export using .::stdlib_1_7 import mx_ifgreater_integer; +export using .::stdlib_1_7 import mx_ifgreater_color3; +export using .::stdlib_1_7 import mx_ifgreater_color4; +export using .::stdlib_1_7 import mx_ifgreater_vector2; +export using .::stdlib_1_7 import mx_ifgreater_vector3; +export using .::stdlib_1_7 import mx_ifgreater_vector4; +export using .::stdlib_1_7 import mx_ifgreater_matrix33; +export using .::stdlib_1_7 import mx_ifgreater_matrix44; +export using .::stdlib_1_7 import mx_ifgreater_boolean; +export using .::stdlib_1_7 import mx_ifgreater_floatI; +export using .::stdlib_1_7 import mx_ifgreater_integerI; +export using .::stdlib_1_7 import mx_ifgreater_color3I; +export using .::stdlib_1_7 import mx_ifgreater_color4I; +export using .::stdlib_1_7 import mx_ifgreater_vector2I; +export using .::stdlib_1_7 import mx_ifgreater_vector3I; +export using .::stdlib_1_7 import mx_ifgreater_vector4I; +export using .::stdlib_1_7 import mx_ifgreater_matrix33I; +export using .::stdlib_1_7 import mx_ifgreater_matrix44I; +export using .::stdlib_1_7 import mx_ifgreater_booleanI; +export using .::stdlib_1_7 import mx_ifgreatereq_float; +export using .::stdlib_1_7 import mx_ifgreatereq_integer; +export using .::stdlib_1_7 import mx_ifgreatereq_color3; +export using .::stdlib_1_7 import mx_ifgreatereq_color4; +export using .::stdlib_1_7 import mx_ifgreatereq_vector2; +export using .::stdlib_1_7 import mx_ifgreatereq_vector3; +export using .::stdlib_1_7 import mx_ifgreatereq_vector4; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix33; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix44; +export using .::stdlib_1_7 import mx_ifgreatereq_boolean; +export using .::stdlib_1_7 import mx_ifgreatereq_floatI; +export using .::stdlib_1_7 import mx_ifgreatereq_integerI; +export using .::stdlib_1_7 import mx_ifgreatereq_color3I; +export using .::stdlib_1_7 import mx_ifgreatereq_color4I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector2I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector3I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector4I; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix33I; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix44I; +export using .::stdlib_1_7 import mx_ifgreatereq_booleanI; +export using .::stdlib_1_7 import mx_ifequal_float; +export using .::stdlib_1_7 import mx_ifequal_integer; +export using .::stdlib_1_7 import mx_ifequal_color3; +export using .::stdlib_1_7 import mx_ifequal_color4; +export using .::stdlib_1_7 import mx_ifequal_vector2; +export using .::stdlib_1_7 import mx_ifequal_vector3; +export using .::stdlib_1_7 import mx_ifequal_vector4; +export using .::stdlib_1_7 import mx_ifequal_matrix33; +export using .::stdlib_1_7 import mx_ifequal_matrix44; +export using .::stdlib_1_7 import mx_ifequal_boolean; +export using .::stdlib_1_7 import mx_ifequal_floatI; +export using .::stdlib_1_7 import mx_ifequal_integerI; +export using .::stdlib_1_7 import mx_ifequal_color3I; +export using .::stdlib_1_7 import mx_ifequal_color4I; +export using .::stdlib_1_7 import mx_ifequal_vector2I; +export using .::stdlib_1_7 import mx_ifequal_vector3I; +export using .::stdlib_1_7 import mx_ifequal_vector4I; +export using .::stdlib_1_7 import mx_ifequal_matrix33I; +export using .::stdlib_1_7 import mx_ifequal_matrix44I; +export using .::stdlib_1_7 import mx_ifequal_booleanI; +export using .::stdlib_1_7 import mx_ifequal_floatB; +export using .::stdlib_1_7 import mx_ifequal_integerB; +export using .::stdlib_1_7 import mx_ifequal_color3B; +export using .::stdlib_1_7 import mx_ifequal_color4B; +export using .::stdlib_1_7 import mx_ifequal_vector2B; +export using .::stdlib_1_7 import mx_ifequal_vector3B; +export using .::stdlib_1_7 import mx_ifequal_vector4B; +export using .::stdlib_1_7 import mx_ifequal_matrix33B; +export using .::stdlib_1_7 import mx_ifequal_matrix44B; +export using .::stdlib_1_7 import mx_ifequal_booleanB; +export using .::stdlib_1_7 import mx_creatematrix_vector3_matrix33; +export using .::stdlib_1_7 import mx_creatematrix_vector3_matrix44; +export using .::stdlib_1_7 import mx_creatematrix_vector4_matrix44; +export using .::stdlib_1_7 import mx_extract_color3; +export using .::stdlib_1_7 import mx_extract_color4; +export using .::stdlib_1_7 import mx_extract_vector2; +export using .::stdlib_1_7 import mx_extract_vector3; +export using .::stdlib_1_7 import mx_extract_vector4; +export using .::stdlib_1_7 import mx_blur_float; +export using .::stdlib_1_7 import mx_blur_color3; +export using .::stdlib_1_7 import mx_blur_color4; +export using .::stdlib_1_7 import mx_blur_vector2; +export using .::stdlib_1_7 import mx_blur_vector3; +export using .::stdlib_1_7 import mx_blur_vector4; +export using .::stdlib_1_7 import mx_heighttonormal_vector3; +export using .::stdlib_1_7 import mx_noise2d_float; +export using .::stdlib_1_7 import mx_noise2d_float2; +export using .::stdlib_1_7 import mx_noise2d_float3; +export using .::stdlib_1_7 import mx_noise2d_float4; +export using .::stdlib_1_7 import mx_noise3d_float; +export using .::stdlib_1_7 import mx_noise3d_float2; +export using .::stdlib_1_7 import mx_noise3d_float3; +export using .::stdlib_1_7 import mx_noise3d_float4; +export using .::stdlib_1_7 import mx_fractal3d_float; +export using .::stdlib_1_7 import mx_fractal3d_float2; +export using .::stdlib_1_7 import mx_fractal3d_float3; +export using .::stdlib_1_7 import mx_fractal3d_float4; +export using .::stdlib_1_7 import mx_cellnoise2d_float; +export using .::stdlib_1_7 import mx_cellnoise3d_float; +export using .::stdlib_1_7 import mx_worleynoise2d_float; +export using .::stdlib_1_7 import mx_worleynoise2d_float2; +export using .::stdlib_1_7 import mx_worleynoise2d_float3; +export using .::stdlib_1_7 import mx_worleynoise3d_float; +export using .::stdlib_1_7 import mx_worleynoise3d_float2; +export using .::stdlib_1_7 import mx_worleynoise3d_float3; +export using .::stdlib_1_7 import mx_combine2_color4CF; + +export using .::stdlib_1_7 import mx_geompropvalue_string; +export using .::stdlib_1_8 import mx_geompropvalue_boolean; +export using .::stdlib_1_8 import mx_geompropvalue_integer; +export using .::stdlib_1_8 import mx_geompropvalue_float; +export using .::stdlib_1_8 import mx_geompropvalue_color3; +export using .::stdlib_1_8 import mx_geompropvalue_color4; +export using .::stdlib_1_8 import mx_geompropvalue_vector2; +export using .::stdlib_1_8 import mx_geompropvalue_vector3; +export using .::stdlib_1_8 import mx_geompropvalue_vector4; +export using .::stdlib_1_8 import mx_viewdirection_vector3; + + + +// mix all parts of the material, bsdf, edf, and vdf, geometry +export material mx_mix_surfaceshader( + material mxp_fg = material() [[ anno::usage( "materialx:surfaceshader") ]], + material mxp_bg = material() [[ anno::usage( "materialx:surfaceshader") ]], + float mxp_mix = 0.0 +) [[ + anno::description("Node Group: compositing"), + anno::usage( "materialx:surfaceshader") +]] += material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mxp_mix, + layer: mxp_fg.surface.scattering, + base: mxp_bg.surface.scattering + ), + emission: material_emission( + emission: df::clamped_mix( + df::edf_component[]( + df::edf_component( mxp_mix, mxp_fg.surface.emission.emission), + df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission)) + ), + intensity: mxp_mix * mxp_fg.surface.emission.intensity + + (1.0 - mxp_mix) * mxp_bg.surface.emission.intensity + ) + ), + + // we need to carry volume properties along for SSS + ior: mxp_mix * mxp_fg.ior + (1.0 - mxp_mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component( mxp_mix, mxp_fg.volume.scattering), + df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mxp_mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mxp_mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: mxp_mix * mxp_fg.volume.scattering_coefficient + + (1.0 - mxp_mix) * mxp_bg.volume.scattering_coefficient + ), + geometry: material_geometry( + displacement: mxp_mix * mxp_fg.geometry.displacement + + (1.0 - mxp_mix) * mxp_bg.geometry.displacement, + cutout_opacity: mxp_mix * mxp_fg.geometry.cutout_opacity + + (1.0 - mxp_mix) * mxp_bg.geometry.cutout_opacity, + normal: mxp_mix * mxp_fg.geometry.normal + + (1.0 - mxp_mix) * mxp_bg.geometry.normal + ) +); diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index e1a23cf7d4..638a4fd10c 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -225,15 +225,9 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so moduleToTest = moduleToTest.substr(0, moduleToTest.size() - sourceCodePaths[0].getExtension().length() - 1); std::string renderExec(MATERIALX_MDL_RENDER_EXECUTABLE); - bool testMDLC = renderExec.empty(); - if (testMDLC) + std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); + if (!mdlcExec.empty()) // always run compiler { - std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); - if (mdlcExec.empty()) - { - return; - } - std::string mdlcCommand = mdlcExec; // use the same paths as the resolver @@ -264,12 +258,19 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so _logFile << "\tReturn code: " << std::to_string(returnValue) << std::endl; writeErrorCode = true; } - _logFile << "\tError: " << line << std::endl; + if (line.find(": Warning ") != std::string::npos) + { + _logFile << "\tWarning: " << line << std::endl; + } + else + { + _logFile << "\tError: " << line << std::endl; + } } CHECK(returnValue == 0); } - else + if (!renderExec.empty()) // render if renderer is availabe { std::string renderCommand = renderExec; @@ -358,6 +359,7 @@ TEST_CASE("GenShader: MDL Shader Generation", "[genmdl]") mx::FilePathVec testRootPaths; testRootPaths.push_back(searchPath.find("resources/Materials/TestSuite")); testRootPaths.push_back(searchPath.find("resources/Materials/Examples/StandardSurface")); + testRootPaths.push_back(searchPath.find("resources/Materials/Examples/UsdPreviewSurface")); const mx::FilePath logPath("genmdl_mdl_generate_test.txt"); From 6fd2dc2f3ebea66afa705c24cc795aa9e8f64420 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 25 Nov 2024 14:03:35 -0800 Subject: [PATCH 116/137] Remove unimplemented nodes from libraries (#2120) This changelist removes the unimplemented 'ambientocclusion', 'arrayappend', and 'curveadjust' nodes from the MaterialX data libraries, aligning the data libraries with the current 1.39 specification. Additionally, this change removes hardcoded skip count checks from MaterialXTest, as these tests have not proven themselves to be a beneficial safeguard against regressions, and frequently trip up contributors to the MaterialX project. --- libraries/README.md | 3 -- .../stdlib/genglsl/stdlib_genglsl_impl.mtlx | 6 --- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 7 --- .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 4 -- .../genosl/mx_ambientocclusion_float.osl | 5 -- .../stdlib/genosl/stdlib_genosl_impl.mtlx | 7 --- libraries/stdlib/stdlib_defs.mtlx | 53 ------------------- python/Scripts/genmdl.py | 8 +-- .../mdl/materialx/stdlib_1_6.mdl | 17 ------ .../mdl/materialx/stdlib_1_8.mdl | 1 - .../mdl/materialx/stdlib_1_9.mdl | 1 - .../MaterialXGenGlsl/GenGlsl.cpp | 2 +- .../MaterialXTest/MaterialXGenGlsl/GenGlsl.h | 2 +- .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 2 +- source/MaterialXTest/MaterialXGenMdl/GenMdl.h | 2 +- .../MaterialXTest/MaterialXGenMsl/GenMsl.cpp | 2 +- source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 2 +- .../MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 2 +- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 2 +- .../MaterialXGenShader/GenShaderUtil.cpp | 6 +-- .../MaterialXGenShader/GenShaderUtil.h | 3 +- .../MaterialXRenderOsl/GenReference.cpp | 3 +- 22 files changed, 12 insertions(+), 128 deletions(-) delete mode 100644 libraries/stdlib/genosl/mx_ambientocclusion_float.osl diff --git a/libraries/README.md b/libraries/README.md index 15916f76e2..0ace221bcc 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -74,7 +74,4 @@ This folder contains the standard data libraries for MaterialX, providing declar - Basic GLSL and MSL `lightshader` node definitions and implementations are provided for the following light types: - point, directional, spot - Shader generation does not currently support: - - `ambientocclusion` node. - - `arrayappend` node. - - `curveadjust` node. - `displacementshader` and `volumeshader` nodes for hardware shading targets (GLSL, MSL). diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index 69f8f9a7f8..ad3a21e9cf 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -129,12 +129,6 @@ - - - - - - diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index b190937c41..6ac2b862dd 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -131,13 +131,6 @@ - - - - - - - diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index afdfb2cfbb..3cb99052cf 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -45,10 +45,6 @@ - - - - diff --git a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl b/libraries/stdlib/genosl/mx_ambientocclusion_float.osl deleted file mode 100644 index 10baf0b736..0000000000 --- a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_ambientocclusion_float(float coneangle, float maxdistance, output float result) -{ - // This node is a stub and does not currently operate to specification - result = 0; -} diff --git a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx index 716e1072d7..db318976c5 100644 --- a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -131,13 +131,6 @@ - - - - - - - diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 943e36ec88..e6f8d431e7 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -1354,21 +1354,6 @@ - - - - - - - - - - - @@ -2899,44 +2884,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp index b77eebbd86..a72207c581 100644 --- a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp +++ b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp @@ -37,51 +37,6 @@ void ClosureLayerNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& ShaderNode* top = topInput->getConnection()->getNode(); ShaderNode* base = baseInput->getConnection()->getNode(); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - ClosureContext* cct = context.getClosureContext(); - - // Evaluate top and base nodes and combine their result - // according to throughput. - // - // TODO: In the BSDF over BSDF case should we emit code - // to check the top throughput amount before calling - // the base BSDF? - - // Make sure the connections are sibling nodes and not the graph interface. - if (top->getParent() == node.getParent()) - { - // If this layer node has closure parameters set, - // we pass this on to the top component only. - ScopedSetClosureParams setParams(&node, top, cct); - shadergen.emitFunctionCall(*top, context, stage); - } - if (base->getParent() == node.getParent()) - { - shadergen.emitFunctionCall(*base, context, stage); - } - - // Get the result variables. - const string& topResult = topInput->getConnection()->getVariable(); - const string& baseResult = baseInput->getConnection()->getVariable(); - - // Calculate the layering result. - emitOutputVariables(node, context, stage); - if (base->getOutput()->getType() == Type::VDF) - { - // Combining a surface closure with a volumetric closure is simply done with the add operator in OSL. - shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult, stage); - // Just pass the throughput along. - shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput", stage); - } - else - { - shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult + ".response * " + topResult + ".throughput", stage); - shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput * " + baseResult + ".throughput", stage); - } - -#else - // Emit the function call for top and base layer. // Make sure the connections are sibling nodes and not the graph interface. if (top->getParent() == node.getParent()) @@ -102,8 +57,6 @@ void ClosureLayerNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& shadergen.emitOutput(output, true, false, context, stage); shadergen.emitString(" = layer(" + topResult + ", " + baseResult + ")", stage); shadergen.emitLineEnd(stage); - -#endif // MATERIALX_OSL_LEGACY_CLOSURES } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index d0d9d96cba..ff8cad36f5 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -45,22 +45,6 @@ OslShaderGenerator::OslShaderGenerator() : registerImplementation("IM_layer_bsdf_" + OslShaderGenerator::TARGET, ClosureLayerNodeOsl::create); registerImplementation("IM_layer_vdf_" + OslShaderGenerator::TARGET, ClosureLayerNodeOsl::create); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - // - registerImplementation("IM_mix_bsdf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - registerImplementation("IM_mix_edf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - // - registerImplementation("IM_add_bsdf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - registerImplementation("IM_add_edf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - // - registerImplementation("IM_multiply_bsdfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_bsdfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - -#endif // MATERIALX_OSL_LEGACY_CLOSURES - // registerImplementation("IM_surface_" + OslShaderGenerator::TARGET, SurfaceNodeOsl::create); @@ -158,10 +142,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G const bool isSurfaceShaderOutput = singleOutput && singleOutput->getType() == Type::SURFACESHADER; -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - const bool isBsdfOutput = singleOutput && singleOutput->getType() == Type::BSDF; -#endif - if (isSurfaceShaderOutput) { // Special case for having 'surfaceshader' as final output type. @@ -170,16 +150,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G // to understand this output. emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); - } -#endif else { // Just emit all outputs the way they are declared. @@ -253,18 +223,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G emitLine(singleOutput->getVariable() + " = (" + result + ".bsdf + " + result + ".edf) * opacity_weight + transparent() * (1.0 - opacity_weight)", stage); emitScopeEnd(stage); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - const ShaderGraphOutputSocket* socket = graph.getOutputSocket(0); - const string result = getUpstreamResult(socket, context); - emitLine(singleOutput->getVariable() + " = " + result + ".response", stage); - } -#endif else { // Assign results to final outputs. diff --git a/source/MaterialXGenOsl/OslSyntax.cpp b/source/MaterialXGenOsl/OslSyntax.cpp index 797a891ce6..a85821c4fd 100644 --- a/source/MaterialXGenOsl/OslSyntax.cpp +++ b/source/MaterialXGenOsl/OslSyntax.cpp @@ -371,19 +371,6 @@ OslSyntax::OslSyntax() EMPTY_STRING, "struct textureresource { string filename; string colorspace; };")); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - registerTypeSyntax( - Type::BSDF, - std::make_shared( - "BSDF", - "BSDF(null_closure, color(1.0))", - "{ 0, color(1.0) }", - "closure color", - "struct BSDF { closure color response; color throughput; };")); - -#else - registerTypeSyntax( Type::BSDF, std::make_shared( @@ -393,8 +380,6 @@ OslSyntax::OslSyntax() "closure color", "#define BSDF closure color")); -#endif // MATERIALX_OSL_LEGACY_CLOSURES - registerTypeSyntax( Type::EDF, std::make_shared( diff --git a/source/MaterialXTest/CMakeLists.txt b/source/MaterialXTest/CMakeLists.txt index 4835787ed8..c3fae603dc 100644 --- a/source/MaterialXTest/CMakeLists.txt +++ b/source/MaterialXTest/CMakeLists.txt @@ -96,11 +96,6 @@ endif() add_custom_command(TARGET MaterialXTest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/../../libraries ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries) -if(MATERIALX_OSL_LEGACY_CLOSURES) - add_custom_command(TARGET MaterialXTest POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx) -endif() if(MATERIALX_BUILD_GEN_MDL) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../source/MaterialXGenMdl/mdl/" From 344705f0214332a8b7199832ff90aefb9b054200 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Tue, 26 Nov 2024 12:49:28 -0500 Subject: [PATCH 118/137] Fix mxvalidate to check for stdlib usage (#2122) Patch `mxvalidate.py` script to avoid trying to access an undefined object `stdlib` if not specified from the command line (default). --- python/Scripts/mxvalidate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/Scripts/mxvalidate.py b/python/Scripts/mxvalidate.py index 8cc1ee78fd..e0ccf34a4e 100755 --- a/python/Scripts/mxvalidate.py +++ b/python/Scripts/mxvalidate.py @@ -17,6 +17,7 @@ def main(): opts = parser.parse_args() # Load standard libraries if requested. + stdlib = None if opts.stdlib: stdlib = mx.createDocument() try: @@ -29,7 +30,8 @@ def main(): doc = mx.createDocument() try: mx.readFromXmlFile(doc, opts.inputFilename) - doc.setDataLibrary(stdlib) + if stdlib: + doc.setDataLibrary(stdlib) except mx.ExceptionFileMissing as err: print(err) sys.exit(0) From cbb63ec82de7be3cea6bc0c85f12223be1e87d5e Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 26 Nov 2024 16:26:27 -0800 Subject: [PATCH 119/137] Update MacOS version in GitHub CI (#2123) This changelist updates Python wheel generation to the `macos-14-large` environment in GitHub CI, as Python versions before 3.11 have been removed from the `macos-13` environment. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b2d5f182bf..3f67667550 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -389,7 +389,7 @@ jobs: fail-fast: false matrix: python-minor: ['7', '8', '9', '10', '11', '12'] - os: ['ubuntu-22.04', 'windows-2022', 'macos-13'] + os: ['ubuntu-22.04', 'windows-2022', 'macos-14-large'] steps: - name: Sync Repository From b6d473d01edcf2b61291e22f09ac182c32555a68 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 3 Dec 2024 17:28:54 -0800 Subject: [PATCH 120/137] Update changelog for recent work (#2129) --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fedc1ceaa..6fb0c98143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ ## [1.39.2] - Development +### Added +- Added support for the [Chiang Hair BSDF](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1968), with initial implementations in hardware shading languages and MDL. +- Added support for the [Disney Principled](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2004) shading model, implemented as a language-independent graph. +- Added support for [data library referencing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2054), enabling improved performance in shader generation. +- Added support for [custom structure types](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1831) in MaterialX. +- Added support for [functional equivalence](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2003) tests between MaterialX elements. +- Added support for [transmission effects](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2027) in the translation graph from Standard Surface to glTF PBR. +- Added support for [coated emission](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2087) in the translation graph from Standard Surface to UsdPreviewSurface. +- Added support for [Apple framework builds](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2020). +- Added support for [MDL 1.9](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2102) in shader generation. +- Added support for [viewdirection space](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2036) in hardware shading languages. +- Added a [combined version define](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2031) to MaterialX C++. +- Added a [release signing workflow](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2009) to GitHub Actions. +- Added documentation for [keyboard shortcuts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2026) in the MaterialX Viewer. + +### Changed +- Reduced duplication between the [MSL and GLSL implementations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2068) of nodes. + +### Fixed +- Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. +- Fixed [banding artifacts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1977) in the MaterialX Viewer on MacOS. +- Fixed a call to the [anisotropic_vdf closure](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2016) in OSL shader generation. + +### Removed +- Removed support for the [legacy OSL closures](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2121), focusing exclusively on the MaterialX-synchronized closures in OSL 1.12 and beyond. + ## [1.39.1] - 2024-09-03 ### Added From bfbf6729385a7820dc2ab00332b30b93eff6a3e8 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 4 Dec 2024 10:36:45 -0800 Subject: [PATCH 121/137] Static analysis fixes (#2130) This changelist addresses a handful of static analysis warnings flagged by PVS-Studio: - Add a missing reference to `rhs` in `ValueElement::isAttributeEquivalent`. - Remove unused variables and unneeded string copies in `StructTypeSyntax::getValue` and `GlslStructTypeSyntax::getValue`. - Simplify boolean logic in `ClosureLayerNodeMdl::emitFunctionCall`. - Declare an immutable array as a `std::array` in `Viewer::createDocumentationInterface`. --- source/MaterialXCore/Element.cpp | 2 +- source/MaterialXGenGlsl/GlslSyntax.cpp | 4 ++-- source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp | 2 +- source/MaterialXGenShader/Syntax.cpp | 7 ++----- source/MaterialXView/Viewer.cpp | 2 +- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 3bede2fe74..78c59e9efc 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -749,7 +749,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr else if (uiAttributes.find(attributeName) != uiAttributes.end()) { const string& uiAttribute = getAttribute(attributeName); - const string& rhsUiAttribute = getAttribute(attributeName); + const string& rhsUiAttribute = rhs->getAttribute(attributeName); ValuePtr uiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(uiAttribute, getType()) : nullptr; ValuePtr rhsUiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(rhsUiAttribute, getType()) : nullptr; if (uiValue && rhsUiValue) diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp index 651a4ab5ff..7054725b76 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.cpp +++ b/source/MaterialXGenGlsl/GlslSyntax.cpp @@ -400,8 +400,8 @@ string GlslStructTypeSyntax::getValue(const Value& value, bool /* uniform */) co result += separator; separator = ","; - auto memberTypeName = memberValue->getTypeString(); - auto memberTypeDesc = TypeDesc::get(memberTypeName); + const string& memberTypeName = memberValue->getTypeString(); + TypeDesc memberTypeDesc = TypeDesc::get(memberTypeName); // Recursively use the syntax to generate the output, so we can supported nested structs. result += _parentSyntax->getValue(memberTypeDesc, *memberValue, true); diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index 8949ae6cc0..5b187f80aa 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -128,7 +128,7 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& ShaderNode* fg = fgOutput ? fgOutput->getNode() : nullptr; ShaderNode* bg = bgOutput ? bgOutput->getNode() : nullptr; ShaderNode* mix = mixOutput ? mixOutput->getNode() : nullptr; - if ((fg && !bg) || (!fg && bg)) + if ((bool) fg != (bool) bg) { baseReceiverNode = fg ? fg : bg; // take the node that is valid top = baseReceiverNode; diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index b8eed3e9b8..81daa9e0a7 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -286,9 +286,6 @@ string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const { const AggregateValue& aggValue = static_cast(value); - auto typeDesc = TypeDesc::get(aggValue.getTypeString()); - auto structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); - string result = "{"; string separator = ""; @@ -297,8 +294,8 @@ string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const result += separator; separator = ";"; - auto memberTypeName = memberValue->getTypeString(); - auto memberTypeDesc = TypeDesc::get(memberTypeName); + const string& memberTypeName = memberValue->getTypeString(); + TypeDesc memberTypeDesc = TypeDesc::get(memberTypeName); // Recursively use the syntax to generate the output, so we can support nested structs. const string valueStr = _parentSyntax->getValue(memberTypeDesc, *memberValue, true); diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 46d03a1665..aefdf2d401 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -702,7 +702,7 @@ void Viewer::createDocumentationInterface(ng::ref parent) ng::Alignment::Minimum, 2, 2); gridLayout2->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); - const std::vector> KEYBOARD_SHORTCUTS = + const std::array, 16> KEYBOARD_SHORTCUTS = { std::make_pair("R", "Reload the current material from file. " "Hold SHIFT to reload all standard libraries as well."), From f9a4222c8251c1d8bf808e5a705f74b72531bb88 Mon Sep 17 00:00:00 2001 From: JGamache-autodesk <56274617+JGamache-autodesk@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:28:45 -0500 Subject: [PATCH 122/137] Consider subsurface color in dielectric albedo (#2105) I am experimenting with OpenPBR to UsdPreviewSurface export code in Maya and tried chaining the two translator graphs already provided in MaterialX. Results are quite good, except when the subsurface color is extremely different from the base color. This can be fixed by computing a dielectric base albedo that mixes the scaled base color and the subsurface color. --- libraries/bxdf/translation/standard_surface_to_usd.mtlx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/bxdf/translation/standard_surface_to_usd.mtlx b/libraries/bxdf/translation/standard_surface_to_usd.mtlx index 51c7d5fc6e..f1009e3a4c 100644 --- a/libraries/bxdf/translation/standard_surface_to_usd.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_usd.mtlx @@ -12,6 +12,8 @@ + + @@ -47,13 +49,18 @@
+ + + + + - + From bf2804d21aae379937ebbefcef62f62c9604dc0b Mon Sep 17 00:00:00 2001 From: samip Date: Wed, 4 Dec 2024 17:13:56 -0800 Subject: [PATCH 123/137] Fix handling of missing scenes in the Web Viewer (#2124) JsViewerX attempted to use a cube when the selected GLTF file contained no model, but the code never added it to the scene. --- javascript/MaterialXView/source/viewer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index febe34c809..e558ad0bc9 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -90,14 +90,14 @@ export class Scene } this.#_rootNode = null; - const model = gltfData.scene; + let model = gltfData.scene; if (!model) { const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0xdddddd }); const cube = new THREE.Mesh(geometry, material); - obj = new Group(); - obj.add(geometry); + model = new Group(); + model.add(cube); } else { From f0f9eacd83cf60851882293a413b3077941f277a Mon Sep 17 00:00:00 2001 From: Krzysztof Jakubowski Date: Fri, 6 Dec 2024 00:33:20 +0100 Subject: [PATCH 124/137] Improve performance of graph traversal (#2023) In complex materials graph and shader graph edge iteration can be extremely slow, because some edges may be visited unnecessarily multiple times. This is especially noticeable in two functions: ShaderGraph::addUpstreamDependencies and ShaderGraph::optimize. This changelist optimizes graph edge iteration by marking and skipping edges that have previously been visited. --- source/MaterialXCore/Traversal.cpp | 10 ++++++++-- source/MaterialXCore/Traversal.h | 2 ++ source/MaterialXGenShader/ShaderGraph.cpp | 12 +++++++++--- source/MaterialXGenShader/ShaderGraph.h | 18 ++++++++++++++++++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/source/MaterialXCore/Traversal.cpp b/source/MaterialXCore/Traversal.cpp index c78b5825d4..285083da2e 100644 --- a/source/MaterialXCore/Traversal.cpp +++ b/source/MaterialXCore/Traversal.cpp @@ -113,7 +113,7 @@ GraphIterator& GraphIterator::operator++() // Traverse to the first upstream edge of this element. _stack.emplace_back(_upstreamElem, 0); Edge nextEdge = _upstreamElem->getUpstreamEdge(0); - if (nextEdge && nextEdge.getUpstreamElement()) + if (nextEdge && nextEdge.getUpstreamElement() && !skipOrMarkAsVisited(nextEdge)) { extendPathUpstream(nextEdge.getUpstreamElement(), nextEdge.getConnectingElement()); return *this; @@ -140,7 +140,7 @@ GraphIterator& GraphIterator::operator++() if (parentFrame.second + 1 < parentFrame.first->getUpstreamEdgeCount()) { Edge nextEdge = parentFrame.first->getUpstreamEdge(++parentFrame.second); - if (nextEdge && nextEdge.getUpstreamElement()) + if (nextEdge && nextEdge.getUpstreamElement() && !skipOrMarkAsVisited(nextEdge)) { extendPathUpstream(nextEdge.getUpstreamElement(), nextEdge.getConnectingElement()); return *this; @@ -177,6 +177,12 @@ void GraphIterator::returnPathDownstream(ElementPtr upstreamElem) _connectingElem = ElementPtr(); } +bool GraphIterator::skipOrMarkAsVisited(const Edge& edge) +{ + auto [it, inserted] = _visitedEdges.emplace(edge); + return !inserted; +} + // // InheritanceIterator methods // diff --git a/source/MaterialXCore/Traversal.h b/source/MaterialXCore/Traversal.h index a22d909cbe..08dcdaeaf8 100644 --- a/source/MaterialXCore/Traversal.h +++ b/source/MaterialXCore/Traversal.h @@ -316,12 +316,14 @@ class MX_CORE_API GraphIterator private: void extendPathUpstream(ElementPtr upstreamElem, ElementPtr connectingElem); void returnPathDownstream(ElementPtr upstreamElem); + bool skipOrMarkAsVisited(const Edge&); private: ElementPtr _upstreamElem; ElementPtr _connectingElem; ElementSet _pathElems; vector _stack; + std::set _visitedEdges; bool _prune; size_t _holdCount; }; diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index e9a3b50b79..8cc71567e4 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -916,7 +916,7 @@ void ShaderGraph::optimize() ShaderOutput* upstreamPort = outputSocket->getConnection(); if (upstreamPort && upstreamPort->getNode() != this) { - for (ShaderGraphEdge edge : ShaderGraph::traverseUpstream(upstreamPort)) + for (ShaderGraphEdge edge : traverseUpstream(upstreamPort)) { ShaderNode* node = edge.upstream->getNode(); if (usedNodesSet.count(node) == 0) @@ -1206,7 +1206,7 @@ ShaderGraphEdgeIterator& ShaderGraphEdgeIterator::operator++() ShaderInput* input = _upstream->getNode()->getInput(0); ShaderOutput* output = input->getConnection(); - if (output && !output->getNode()->isAGraph()) + if (output && !output->getNode()->isAGraph() && !skipOrMarkAsVisited({ output, input })) { extendPathUpstream(output, input); return *this; @@ -1234,7 +1234,7 @@ ShaderGraphEdgeIterator& ShaderGraphEdgeIterator::operator++() ShaderInput* input = parentFrame.first->getNode()->getInput(++parentFrame.second); ShaderOutput* output = input->getConnection(); - if (output && !output->getNode()->isAGraph()) + if (output && !output->getNode()->isAGraph() && !skipOrMarkAsVisited({ output, input })) { extendPathUpstream(output, input); return *this; @@ -1275,4 +1275,10 @@ void ShaderGraphEdgeIterator::returnPathDownstream(ShaderOutput* upstream) _downstream = nullptr; } +bool ShaderGraphEdgeIterator::skipOrMarkAsVisited(ShaderGraphEdge edge) +{ + auto [it, inserted] = _visitedEdges.emplace(edge); + return !inserted; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/ShaderGraph.h b/source/MaterialXGenShader/ShaderGraph.h index 6320d04296..77fd090b66 100644 --- a/source/MaterialXGenShader/ShaderGraph.h +++ b/source/MaterialXGenShader/ShaderGraph.h @@ -209,6 +209,22 @@ class MX_GENSHADER_API ShaderGraphEdge downstream(down) { } + + bool operator==(const ShaderGraphEdge& rhs) const + { + return upstream == rhs.upstream && downstream == rhs.downstream; + } + + bool operator!=(const ShaderGraphEdge& rhs) const + { + return !(*this == rhs); + } + + bool operator<(const ShaderGraphEdge& rhs) const + { + return std::tie(upstream, downstream) < std::tie(rhs.upstream, rhs.downstream); + } + ShaderOutput* upstream; ShaderInput* downstream; }; @@ -254,12 +270,14 @@ class MX_GENSHADER_API ShaderGraphEdgeIterator private: void extendPathUpstream(ShaderOutput* upstream, ShaderInput* downstream); void returnPathDownstream(ShaderOutput* upstream); + bool skipOrMarkAsVisited(ShaderGraphEdge); ShaderOutput* _upstream; ShaderInput* _downstream; using StackFrame = std::pair; std::vector _stack; std::set _path; + std::set _visitedEdges; }; MATERIALX_NAMESPACE_END From 9fcef07612dd1dfceb4293e2e5eb7074a3956418 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Thu, 5 Dec 2024 23:08:57 -0500 Subject: [PATCH 125/137] Allow for choice of font in Graph Editor (#2046) Allow the user to specify a true-type font file and size from the command line. --- source/MaterialXGraphEditor/Main.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/source/MaterialXGraphEditor/Main.cpp b/source/MaterialXGraphEditor/Main.cpp index 38c755cdd9..0c550dbdd1 100644 --- a/source/MaterialXGraphEditor/Main.cpp +++ b/source/MaterialXGraphEditor/Main.cpp @@ -30,6 +30,8 @@ const std::string options = " --path [FILEPATH] Specify an additional data search path location (e.g. '/projects/MaterialX'). This absolute path will be queried when locating data libraries, XInclude references, and referenced images.\n" " --library [FILEPATH] Specify an additional data library folder (e.g. 'vendorlib', 'studiolib'). This relative path will be appended to each location in the data search path when loading data libraries.\n" " --uiScale [FACTOR] Manually specify a UI scaling factor\n" + " --font [FILENAME] Specify the name of the custom font file to use. If not specified the default font will be used.\n" + " --fontSize [SIZE] Specify font size to use for the custom font. If not specified a default of 18 will be used.\n" " --captureFilename [FILENAME] Specify the filename to which the first rendered frame should be written\n" " --help Display the complete list of command-line options\n"; @@ -67,6 +69,8 @@ int main(int argc, char* const argv[]) int viewWidth = 256; int viewHeight = 256; float uiScale = 0.0f; + std::string fontFilename; + int fontSize = 18; std::string captureFilename; for (size_t i = 0; i < tokens.size(); i++) @@ -102,6 +106,14 @@ int main(int argc, char* const argv[]) { parseToken(nextToken, "float", uiScale); } + else if (token == "--font") + { + parseToken(nextToken, "string", fontFilename); + } + else if (token == "--fontSize") + { + parseToken(nextToken, "integer", fontSize); + } else if (token == "--captureFilename") { parseToken(nextToken, "string", captureFilename); @@ -172,7 +184,15 @@ int main(int argc, char* const argv[]) io.IniFilename = NULL; io.LogFilename = NULL; - io.Fonts->AddFontDefault(); + ImFont* customFont = nullptr; + if (!fontFilename.empty()) + { + customFont = io.Fonts->AddFontFromFileTTF(fontFilename.c_str(), fontSize); + } + if (!customFont) + { + io.Fonts->AddFontDefault(); + } // Setup Dear ImGui style ImGui::StyleColorsDark(); From 142460efb8f1d788b530fbbf5ba93fb26f06046a Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 6 Dec 2024 15:01:27 -0800 Subject: [PATCH 126/137] Simplify element equivalence interface (#2133) This changelist simplifies the interface of the Element::isEquivalent method in MaterialX C++, aligning it with the behavior of Element::validate and proposed use cases for element equivalence in JavaScript. --- source/MaterialXCore/Element.cpp | 68 +++++++++++-------- source/MaterialXCore/Element.h | 45 ++---------- .../MaterialXTest/MaterialXCore/Document.cpp | 19 ++---- .../PyMaterialX/PyMaterialXCore/PyElement.cpp | 18 +---- 4 files changed, 55 insertions(+), 95 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 78c59e9efc..5d0cf693d0 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -39,12 +39,6 @@ const string ValueElement::UI_ADVANCED_ATTRIBUTE = "uiadvanced"; const string ValueElement::UNIT_ATTRIBUTE = "unit"; const string ValueElement::UNITTYPE_ATTRIBUTE = "unittype"; const string ValueElement::UNIFORM_ATTRIBUTE = "uniform"; -const string ElementEquivalenceResult::ATTRIBUTE = "attribute"; -const string ElementEquivalenceResult::ATTRIBUTE_NAMES = "attribute names"; -const string ElementEquivalenceResult::CHILD_COUNT = "child count"; -const string ElementEquivalenceResult::CHILD_NAME = "child name"; -const string ElementEquivalenceResult::NAME = "name"; -const string ElementEquivalenceResult::CATEGORY = "category"; Element::CreatorMap Element::_creatorMap; @@ -375,19 +369,22 @@ bool Element::hasInheritanceCycle() const return false; } -bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, - ElementEquivalenceResultVec* results) const +bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, string* message) const { if (getName() != rhs->getName()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::NAME)); + if (message) + { + *message += "Name of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } if (getCategory() != rhs->getCategory()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::CATEGORY)); + if (message) + { + *message += "Category of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } @@ -413,14 +410,16 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& if (attributeNames != rhsAttributeNames) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE_NAMES)); + if (message) + { + *message += "Attribute names of '" + getNamePath() + "' differ from '" + rhs->getNamePath() + "\n"; + } return false; } for (const string& attr : rhsAttributeNames) { - if (!isAttributeEquivalent(rhs, attr, options, results)) + if (!isAttributeEquivalent(rhs, attr, options, message)) { return false; } @@ -447,8 +446,10 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& } if (children.size() != rhsChildren.size()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::CHILD_COUNT)); + if (message) + { + *message += "Child count of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } for (size_t i = 0; i < children.size(); i++) @@ -468,26 +469,29 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& rhsElement = rhs->getChild(childName); if (!rhsElement) { - if (results) - results->push_back(ElementEquivalenceResult(children[i]->getNamePath(), "", - ElementEquivalenceResult::CHILD_NAME, childName)); + if (message) + { + *message += "Child name `" + childName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } } } - if (!children[i]->isEquivalent(rhsElement, options, results)) + if (!children[i]->isEquivalent(rhsElement, options, message)) return false; } return true; } bool Element::isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, - const ElementEquivalenceOptions& /*options*/, ElementEquivalenceResultVec* results) const + const ElementEquivalenceOptions& /*options*/, string* message) const { if (getAttribute(attributeName) != rhs->getAttribute(attributeName)) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE, attributeName)); + if (message) + { + *message += "Attribute name `" + attributeName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } return true; @@ -710,7 +714,7 @@ const string& ValueElement::getActiveUnit() const } bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, - const ElementEquivalenceOptions& options, ElementEquivalenceResultVec* results) const + const ElementEquivalenceOptions& options, string* message) const { // Perform value comparisons bool performedValueComparison = false; @@ -737,8 +741,10 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr { if (thisValue->getValueString() != rhsValue->getValueString()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE, attributeName)); + if (message) + { + *message += "Attribute `" + attributeName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } } @@ -756,8 +762,10 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr { if (uiValue->getValueString() != rhsUiValue->getValueString()) { - if (results) - results->push_back(ElementEquivalenceResult(getNamePath(), rhs->getNamePath(), ElementEquivalenceResult::ATTRIBUTE, attributeName)); + if (message) + { + *message += "Attribute `" + attributeName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } return false; } } @@ -769,7 +777,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr // If did not peform a value comparison, perform the default comparison if (!performedValueComparison) { - return Element::isAttributeEquivalent(rhs, attributeName, options, results); + return Element::isAttributeEquivalent(rhs, attributeName, options, message); } return true; diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 05eb2235f3..6b145a57b1 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -72,8 +72,6 @@ using ElementMap = std::unordered_map; using ElementPredicate = std::function; class ElementEquivalenceOptions; -class ElementEquivalenceResult; -using ElementEquivalenceResultVec = vector; /// @class Element /// The base class for MaterialX elements. @@ -608,21 +606,21 @@ class MX_CORE_API Element : public std::enable_shared_from_this /// criteria provided. /// @param rhs Element to compare against /// @param options Equivalence criteria - /// @param results Results of comparison if argument is specified. + /// @param message Optional text description of differences /// @return True if the elements are equivalent. False otherwise. - bool isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, - ElementEquivalenceResultVec* results = nullptr) const; + bool isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, + string* message = nullptr) const; /// Return true if the attribute on a given element is equivalent /// based on the equivalence criteria provided. /// @param rhs Element to compare against /// @param attributeName Name of attribute to compare /// @param options Equivalence criteria - /// @param results Results of comparison if argument is specified. + /// @param message Optional text description of differences /// @return True if the attribute on the elements are equivalent. False otherwise. virtual bool isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, const ElementEquivalenceOptions& options, - ElementEquivalenceResultVec* results = nullptr) const; + string* message = nullptr) const; /// @} /// @name Traversal @@ -1125,11 +1123,11 @@ class MX_CORE_API ValueElement : public TypedElement /// @param rhs Element to compare against /// @param attributeName Name of attribute to compare /// @param options Equivalence criteria - /// @param results Results of comparison if argument is specified. + /// @param message Optional text description of differences /// @return True if the attribute on the elements are equivalent. False otherwise. bool isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, const ElementEquivalenceOptions& options, - ElementEquivalenceResultVec* results = nullptr) const override; + string* message = nullptr) const override; /// @} /// @name Validation @@ -1353,35 +1351,6 @@ class MX_CORE_API StringResolver StringMap _geomNameMap; }; -/// @class ElementEquivalenceResult -/// A comparison result for the functional equivalence of two elements. -class MX_CORE_API ElementEquivalenceResult -{ - public: - ElementEquivalenceResult(const string& p1, const string& p2, const string& type, - const string& attrName = EMPTY_STRING) - { - path1 = p1; - path2 = p2; - differenceType = type; - attributeName = attrName; - } - ElementEquivalenceResult() = delete; - ~ElementEquivalenceResult() = default; - - string path1; - string path2; - string differenceType; - string attributeName; - - static const string ATTRIBUTE; - static const string ATTRIBUTE_NAMES; - static const string CHILD_COUNT; - static const string CHILD_NAME; - static const string NAME; - static const string CATEGORY; -}; - /// @class ElementEquivalenceOptions /// A set of options for comparing the functional equivalence of elements. class MX_CORE_API ElementEquivalenceOptions diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index b593969ccb..223aae5694 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -215,17 +215,16 @@ TEST_CASE("Document equivalence", "[document]") comment->setDocString("Comment 3"); mx::ElementEquivalenceOptions options; - mx::ElementEquivalenceResultVec results; + std::string message; // Check that this fails when not performing value comparisons options.performValueComparisons = false; - bool equivalent = doc->isEquivalent(doc2, options, &results); + bool equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(!equivalent); // Check attibute values options.performValueComparisons = true; - results.clear(); - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(equivalent); unsigned int currentPrecision = mx::Value::getFloatPrecision(); @@ -236,14 +235,13 @@ TEST_CASE("Document equivalence", "[document]") options.floatPrecision = currentPrecision; // Check attribute filtering of inputs - results.clear(); options.attributeExclusionList = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; for (mx::InputPtr floatInput : floatInputs) { floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, "0.9"); floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, "100.0"); } - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(equivalent); for (mx::InputPtr floatInput : floatInputs) { @@ -255,12 +253,10 @@ TEST_CASE("Document equivalence", "[document]") mx::ElementPtr mismatchElement = doc->getDescendant("mygraph/input_color4"); std::string previousName = mismatchElement->getName(); mismatchElement->setName("mismatch_color4"); - results.clear(); - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(!equivalent); mismatchElement->setName(previousName); - results.clear(); - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(equivalent); // Check for functional nodegraphs @@ -272,7 +268,6 @@ TEST_CASE("Document equivalence", "[document]") REQUIRE(nodeGraph2); doc2->addNodeDef("ND_mygraph"); nodeGraph2->setNodeDefString("ND_mygraph"); - results.clear(); - equivalent = doc->isEquivalent(doc2, options, &results); + equivalent = doc->isEquivalent(doc2, options, &message); REQUIRE(!equivalent); } diff --git a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp index 004fa0a670..05f858d4c3 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp @@ -31,9 +31,9 @@ void bindPyElement(py::module& mod) .def(py::self != py::self) .def("isEquivalent", [](const mx::Element& elem, mx::ConstElementPtr& rhs, const mx::ElementEquivalenceOptions& options) { - mx::ElementEquivalenceResultVec results; - bool res = elem.isEquivalent(rhs, options, &results); - return std::pair(res, results); + std::string message; + bool res = elem.isEquivalent(rhs, options, &message); + return std::pair(res, message); }) .def("setCategory", &mx::Element::setCategory) .def("getCategory", &mx::Element::getCategory) @@ -211,18 +211,6 @@ void bindPyElement(py::module& mod) py::class_(mod, "GenericElement") .def_readonly_static("CATEGORY", &mx::GenericElement::CATEGORY); - py::class_(mod, "ElementEquivalenceResult") - .def_readonly_static("ATTRIBUTE", &mx::ElementEquivalenceResult::ATTRIBUTE) - .def_readonly_static("ATTRIBUTE_NAMES", &mx::ElementEquivalenceResult::ATTRIBUTE_NAMES) - .def_readonly_static("CHILD_COUNT", &mx::ElementEquivalenceResult::CHILD_COUNT) - .def_readonly_static("CHILD_NAME", &mx::ElementEquivalenceResult::CHILD_NAME) - .def_readonly_static("NAME", &mx::ElementEquivalenceResult::NAME) - .def_readonly_static("CATEGORY", &mx::ElementEquivalenceResult::CATEGORY) - .def_readwrite("path1", &mx::ElementEquivalenceResult::path1) - .def_readwrite("path2", &mx::ElementEquivalenceResult::path2) - .def_readwrite("differenceType", &mx::ElementEquivalenceResult::differenceType) - .def_readwrite("attributeName", &mx::ElementEquivalenceResult::attributeName); - py::class_(mod, "ElementEquivalenceOptions") .def_readwrite("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) .def_readwrite("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) From e7f2840974761a852d856e6637e5901bb7b98f2f Mon Sep 17 00:00:00 2001 From: fnRaihanKibria <45946106+fnRaihanKibria@users.noreply.github.com> Date: Fri, 6 Dec 2024 23:13:18 +0000 Subject: [PATCH 127/137] Add checks for loops being created on nodes (#2029) Addressing issue #1932 The cause of the crash is a buffer overrun in ShaderGraph::topologicalSort() in the line `_nodeOrder[count++] = node;`. This is caused by a loop edge being present on the 'color_mix' node of the graph object this was called on, which made the sort algorithm malfunction. Unfortunately I was unable to determine in the time I have available why this loop is created. I didn't want to add a change that hides the underlying problem, which still needs to be fixed. Instead, this PR adds some checks to two locations in the code that throw exceptions when a case of a loop being created is detected, to aid in fixing the real issue and maybe help diagnosing other problems in the future. With this PR the graph editor does not crash any more, instead an error message "Upstream node 'color_mix' has itself as downstream node, creating a loop" is printed to console. --- source/MaterialXGenShader/ShaderGraph.cpp | 5 +++++ source/MaterialXGenShader/ShaderNode.cpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index 8cc71567e4..a8ec936014 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -138,6 +138,11 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, { // We have a node downstream ShaderNode* downstream = getNode(downstreamNode->getName()); + if (downstream == newNode) + { + throw ExceptionShaderGenError("Upstream node '" + downstream->getName() + "' has itself as downstream node, creating a loop"); + } + if (downstream && connectingElement) { ShaderInput* input = downstream->getInput(connectingElement->getName()); diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index d52810ffc4..12b9bbf548 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -57,6 +57,13 @@ void ShaderInput::makeConnection(ShaderOutput* src) if (src) { // Make the new connection. + if (src->getNode() == getNode() && !getNode()->isAGraph()) + { + throw ExceptionShaderGenError( + "Tried to create looping connection on node " + getNode()->getName() + + " from output: " + src->getFullName() + " to input: " + getFullName()); + } + _connection = src; src->_connections.push_back(this); } From 9be30a29102028b2d1ed3afd5c196d2cbe9da3ee Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 8 Dec 2024 11:08:36 -0800 Subject: [PATCH 128/137] Static analysis fixes (#2135) This changelist addresses a handful of static analysis warnings flagged by PVS-Studio: - Validate `downstream` before dereferencing in `ShaderGraph::createConnectedNodes`. - Pass a string argument by const reference in `StructTypeDesc::addMember`. - Avoid repeated calls to `Value::asA` in `Graph::setConstant`. --- source/MaterialXGenShader/ShaderGraph.cpp | 31 +++++++++++++---------- source/MaterialXGenShader/TypeDesc.cpp | 2 +- source/MaterialXGenShader/TypeDesc.h | 2 +- source/MaterialXGraphEditor/Graph.cpp | 30 ++++++++++++++-------- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index a8ec936014..c60910aaed 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -138,24 +138,27 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, { // We have a node downstream ShaderNode* downstream = getNode(downstreamNode->getName()); - if (downstream == newNode) + if (downstream) { - throw ExceptionShaderGenError("Upstream node '" + downstream->getName() + "' has itself as downstream node, creating a loop"); - } + if (downstream == newNode) + { + throw ExceptionShaderGenError("Upstream node '" + downstream->getName() + "' has itself as downstream node, creating a loop"); + } - if (downstream && connectingElement) - { - ShaderInput* input = downstream->getInput(connectingElement->getName()); - if (!input) + if (connectingElement) + { + ShaderInput* input = downstream->getInput(connectingElement->getName()); + if (!input) + { + throw ExceptionShaderGenError("Could not find an input named '" + connectingElement->getName() + + "' on downstream node '" + downstream->getName() + "'"); + } + input->makeConnection(output); + } + else { - throw ExceptionShaderGenError("Could not find an input named '" + connectingElement->getName() + - "' on downstream node '" + downstream->getName() + "'"); + throw ExceptionShaderGenError("Could not find downstream node ' " + downstreamNode->getName() + "'"); } - input->makeConnection(output); - } - else - { - throw ExceptionShaderGenError("Could not find downstream node ' " + downstreamNode->getName() + "'"); } } else diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp index 5d51680211..5ea0e31764 100644 --- a/source/MaterialXGenShader/TypeDesc.cpp +++ b/source/MaterialXGenShader/TypeDesc.cpp @@ -145,7 +145,7 @@ TYPEDESC_REGISTER_TYPE(MATERIAL, "material") // StructTypeDesc methods // -void StructTypeDesc::addMember(const string& name, TypeDesc type, string defaultValueStr) +void StructTypeDesc::addMember(const string& name, TypeDesc type, const string& defaultValueStr) { _members.emplace_back(StructTypeDesc::StructMemberTypeDesc(name, type, defaultValueStr)); } diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index 95d2851915..d19fea604a 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -255,7 +255,7 @@ class MX_GENSHADER_API StructTypeDesc /// Empty constructor. StructTypeDesc() noexcept{} - void addMember(const string& name, TypeDesc type, string defaultValueStr); + void addMember(const string& name, TypeDesc type, const string& defaultValueStr); void setTypeDesc(TypeDesc typedesc) { _typedesc = typedesc; } /// Return a type description by index. diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index d09961d42f..9e075b9dc4 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -926,7 +926,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert if (val && val->isA()) { // Update the value to the default for new nodes - float prev = val->asA(), temp = val->asA(); + float prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA() : 0.f; float max = maxVal ? maxVal->asA() : 100.f; float speed = (max - min) / 1000.0f; @@ -946,7 +947,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - int prev = val->asA(), temp = val->asA(); + int prev, temp; + prev = temp = val->asA(); int min = minVal ? minVal->asA() : 0; int max = maxVal ? maxVal->asA() : 100; float speed = (max - min) / 100.0f; @@ -966,7 +968,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Color3 prev = val->asA(), temp = val->asA(); + mx::Color3 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -990,7 +993,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Color4 prev = val->asA(), temp = val->asA(); + mx::Color4 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1016,7 +1020,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Vector2 prev = val->asA(), temp = val->asA(); + mx::Vector2 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1036,7 +1041,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Vector3 prev = val->asA(), temp = val->asA(); + mx::Vector3 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1056,7 +1062,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Vector4 prev = val->asA(), temp = val->asA(); + mx::Vector4 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1076,7 +1083,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - std::string prev = val->asA(), temp = val->asA(); + std::string prev, temp; + prev = temp = val->asA(); ImGui::InputText("##constant", &temp); // Set input value and update materials if different from previous value @@ -1094,7 +1102,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert if (val && val->isA()) { - std::string temp = val->asA(), prev = val->asA(); + std::string prev, temp; + prev = temp = val->asA(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.15f, .15f, .15f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.2f, .4f, .6f, 1.0f)); @@ -1142,7 +1151,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - bool prev = val->asA(), temp = val->asA(); + bool prev, temp; + prev = temp = val->asA(); ImGui::Checkbox("", &temp); // Set input value and update materials if different from previous value From 8929e07e7a3888b32656eb0ffef05b2d39b4381a Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 8 Dec 2024 16:32:51 -0800 Subject: [PATCH 129/137] Improve usage of setDataLibrary (#2136) This changelist improves the usage of Document::setDataLibrary in MaterialXRender functions, leveraging this more efficient alternative to Document::importLibrary where appropriate. --- source/MaterialXRender/ShaderMaterial.cpp | 6 ++---- source/MaterialXRender/Util.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/source/MaterialXRender/ShaderMaterial.cpp b/source/MaterialXRender/ShaderMaterial.cpp index c61c6d3c04..6fcc1a661d 100644 --- a/source/MaterialXRender/ShaderMaterial.cpp +++ b/source/MaterialXRender/ShaderMaterial.cpp @@ -68,10 +68,8 @@ bool ShaderMaterial::generateEnvironmentShader(GenContext& context, { // Read in the environment nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); - DocumentPtr envDoc = createDocument(); - readFromXmlFile(envDoc, filename); - doc->importLibrary(envDoc); + doc->setDataLibrary(stdLib); + readFromXmlFile(doc, filename); NodeGraphPtr envGraph = doc->getNodeGraph("envMap"); if (!envGraph) diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index c206514412..9aab6b4811 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -24,7 +24,7 @@ ShaderPtr createConstantShader(GenContext& context, { // Construct the constant color nodegraph DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); constant->setInputValue("value", color); @@ -41,7 +41,7 @@ ShaderPtr createDepthShader(GenContext& context, { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); OutputPtr output = nodeGraph->addOutput(); @@ -61,7 +61,7 @@ ShaderPtr createAlbedoTableShader(GenContext& context, { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); OutputPtr output = nodeGraph->addOutput(); @@ -82,7 +82,7 @@ ShaderPtr createEnvPrefilterShader(GenContext& context, { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); OutputPtr output = nodeGraph->addOutput(); @@ -104,7 +104,7 @@ ShaderPtr createBlurShader(GenContext& context, { // Construct the blur nodegraph DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr imageNode = nodeGraph->addNode("image", "image"); NodePtr blurNode = nodeGraph->addNode("blur", "blur"); From 12235809a1e26a7a80da9c990723e804fd6562fc Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 9 Dec 2024 09:57:53 -0800 Subject: [PATCH 130/137] Use setDataLibrary in Graph Editor (#2137) This changelist updates the Graph Editor to use Element::setDataLibrary rather than Element::importLibrary, improving the efficiency of document loading. Additionally, it removes an unused method and member variable from the RenderView class. --- source/MaterialXGraphEditor/Graph.cpp | 6 +++--- source/MaterialXGraphEditor/RenderView.cpp | 18 ++++-------------- source/MaterialXGraphEditor/RenderView.h | 4 ++-- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 9e075b9dc4..1c3dfa66ba 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -171,7 +171,7 @@ Graph::Graph(const std::string& materialFilename, // Create a renderer using the initial startup document. mx::FilePath captureFilename = "resources/Materials/Examples/example.png"; std::string envRadianceFilename = "resources/Lights/san_giuseppe_bridge_split.hdr"; - _renderer = std::make_shared(_graphDoc, meshFilename, envRadianceFilename, + _renderer = std::make_shared(_graphDoc, _stdLib, meshFilename, envRadianceFilename, _searchPath, viewWidth, viewHeight); _renderer->initialize(); for (const std::string& ext : _renderer->getImageHandler()->supportedExtensions()) @@ -249,7 +249,7 @@ mx::DocumentPtr Graph::loadDocument(const mx::FilePath& filename) if (!filename.isEmpty()) { mx::readFromXmlFile(doc, filename, _searchPath, &readOptions); - doc->importLibrary(_stdLib); + doc->setDataLibrary(_stdLib); std::string message; if (!doc->validate(&message)) { @@ -3050,7 +3050,7 @@ void Graph::clearGraph() _newLinks.clear(); _currPins.clear(); _graphDoc = mx::createDocument(); - _graphDoc->importLibrary(_stdLib); + _graphDoc->setDataLibrary(_stdLib); _currGraphElem = _graphDoc; if (_currUiNode != nullptr) diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index 92cd8f07c7..fe419c7908 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -108,6 +108,7 @@ void RenderView::setDocument(mx::DocumentPtr document) } RenderView::RenderView(mx::DocumentPtr doc, + mx::DocumentPtr stdLib, const std::string& meshFilename, const std::string& envRadianceFilename, const mx::FileSearchPath& searchPath, @@ -162,6 +163,7 @@ RenderView::RenderView(mx::DocumentPtr doc, _genContext.getOptions().shaderInterfaceType = mx::SHADER_INTERFACE_COMPLETE; setDocument(doc); + _stdLib = stdLib; } void RenderView::initialize() @@ -214,18 +216,6 @@ void RenderView::assignMaterial(mx::MeshPartitionPtr geometry, mx::GlslMaterialP } } -mx::ElementPredicate RenderView::getElementPredicate() -{ - return [this](mx::ConstElementPtr elem) - { - if (elem->hasSourceUri()) - { - return (_xincludeFiles.count(elem->getSourceUri()) == 0); - } - return true; - }; -} - void RenderView::updateGeometrySelections() { _geometryList.clear(); @@ -935,7 +925,7 @@ mx::ImagePtr RenderView::getShadowMap() { try { - mx::ShaderPtr hwShader = mx::createDepthShader(_genContext, _document, "__SHADOW_SHADER__"); + mx::ShaderPtr hwShader = mx::createDepthShader(_genContext, _stdLib, "__SHADOW_SHADER__"); _shadowMaterial = mx::GlslMaterial::create(); _shadowMaterial->generateShader(hwShader); } @@ -949,7 +939,7 @@ mx::ImagePtr RenderView::getShadowMap() { try { - mx::ShaderPtr hwShader = mx::createBlurShader(_genContext, _document, "__SHADOW_BLUR_SHADER__", "gaussian", 1.0f); + mx::ShaderPtr hwShader = mx::createBlurShader(_genContext, _stdLib, "__SHADOW_BLUR_SHADER__", "gaussian", 1.0f); _shadowBlurMaterial = mx::GlslMaterial::create(); _shadowBlurMaterial->generateShader(hwShader); } diff --git a/source/MaterialXGraphEditor/RenderView.h b/source/MaterialXGraphEditor/RenderView.h index 354e898ce1..c4c709dc9f 100644 --- a/source/MaterialXGraphEditor/RenderView.h +++ b/source/MaterialXGraphEditor/RenderView.h @@ -29,6 +29,7 @@ class RenderView { public: RenderView(mx::DocumentPtr doc, + mx::DocumentPtr stdLib, const std::string& meshFilename, const std::string& envRadianceFilename, const mx::FileSearchPath& searchPath, @@ -159,7 +160,6 @@ class RenderView { return _xincludeFiles; } - mx::ElementPredicate getElementPredicate(); // Request a capture of the current frame, writing it to the given filename. void requestFrameCapture(const mx::FilePath& filename) @@ -232,7 +232,6 @@ class RenderView void updateGeometrySelections(); mx::ImagePtr getShadowMap(); - mx::ImagePtr _renderMap; void renderFrame(); void renderScreenSpaceQuad(mx::GlslMaterialPtr material); @@ -268,6 +267,7 @@ class RenderView // Document management mx::DocumentPtr _document; + mx::DocumentPtr _stdLib; DocumentModifiers _modifiers; mx::StringSet _xincludeFiles; From 31d8240036ba45bf363414db83b6542d0c3eabac Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Mon, 9 Dec 2024 13:43:42 -0500 Subject: [PATCH 131/137] Improve input filtering in Graph Editor (#2134) - Move "show all inputs" to the top. - Make name field expand to right marge on panel. - Format the title of the property editor. - Remove extraneous "Inputs:" line since only inputs are displayed. --- source/MaterialXGraphEditor/Graph.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 1c3dfa66ba..aa04339469 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -3288,7 +3288,20 @@ void Graph::graphButtons() void Graph::propertyEditor() { + // Get parent dimensions + ImVec2 textPos = ImGui::GetCursorScreenPos(); // Position for the background + float parentWidth = ImGui::GetContentRegionAvail().x; // Available width in the parent + + // Draw the title bar + const ImGuiStyle& style = ImGui::GetStyle(); + ImVec4 menuBarBgColor = style.Colors[ImGuiCol_MenuBarBg]; + ImU32 bgColor = ImGui::ColorConvertFloat4ToU32(menuBarBgColor); // Convert to 32-bit color + ImDrawList* drawList = ImGui::GetWindowDrawList(); + drawList->AddRectFilled(textPos, + ImVec2(textPos.x + parentWidth, textPos.y + ImGui::GetTextLineHeight()), + bgColor); ImGui::Text("Node Property Editor"); + if (_currUiNode) { // Set and edit name @@ -3296,7 +3309,11 @@ void Graph::propertyEditor() ImGui::SameLine(); std::string original = _currUiNode->getName(); std::string temp = original; + float availableWidth = ImGui::GetContentRegionAvail().x; + ImGui::PushItemWidth(availableWidth); ImGui::InputText("##edit", &temp); + ImGui::PopItemWidth(); + std::string docString = "NodeDef Doc String: \n"; if (_currUiNode->getNode()) { @@ -3423,7 +3440,8 @@ void Graph::propertyEditor() ImGui::SetTooltip("%s", _currUiNode->getNode()->getNodeDef()->getDocString().c_str()); } - ImGui::Text("Inputs:"); + ImGui::Checkbox("Show all inputs", &_currUiNode->_showAllInputs); + int count = 0; for (UiPinPtr input : _currUiNode->inputPins) { @@ -3487,14 +3505,12 @@ void Graph::propertyEditor() ImGui::SetWindowFontScale(1.0f); } } - ImGui::Checkbox("Show all inputs", &_currUiNode->_showAllInputs); } else if (_currUiNode->getInput() != nullptr) { ImGui::Text("%s", _currUiNode->getCategory().c_str()); std::vector inputs = _currUiNode->inputPins; - ImGui::Text("Inputs:"); int count = static_cast(inputs.size()); if (count) @@ -3545,7 +3561,6 @@ void Graph::propertyEditor() { std::vector inputs = _currUiNode->inputPins; ImGui::Text("%s", _currUiNode->getCategory().c_str()); - ImGui::Text("Inputs:"); int count = 0; for (UiPinPtr input : inputs) { From bc2466e1856fed9415fcda4031dc1e069c247a90 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 9 Dec 2024 20:01:52 -0800 Subject: [PATCH 132/137] Use setDataLibrary in Web Viewer (#2138) This changelist updates the Web Viewer to use Document::setDataLibrary rather than Document::importLibrary, improving the efficiency of document loading. --- javascript/MaterialXView/source/viewer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index e558ad0bc9..77437b8c56 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -606,7 +606,7 @@ export class Material // Re-initialize document var startDocTime = performance.now(); var doc = mx.createDocument(); - doc.importLibrary(viewer.getLibrary()); + doc.setDataLibrary(viewer.getLibrary()); viewer.setDocument(doc); const fileloader = viewer.getFileLoader(); @@ -1491,7 +1491,7 @@ export class Viewer this.document = this.mx.createDocument(); this.stdlib = this.mx.loadStandardLibraries(this.genContext); - this.document.importLibrary(this.stdlib); + this.document.setDataLibrary(this.stdlib); this.initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml); From 95d26ff6355526b82a4a2d4ce7ba1d69d4d3f7f0 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 11 Dec 2024 07:03:31 -0800 Subject: [PATCH 133/137] Simplify shader generator exclusions (#2139) This changelist simplifies the shader generator exclusion lists used in unit testing, removing legacy exclusions that are no longer needed with the current data libraries. --- source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h | 7 +++---- source/MaterialXTest/MaterialXGenMdl/GenMdl.h | 5 ++--- source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 8 ++++---- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 4 ++-- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h index bc96ac0268..8d3e8c8720 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h @@ -51,10 +51,9 @@ class GlslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "screen", "displacementshader", "volumeshader", - "IM_constant_", "IM_dot_", "IM_geompropvalue_boolean", "IM_geompropvalue_string", - "IM_light_genglsl", "IM_point_light_genglsl", "IM_spot_light_genglsl", "IM_directional_light_genglsl", - "IM_angle", "volumematerial", "ND_volumematerial" + "volumeshader", "volumematerial", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", + "IM_light_", "IM_point_light_", "IM_spot_light_", "IM_directional_light_" }; ShaderGeneratorTester::getImplementationWhiteList(whiteList); } diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h index e51dbbd7e5..ff2be4205d 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h @@ -76,9 +76,8 @@ class MdlShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "backfacing", "screen", "displacementshader", - "volumeshader", "IM_constant_", "IM_dot_", "IM_geomattrvalue", "IM_angle", - "geompropvalue", "surfacematerial", "volumematerial", + "displacementshader", "volumeshader", "surfacematerial", "volumematerial", "geompropvalue", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geomattrvalue", "IM_absorption_vdf_", "IM_mix_vdf_", "IM_add_vdf_", "IM_multiply_vdf", "IM_measured_edf_", "IM_blackbody_", "IM_conical_edf_", "IM_displacement_", "IM_volume_", "IM_light_" diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h index c281abde1c..eea7b86acb 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h @@ -70,10 +70,10 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "backfacing", "screen", "displacementshader", - "volumeshader", "IM_constant_", "IM_dot_", "IM_geompropvalue_boolean", "IM_geompropvalue_string", - "IM_light_genmsl", "IM_point_light_genmsl", "IM_spot_light_genmsl", "IM_directional_light_genmsl", - "IM_angle", "surfacematerial", "volumematerial", "ND_surfacematerial", "ND_volumematerial", "ND_backface_util", "IM_backface_util_genmsl" + "displacementshader", "volumeshader", "surfacematerial", "volumematerial", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", + "IM_light_", "IM_point_light_", "IM_spot_light_", "IM_directional_light_", + "ND_surfacematerial", "ND_volumematerial" }; } }; diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h index cc97558e59..aa84a62218 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h @@ -63,8 +63,8 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "backfacing", "screen", "displacementshader", - "volumeshader", "IM_constant_", "IM_dot_", "IM_geompropvalue", "IM_angle", "ND_backface_util" + "displacementshader", "volumeshader", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue" }; ShaderGeneratorTester::getImplementationWhiteList(whiteList); } From d075eb28f3c0b15d90ef2198498107c7471edcd5 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 11 Dec 2024 07:16:51 -0800 Subject: [PATCH 134/137] Update changelog for recent work (#2140) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fb0c98143..8ab737cbe6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,11 +18,13 @@ - Added documentation for [keyboard shortcuts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2026) in the MaterialX Viewer. ### Changed +- Improved the performance of [graph traversal](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2023) by skipping edges that have already been visited. - Reduced duplication between the [MSL and GLSL implementations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2068) of nodes. ### Fixed - Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. - Fixed [banding artifacts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1977) in the MaterialX Viewer on MacOS. +- Fixed the handling of [missing scenes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2124) in the MaterialX Web Viewer. - Fixed a call to the [anisotropic_vdf closure](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2016) in OSL shader generation. ### Removed From ce1168abf62351215653ce0f3ed00c9c1c031501 Mon Sep 17 00:00:00 2001 From: Jonathan Feldstein Date: Wed, 11 Dec 2024 17:46:17 -0500 Subject: [PATCH 135/137] Initial graph implementation of ramp node (#1884) This change includes the ramp nodedef, ramp gradient nodedef and subsequent nodegraph implementations for these two nodedefs. The ramp node includes support for both linear, smoothstep and step interpolation. The ramp also supports up to 10 control points and the following ramp types: standard, radial, circular and box. --- libraries/stdlib/stdlib_defs.mtlx | 49 +++++++ libraries/stdlib/stdlib_ng.mtlx | 221 ++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index e6f8d431e7..8f86a03b44 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -465,6 +465,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c46e8a3ff7313f29e2c3674ba48273eea7552a22 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Wed, 11 Dec 2024 22:28:54 -0500 Subject: [PATCH 136/137] Add JavaScript bindings for element equivalence (#2126) Expose the `Element::isEquivalent()` + options structure API in Javascript. --- javascript/MaterialXTest/element.spec.js | 25 +++++++++++++++++++ .../JsMaterialX/JsMaterialXCore/JsElement.cpp | 24 ++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/javascript/MaterialXTest/element.spec.js b/javascript/MaterialXTest/element.spec.js index cbb672c5c2..bafee4d6af 100644 --- a/javascript/MaterialXTest/element.spec.js +++ b/javascript/MaterialXTest/element.spec.js @@ -164,3 +164,28 @@ describe('Element', () => }); }); }); + +describe('Equivalence', () => +{ + let mx, doc, doc2 + + before(async () => { + mx = await Module(); + doc = mx.createDocument(); + doc.addNodeGraph("graph"); + doc2 = mx.createDocument(); + doc2.addNodeGraph("graph1"); + }); + + it('Compare document equivalency', () => + { + let options = new mx.ElementEquivalenceOptions(); + let differences = {}; + options.performValueComparisons = false; + let result = doc.isEquivalent(doc2, options, differences); + expect(result).to.be.false; + expect(differences.message).to.not.be.empty; + result = doc.isEquivalent(doc2, options, undefined); + expect(result).to.be.false; + }); +}); diff --git a/source/JsMaterialX/JsMaterialXCore/JsElement.cpp b/source/JsMaterialX/JsMaterialXCore/JsElement.cpp index c912d036c1..31670ad090 100644 --- a/source/JsMaterialX/JsMaterialXCore/JsElement.cpp +++ b/source/JsMaterialX/JsMaterialXCore/JsElement.cpp @@ -35,11 +35,35 @@ namespace mx = MaterialX; EMSCRIPTEN_BINDINGS(element) { + ems::class_("ElementEquivalenceOptions") + .constructor<>() + .property("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) + .property("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) + .property("floatPrecision", &mx::ElementEquivalenceOptions::floatPrecision) + .function("setAttributeExclusionList", ems::optional_override([](mx::ElementEquivalenceOptions& self, const std::vector& exclusionList) + { + self.attributeExclusionList = std::set(exclusionList.begin(), exclusionList.end()); + })); + ems::class_("Element") .smart_ptr>("Element") .smart_ptr>("Element") // mx::ConstElementPtr .function("equals", ems::optional_override([](mx::Element& self, const mx::Element& rhs) { return self == rhs; })) .function("notEquals", ems::optional_override([](mx::Element& self, const mx::Element& rhs) { return self != rhs; })) + .function("isEquivalent", ems::optional_override([](mx::Element &self, const mx::Element& rhs, + const mx::ElementEquivalenceOptions& options, + ems::val message = ems::val::undefined()) + { + mx::ConstElementPtr rhsPtr = rhs.getSelf(); + std::string nativeMessage; + bool handleMessage = !message.isUndefined() && message.typeOf().as() == "object"; + bool res = self.isEquivalent(rhsPtr, options, handleMessage ? &nativeMessage : nullptr); + if (!res && handleMessage) + { + message.set("message", nativeMessage); + } + return res; + })) .function("setCategory", &mx::Element::setCategory) .function("getCategory", &mx::Element::getCategory) .function("setName", &mx::Element::setName) From 94ce95d7b814b188d6a2adc2aa3f521ed3a20643 Mon Sep 17 00:00:00 2001 From: krohmerNV <42233792+krohmerNV@users.noreply.github.com> Date: Thu, 12 Dec 2024 19:24:40 +0100 Subject: [PATCH 137/137] Add support for custom MDL nodes (#2125) The MDL generator is limited in a way that it only supported the mappings defined in the libraries/***lib/genmdl files. With this pull request we now fully support nodes. This comes in two flavors: 1. External .mdl file references: We allow to specify an MDL module located in an MDL search path using the `file` attribute. In combination with the `function` attribute a particular exported function can be selected. There is one aspect that needs to be considered when using this approach: - Input and output names defined in MaterialX could conflict with reserved names in MDL. Therefore, we add a `mxp_` prefix in case of such a conflict. The prefix is not applied in general because we want to be able to reference MDL modules without modifying them. 2. Inline MDL source code: By specifying the `sourcecode` attribute, MDL code can be added directly. The generator will inline this code into the generated MDL code, based on the interface of the corresponding node definition. Here, more aspects need to be considered: - all input and input names defined in MaterialX are prefixed with `mxp_` to keep things simple for authors that otherwise would need knowledge about the keywords in MDL. - because the source code parsed from the MaterialX document contains no line breaks, we need to forbid comments using `//`. Instead the `/* comment */` syntax can be used. - to keep these inline source code nodes portable, it is not allowed to import additional MDL modules --- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 58 +++- source/MaterialXGenMdl/MdlSyntax.cpp | 89 +++++- source/MaterialXGenMdl/MdlSyntax.h | 11 + .../Nodes/ClosureCompoundNodeMdl.cpp | 4 +- .../MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp | 8 +- .../MaterialXGenMdl/Nodes/CustomNodeMdl.cpp | 278 ++++++++++++++++++ source/MaterialXGenMdl/Nodes/CustomNodeMdl.h | 56 ++++ source/MaterialXGenMdl/Nodes/ImageNodeMdl.h | 2 +- .../MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp | 5 +- .../Nodes/SourceCodeNodeMdl.cpp | 62 ++-- .../MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h | 1 + .../MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp | 5 +- .../Nodes/SourceCodeNode.cpp | 24 +- .../MaterialXGenShader/Nodes/SourceCodeNode.h | 3 + .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 2 +- 15 files changed, 526 insertions(+), 82 deletions(-) create mode 100644 source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp create mode 100644 source/MaterialXGenMdl/Nodes/CustomNodeMdl.h diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index 71db0d7cf4..1bc65d5cc4 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -157,6 +158,24 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G emitLineEnd(stage, true); } + // Emit custom node imports for nodes in the graph + for (ShaderNode* node : graph.getNodes()) + { + const ShaderNodeImpl& impl = node->getImplementation(); + const CustomCodeNodeMdl* customNode = dynamic_cast(&impl); + if (customNode) + { + const string& importName = customNode->getQualifiedModuleName(); + if (!importName.empty()) + { + emitString("import ", stage); + emitString(importName, stage); + emitString("::*", stage); + emitLineEnd(stage, true); + } + } + } + // Add global constants and type definitions emitTypeDefinitions(context, stage); @@ -353,14 +372,31 @@ ShaderNodeImplPtr MdlShaderGenerator::getImplementation(const NodeDef& nodedef, impl = _implFactory.create(name); if (!impl) { - // Fall back to source code implementation. - if (outputType.isClosure()) + // When `file` and `function` are provided we consider this node a user node + const string file = implElement->getTypedAttribute("file"); + const string function = implElement->getTypedAttribute("function"); + // Or, if `sourcecode` is provided we consider this node a user node with inline implementation + // inline implementations are not supposed to have replacement markers + const string sourcecode = implElement->getTypedAttribute("sourcecode"); + if ((!file.empty() && !function.empty()) || (!sourcecode.empty() && sourcecode.find("{{") == string::npos)) + { + impl = CustomCodeNodeMdl::create(); + } + else if (file.empty() && sourcecode.empty()) { - impl = ClosureSourceCodeNodeMdl::create(); + throw ExceptionShaderGenError("No valid MDL implementation found for '" + name + "'"); } else { - impl = SourceCodeNodeMdl::create(); + // Fall back to source code implementation. + if (outputType.isClosure()) + { + impl = ClosureSourceCodeNodeMdl::create(); + } + else + { + impl = SourceCodeNodeMdl::create(); + } } } } @@ -386,6 +422,7 @@ string MdlShaderGenerator::getUpstreamResult(const ShaderInput* input, GenContex return ShaderGenerator::getUpstreamResult(input, context); } + const MdlSyntax& mdlSyntax = static_cast(getSyntax()); string variable; const ShaderNode* upstreamNode = upstreamOutput->getNode(); if (!upstreamNode->isAGraph() && upstreamNode->numOutputs() > 1) @@ -397,7 +434,18 @@ string MdlShaderGenerator::getUpstreamResult(const ShaderInput* input, GenContex } else { - variable = upstreamNode->getName() + "_result.mxp_" + upstreamOutput->getName(); + const string& fieldName = upstreamOutput->getName(); + const CustomCodeNodeMdl* upstreamCustomNodeMdl = dynamic_cast(&upstreamNode->getImplementation()); + if (upstreamCustomNodeMdl) + { + // Prefix the port name depending on the CustomCodeNode + variable = upstreamNode->getName() + "_result." + upstreamCustomNodeMdl->modifyPortName(fieldName, mdlSyntax); + } + else + { + // Existing implementations and none user defined structs will keep the prefix always to not break existing content + variable = upstreamNode->getName() + "_result." + mdlSyntax.modifyPortName(upstreamOutput->getName()); + } } } else diff --git a/source/MaterialXGenMdl/MdlSyntax.cpp b/source/MaterialXGenMdl/MdlSyntax.cpp index 0244a8352f..c0859f5ae2 100644 --- a/source/MaterialXGenMdl/MdlSyntax.cpp +++ b/source/MaterialXGenMdl/MdlSyntax.cpp @@ -29,6 +29,8 @@ TYPEDESC_REGISTER_TYPE(MDL_SCATTER_MODE, "scatter_mode") namespace { +const string MARKER_MDL_VERSION_SUFFIX = "MDL_VERSION_SUFFIX"; + class MdlFilenameTypeSyntax : public ScalarTypeSyntax { public: @@ -195,6 +197,8 @@ const StringVec MdlSyntax::FILTERTYPE_MEMBERS = { "box", "gaussian" }; const StringVec MdlSyntax::DISTRIBUTIONTYPE_MEMBERS = { "ggx" }; const StringVec MdlSyntax::SCATTER_MODE_MEMBERS = { "R", "T", "RT" }; +const string MdlSyntax::PORT_NAME_PREFIX = "mxp_"; + // // MdlSyntax methods // @@ -202,22 +206,40 @@ const StringVec MdlSyntax::SCATTER_MODE_MEMBERS = { "R", "T", "RT" }; MdlSyntax::MdlSyntax() { // Add in all reserved words and keywords in MDL + // Formatted as in the MDL Specification 1.9.2 for easy comparing registerReservedWords( - { // Reserved words - "annotation", "bool", "bool2", "bool3", "bool4", "break", "bsdf", "bsdf_measurement", "case", "cast", "color", "const", - "continue", "default", "do", "double", "double2", "double2x2", "double2x3", "double3", "double3x2", "double3x3", "double3x4", - "double4", "double4x3", "double4x4", "double4x2", "double2x4", "edf", "else", "enum", "export", "false", "float", "float2", - "float2x2", "float2x3", "float3", "float3x2", "float3x3", "float3x4", "float4", "float4x3", "float4x4", "float4x2", "float2x4", - "for", "hair_bsdf", "if", "import", "in", "int", "int2", "int3", "int4", "intensity_mode", "intensity_power", "intensity_radiant_exitance", - "let", "light_profile", "material", "material_emission", "material_geometry", "material_surface", "material_volume", "mdl", "module", - "package", "return", "string", "struct", "switch", "texture_2d", "texture_3d", "texture_cube", "texture_ptex", "true", "typedef", "uniform", - "using", "varying", "vdf", "while", - // Reserved for future use - "auto", "catch", "char", "class", "const_cast", "delete", "dynamic_cast", "explicit", "extern", "external", "foreach", "friend", "goto", - "graph", "half", "half2", "half2x2", "half2x3", "half3", "half3x2", "half3x3", "half3x4", "half4", "half4x3", "half4x4", "half4x2", "half2x4", - "inline", "inout", "lambda", "long", "mutable", "namespace", "native", "new", "operator", "out", "phenomenon", "private", "protected", "public", - "reinterpret_cast", "sampler", "shader", "short", "signed", "sizeof", "static", "static_cast", "technique", "template", "this", "throw", "try", - "typeid", "typename", "union", "unsigned", "virtual", "void", "volatile", "wchar_t" }); + { // Reserved words + "annotation", "double2", "float", "in", "operator", + "auto", "double2x2", "float2", "int", "package", + "bool", "double2x3", "float2x2", "int2", "return", + "bool2", "double3", "float2x3", "int3", "string", + "bool3", "double3x2", "float3", "int4", "struct", + "bool4", "double3x3", "float3x2", "intensity_mode", "struct_category", + "break", "double3x4", "float3x3", "intensity_power", "switch", + "bsdf", "double4", "float3x4", "intensity_radiant_exitance", "texture_2d", + "bsdf_measurement", "double4x3", "float4", "let", "texture_3d", + "case", "double4x4", "float4x3", "light_profile", "texture_cube", + "cast", "double4x2", "float4x4", "material", "texture_ptex", + "color", "double2x4", "float4x2", "material_emission", "true", + "const", "edf", "float2x4", "material_geometry", "typedef", + "continue", "else", "for", "material_surface", "uniform", + "declarative", "enum", "hair_bsdf", "material_volume", "using", + "default", "export", "if", "mdl", "varying", + "do", "false", "import", "module", "vdf", + "double", "while", + + // Reserved for future use + "catch", "friend", "half3x4", "mutable", "sampler", "throw", + "char", "goto", "half4", "namespace", "shader", "try", + "class", "graph", "half4x3", "native", "short", "typeid", + "const_cast", "half", "half4x4", "new", "signed", "typename", + "delete", "half2", "half4x2", "out", "sizeof", "union", + "dynamic_cast", "half2x2", "half2x4", "phenomenon", "static", "unsigned", + "explicit", "half2x3", "inline", "private", "static_cast", "virtual", + "extern", "half3", "inout", "protected", "technique", "void", + "external", "half3x2", "lambda", "public", "template", "volatile", + "foreach", "half3x3", "long", "reinterpret_cast", "this", "wchar_t", + }); // Register restricted tokens in MDL StringMap tokens; @@ -533,4 +555,41 @@ void MdlSyntax::makeValidName(string& name) const } } +string MdlSyntax::modifyPortName(const string& word) const +{ + return PORT_NAME_PREFIX + word; +} + +string MdlSyntax::replaceSourceCodeMarkers(const string& nodeName, const string& soureCode, std::function lambda) const +{ + // An inline function call + // Replace tokens of the format "{{}}" + static const string prefix("{{"); + static const string postfix("}}"); + + size_t pos = 0; + size_t i = soureCode.find_first_of(prefix); + StringVec code; + while (i != string::npos) + { + code.push_back(soureCode.substr(pos, i - pos)); + size_t j = soureCode.find_first_of(postfix, i + 2); + if (j == string::npos) + { + throw ExceptionShaderGenError("Malformed inline expression in implementation for node " + nodeName); + } + const string marker = soureCode.substr(i + 2, j - i - 2); + code.push_back(lambda(marker)); + pos = j + 2; + i = soureCode.find_first_of(prefix, pos); + } + code.push_back(soureCode.substr(pos)); + return joinStrings(code, EMPTY_STRING); +} + +const string MdlSyntax::getMdlVersionSuffixMarker() const +{ + return MARKER_MDL_VERSION_SUFFIX; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/MdlSyntax.h b/source/MaterialXGenMdl/MdlSyntax.h index e282cefeca..48fd6214c0 100644 --- a/source/MaterialXGenMdl/MdlSyntax.h +++ b/source/MaterialXGenMdl/MdlSyntax.h @@ -53,6 +53,7 @@ class MX_GENMDL_API MdlSyntax : public Syntax static const StringVec FILTERTYPE_MEMBERS; static const StringVec DISTRIBUTIONTYPE_MEMBERS; static const StringVec SCATTER_MODE_MEMBERS; + static const string PORT_NAME_PREFIX; // Applied to input and output names to avoid collisions with reserved words in MDL /// Get an type description for an enumeration based on member value TypeDesc getEnumeratedType(const string& value) const; @@ -63,6 +64,16 @@ class MX_GENMDL_API MdlSyntax : public Syntax /// Modify the given name string to remove any invalid characters or tokens. void makeValidName(string& name) const override; + + /// To avoid collisions with reserved names in MDL, input and output names are prefixed. + string modifyPortName(const string& word) const; + + /// Replaces all markers in a source code string indicated by {{...}}. + /// The replacement is defined by a callback function. + string replaceSourceCodeMarkers(const string& nodeName, const string& soureCode, std::function lambda) const; + + /// Get the MDL language versing marker: {{MDL_VERSION_SUFFIX}}. + const string getMdlVersionSuffixMarker() const; }; namespace Type diff --git a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp index 0a2004cd71..59b488c875 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp @@ -4,6 +4,7 @@ // #include +#include #include #include @@ -29,6 +30,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& mdlSyntax = static_cast(shadergen.getSyntax()); // Emit functions for all child nodes shadergen.emitFunctionDefinitions(*_rootGraph, context, stage); @@ -146,7 +148,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { const string result = shadergen.getUpstreamResult(output, context); - shadergen.emitLine(resultVariableName + ".mxp_" + output->getName() + " = " + result, stage); + shadergen.emitLine(resultVariableName + mdlSyntax.modifyPortName(output->getName()) + " = " + result, stage); } shadergen.emitLine("return " + resultVariableName, stage); } diff --git a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp index 80c449e507..2dab721e24 100644 --- a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -46,6 +47,7 @@ void CompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); const bool isMaterialExpr = (_rootGraph->hasClassification(ShaderNode::Classification::CLOSURE) || _rootGraph->hasClassification(ShaderNode::Classification::SHADER)); @@ -83,7 +85,7 @@ void CompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { const string result = shadergen.getUpstreamResult(output, context); - shadergen.emitLine(resultVariableName + ".mxp_" + output->getName() + " = " + result, stage); + shadergen.emitLine(resultVariableName + "." + syntax.modifyPortName(output->getName()) + " = " + result, stage); } shadergen.emitLine("return " + resultVariableName, stage); } @@ -180,7 +182,7 @@ void CompoundNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& conte void CompoundNodeMdl::emitFunctionSignature(const ShaderNode&, GenContext& context, ShaderStage& stage) const { const ShaderGenerator& shadergen = context.getShaderGenerator(); - const Syntax& syntax = shadergen.getSyntax(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); if (!_returnStruct.empty()) { @@ -208,7 +210,7 @@ void CompoundNodeMdl::emitFunctionSignature(const ShaderNode&, GenContext& conte shadergen.emitScopeBegin(stage, Syntax::CURLY_BRACKETS); for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { - shadergen.emitLine(syntax.getTypeName(output->getType()) + " mxp_" + output->getName(), stage); + shadergen.emitLine(syntax.getTypeName(output->getType()) + " " + syntax.modifyPortName(output->getName()), stage); } shadergen.emitScopeEnd(stage, true); shadergen.emitLineBreak(stage); diff --git a/source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp new file mode 100644 index 0000000000..7215b90256 --- /dev/null +++ b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp @@ -0,0 +1,278 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include + +#include +#include +#include +#include +#include + +MATERIALX_NAMESPACE_BEGIN + +ShaderNodeImplPtr CustomCodeNodeMdl::create() +{ + return std::make_shared(); +} + +const string& CustomCodeNodeMdl::getQualifiedModuleName() const +{ + return _qualifiedModuleName; +} + +string CustomCodeNodeMdl::modifyPortName(const string& name, const MdlSyntax& syntax) const +{ + if (_useExternalSourceCode) + { + const StringSet& reservedWords = syntax.getReservedWords(); + if (reservedWords.find(name) == reservedWords.end()) + { + // Use existing MDL parameter names if they don't collide with a reserved word. + // This allows us to reference MDL existing functions without changing the MDL source code. + return name; + } + } + return syntax.modifyPortName(name); +} + +void CustomCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& context) +{ + SourceCodeNodeMdl::initialize(element, context); + if (_inlined) + { + _useExternalSourceCode = false; + initializeForInlineSourceCode(element, context); + } + else + { + _useExternalSourceCode = true; + initializeForExternalSourceCode(element, context); + } +} + +void CustomCodeNodeMdl::initializeForInlineSourceCode(const InterfaceElement& element, GenContext& context) +{ + const Implementation& impl = static_cast(element); + // Store the inline source because the `_functionSource` is used for the function call template string + // that matched the regular MaterialX to MDL function mapping. + _inlineSourceCode = impl.getAttribute("sourcecode"); + if (_inlineSourceCode.empty()) + { + throw ExceptionShaderGenError("No source code was specified for the implementation '" + impl.getName() + "'"); + } + if (_inlineSourceCode.find("//") != string::npos) + { + throw ExceptionShaderGenError("Source code contains unsupported comments '//', please use '/* comment */' instead in '" + impl.getName() + "'"); + } + + NodeDefPtr nodeDef = impl.getNodeDef(); + _inlineFunctionName = nodeDef->getName(); + _hash = std::hash{}(_inlineFunctionName); // make sure we emit the function definition only once + + const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); + // Construct the function call template string + initializeFunctionCallTemplateString(syntax, *nodeDef); + // Collect information about output names and defaults + initializeOutputDefaults(syntax, *nodeDef); +} + +void CustomCodeNodeMdl::initializeForExternalSourceCode(const InterfaceElement& element, GenContext& context) +{ + // Format the function source in a way that the ShaderCodeNodeMdl (the base class of the current one) can deal with it + const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); + const string uniformPrefix = syntax.getUniformQualifier() + " "; + + // Map `file` to a qualified MDL module name + const Implementation& impl = static_cast(element); + string moduleName = impl.getAttribute("file"); + if (moduleName.empty()) + { + throw ExceptionShaderGenError("No source file was specified for the implementation '" + impl.getName() + "'"); + } + if (_functionName.empty()) + { + throw ExceptionShaderGenError("No function name was specified for the implementation '" + impl.getName() + "'"); + } + + string mdlModuleName = replaceSubstrings(moduleName, { { "/", "::" } }); + if (!stringStartsWith(mdlModuleName, "::")) + { + mdlModuleName = "::" + mdlModuleName; + } + + if (!stringEndsWith(mdlModuleName, ".mdl")) + { + throw ExceptionShaderGenError("Referenced source file is not an MDL module: '" + moduleName + + "' used by implementation '" + impl.getName() + "'"); + } + else + { + mdlModuleName = mdlModuleName.substr(0, mdlModuleName.size() - 4); + } + const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); + _qualifiedModuleName = syntax.replaceSourceCodeMarkers(element.getName(), mdlModuleName, + [&versionSuffix, &syntax](const string& marker) + { + return marker == syntax.getMdlVersionSuffixMarker() ? versionSuffix : marker; + }); + + NodeDefPtr nodeDef = impl.getNodeDef(); + // Construct the function call template string + initializeFunctionCallTemplateString(syntax, *nodeDef); + // Collect information about output names and defaults + initializeOutputDefaults(syntax, *nodeDef); +} + +void CustomCodeNodeMdl::initializeFunctionCallTemplateString(const MdlSyntax& syntax, const NodeDef& nodeDef) +{ + // Construct the fully qualified function name for external functions + if (_useExternalSourceCode) + { + _functionSource = _qualifiedModuleName.substr(2) + "::" + _functionName + "("; + } + // or simple name for local functions + else + { + _functionSource = _inlineFunctionName + "("; + } + + // Function parameters + string delim = EMPTY_STRING; + for (const InputPtr& input : nodeDef.getInputs()) + { + string inputName = modifyPortName(input->getName(), syntax); + _functionSource += delim + inputName + ": {{" + input->getName() + "}}"; + if (delim == EMPTY_STRING) + delim = Syntax::COMMA + " "; + } + _functionSource += ")"; + _inlined = true; +} + +void CustomCodeNodeMdl::initializeOutputDefaults(const MdlSyntax&, const NodeDef& nodeDef) +{ + for (const OutputPtr& output : nodeDef.getOutputs()) + { + _outputDefaults.push_back(output->getValue()); + } +} + +void CustomCodeNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const +{ + // No source code printing for externally defined functions + if (_useExternalSourceCode) + { + return; + } + + const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); + shadergen.emitComment("generated code for implementation: '" + node.getImplementation().getName() + "'", stage); + + // Function return type + struct Field + { + string name; + string type_name; + string default_value; + }; + vector outputs; + size_t i = 0; + for (const ShaderOutput* output : node.getOutputs()) + { + string name = modifyPortName(output->getName(), syntax); + TypeDesc type = output->getType(); + const ValuePtr defaultValue = _outputDefaults[i]; + outputs.push_back({ + name, + syntax.getTypeName(type), + defaultValue ? syntax.getValue(type, *defaultValue.get()) : syntax.getDefaultValue(type) + }); + ++i; + } + + size_t numOutputs = node.getOutputs().size(); + string returnTypeName; + if (numOutputs == 1) + { + returnTypeName = outputs.back().type_name; + } + else + { + returnTypeName = _inlineFunctionName + "_return_type"; + shadergen.emitLine("struct " + returnTypeName, stage, false); + shadergen.emitScopeBegin(stage, Syntax::CURLY_BRACKETS); + for (const auto& field : outputs) + { + // ignore the default values here, they have to be initialized in the body + shadergen.emitLine(field.type_name + " " + field.name, stage); + } + shadergen.emitScopeEnd(stage, Syntax::CURLY_BRACKETS); + shadergen.emitLineEnd(stage, false); + } + // Signature + shadergen.emitString(returnTypeName + " " + _inlineFunctionName, stage); + { + // Function parameters + shadergen.emitScopeBegin(stage, Syntax::PARENTHESES); + size_t paramCount = node.getInputs().size(); + const string uniformPrefix = syntax.getUniformQualifier() + " "; + for (const ShaderInput* input : node.getInputs()) + { + const string& qualifier = input->isUniform() || input->getType() == Type::FILENAME ? uniformPrefix : EMPTY_STRING; + const string& type = syntax.getTypeName(input->getType()); + const string name = modifyPortName(input->getName(), syntax); + const string& delim = --paramCount == 0 ? EMPTY_STRING : Syntax::COMMA; + shadergen.emitString(" " + qualifier + type + " " + name + delim + Syntax::NEWLINE, stage); + } + shadergen.emitScopeEnd(stage, false, true); + } + { + // Function body + shadergen.emitScopeBegin(stage, Syntax::CURLY_BRACKETS); + + // Out variable initialization + shadergen.emitComment("initialize outputs:", stage); + for (const auto& field : outputs) + { + shadergen.emitLine(field.type_name + " " + field.name + " = " + field.default_value, stage); + } + + // User defined code + shadergen.emitComment("inlined shader source code:", stage); + shadergen.emitLine(_inlineSourceCode, stage, false); + + // Output packing + shadergen.emitComment("pack (in case of multiple outputs) and return outputs:", stage); + if (numOutputs == 1) + { + shadergen.emitLine("return " + outputs.back().name, stage, true); + } + else + { + // Return a constructor call of the return struct type + shadergen.emitString(" return " + returnTypeName + "(", stage); + string delim = EMPTY_STRING; + for (const auto& field : outputs) + { + shadergen.emitString(delim + field.name, stage); + if (delim == EMPTY_STRING) + delim = Syntax::COMMA + " "; + } + shadergen.emitString(")", stage); + shadergen.emitLineEnd(stage, true); + } + shadergen.emitScopeEnd(stage, false, true); + } + shadergen.emitLine("", stage, false); // empty line for spacing +} + +MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/CustomNodeMdl.h b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.h new file mode 100644 index 0000000000..daf4c873a5 --- /dev/null +++ b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.h @@ -0,0 +1,56 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef MATERIALX_CUSTOMNODEMDL_H +#define MATERIALX_CUSTOMNODEMDL_H + +#include + +MATERIALX_NAMESPACE_BEGIN + +class MdlSyntax; +class NodeDef; + +/// Node to handle user defined implementations in external MDL files or using the inline `sourcecode` attribute. +class MX_GENMDL_API CustomCodeNodeMdl : public SourceCodeNodeMdl +{ + public: + static ShaderNodeImplPtr create(); + void initialize(const InterfaceElement& element, GenContext& context) override; + void emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; + + /// Get the MDL qualified name of the externally references user module. + /// It's used for import statements and functions calls in the generated target code. + const string& getQualifiedModuleName() const; + + /// To avoid collisions with reserved names in MDL, input and output names are prefixed. + /// In the `sourcecode` case all inputs and outputs are prefixed so authors don't need knowledge about reserved words in MDL. + /// In the `file` and `function` case, only reserved names are prefixed to support existing MDL implementations without changes. + string modifyPortName(const string& name, const MdlSyntax& syntax) const; + + protected: + /// Initialize function for nodes that use the inline `sourcecode` attribute. + void initializeForInlineSourceCode(const InterfaceElement& element, GenContext& context); + + /// Initialize function for nodes that use the `file` and `function` attribute. + void initializeForExternalSourceCode(const InterfaceElement& element, GenContext& context); + + /// Computes the function call string with replacement markers use by base class. + void initializeFunctionCallTemplateString(const MdlSyntax& syntax, const NodeDef& node); + + /// Keep track of the default values needed for the inline `sourcecode` case. + void initializeOutputDefaults(const MdlSyntax& syntax, const NodeDef& node); + + std::vector _outputDefaults; ///< store default values of the node definition + + bool _useExternalSourceCode; // Indicates that `file` and `function` are used by this node implementation + string _inlineFunctionName; // Name of the functionDefinition to emit + string _inlineSourceCode; // The actual inline source code + string _qualifiedModuleName; // MDL qualified name derived from the `file` attribute +}; + +MATERIALX_NAMESPACE_END + +#endif diff --git a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h index fe88b2ce09..8363c6f4fa 100644 --- a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h @@ -18,7 +18,7 @@ class MX_GENMDL_API ImageNodeMdl : public SourceCodeNodeMdl using BASE = SourceCodeNodeMdl; public: - static const string FLIP_V; ///< the empty string "" + static const string FLIP_V; ///< name of the additional parameter "flip_v" static ShaderNodeImplPtr create(); diff --git a/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp index d13aa2871f..6891fc1778 100644 --- a/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ void MaterialNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& cont const ShaderGenerator& shadergen = context.getShaderGenerator(); const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); + const MdlSyntax& mdlSyntax = static_cast(shadergen.getSyntax()); // Emit the function call for upstream surface shader. const ShaderNode* surfaceshaderNode = surfaceshaderInput->getConnection()->getNode(); @@ -50,8 +52,7 @@ void MaterialNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& cont for (ShaderInput* input : node.getInputs()) { shadergen.emitString(delim, stage); - shadergen.emitString("mxp_", stage); - shadergen.emitString(input->getName(), stage); + shadergen.emitString(mdlSyntax.modifyPortName(input->getName()), stage); shadergen.emitString(": ", stage); shadergen.emitInput(input, context, stage); delim = ", "; diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp index f237a0db54..5547ae309d 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp @@ -13,51 +13,28 @@ #include #include +#include + #include MATERIALX_NAMESPACE_BEGIN -namespace // anonymous -{ -const string MARKER_MDL_VERSION_SUFFIX = "MDL_VERSION_SUFFIX"; - -StringVec replaceSourceCodeMarkers(const string& nodeName, const string& soureCode, std::function lambda) +ShaderNodeImplPtr SourceCodeNodeMdl::create() { - // An inline function call - // Replace tokens of the format "{{}}" - static const string prefix("{{"); - static const string postfix("}}"); - - size_t pos = 0; - size_t i = soureCode.find_first_of(prefix); - StringVec code; - while (i != string::npos) - { - code.push_back(soureCode.substr(pos, i - pos)); - size_t j = soureCode.find_first_of(postfix, i + 2); - if (j == string::npos) - { - throw ExceptionShaderGenError("Malformed inline expression in implementation for node " + nodeName); - } - const string marker = soureCode.substr(i + 2, j - i - 2); - code.push_back(lambda(marker)); - pos = j + 2; - i = soureCode.find_first_of(prefix, pos); - } - code.push_back(soureCode.substr(pos)); - return code; + return std::make_shared(); } -} // anonymous namespace - -ShaderNodeImplPtr SourceCodeNodeMdl::create() +void SourceCodeNodeMdl::resolveSourceCode(const InterfaceElement& /*element*/, GenContext& /*context*/) { - return std::make_shared(); + // Initialize without fetching the source code from file. + // The resolution of MDL modules is done by the MDL compiler when loading the generated source code. + // All references MDL modules must be accessible via MDL search paths set up by the consuming application. } void SourceCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& context) { SourceCodeNode::initialize(element, context); + const MdlSyntax& syntax = static_cast(context.getShaderGenerator().getSyntax()); const Implementation& impl = static_cast(element); NodeDefPtr nodeDef = impl.getNodeDef(); @@ -77,11 +54,10 @@ void SourceCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& const ShaderGenerator& shadergen = context.getShaderGenerator(); const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); - StringVec code = replaceSourceCodeMarkers(getName(), functionName, [&versionSuffix](const string& marker) + functionName = syntax.replaceSourceCodeMarkers(getName(), functionName, [&versionSuffix, syntax](const string& marker) { - return marker == MARKER_MDL_VERSION_SUFFIX ? versionSuffix : EMPTY_STRING; + return marker == syntax.getMdlVersionSuffixMarker() ? versionSuffix : EMPTY_STRING; }); - functionName = std::accumulate(code.begin(), code.end(), EMPTY_STRING); _returnStruct = functionName + "__result"; } else @@ -103,12 +79,13 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); if (_inlined) { + const MdlSyntax& syntax = static_cast(shadergenMdl.getSyntax()); const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); - StringVec code = replaceSourceCodeMarkers(node.getName(), _functionSource, - [&shadergenMdl, &context, &node, &versionSuffix](const string& marker) + string code = syntax.replaceSourceCodeMarkers(node.getName(), _functionSource, + [&shadergenMdl, &context, &node, &versionSuffix, syntax](const string& marker) { // Special handling for the version suffix of MDL source code modules. - if (marker == MARKER_MDL_VERSION_SUFFIX) + if (marker == syntax.getMdlVersionSuffixMarker()) { return versionSuffix; } @@ -131,7 +108,7 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con // Emit the struct multioutput. const string resultVariableName = node.getName() + "_result"; shadergen.emitLineBegin(stage); - shadergen.emitString(_returnStruct + " " + resultVariableName + " = ", stage); + shadergen.emitString("auto " + resultVariableName + " = ", stage); } else { @@ -141,10 +118,7 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con shadergen.emitString(" = ", stage); } - for (const string& c : code) - { - shadergen.emitString(c, stage); - } + shadergen.emitString(code, stage); shadergen.emitLineEnd(stage); } else @@ -156,7 +130,7 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con // Emit the struct multioutput. const string resultVariableName = node.getName() + "_result"; shadergen.emitLineBegin(stage); - shadergen.emitString(_returnStruct + " " + resultVariableName + " = ", stage); + shadergen.emitString("auto " + resultVariableName + " = ", stage); } else { diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h index 23c47e6249..7f595704cc 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h @@ -25,6 +25,7 @@ class MX_GENMDL_API SourceCodeNodeMdl : public SourceCodeNode void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; protected: + void resolveSourceCode(const InterfaceElement& element, GenContext& context) override; string _returnStruct; }; diff --git a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp index dd0444d129..8904d835f4 100644 --- a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -55,6 +56,7 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { const MdlShaderGenerator& shadergen = static_cast(context.getShaderGenerator()); + const MdlSyntax& mdlSyntax = static_cast(shadergen.getSyntax()); // Emit calls for the closure dependencies upstream from this node. shadergen.emitDependentFunctionCalls(node, context, stage, ShaderNode::Classification::CLOSURE); @@ -84,8 +86,7 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex for (ShaderInput* input : node.getInputs()) { shadergen.emitString(delim, stage); - shadergen.emitString("mxp_", stage); - shadergen.emitString(input->getName(), stage); + shadergen.emitString(mdlSyntax.modifyPortName(input->getName()), stage); shadergen.emitString(": ", stage); shadergen.emitInput(input, context, stage); delim = ", "; diff --git a/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp b/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp index 936edf9b46..32fc345354 100644 --- a/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp +++ b/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp @@ -25,6 +25,20 @@ ShaderNodeImplPtr SourceCodeNode::create() return std::make_shared(); } +void SourceCodeNode::resolveSourceCode(const InterfaceElement& element, GenContext& context) +{ + const Implementation& impl = static_cast(element); + + FilePath localPath = FilePath(impl.getActiveSourceUri()).getParentPath(); + _sourceFilename = context.resolveSourceFile(impl.getAttribute("file"), localPath); + _functionSource = readFile(_sourceFilename); + if (_functionSource.empty()) + { + throw ExceptionShaderGenError("Failed to get source code from file '" + _sourceFilename.asString() + + "' used by implementation '" + impl.getName() + "'"); + } +} + void SourceCodeNode::initialize(const InterfaceElement& element, GenContext& context) { ShaderNodeImpl::initialize(element, context); @@ -40,19 +54,13 @@ void SourceCodeNode::initialize(const InterfaceElement& element, GenContext& con _functionSource = impl.getAttribute("sourcecode"); if (_functionSource.empty()) { - FilePath localPath = FilePath(impl.getActiveSourceUri()).getParentPath(); - _sourceFilename = context.resolveSourceFile(impl.getAttribute("file"), localPath); - _functionSource = readFile(_sourceFilename); - if (_functionSource.empty()) - { - throw ExceptionShaderGenError("Failed to get source code from file '" + _sourceFilename.asString() + - "' used by implementation '" + impl.getName() + "'"); - } + resolveSourceCode(element, context); } // Find the function name to use // If no function is given the source will be inlined. _functionName = impl.getAttribute("function"); + _inlined = _functionName.empty(); if (!_inlined) { diff --git a/source/MaterialXGenShader/Nodes/SourceCodeNode.h b/source/MaterialXGenShader/Nodes/SourceCodeNode.h index a208185a8d..6169dc0f61 100644 --- a/source/MaterialXGenShader/Nodes/SourceCodeNode.h +++ b/source/MaterialXGenShader/Nodes/SourceCodeNode.h @@ -26,6 +26,9 @@ class MX_GENSHADER_API SourceCodeNode : public ShaderNodeImpl void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; protected: + /// Resolve the source file and read the source code during the initialization of the node. + virtual void resolveSourceCode(const InterfaceElement& element, GenContext& context); + bool _inlined; string _functionName; string _functionSource; diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index 4bec0016de..610b237163 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -270,7 +270,7 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so CHECK(returnValue == 0); } - if (!renderExec.empty()) // render if renderer is availabe + if (!renderExec.empty()) // render if renderer is available { std::string renderCommand = renderExec;