From 426389c91d7b95764f087cb156cd8ba586fb9f34 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 12 Jul 2023 17:32:44 -0700 Subject: [PATCH 01/20] Update development build to 1.39.0 This changelist updates the development build to 1.39.0, and addresses a few minor edits required to support minor versions more advanced than our test documents. --- CMakeLists.txt | 4 ++-- source/MaterialXCore/Document.cpp | 8 +++++++- source/MaterialXTest/MaterialXFormat/XmlIo.cpp | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86872f26de..a1731b0df0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # MaterialX Version set(MATERIALX_MAJOR_VERSION 1) -set(MATERIALX_MINOR_VERSION 38) -set(MATERIALX_BUILD_VERSION 8) +set(MATERIALX_MINOR_VERSION 39) +set(MATERIALX_BUILD_VERSION 0) set(MATERIALX_LIBRARY_VERSION ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}) # Cmake setup diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index f1a0c4bd1a..a5ecbf733b 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -896,7 +896,7 @@ void Document::upgradeVersion() } // Upgrade from 1.37 to 1.38 - if (majorVersion == 1 && minorVersion >= 37) + if (majorVersion == 1 && minorVersion == 37) { // Convert color2 types to vector2 const StringMap COLOR2_CHANNEL_MAP = { { "r", "x" }, { "a", "y" } }; @@ -1393,6 +1393,12 @@ void Document::upgradeVersion() minorVersion = 38; } + // Upgrade from 1.38 to 1.39 + if (majorVersion == 1 && minorVersion == 38) + { + minorVersion = 39; + } + std::pair upgradedVersion(majorVersion, minorVersion); if (upgradedVersion == expectedVersion) { diff --git a/source/MaterialXTest/MaterialXFormat/XmlIo.cpp b/source/MaterialXTest/MaterialXFormat/XmlIo.cpp index 1336a080c4..0219be87af 100644 --- a/source/MaterialXTest/MaterialXFormat/XmlIo.cpp +++ b/source/MaterialXTest/MaterialXFormat/XmlIo.cpp @@ -253,6 +253,7 @@ TEST_CASE("Comments and newlines", "[xmlio]") mx::XmlReadOptions readOptions; readOptions.readComments = true; readOptions.readNewlines = true; + readOptions.upgradeVersion = false; mx::readFromXmlString(doc, origXml, mx::FileSearchPath(), &readOptions); // Write the document to a new XML string buffer. From c6dcd5d3d415b0a73b5e2edf54b7525ab9985e19 Mon Sep 17 00:00:00 2001 From: Niklas Harrysson Date: Fri, 18 Aug 2023 00:55:09 +0200 Subject: [PATCH 02/20] Simplify thin-film layering into thin-film BSDF parameters (#1413) This change list simplifies the way thin-film iridescence is specified in the PBR library, as discussed in issue #1384. --- .../pbrlib/genglsl/mx_conductor_bsdf.glsl | 12 +- .../pbrlib/genglsl/mx_dielectric_bsdf.glsl | 18 +- .../genglsl/mx_generalized_schlick_bsdf.glsl | 18 +- .../pbrlib/genglsl/pbrlib_genglsl_impl.mtlx | 3 - .../pbrlib/genmdl/pbrlib_genmdl_impl.mtlx | 9 +- .../pbrlib/genmsl/pbrlib_genmsl_impl.mtlx | 3 - .../genosl/legacy/mx_conductor_bsdf.osl | 2 +- .../genosl/legacy/mx_dielectric_bsdf.osl | 2 +- .../legacy/mx_generalized_schlick_bsdf.osl | 2 +- .../pbrlib/genosl/mx_dielectric_bsdf.osl | 8 +- .../genosl/mx_generalized_schlick_bsdf.osl | 8 +- .../pbrlib/genosl/pbrlib_genosl_impl.legacy | 3 - .../pbrlib/genosl/pbrlib_genosl_impl.mtlx | 5 +- libraries/pbrlib/pbrlib_defs.mtlx | 16 +- .../TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx | 5 + .../pbrlib/bsdf/vertical_layering.mtlx | 135 ++--------- source/MaterialXCore/Document.cpp | 85 +++++++ source/MaterialXGenGlsl/GlslSyntax.cpp | 6 +- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 15 +- .../Nodes/ClosureLayerNodeMdl.cpp | 227 +----------------- .../Nodes/ClosureLayerNodeMdl.h | 105 +------- .../MaterialXGenMdl/mdl/materialx/pbrlib.mdl | 38 +-- .../Nodes/ClosureLayerNodeOsl.cpp | 137 ++++------- source/MaterialXGenOsl/OslSyntax.cpp | 6 +- .../Nodes/ClosureLayerNode.cpp | 86 +++---- 25 files changed, 252 insertions(+), 702 deletions(-) diff --git a/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl b/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl index 532550554a..04bbe42dbb 100644 --- a/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl @@ -1,6 +1,6 @@ #include "lib/mx_microfacet_specular.glsl" -void mx_conductor_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, vec3 N, vec3 X, int distribution, inout BSDF bsdf) +void mx_conductor_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, inout BSDF bsdf) { bsdf.throughput = vec3(0.0); @@ -24,8 +24,8 @@ void mx_conductor_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); FresnelData fd; - if (bsdf.thickness > 0.0) - fd = mx_init_fresnel_conductor_airy(ior_n, ior_k, bsdf.thickness, bsdf.ior); + if (thinfilm_thickness > 0.0) + fd = mx_init_fresnel_conductor_airy(ior_n, ior_k, thinfilm_thickness, thinfilm_ior); else fd = mx_init_fresnel_conductor(ior_n, ior_k); @@ -39,7 +39,7 @@ void mx_conductor_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV); } -void mx_conductor_bsdf_indirect(vec3 V, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, vec3 N, vec3 X, int distribution, inout BSDF bsdf) +void mx_conductor_bsdf_indirect(vec3 V, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, inout BSDF bsdf) { bsdf.throughput = vec3(0.0); @@ -53,8 +53,8 @@ void mx_conductor_bsdf_indirect(vec3 V, float weight, vec3 ior_n, vec3 ior_k, ve float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); FresnelData fd; - if (bsdf.thickness > 0.0) - fd = mx_init_fresnel_conductor_airy(ior_n, ior_k, bsdf.thickness, bsdf.ior); + if (thinfilm_thickness > 0.0) + fd = mx_init_fresnel_conductor_airy(ior_n, ior_k, thinfilm_thickness, thinfilm_ior); else fd = mx_init_fresnel_conductor(ior_n, ior_k); diff --git a/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl b/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl index dcaaadf1fa..826b9c24e5 100644 --- a/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl @@ -1,6 +1,6 @@ #include "lib/mx_microfacet_specular.glsl" -void mx_dielectric_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 tint, float ior, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +void mx_dielectric_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 tint, float ior, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) { if (weight < M_FLOAT_EPS) { @@ -22,9 +22,9 @@ void mx_dielectric_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, floa vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); FresnelData fd; - if (bsdf.thickness > 0.0) + if (thinfilm_thickness > 0.0) { - fd = mx_init_fresnel_dielectric_airy(ior, bsdf.thickness, bsdf.ior); + fd = mx_init_fresnel_dielectric_airy(ior, thinfilm_thickness, thinfilm_ior); } else { @@ -43,7 +43,7 @@ void mx_dielectric_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, floa bsdf.response = D * F * G * comp * tint * occlusion * weight / (4.0 * NdotV); } -void mx_dielectric_bsdf_transmission(vec3 V, float weight, vec3 tint, float ior, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +void mx_dielectric_bsdf_transmission(vec3 V, float weight, vec3 tint, float ior, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) { if (weight < M_FLOAT_EPS) { @@ -54,9 +54,9 @@ void mx_dielectric_bsdf_transmission(vec3 V, float weight, vec3 tint, float ior, float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); FresnelData fd; - if (bsdf.thickness > 0.0) + if (thinfilm_thickness > 0.0) { - fd = mx_init_fresnel_dielectric_airy(ior, bsdf.thickness, bsdf.ior); + fd = mx_init_fresnel_dielectric_airy(ior, thinfilm_thickness, thinfilm_ior); } else { @@ -78,7 +78,7 @@ void mx_dielectric_bsdf_transmission(vec3 V, float weight, vec3 tint, float ior, } } -void mx_dielectric_bsdf_indirect(vec3 V, float weight, vec3 tint, float ior, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +void mx_dielectric_bsdf_indirect(vec3 V, float weight, vec3 tint, float ior, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) { if (weight < M_FLOAT_EPS) { @@ -90,9 +90,9 @@ void mx_dielectric_bsdf_indirect(vec3 V, float weight, vec3 tint, float ior, vec float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); FresnelData fd; - if (bsdf.thickness > 0.0) + if (thinfilm_thickness > 0.0) { - fd = mx_init_fresnel_dielectric_airy(ior, bsdf.thickness, bsdf.ior); + fd = mx_init_fresnel_dielectric_airy(ior, thinfilm_thickness, thinfilm_ior); } else { diff --git a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl index ebeaa66f7a..4aa7e9efe6 100644 --- a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl @@ -1,6 +1,6 @@ #include "lib/mx_microfacet_specular.glsl" -void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) { if (weight < M_FLOAT_EPS) { @@ -22,9 +22,9 @@ void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlus vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); FresnelData fd; - if (bsdf.thickness > 0.0) + if (thinfilm_thickness > 0.0) { - fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); + fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, thinfilm_thickness, thinfilm_ior); } else { @@ -43,7 +43,7 @@ void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlus bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV); } -void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) { if (weight < M_FLOAT_EPS) { @@ -54,9 +54,9 @@ void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); FresnelData fd; - if (bsdf.thickness > 0.0) + if (thinfilm_thickness > 0.0) { - fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); + fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, thinfilm_thickness, thinfilm_thickness); } else { @@ -80,7 +80,7 @@ void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, } } -void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) { if (weight < M_FLOAT_EPS) { @@ -91,9 +91,9 @@ void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); FresnelData fd; - if (bsdf.thickness > 0.0) + if (thinfilm_thickness > 0.0) { - fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); + fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, thinfilm_thickness, thinfilm_ior); } else { diff --git a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx index fa4617375f..5980b1f02c 100644 --- a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx +++ b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx @@ -28,9 +28,6 @@ - - - diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index 800e32edd0..429e103b84 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -11,13 +11,13 @@ - + - + - + @@ -25,9 +25,6 @@ - - - diff --git a/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx b/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx index 8d1d2a4729..51f0ba14b8 100644 --- a/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx +++ b/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx @@ -28,9 +28,6 @@ - - - diff --git a/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl index 850ff58f62..82cb6f32be 100644 --- a/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl +++ b/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl @@ -1,6 +1,6 @@ #include "../lib/mx_microfacet_specular.osl" -void mx_conductor_bsdf(float weight, color ior_n, color ior_k, vector2 roughness, normal N, vector U, string distribution, output BSDF bsdf) +void mx_conductor_bsdf(float weight, color ior_n, color ior_k, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, output BSDF bsdf) { bsdf.throughput = color(0.0); diff --git a/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl index a17fdd40cf..5e50834746 100644 --- a/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl +++ b/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl @@ -1,6 +1,6 @@ #include "../lib/mx_microfacet_specular.osl" -void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) +void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) { if (scatter_mode == "T") { diff --git a/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl index ee34727ec1..59fc64bfd4 100644 --- a/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl +++ b/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl @@ -1,6 +1,6 @@ #include "../lib/mx_microfacet_specular.osl" -void mx_generalized_schlick_bsdf(float weight, color color0, color color90, float exponent, vector2 roughness, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) +void mx_generalized_schlick_bsdf(float weight, color color0, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) { float avgF0 = dot(color0, color(1.0 / 3.0)); float ior = mx_f0_to_ior(avgF0); diff --git a/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl b/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl index 69773b3ced..fe570e1546 100644 --- a/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl +++ b/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl @@ -1,15 +1,15 @@ -void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) +void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) { if (scatter_mode == "R") { - bsdf = weight * dielectric_bsdf(N, U, tint, color(0.0), roughness.x, roughness.y, ior, distribution); + bsdf = weight * dielectric_bsdf(N, U, tint, color(0.0), roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); } else if (scatter_mode == "T") { - bsdf = weight * dielectric_bsdf(N, U, color(0.0), tint, roughness.x, roughness.y, ior, distribution); + bsdf = weight * dielectric_bsdf(N, U, color(0.0), tint, roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); } else { - bsdf = weight * dielectric_bsdf(N, U, tint, tint, roughness.x, roughness.y, ior, distribution); + bsdf = weight * dielectric_bsdf(N, U, tint, tint, roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); } } diff --git a/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl b/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl index 955de3c1fa..80431b5af2 100644 --- a/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl +++ b/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl @@ -1,15 +1,15 @@ -void mx_generalized_schlick_bsdf(float weight, color color0, color color90, float exponent, vector2 roughness, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) +void mx_generalized_schlick_bsdf(float weight, color color0, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) { if (scatter_mode == "R") { - bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(0.0), roughness.x, roughness.y, color0, color90, exponent, distribution); + bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(0.0), roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); } else if (scatter_mode == "T") { - bsdf = weight * generalized_schlick_bsdf(N, U, color(0.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution); + bsdf = weight * generalized_schlick_bsdf(N, U, color(0.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); } else { - bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution); + bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); } } diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy b/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy index 6ab7cc9e61..e4a424e1ac 100644 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy +++ b/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy @@ -28,9 +28,6 @@ - - - diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx index 7a38f0fb12..69e4574e45 100644 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx +++ b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx @@ -14,7 +14,7 @@ - + @@ -28,9 +28,6 @@ - - - diff --git a/libraries/pbrlib/pbrlib_defs.mtlx b/libraries/pbrlib/pbrlib_defs.mtlx index e63625a45d..47fa249b08 100644 --- a/libraries/pbrlib/pbrlib_defs.mtlx +++ b/libraries/pbrlib/pbrlib_defs.mtlx @@ -63,6 +63,8 @@ + + @@ -79,6 +81,8 @@ + + @@ -95,6 +99,8 @@ + + @@ -127,16 +133,6 @@ - - - - - - - diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx index a6bc23bfa2..68bd46b52f 100644 --- a/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx +++ b/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx @@ -1,5 +1,10 @@ + + + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/vertical_layering.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/vertical_layering.mtlx index 206f6b1f00..657b9a6462 100644 --- a/resources/Materials/TestSuite/pbrlib/bsdf/vertical_layering.mtlx +++ b/resources/Materials/TestSuite/pbrlib/bsdf/vertical_layering.mtlx @@ -17,129 +17,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -183,7 +90,7 @@ - + @@ -205,7 +112,7 @@ - + @@ -234,7 +141,7 @@ - + @@ -274,7 +181,7 @@ - + diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index a5ecbf733b..46d0552250 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -46,6 +46,44 @@ NodeDefPtr getShaderNodeDef(ElementPtr shaderRef) return NodeDefPtr(); } +void copyConnectionOrValue(NodePtr srcNode, const string& srcInput, NodePtr dstNode, const string& dstInput) +{ + InputPtr src = srcNode->getInput(srcInput); + if (src) + { + InputPtr dst = dstNode->getInput(dstInput); + if (!dst) + { + dst = dstNode->addInput(dstInput, src->getType()); + } + + if (src->hasNodeName()) + { + dst->setNodeName(src->getNodeName()); + if (src->hasOutputString()) + { + dst->setOutputString(src->getOutputString()); + } + } + else if (src->hasNodeGraphString()) + { + dst->setNodeGraphString(src->getNodeGraphString()); + if (src->hasOutputString()) + { + dst->setOutputString(src->getOutputString()); + } + } + else if (src->hasInterfaceName()) + { + dst->setInterfaceName(src->getInterfaceName()); + } + else if (src->hasValueString()) + { + dst->setValueString(src->getValueString()); + } + } +} + } // anonymous namespace // @@ -1396,6 +1434,53 @@ void Document::upgradeVersion() // Upgrade from 1.38 to 1.39 if (majorVersion == 1 && minorVersion == 38) { + const StringSet BSDF_WITH_THINFILM = { "dielectric_bsdf", "conductor_bsdf", "generalized_schlick_bsdf" }; + const string LAYER = "layer"; + const string TOP = "top"; + const string BASE = "base"; + const string THIN_FILM_BSDF = "thin_film_bsdf"; + const string THICKNESS = "thickness"; + const string IOR = "ior"; + const string THINFILM_THICKNESS = "thinfilm_thickness"; + const string THINFILM_IOR = "thinfilm_ior"; + + // Convert layering of thin_film_bsdf nodes to thin-film parameters on the affected BSDF nodes. + for (ElementPtr elem : traverseTree()) + { + if (elem->isA(LAYER)) + { + NodePtr layer = elem->asA(); + NodePtr top = layer->getConnectedNode(TOP); + NodePtr base = layer->getConnectedNode(BASE); + if (top && base && top->getCategory() == THIN_FILM_BSDF) + { + // Apply thin-film parameters to all supported BSDF's upstream. + for (Edge edge : layer->traverseGraph()) + { + NodePtr upstream = edge.getUpstreamElement()->asA(); + if (upstream && BSDF_WITH_THINFILM.count(upstream->getCategory())) + { + copyConnectionOrValue(top, THICKNESS, upstream, THINFILM_THICKNESS); + copyConnectionOrValue(top, IOR, upstream, THINFILM_IOR); + } + } + + // Bypass the thin-film layer operator. + vector downstreamPorts = layer->getDownstreamPorts(); + for (auto port : downstreamPorts) + { + port->setNodeName(base->getName()); + } + + // Remove the now unused nodes. + removeNode(layer->getName()); + removeNode(top->getName()); + } + } + } + + removeNodeDef("ND_thin_film_bsdf"); + minorVersion = 39; } diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp index afd6f033dc..bf9964642e 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.cpp +++ b/source/MaterialXGenGlsl/GlslSyntax.cpp @@ -281,10 +281,10 @@ GlslSyntax::GlslSyntax() Type::BSDF, std::make_shared( "BSDF", - "BSDF(vec3(0.0),vec3(1.0), 0.0, 0.0)", + "BSDF(vec3(0.0),vec3(1.0))", EMPTY_STRING, EMPTY_STRING, - "struct BSDF { vec3 response; vec3 throughput; float thickness; float ior; };")); + "struct BSDF { vec3 response; vec3 throughput; };")); registerTypeSyntax( Type::EDF, @@ -299,7 +299,7 @@ GlslSyntax::GlslSyntax() Type::VDF, std::make_shared( "BSDF", - "BSDF(vec3(0.0),vec3(1.0), 0.0, 0.0)", + "BSDF(vec3(0.0),vec3(1.0))", EMPTY_STRING)); registerTypeSyntax( diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index dddf1f2f13..2977f83f56 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -168,22 +168,11 @@ MdlShaderGenerator::MdlShaderGenerator() : registerImplementation("IM_layer_bsdf_" + MdlShaderGenerator::TARGET, ClosureLayerNodeMdl::create); registerImplementation("IM_layer_vdf_" + MdlShaderGenerator::TARGET, ClosureLayerNodeMdl::create); - registerImplementation("IM_mix_bsdf_" + MdlShaderGenerator::TARGET, MixBsdfNodeMdl::create); - registerImplementation("IM_add_bsdf_" + MdlShaderGenerator::TARGET, AddOrMultiplyBsdfNodeMdl::create); - registerImplementation("IM_multiply_bsdfC_" + MdlShaderGenerator::TARGET, AddOrMultiplyBsdfNodeMdl::create); - registerImplementation("IM_multiply_bsdfF_" + MdlShaderGenerator::TARGET, AddOrMultiplyBsdfNodeMdl::create); - - // - registerImplementation("IM_thin_film_bsdf_" + MdlShaderGenerator::TARGET, ClosureLayerNodeMdl::create); - // - registerImplementation("IM_dielectric_bsdf_" + MdlShaderGenerator::TARGET, ThinFilmReceiverNodeMdl::create); - - // - registerImplementation("IM_conductor_bsdf_" + MdlShaderGenerator::TARGET, ThinFilmReceiverNodeMdl::create); + registerImplementation("IM_dielectric_bsdf_" + MdlShaderGenerator::TARGET, LayerableNodeMdl::create); // - registerImplementation("IM_generalized_schlick_bsdf_" + MdlShaderGenerator::TARGET, ThinFilmReceiverNodeMdl::create); + registerImplementation("IM_generalized_schlick_bsdf_" + MdlShaderGenerator::TARGET, LayerableNodeMdl::create); // registerImplementation("IM_sheen_bsdf_" + MdlShaderGenerator::TARGET, LayerableNodeMdl::create); diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index fd27d5e547..1dfa45317f 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -16,17 +16,6 @@ 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::IN1 = "in1"; -const string StringConstantsMdl::IN2 = "in2"; - -const string StringConstantsMdl::THICKNESS = "thickness"; -const string StringConstantsMdl::IOR = "ior"; -const string StringConstantsMdl::THIN_FILM_THICKNESS = "thinfilm_thickness"; -const string StringConstantsMdl::THIN_FILM_IOR = "thinfilm_ior"; - -const string StringConstantsMdl::EMPTY = ""; ShaderNodeImplPtr ClosureLayerNodeMdl::create() { @@ -109,69 +98,11 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& return; } - // Special composition based on the layers. - - // Handle the layering of thin film onto another node separately. - // This reads the parameters from the thin film bsdf and passes them to base. - if (top->hasClassification(ShaderNode::Classification::THINFILM)) - { - emitBsdfOverBsdfFunctionCalls_thinFilm(node, context, stage, shadergen, top, base, output); - return; - } - - // Otherwise, if the layer is carrying thin film parameters already, - // they are pushed further down to the top and base node if they supported it. - ShaderInput* layerNodeThicknessInput = node.getInput(StringConstantsMdl::THIN_FILM_THICKNESS); - ShaderInput* layerNodeIorInput = node.getInput(StringConstantsMdl::THIN_FILM_IOR); - - ShaderInput* topNodeThicknessInput = top->getInput(StringConstantsMdl::THIN_FILM_THICKNESS); - ShaderInput* topNodeIorInput = top->getInput(StringConstantsMdl::THIN_FILM_IOR); - bool breakTopConnection = false; - if (layerNodeThicknessInput && layerNodeIorInput && topNodeThicknessInput && topNodeIorInput) - { - topNodeThicknessInput->makeConnection(layerNodeThicknessInput->getConnection()); - topNodeIorInput->makeConnection(layerNodeIorInput->getConnection()); - breakTopConnection = true; - } - ShaderInput* baseNodeThicknessInput = base->getInput(StringConstantsMdl::THIN_FILM_THICKNESS); - ShaderInput* baseNodeIorInput = base->getInput(StringConstantsMdl::THIN_FILM_IOR); - bool breakBaseConnection = false; - if (layerNodeThicknessInput && layerNodeIorInput && baseNodeThicknessInput && baseNodeIorInput) - { - baseNodeThicknessInput->makeConnection(layerNodeThicknessInput->getConnection()); - baseNodeIorInput->makeConnection(layerNodeIorInput->getConnection()); - breakBaseConnection = true; - } - - // note, this called for all layering operations independent of thin film - emitBsdfOverBsdfFunctionCalls(node, context, stage, shadergen, top, base, output); - - if (breakTopConnection) - { - topNodeThicknessInput->breakConnection(); - topNodeIorInput->breakConnection(); - } - if (breakBaseConnection) - { - baseNodeThicknessInput->breakConnection(); - baseNodeIorInput->breakConnection(); - } -} - -void ClosureLayerNodeMdl::emitBsdfOverBsdfFunctionCalls( - const ShaderNode& node, - GenContext& context, - ShaderStage& stage, - const ShaderGenerator& shadergen, - ShaderNode* top, - ShaderNode* base, - ShaderOutput* output) const -{ - // transport the base bsdf further than one layer + // Transport the base bsdf further than one layer ShaderNode* baseReceiverNode = top; while (true) { - // if the top node is again a layer, we don't want to override the base + // If the top node is again a layer, we don't want to override the base // parameter but instead aim for the base parameter of layers base if (baseReceiverNode->hasClassification(ShaderNode::Classification::LAYER)) { @@ -230,58 +161,6 @@ void ClosureLayerNodeMdl::emitBsdfOverBsdfFunctionCalls( topNodeBaseInput->breakConnection(); } -void ClosureLayerNodeMdl::emitBsdfOverBsdfFunctionCalls_thinFilm( - const ShaderNode& node, - GenContext& context, - ShaderStage& stage, - const ShaderGenerator& shadergen, - ShaderNode* top, - ShaderNode* base, - ShaderOutput* output) const -{ - ShaderInput* thinFilmThicknessInput = top->getInput(StringConstantsMdl::THICKNESS); - ShaderInput* thinFilmIorInput = top->getInput(StringConstantsMdl::IOR); - - ShaderInput* baseNodeThicknessInput = base->getInput(StringConstantsMdl::THIN_FILM_THICKNESS); - ShaderInput* baseNodeIorInput = base->getInput(StringConstantsMdl::THIN_FILM_IOR); - - // Make sure the base node has thickness and IOR inputs for thin film. - if (!baseNodeThicknessInput || !baseNodeIorInput) - { - shadergen.emitComment("Warning: The base node does not have parameters to transport thin-film thickness and IOR.", stage); - - // Change the state so we emit the base BSDF function without thin film - // with output variable name from the layer node itself. - ScopedSetVariableName setVariable(output->getVariable(), base->getOutput()); - - // Make the call. - if (base->getParent() == node.getParent()) - { - base->getImplementation().emitFunctionCall(*base, context, stage); - } - return; - } - - // Emit the base operation with the thin-film parameters of the top node - // pushed down to the base node. - baseNodeThicknessInput->makeConnection(thinFilmThicknessInput->getConnection()); - baseNodeIorInput->makeConnection(thinFilmIorInput->getConnection()); - - // Change the output of this node to the output of base. - // This basically removes the top as it is not needed anymore. - ScopedSetVariableName setVariable(output->getVariable(), base->getOutput()); - - // Make the call. - if (base->getParent() == node.getParent()) - { - base->getImplementation().emitFunctionCall(*base, context, stage); - } - - // Restore state. - baseNodeThicknessInput->breakConnection(); - baseNodeIorInput->breakConnection(); -} - ShaderNodeImplPtr LayerableNodeMdl::create() { return std::make_shared(); @@ -293,106 +172,4 @@ void LayerableNodeMdl::addInputs(ShaderNode& node, GenContext& /*context*/) cons node.addInput(StringConstantsMdl::BASE, Type::BSDF); } -ShaderNodeImplPtr ThinFilmReceiverNodeMdl::create() -{ - return std::make_shared(); -} - -void ThinFilmCombineNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& context, ShaderStage& stage) const -{ - const ShaderGenerator& shadergen = context.getShaderGenerator(); - ShaderNode& node = const_cast(_node); - - ShaderInput* topInput = node.getInput(getOperatorName(0)); - ShaderInput* baseInput = node.getInput(getOperatorName(1)); - - ShaderNode* top = topInput->getConnection()->getNode(); - ShaderNode* base = baseInput->getConnection()->getNode(); - - // Otherwise, if the combine node is carrying thin film parameters already, - // they are pushed further down to the top and base node if they supported it. - ShaderInput* layerNodeThicknessInput = node.getInput(StringConstantsMdl::THIN_FILM_THICKNESS); - ShaderInput* layerNodeIorInput = node.getInput(StringConstantsMdl::THIN_FILM_IOR); - - ShaderInput* topNodeThicknessInput = top->getInput(StringConstantsMdl::THIN_FILM_THICKNESS); - ShaderInput* topNodeIorInput = top->getInput(StringConstantsMdl::THIN_FILM_IOR); - bool breakTopConnection = false; - if (layerNodeThicknessInput && layerNodeIorInput && topNodeThicknessInput && topNodeIorInput) - { - topNodeThicknessInput->makeConnection(layerNodeThicknessInput->getConnection()); - topNodeIorInput->makeConnection(layerNodeIorInput->getConnection()); - breakTopConnection = true; - } - ShaderInput* baseNodeThicknessInput = base->getInput(StringConstantsMdl::THIN_FILM_THICKNESS); - ShaderInput* baseNodeIorInput = base->getInput(StringConstantsMdl::THIN_FILM_IOR); - bool breakBaseConnection = false; - if (layerNodeThicknessInput && layerNodeIorInput && baseNodeThicknessInput && baseNodeIorInput) - { - baseNodeThicknessInput->makeConnection(layerNodeThicknessInput->getConnection()); - baseNodeIorInput->makeConnection(layerNodeIorInput->getConnection()); - breakBaseConnection = true; - } - - // Emit the fore and background calls. - // Make sure it's a sibling node and not the graph interface. - if (top->getParent() == node.getParent()) - { - shadergen.emitFunctionCall(*top, context, stage); - } - if (base->getParent() == node.getParent()) - { - shadergen.emitFunctionCall(*base, context, stage); - } - - // Note, this is called for all combine operations independent of thin film. - Base::emitFunctionCall(_node, context, stage); - - if (breakTopConnection) - { - topNodeThicknessInput->breakConnection(); - topNodeIorInput->breakConnection(); - } - if (breakBaseConnection) - { - baseNodeThicknessInput->breakConnection(); - baseNodeIorInput->breakConnection(); - } -} - -ShaderNodeImplPtr MixBsdfNodeMdl::create() -{ - return std::make_shared(); -} - -const string& MixBsdfNodeMdl::getOperatorName(size_t index) const -{ - switch (index) - { - case 0: - return StringConstantsMdl::FG; - case 1: - return StringConstantsMdl::BG; - default: - return StringConstantsMdl::EMPTY; - } -} - -ShaderNodeImplPtr AddOrMultiplyBsdfNodeMdl::create() -{ - return std::make_shared(); -} - -const string& AddOrMultiplyBsdfNodeMdl::getOperatorName(size_t index) const -{ - switch (index) - { - case 0: - return StringConstantsMdl::IN1; - case 1: - return StringConstantsMdl::IN2; - default: - return StringConstantsMdl::EMPTY; - } -} - MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h index 75ea46046c..729b835560 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h @@ -23,75 +23,15 @@ 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; ///< parameter of the mix node - static const string BG; ///< parameter of the mix node - static const string IN1; ///< parameter of the add and multiply nodes - static const string IN2; ///< parameter of the add and multiply nodes - - static const string THICKNESS; ///< thickness parameter name of the thin_film_bsdf - static const string IOR; ///< ior parameter name of the thin_film_bsdf - - static const string THIN_FILM_THICKNESS; ///< helper parameter name for transporting thickness - static const string THIN_FILM_IOR; ///< helper parameter name for transporting ior - - static const string EMPTY; ///< the empty string "" -}; - -/// Helper class to be injected into nodes that need to carry thin film parameters from the -/// thin_film_bsdf through layers and mixers, etc., to the elemental bsdfs that support thin film. -/// Because thin-film can not be layered on any BSDF in MDL, we try to push down the parameters to -/// the nodes that support thin-film. -template class CarryThinFilmParameters : public TBase -{ - public: - /// Add the thin film inputs for transporting the parameter. - /// `addInputs` for the injected base class is called first. - void addInputs(ShaderNode& node, GenContext& context) const override - { - TBase::addInputs(node, context); - node.addInput(StringConstantsMdl::THIN_FILM_THICKNESS, Type::FLOAT); - node.addInput(StringConstantsMdl::THIN_FILM_IOR, Type::FLOAT); - } - - /// Mark the thin film parameters as not editable because connections are - /// created while emitting the MDL code and the default values should not - /// get exposed to the public material interface. - bool isEditable(const ShaderInput& input) const override - { - if (input.getName() == StringConstantsMdl::THIN_FILM_THICKNESS || - input.getName() == StringConstantsMdl::THIN_FILM_IOR) - { - return false; - } - return TBase::isEditable(input); - } }; /// Closure layer node implementation for MDL. -class MX_GENMDL_API ClosureLayerNodeMdl : public CarryThinFilmParameters +class MX_GENMDL_API ClosureLayerNodeMdl : public ShaderNodeImpl { public: static ShaderNodeImplPtr create(); void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; - - void emitBsdfOverBsdfFunctionCalls( - const ShaderNode& node, - GenContext& context, - ShaderStage& stage, - const ShaderGenerator& shadergen, - ShaderNode* top, - ShaderNode* base, - ShaderOutput* output) const; - - void emitBsdfOverBsdfFunctionCalls_thinFilm( - const ShaderNode& node, - GenContext& context, - ShaderStage& stage, - const ShaderGenerator& shadergen, - ShaderNode* top, - ShaderNode* base, - ShaderOutput* output) const; }; /// Layerable BSDF node. @@ -107,49 +47,6 @@ class MX_GENMDL_API LayerableNodeMdl : public SourceCodeNodeMdl void addInputs(ShaderNode& node, GenContext&) const override; }; -/// Used for elemental nodes that can consume thin film. -class MX_GENMDL_API ThinFilmReceiverNodeMdl : public CarryThinFilmParameters -{ - using Base = CarryThinFilmParameters; - - public: - static ShaderNodeImplPtr create(); -}; - -/// Base class for operators that on bsdfs that need to transport the thin film parameters -class ThinFilmCombineNodeMdl : public CarryThinFilmParameters -{ - using Base = CarryThinFilmParameters; - - public: - virtual ~ThinFilmCombineNodeMdl() = default; - - void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; - - protected: - virtual const string& getOperatorName(size_t index) const = 0; -}; - -/// Used for mix_bsdf nodes. -class MX_GENMDL_API MixBsdfNodeMdl : public ThinFilmCombineNodeMdl -{ - public: - static ShaderNodeImplPtr create(); - - protected: - virtual const string& getOperatorName(size_t index) const final; -}; - -/// Used for add_bsdf and multpli_bsdf nodes. -class MX_GENMDL_API AddOrMultiplyBsdfNodeMdl : public ThinFilmCombineNodeMdl -{ - public: - static ShaderNodeImplPtr create(); - - protected: - virtual const string& getOperatorName(size_t index) const final; -}; - MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl index 61234c4037..3f285890bd 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl @@ -147,13 +147,13 @@ export material mx_dielectric_bsdf( color mxp_tint = color(1.0), float mxp_ior = 1.5, float2 mxp_roughness = float2(0.0), + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0, float3 mxp_normal = state::normal(), float3 mxp_tangent = state::texture_tangent_u(0), uniform mx_distribution_type mxp_distribution = 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") ]], - float mxp_thinfilm_thickness = 0.0, - float mxp_thinfilm_ior = 1.0 + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]] ) [[ anno::usage( "materialx:bsdf") ]] @@ -220,11 +220,11 @@ export material mx_conductor_bsdf( 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), + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0, float3 mxp_normal = state::normal(), float3 mxp_tangent = state::texture_tangent_u(0), - uniform mx_distribution_type mxp_distribution = mx_distribution_type_ggx [[ anno::unused() ]], - float mxp_thinfilm_thickness = 0.0, - float mxp_thinfilm_ior = 1.0 + uniform mx_distribution_type mxp_distribution = mx_distribution_type_ggx [[ anno::unused() ]] ) [[ anno::usage( "materialx:bsdf") ]] @@ -261,13 +261,13 @@ export material mx_generalized_schlick_bsdf( color mxp_color90 = color(1.0), float mxp_exponent = 5.0, float2 mxp_roughness = float2(0.05), + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0, float3 mxp_normal = state::normal(), float3 mxp_tangent = state::texture_tangent_u(0), uniform mx_distribution_type mxp_distribution = 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") ]], - float mxp_thinfilm_thickness = 0.0, - float mxp_thinfilm_ior = 1.0 + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]] ) [[ anno::usage( "materialx:bsdf") ]] @@ -399,26 +399,6 @@ export material mx_sheen_bsdf( volume: mxp_base.volume ); -export material mx_thin_film_bsdf( - float mxp_thickness = 1000.0, - float mxp_ior = 1.5, - material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]] -) [[ - anno::usage( "materialx:bsdf") -]] -= material( - surface: material_surface( - scattering: df::thin_film( - thickness: mxp_thickness, - ior: color(mxp_ior), - base: mxp_base.surface.scattering - ) - ), - // we need to carry volume properties along for SSS - ior: mxp_base.ior, - volume: mxp_base.volume -); - // EDF Nodes export material mx_uniform_edf( diff --git a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp index 7c3f9d460c..b77eebbd86 100644 --- a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp +++ b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp @@ -41,111 +41,68 @@ void ClosureLayerNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& ClosureContext* cct = context.getClosureContext(); - if (top->hasClassification(ShaderNode::Classification::THINFILM)) + // 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()) { - // This is a layer node with thin-film as top layer. - // Call only the base BSDF but with thin-film parameters set. - - // Make sure the connection to base is a sibling node and not the graph interface. - if (base->getParent() != node.getParent()) - { - throw ExceptionShaderGenError("Thin-film can only be applied to a sibling node, not through a graph interface"); - } - - // Set the extra parameters for thin-film. - ClosureContext::ClosureParams params; - params[THICKNESS] = top->getInput(THICKNESS); - params[IOR] = top->getInput(IOR); - ScopedSetClosureParams setParams(¶ms, base, cct); + // 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); + } - // Store the base result in the layer result variable. - ScopedSetVariableName setVariable(output->getVariable(), base->getOutput()); + // Get the result variables. + const string& topResult = topInput->getConnection()->getVariable(); + const string& baseResult = baseInput->getConnection()->getVariable(); - // Emit the function call. - shadergen.emitFunctionCall(*base, context, stage); + // 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 { - // 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); - } + shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult + ".response * " + topResult + ".throughput", stage); + shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput * " + baseResult + ".throughput", stage); } #else - if (top->hasClassification(ShaderNode::Classification::THINFILM)) + // 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()) { - // Make sure the connection to base is a sibling node and not the graph interface. - if (base->getParent() != node.getParent()) - { - throw ExceptionShaderGenError("Thin-film can only be applied to a sibling node, not through a graph interface"); - } - - // TODO: Thin-film is not supported yet. - // Emit the function call for base layer but - // store the base result in the layer result variable. - ScopedSetVariableName setVariable(output->getVariable(), base->getOutput()); - shadergen.emitFunctionCall(*base, context, stage); + shadergen.emitFunctionCall(*top, context, stage); } - else + if (base->getParent() == node.getParent()) { - // 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()) - { - 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(); - - // Emit the layer closure call. - shadergen.emitLineBegin(stage); - shadergen.emitOutput(output, true, false, context, stage); - shadergen.emitString(" = layer(" + topResult + ", " + baseResult + ")", stage); - shadergen.emitLineEnd(stage); + shadergen.emitFunctionCall(*base, context, stage); } + // Get the result variables. + const string& topResult = topInput->getConnection()->getVariable(); + const string& baseResult = baseInput->getConnection()->getVariable(); + + // Emit the layer closure call. + shadergen.emitLineBegin(stage); + shadergen.emitOutput(output, true, false, context, stage); + shadergen.emitString(" = layer(" + topResult + ", " + baseResult + ")", stage); + shadergen.emitLineEnd(stage); + #endif // MATERIALX_OSL_LEGACY_CLOSURES } diff --git a/source/MaterialXGenOsl/OslSyntax.cpp b/source/MaterialXGenOsl/OslSyntax.cpp index d421c5e3d9..68888c6440 100644 --- a/source/MaterialXGenOsl/OslSyntax.cpp +++ b/source/MaterialXGenOsl/OslSyntax.cpp @@ -451,10 +451,10 @@ OslSyntax::OslSyntax() Type::BSDF, std::make_shared( "BSDF", - "BSDF(null_closure, color(1.0), 0.0, 0.0)", - "{ 0, color(1.0), 0.0, 0.0 }", + "BSDF(null_closure, color(1.0))", + "{ 0, color(1.0) }", "closure color", - "struct BSDF { closure color response; color throughput; float thickness; float ior; };")); + "struct BSDF { closure color response; color throughput; };")); #else diff --git a/source/MaterialXGenShader/Nodes/ClosureLayerNode.cpp b/source/MaterialXGenShader/Nodes/ClosureLayerNode.cpp index a2554365c1..32127de997 100644 --- a/source/MaterialXGenShader/Nodes/ClosureLayerNode.cpp +++ b/source/MaterialXGenShader/Nodes/ClosureLayerNode.cpp @@ -12,8 +12,6 @@ MATERIALX_NAMESPACE_BEGIN const string ClosureLayerNode::TOP = "top"; const string ClosureLayerNode::BASE = "base"; -const string ClosureLayerNode::THICKNESS = "thickness"; -const string ClosureLayerNode::IOR = "ior"; ShaderNodeImplPtr ClosureLayerNode::create() { @@ -44,67 +42,41 @@ void ClosureLayerNode::emitFunctionCall(const ShaderNode& _node, GenContext& con ShaderNode* top = topInput->getConnection()->getNode(); ShaderNode* base = baseInput->getConnection()->getNode(); - if (top->hasClassification(ShaderNode::Classification::THINFILM)) - { - // This is a layer node with thin-film as top layer. - // Call only the base BSDF but with thin-film parameters set. - - // Make sure the connection to base is a sibling node and not the graph interface. - if (base->getParent() != node.getParent()) - { - throw ExceptionShaderGenError("Thin-film can only be applied to a sibling node, not through a graph interface"); - } + // 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? - // Set the extra parameters for thin-film. - ClosureContext::ClosureParams params; - params[THICKNESS] = top->getInput(THICKNESS); - params[IOR] = top->getInput(IOR); - ScopedSetClosureParams setParams(¶ms, base, cct); + // 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); + } - // Store the base result in the layer result variable. - ScopedSetVariableName setVariable(output->getVariable(), base->getOutput()); + // Get the result variables. + const string& topResult = topInput->getConnection()->getVariable(); + const string& baseResult = baseInput->getConnection()->getVariable(); - // Emit the function call. - shadergen.emitFunctionCall(*base, context, stage); + // Calculate the layering result. + emitOutputVariables(node, context, stage); + if (base->getOutput()->getType() == Type::VDF) + { + shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response * " + baseResult + ".throughput", stage); + shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput * " + baseResult + ".throughput", stage); } else { - // 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) - { - shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response * " + baseResult + ".throughput", stage); - shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput * " + baseResult + ".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); - } + shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult + ".response * " + topResult + ".throughput", stage); + shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput * " + baseResult + ".throughput", stage); } } } From e8d9171888bd9a5308797e1922be43e305a4acb3 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 10 Sep 2023 10:20:01 -0700 Subject: [PATCH 03/20] Merge from main to dev_1.39 (#1529) --- .github/workflows/main.yml | 108 +- .gitignore | 1 + CHANGELOG.md | 36 +- CMakeLists.txt | 84 +- cmake/modules/MaterialXConfig.cmake.in | 4 +- cmake/modules/MaterialXVersion.rc.in | 34 + .../Specification/MaterialX.Specification.md | 7 +- javascript/MaterialXView/package-lock.json | 70 +- javascript/MaterialXView/package.json | 4 +- .../MaterialXView/source/dropHandling.js | 281 +++++ javascript/MaterialXView/source/helper.js | 2 - javascript/MaterialXView/source/index.js | 15 + javascript/MaterialXView/source/viewer.js | 1 + libraries/CMakeLists.txt | 34 +- libraries/bxdf/gltf_pbr.mtlx | 46 +- libraries/pbrlib/genosl/mx_blackbody.osl | 11 +- libraries/stdlib/genglsl/mx_image_color3.glsl | 11 +- libraries/stdlib/genglsl/mx_image_color4.glsl | 11 +- libraries/stdlib/genglsl/mx_image_float.glsl | 11 +- .../stdlib/genglsl/mx_image_vector2.glsl | 11 +- .../stdlib/genglsl/mx_image_vector3.glsl | 11 +- .../stdlib/genglsl/mx_image_vector4.glsl | 11 +- libraries/stdlib/stdlib_defs.mtlx | 129 +- libraries/stdlib/stdlib_ng.mtlx | 1049 +++++++++++++++- pyproject.toml | 78 ++ python/CMakeLists.txt | 25 +- python/MaterialX/_scripts/README.md | 2 + python/MaterialX/_scripts/__init__.py | 1 + python/mtx_skbuild_plugin.py | 90 ++ python/setup.py.in | 3 +- resources/CMakeLists.txt | 6 +- .../nodegraph_inputs/top_level_input.mtlx | 10 + .../stdlib/organization/organization.mtlx | 10 + .../stdlib/procedural/linepattern.mtlx | 39 + .../stdlib/procedural/tiledshape.mtlx | 38 + .../stdlib/texture/image_default.mtlx | 36 + source/MaterialXCore/CMakeLists.txt | 38 +- source/MaterialXCore/Definition.cpp | 16 +- source/MaterialXCore/Document.cpp | 12 + source/MaterialXCore/Element.h | 6 +- source/MaterialXCore/Interface.cpp | 9 +- source/MaterialXCore/Interface.h | 3 + source/MaterialXCore/Node.cpp | 29 +- source/MaterialXCore/Node.h | 9 +- source/MaterialXCore/Types.h | 14 +- source/MaterialXFormat/CMakeLists.txt | 40 +- source/MaterialXGenGlsl/CMakeLists.txt | 40 +- source/MaterialXGenMdl/CMakeLists.txt | 44 +- source/MaterialXGenMsl/CMakeLists.txt | 40 +- source/MaterialXGenMsl/MslShaderGenerator.cpp | 2 + source/MaterialXGenOsl/CMakeLists.txt | 41 +- source/MaterialXGenShader/CMakeLists.txt | 44 +- source/MaterialXGenShader/ShaderGraph.cpp | 46 +- source/MaterialXGenShader/ShaderGraph.h | 1 - source/MaterialXGenShader/ShaderNode.cpp | 22 +- source/MaterialXGenShader/ShaderNode.h | 13 +- source/MaterialXGraphEditor/Graph.cpp | 1058 ++++++++++------- source/MaterialXGraphEditor/Graph.h | 104 +- source/MaterialXGraphEditor/RenderView.cpp | 41 +- source/MaterialXGraphEditor/RenderView.h | 6 - source/MaterialXRender/CMakeLists.txt | 44 +- .../OpenImageIO/FindOpenImageIO.cmake | 9 +- source/MaterialXRender/ImageHandler.cpp | 40 +- source/MaterialXRender/ImageHandler.h | 10 +- source/MaterialXRender/ShaderRenderer.cpp | 20 +- source/MaterialXRender/ShaderRenderer.h | 14 +- source/MaterialXRenderGlsl/CMakeLists.txt | 48 +- source/MaterialXRenderGlsl/GlslMaterial.cpp | 2 +- source/MaterialXRenderGlsl/GlslProgram.cpp | 2 +- source/MaterialXRenderGlsl/GlslRenderer.cpp | 12 +- source/MaterialXRenderGlsl/GlslRenderer.h | 3 + source/MaterialXRenderHw/CMakeLists.txt | 53 +- source/MaterialXRenderHw/SimpleWindowIOS.cpp | 40 + source/MaterialXRenderHw/SimpleWindowMac.cpp | 4 + .../MaterialXRenderHw/WindowCocoaWrappers.m | 4 + source/MaterialXRenderHw/WindowWrapper.cpp | 4 + source/MaterialXRenderMsl/CMakeLists.txt | 47 +- source/MaterialXRenderMsl/MslMaterial.mm | 2 +- .../MslPipelineStateObject.mm | 2 +- source/MaterialXRenderMsl/MslRenderer.h | 11 +- source/MaterialXRenderMsl/MslRenderer.mm | 37 +- source/MaterialXRenderOsl/CMakeLists.txt | 40 +- source/MaterialXTest/MaterialXCore/Node.cpp | 18 + .../MaterialXRenderMsl/RenderMsl.mm | 24 +- source/MaterialXView/Viewer.cpp | 4 +- .../PyMaterialXCore/CMakeLists.txt | 4 +- .../PyMaterialXCore/PyInterface.cpp | 1 + source/PyMaterialX/PyMaterialXCore/PyNode.cpp | 1 + .../PyMaterialXFormat/CMakeLists.txt | 4 +- .../PyMaterialXGenGlsl/CMakeLists.txt | 4 +- .../PyMaterialXGenMdl/CMakeLists.txt | 4 +- .../PyMaterialXGenMsl/CMakeLists.txt | 4 +- .../PyMaterialXGenOsl/CMakeLists.txt | 4 +- .../PyMaterialXGenShader/CMakeLists.txt | 4 +- .../PyMaterialXRender/CMakeLists.txt | 4 +- .../PyMaterialXRender/PyImageHandler.cpp | 4 +- .../PyMaterialXRender/PyShaderRenderer.cpp | 1 + .../PyMaterialXRenderGlsl/CMakeLists.txt | 4 +- .../PyMaterialXRenderMsl/CMakeLists.txt | 4 +- .../PyMaterialXRenderOsl/CMakeLists.txt | 4 +- 100 files changed, 3369 insertions(+), 1174 deletions(-) create mode 100644 cmake/modules/MaterialXVersion.rc.in create mode 100644 javascript/MaterialXView/source/dropHandling.js create mode 100644 pyproject.toml create mode 100644 python/MaterialX/_scripts/README.md create mode 100644 python/MaterialX/_scripts/__init__.py create mode 100644 python/mtx_skbuild_plugin.py create mode 100644 resources/Materials/TestSuite/stdlib/nodegraph_inputs/top_level_input.mtlx create mode 100644 resources/Materials/TestSuite/stdlib/procedural/linepattern.mtlx create mode 100644 resources/Materials/TestSuite/stdlib/procedural/tiledshape.mtlx create mode 100644 resources/Materials/TestSuite/stdlib/texture/image_default.mtlx create mode 100644 source/MaterialXRenderHw/SimpleWindowIOS.cpp diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fecdbf7a52..d5ac9d3f79 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -47,18 +47,12 @@ jobs: cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON static_analysis: ON - - name: Linux_Clang_13_Python39 - os: ubuntu-22.04 - compiler: clang - compiler_version: "13" - python: 3.9 - test_render: ON - - name: Linux_Clang_14_Python311 os: ubuntu-22.04 compiler: clang compiler_version: "14" python: 3.11 + test_render: ON clang_format: ON - name: Linux_Clang_14_DynamicAnalysis @@ -89,6 +83,13 @@ jobs: python: 3.11 test_shaders: ON + - name: iOS_Xcode_15 + os: macos-13 + compiler: xcode + compiler_version: "15.0" + python: None + cmake_config: -DMATERIALX_BUILD_IOS=ON -DCMAKE_OSX_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path` -DCMAKE_OSX_ARCHITECTURES=arm64 + - name: Windows_VS2019_Win32_Python37 os: windows-2019 architecture: x86 @@ -159,11 +160,6 @@ jobs: python-version: ${{ matrix.python }} architecture: ${{ matrix.architecture }} - - name: Install OpenImageIO - if: matrix.install_oiio == 'ON' && runner.os == 'Windows' - run: | - vcpkg/vcpkg install openimageio --triplet=x64-windows - - name: Install Emscripten if: matrix.build_javascript == 'ON' run: | @@ -325,3 +321,91 @@ jobs: name: MaterialX_JavaScript path: javascript/build/installed/JavaScript/MaterialX if-no-files-found: ignore + + sdist: + name: Python SDist + runs-on: ubuntu-latest + if: github.repository == 'AcademySoftwareFoundation/MaterialX' + outputs: + sdist_filename: ${{ steps.generate.outputs.filename }} + + steps: + - name: Sync Repository + uses: actions/checkout@v3 + + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + + - name: Build SDist + id: generate + run: | + python -m pip install build + python -m build -s . --outdir dist + echo "filename=$(ls dist)" >> "$GITHUB_OUTPUT" + + - name: Upload SDist + uses: actions/upload-artifact@v3 + with: + name: MaterialX_Python_SDist + path: dist/*.tar.gz + + wheels: + name: Python Wheels + runs-on: ${{ matrix.os }} + needs: ['sdist'] + if: github.repository == 'AcademySoftwareFoundation/MaterialX' + strategy: + fail-fast: false + matrix: + python-minor: ['7', '8', '9', '10', '11'] + os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] + + steps: + - name: Sync Repository + uses: actions/checkout@v3 + + - name: Install Python 3.${{ matrix.python-minor }} + uses: actions/setup-python@v4 + with: + python-version: 3.${{ matrix.python-minor }} + + - name: Download Sdist + uses: actions/download-artifact@v3 + with: + name: MaterialX_Python_SDist + path: sdist + + - name: Build Wheel + uses: pypa/cibuildwheel@v2.13.1 + with: + package-dir: ${{ github.workspace }}/sdist/${{ needs.sdist.outputs.sdist_filename }} + env: + CIBW_BUILD: 'cp3${{ matrix.python-minor }}-*' + CIBW_SKIP: '*musllinux*' + CIBW_ARCHS: 'auto64' + # https://github.com/pypa/manylinux + # manylinux2014 is CentOS 7 based. Which means GCC 10 and glibc 2.17. + CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 + CIBW_BEFORE_ALL_LINUX: yum install -y libXt-devel + CIBW_BEFORE_ALL_MACOS: sudo xcode-select -switch /Applications/Xcode_13.4.app + CIBW_BUILD_VERBOSITY: 1 + CIBW_ENVIRONMENT: CMAKE_BUILD_PARALLEL_LEVEL=2 + # CIBW_BUILD_FRONTEND: build # https://github.com/pypa/build + MACOSX_DEPLOYMENT_TARGET: '10.15' + + - name: Install Wheel + run: python -m pip install MaterialX --find-links wheelhouse --no-index + + - name: Python Tests + run: | + python MaterialXTest/main.py + python MaterialXTest/genshader.py + working-directory: python + + - name: Upload Wheel + uses: actions/upload-artifact@v3 + with: + name: MaterialX_Python_Wheels + path: wheelhouse/*.whl diff --git a/.gitignore b/.gitignore index 378eac25d3..9d0b71a3c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ build +dist diff --git a/CHANGELOG.md b/CHANGELOG.md index a27b8d124c..5704c54b84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,40 @@ # Change Log -## [1.38.8] - Development +## [1.38.8] - 2023-09-08 + +### Added +- Added a broad set of new pattern nodes to MaterialX, including [Circle, Hexagon, Cloverleaf, Line, Grid, Crosshatch](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1411), [Checkerboard](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1328), [Random Color, Random Float](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1330), [Triangle Wave](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1334), [Integer Floor, Integer Ceiling](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1362), and [Distance](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1333). +- Added support for [MaterialX builds on iOS](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1435). +- Added support for [drag-and-drop import](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1482) of MaterialX files in the [Web Viewer](https://academysoftwarefoundation.github.io/MaterialX/). +- Added generation of [MaterialX Python wheels](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1317) in GitHub Actions, enabling the distribution of MaterialX Python packages through PyPI. +- Added support for the [lin_displayp3 and srgb_displayp3](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1368) colorspaces in shader generation. +- Added support for the [blackbody PBR node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1367) in shader generation. +- Added support for [displacement](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1396) in MDL generation. +- Added [blend](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1350) and [up-axis](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1489) controls to the triplanar projection node. +- Added version details to [shared libraries](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1447) on Windows. +- Added a [MacOS 13](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1375) build to GitHub Actions. + +### Changed +- Raised the minimum C++ version for MaterialX builds to [C++14](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1340). +- Upgraded the [PyBind11 library](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1343) to version 2.10.4, raising the minimum Python version to 3.6, and enabling support for Python versions 3.11 and beyond. +- Improved the performance and convergence of [GGX importance sampling](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1390) in GLSL generation, leveraging insights from the HPG 2023 paper by Jonathan Dupuy and Anis Benyoub. +- Improved [property panel display](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1346) in the MaterialX Graph Editor. +- Improved [node spacing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1476) in the MaterialX Graph Editor. +- Improved the robustness of [MaterialX unit tests](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1370) with respect to the current working directory. +- Simplified the handling of [default colors](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1452) in GLSL generation, removing dynamic branches on texture size. +- Simplified the definitions of the [default color transforms](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1352), implementing them as language-independent MaterialX graphs. +- Simplified the interface of [ShaderGenerator::emitFunctionCall](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1344), marking its original interface as deprecated. +- Marked legacy interfaces for [findRenderableElements and findRenderableMaterialNodes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1340) as deprecated, making their usage visible to clients as compiler warnings. +- Moved the MaterialX specification to [public Markdown files in GitHub](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/documents/Specification), enabling direct contributions from the community. + +### Fixed +- Fixed brightness artifacts in the [triplanar projection node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1350). +- Aligned default values for [conductor_bsdf](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1379) with the MaterialX specification. +- Fixed [volume mixing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1395) in MDL generation. +- Fixed a bug to improve [shader generation determinism](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1376). +- Fixed a bug to improve the [consistency of auto layout](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1389) in the MaterialX Graph Editor. +- Fixed a bug to enable [multi-output connection edits](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1506) in the MaterialX Graph Editor. +- Fixed a bug in [dot node optimizations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1522) for shader generation. ## [1.38.7] - 2023-04-21 diff --git a/CMakeLists.txt b/CMakeLists.txt index a1731b0df0..504563d28b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(MATERIALX_BUILD_VERSION 0) set(MATERIALX_LIBRARY_VERSION ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}) # Cmake setup -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) set(CMAKE_CXX_STANDARD 14) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) set(CMAKE_MACOSX_RPATH ON) @@ -31,7 +31,7 @@ if (MATERIALX_BUILD_JS) endif() endif() -project(MaterialX) +project(MaterialX VERSION ${MATERIALX_LIBRARY_VERSION}) option(MATERIALX_BUILD_PYTHON "Build the MaterialX Python package from C++ bindings. Requires Python 3.6 or greater." OFF) option(MATERIALX_BUILD_VIEWER "Build the MaterialX Viewer." OFF) @@ -49,11 +49,25 @@ option(MATERIALX_BUILD_TESTS "Build unit tests." ON) option(MATERIALX_BUILD_SHARED_LIBS "Build MaterialX libraries as shared rather than static." OFF) option(MATERIALX_PYTHON_LTO "Enable link-time optimizations for MaterialX Python." ON) option(MATERIALX_INSTALL_PYTHON "Install the MaterialX Python package as a third-party library when the install target is built." ON) +option(MATERIALX_INSTALL_RESOURCES "Install the resources folder when building render modules." ON) option(MATERIALX_TEST_RENDER "Run rendering tests for MaterialX Render module. GPU required for graphics validation." ON) option(MATERIALX_WARNINGS_AS_ERRORS "Interpret all compiler warnings as errors." OFF) option(MATERIALX_DYNAMIC_ANALYSIS "Build MaterialX libraries with dynamic analysis on supporting platforms." OFF) option(MATERIALX_OSL_LEGACY_CLOSURES "Build OSL shader generation supporting the legacy OSL closures." ON) +option(MATERIALX_BUILD_IOS "Build MaterialX for iOS." OFF) +if (MATERIALX_BUILD_IOS) + set(CMAKE_SYSTEM_NAME iOS) + add_definitions(-DTARGET_OS_IOS=1) + set(MATERIALX_BUILD_PYTHON OFF) + set(MATERIALX_BUILD_VIEWER OFF) + set(MATERIALX_BUILD_GRAPH_EDITOR OFF) + set(MATERIALX_BUILD_GEN_GLSL OFF) + set(MATERIALX_BUILD_GEN_OSL OFF) + set(MATERIALX_BUILD_GEN_MDL OFF) + set(MATERIALX_BUILD_TESTS OFF) +endif() + set(MATERIALX_PYTHON_VERSION "" CACHE STRING "Python version to be used in building the MaterialX Python package (e.g. '3.9').") set(MATERIALX_PYTHON_EXECUTABLE "" CACHE FILEPATH @@ -79,6 +93,12 @@ set(MATERIALX_OSL_BINARY_OSLC "" CACHE FILEPATH "Full path to the OSL compiler b set(MATERIALX_OSL_BINARY_TESTRENDER "" CACHE FILEPATH "Full path to the OSL test render binary.") set(MATERIALX_OSL_INCLUDE_PATH "" CACHE PATH "Full path to OSL shader includes (e.g. 'stdosl.h').") +set(MATERIALX_PYTHON_FOLDER_NAME "python/MaterialX" CACHE INTERNAL "Folder name to user for installing the Python library.") + +if(SKBUILD) + set(MATERIALX_PYTHON_FOLDER_NAME "MaterialX") +endif() + # Helpers for MDL validation if (MATERIALX_BUILD_GEN_MDL) set(MATERIALX_MDLC_EXECUTABLE "" CACHE FILEPATH "Full path to the mdlc binary.") @@ -115,6 +135,7 @@ mark_as_advanced(MATERIALX_NAMESPACE_SUFFIX) mark_as_advanced(MATERIALX_LIBNAME_SUFFIX) mark_as_advanced(MATERIALX_PYTHON_LTO) mark_as_advanced(MATERIALX_INSTALL_PYTHON) +mark_as_advanced(MATERIALX_INSTALL_RESOURCES) mark_as_advanced(MATERIALX_TEST_RENDER) mark_as_advanced(MATERIALX_WARNINGS_AS_ERRORS) mark_as_advanced(MATERIALX_DYNAMIC_ANALYSIS) @@ -132,6 +153,7 @@ mark_as_advanced(MATERIALX_INSTALL_LIB_PATH) 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) if (MATERIALX_BUILD_GEN_MDL) mark_as_advanced(MATERIALX_MDLC_EXECUTABLE) mark_as_advanced(MATERIALX_MDL_RENDER_EXECUTABLE) @@ -183,6 +205,12 @@ set(MATERIALX_SAME_DIR_RPATH "${RPATH_RELATIVE_SYMBOL};${CMAKE_INSTALL_PREFIX}/$ set(MATERIALX_UP_ONE_RPATH "${RPATH_RELATIVE_SYMBOL}/../${MATERIALX_INSTALL_LIB_PATH};${MATERIALX_SAME_DIR_RPATH}") # For linking to libraries where source is two directories deep, ie: "MATX/python/MaterialX/../../lib" set(MATERIALX_UP_TWO_RPATH "${RPATH_RELATIVE_SYMBOL}/../../${MATERIALX_INSTALL_LIB_PATH};${MATERIALX_SAME_DIR_RPATH}") +if(SKBUILD) + # When building the Python wheels, we don't want to set any RPATH because + # we want to wheel to be self-contained. We don't want any interference from + # external paths. + set(MATERIALX_UP_TWO_RPATH "${RPATH_RELATIVE_SYMBOL}") +endif() # Adjust compiler settings if(MSVC) @@ -276,7 +304,9 @@ if(MATERIALX_BUILD_RENDER) if(MATERIALX_BUILD_GRAPH_EDITOR) add_subdirectory(source/MaterialXGraphEditor) endif() - add_subdirectory(resources) + if(MATERIALX_INSTALL_RESOURCES AND NOT SKBUILD) + add_subdirectory(resources) + endif() endif() # Add test subdirectory @@ -309,26 +339,28 @@ if(${CMAKE_VERSION} VERSION_GREATER "3.6.2") endif() # Install root-level documents -install(FILES LICENSE CHANGELOG.md README.md THIRD-PARTY.md - DESTINATION .) - -set(MATERIALX_GEN_CONFIG_PATH "${MATERIALX_INSTALL_LIB_PATH}/cmake/${CMAKE_PROJECT_NAME}") - -include(CMakePackageConfigHelpers) -configure_package_config_file(cmake/modules/MaterialXConfig.cmake.in - ${CMAKE_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}Config.cmake - INSTALL_DESTINATION "${MATERIALX_GEN_CONFIG_PATH}" - PATH_VARS CMAKE_INSTALL_PREFIX CMAKE_PROJECT_NAME) -write_basic_package_version_file(${CMAKE_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}ConfigVersion.cmake - VERSION ${MATERIALX_LIBRARY_VERSION} - COMPATIBILITY AnyNewerVersion) - -# Install the auto-generated CMake configuration files: - -install(EXPORT MaterialX - DESTINATION "${MATERIALX_GEN_CONFIG_PATH}" - FILE ${CMAKE_PROJECT_NAME}Targets.cmake) - -install(FILES "${CMAKE_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}ConfigVersion.cmake" - "${CMAKE_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}Config.cmake" - DESTINATION "${MATERIALX_GEN_CONFIG_PATH}") +if(NOT SKBUILD) + install(FILES LICENSE CHANGELOG.md README.md THIRD-PARTY.md + DESTINATION .) + + set(MATERIALX_GEN_CONFIG_PATH "${MATERIALX_INSTALL_LIB_PATH}/cmake/${CMAKE_PROJECT_NAME}") + + include(CMakePackageConfigHelpers) + configure_package_config_file(cmake/modules/MaterialXConfig.cmake.in + ${CMAKE_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}Config.cmake + INSTALL_DESTINATION "${MATERIALX_GEN_CONFIG_PATH}" + PATH_VARS CMAKE_INSTALL_PREFIX CMAKE_PROJECT_NAME) + write_basic_package_version_file(${CMAKE_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}ConfigVersion.cmake + VERSION ${MATERIALX_LIBRARY_VERSION} + COMPATIBILITY AnyNewerVersion) + + # Install the auto-generated CMake configuration files: + + install(EXPORT MaterialX + DESTINATION "${MATERIALX_GEN_CONFIG_PATH}" + FILE ${CMAKE_PROJECT_NAME}Targets.cmake) + + install(FILES "${CMAKE_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}ConfigVersion.cmake" + "${CMAKE_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}Config.cmake" + DESTINATION "${MATERIALX_GEN_CONFIG_PATH}") +endif() diff --git a/cmake/modules/MaterialXConfig.cmake.in b/cmake/modules/MaterialXConfig.cmake.in index b4c8b7fad6..e1598087bf 100644 --- a/cmake/modules/MaterialXConfig.cmake.in +++ b/cmake/modules/MaterialXConfig.cmake.in @@ -22,6 +22,8 @@ set_and_check(MATERIALX_STDLIB_DIR "@PACKAGE_CMAKE_INSTALL_PREFIX@/libraries") if(@MATERIALX_BUILD_PYTHON@ AND @MATERIALX_INSTALL_PYTHON@) set_and_check(MATERIALX_PYTHON_DIR "@PACKAGE_CMAKE_INSTALL_PREFIX@/python") endif() -set_and_check(MATERIALX_RESOURCES_DIR "@PACKAGE_CMAKE_INSTALL_PREFIX@/resources") +if(@MATERIALX_BUILD_RENDER@ AND @MATERIALX_INSTALL_RESOURCES@) + set_and_check(MATERIALX_RESOURCES_DIR "@PACKAGE_CMAKE_INSTALL_PREFIX@/resources") +endif() check_required_components(@CMAKE_PROJECT_NAME@) diff --git a/cmake/modules/MaterialXVersion.rc.in b/cmake/modules/MaterialXVersion.rc.in new file mode 100644 index 0000000000..989fbb8e55 --- /dev/null +++ b/cmake/modules/MaterialXVersion.rc.in @@ -0,0 +1,34 @@ + +#define MATERIALX_FILEVERSION @MATERIALX_MAJOR_VERSION@,@MATERIALX_MINOR_VERSION@,@MATERIALX_BUILD_VERSION@,0 +#define MATERIALX_FILEVERSION_STR "@MATERIALX_MAJOR_VERSION@.@MATERIALX_MINOR_VERSION@.@MATERIALX_BUILD_VERSION@.0\0" +#define MATERIALX_FILENAME_STR "@MATERIALX_MODULE_NAME@.dll\0" + +1 VERSIONINFO + FILEVERSION MATERIALX_FILEVERSION + PRODUCTVERSION MATERIALX_FILEVERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "FileVersion", MATERIALX_FILEVERSION_STR + VALUE "LegalCopyright", "Apache License 2.0\0" + VALUE "OriginalFilename", MATERIALX_FILENAME_STR + VALUE "ProductName", "MaterialX\0" + VALUE "ProductVersion", MATERIALX_FILEVERSION_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 3a90a269fb..7e876bdb57 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -656,6 +656,7 @@ Standard Texture nodes: * **`image`**: samples data from a single image, or from a layer within a multi-layer image. When used in the context of rendering a geometry, the image is mapped onto the geometry based on geometry UV coordinates, with the lower-left corner of an image mapping to the (0,0) UV coordinate (or to the fractional (0,0) UV coordinate for tiled images). +The type of the <image> node determines the number of channels output, which may be less than the number of channels in the image file, outputting the first N channels from the image file. So a `float` <image> would return the Red channel of an RGB image, and a `color3` <image> would return the RGB channels of an RGBA image. * `file` (uniform filename): the URI of an image file. The filename can include one or more substitutions to change the file name (including frame number) that is accessed, as described in the [Filename Substitutions](#filename-substitutions) section above. * `layer` (uniform string): the name of the layer to extract from a multi-layer input file. If no value for `layer` is provided and the input file has multiple layers, then the "default" layer will be used, or "rgba" if there is no "default" layer. Note: the number of channels defined by the `type` of the `` must match the number of channels in the named layer. * `default` (float or colorN or vectorN): a default value to use if the `file` reference can not be resolved (e.g. if a <_geometry token_>, [_interface token_] or {_hostattr_} is included in the filename but no substitution value or default is defined, or if the resolved `file` URI cannot be read), or if the specified `layer` does not exist in the file. The `default` value must be the same type as the `` element itself. If `default` is not defined, the default color value will be 0.0 in all channels. @@ -786,8 +787,8 @@ Standard Procedural nodes: * **`checkerboard`**: a 2D checkerboard pattern. * `color1` (color3): The first color used in the checkerboard pattern. * `color2` (color3): The second color used in the checkerboard pattern. - * `freq` (vector2): The frequency of checkers, with higher values producing smaller squares. Default is (8, 8). - * `offset` (vector2): Shift the pattern in 2d space. Default is (0, 0). + * `uvtiling` (vector2): The tiling of the checkerboard pattern along each axis, with higher values producing smaller squares. Default is (8, 8). + * `uvoffset` (vector2): The offset of the checkerboard pattern along each axis. Default is (0, 0). * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. @@ -2369,7 +2370,7 @@ An input with a shader-semantic type may be given a value of "" to indicate no s The Standard MaterialX Library defines the following nodes and node variants operating on "shader"-semantic types. Standard library shaders do not respond to external illumination; please refer to the [**MaterialX Physically Based Shading Nodes**](./MaterialX.PBRSpec.md#materialx-pbs-library) document for definitions of additional nodes and shader constructors which do respond to illumination. - + * **`surface_unlit`**: an unlit surface shader node, representing a surface that can emit and transmit light, but does not receive illumination from light sources or other surfaces. Output type surfaceshader. * `emission` (float): the surface emission amount; default is 1.0 diff --git a/javascript/MaterialXView/package-lock.json b/javascript/MaterialXView/package-lock.json index 84d65f8589..7bdf38ceba 100644 --- a/javascript/MaterialXView/package-lock.json +++ b/javascript/MaterialXView/package-lock.json @@ -10,8 +10,8 @@ "license": "ISC", "dependencies": { "dat.gui": "^0.7.9", - "three": "^0.135.0", - "webpack": "^5.88.1" + "three": "^0.136.0", + "webpack": "^5.88.2" }, "devDependencies": { "copy-webpack-plugin": "^8.1.1", @@ -166,9 +166,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.40.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", - "integrity": "sha512-PRVjQ4Eh9z9pmmtaq8nTjZjQwKFk7YIHIud3lRoKRBgUQjgjRmoGxxGEPXQkF+lH7QkHJRNr5F4aBgYCW0lqpQ==", + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.1.tgz", + "integrity": "sha512-XpNDc4Z5Tb4x+SW1MriMVeIsMoONHCkWFMkR/aPJbzEsxqHy+4Glu/BqTdPrApfDeMaXbtNh6bseNgl5KaWrSg==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -245,9 +245,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz", - "integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==" + "version": "20.4.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", + "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -506,9 +506,9 @@ } }, "node_modules/acorn": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "bin": { "acorn": "bin/acorn" }, @@ -798,9 +798,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001512", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz", - "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==", + "version": "1.0.30001517", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz", + "integrity": "sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==", "funding": [ { "type": "opencollective", @@ -1223,9 +1223,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.449", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.449.tgz", - "integrity": "sha512-TxLRpRUj/107ATefeP8VIUWNOv90xJxZZbCW/eIbSZQiuiFANCx2b7u+GbVc9X4gU+xnbvypNMYVM/WArE1DNQ==" + "version": "1.4.470", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.470.tgz", + "integrity": "sha512-zZM48Lmy2FKWgqyvsX9XK+J6FfP7aCDUFLmgooLJzA7v1agCs/sxSoBpTIwDLhmbhpx9yJIxj2INig/ncjJRqg==" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -1427,9 +1427,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", - "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2397,9 +2397,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -3405,9 +3405,9 @@ } }, "node_modules/terser": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.18.2.tgz", - "integrity": "sha512-Ah19JS86ypbJzTzvUCX7KOsEIhDaRONungA4aYBjEP3JZRf4ocuDzTg4QWZnPn9DEMiMYGJPiSOy7aykoCc70w==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -3468,9 +3468,9 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/three": { - "version": "0.135.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.135.0.tgz", - "integrity": "sha512-kuEpuuxRzLv0MDsXai9huCxOSQPZ4vje6y0gn80SRmQvgz6/+rI0NAvCRAw56zYaWKMGMfqKWsxF9Qa2Z9xymQ==" + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.136.0.tgz", + "integrity": "sha512-+fEMX7nYLz2ZesVP/dyifli5Jf8gR3XPAnFJveQ80aMhibFduzrADnjMbARXh8+W9qLK7rshJCjAIL/6cDxC+A==" }, "node_modules/thunky": { "version": "1.1.0", @@ -3500,9 +3500,9 @@ } }, "node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", "dev": true }, "node_modules/type-is": { @@ -3625,9 +3625,9 @@ } }, "node_modules/webpack": { - "version": "5.88.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.1.tgz", - "integrity": "sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", diff --git a/javascript/MaterialXView/package.json b/javascript/MaterialXView/package.json index 2113d145cf..adce3d2e82 100644 --- a/javascript/MaterialXView/package.json +++ b/javascript/MaterialXView/package.json @@ -11,8 +11,8 @@ "license": "ISC", "dependencies": { "dat.gui": "^0.7.9", - "three": "^0.135.0", - "webpack": "^5.88.1" + "three": "^0.136.0", + "webpack": "^5.88.2" }, "devDependencies": { "copy-webpack-plugin": "^8.1.1", diff --git a/javascript/MaterialXView/source/dropHandling.js b/javascript/MaterialXView/source/dropHandling.js new file mode 100644 index 0000000000..adcbef2ca1 --- /dev/null +++ b/javascript/MaterialXView/source/dropHandling.js @@ -0,0 +1,281 @@ +import * as THREE from 'three'; +import * as fflate from 'three/examples/jsm/libs/fflate.module.js'; + +const debugFileHandling = false; +let loadingCallback; + +export function setLoadingCallback(cb) { + loadingCallback = cb; +} + +export function dropHandler(ev) { + if (debugFileHandling) console.log('File(s) dropped', ev.dataTransfer.items, ev.dataTransfer.files); + + // Prevent default behavior (Prevent file from being opened) + ev.preventDefault(); + + if (ev.dataTransfer.items) + { + const allEntries = []; + + let haveGetAsEntry = false; + if (ev.dataTransfer.items.length > 0) + haveGetAsEntry = + ("getAsEntry" in ev.dataTransfer.items[0]) || + ("webkitGetAsEntry" in ev.dataTransfer.items[0]); + + // Useful for debugging file handling on platforms that don't support newer file system APIs + // haveGetAsEntry = false; + + if (haveGetAsEntry) { + for (var i = 0; i < ev.dataTransfer.items.length; i++) + { + let item = ev.dataTransfer.items[i]; + let entry = ("getAsEntry" in item) ? item.getAsEntry() : item.webkitGetAsEntry(); + allEntries.push(entry); + } + handleFilesystemEntries(allEntries); + return; + } + + for (var i = 0; i < ev.dataTransfer.items.length; i++) + { + let item = ev.dataTransfer.items[i]; + + // API when there's no "getAsEntry" support + console.log(item.kind, item); + if (item.kind === 'file') + { + var file = item.getAsFile(); + testAndLoadFile(file); + } + // could also be a directory + else if (item.kind === 'directory') + { + var dirReader = item.createReader(); + dirReader.readEntries(function(entries) { + for (var i = 0; i < entries.length; i++) { + console.log(entries[i].name); + var entry = entries[i]; + if (entry.isFile) { + entry.file(function(file) { + testAndLoadFile(file); + }); + } + } + }); + } + } + } else { + for (var i = 0; i < ev.dataTransfer.files.length; i++) { + let file = ev.dataTransfer.files[i]; + testAndLoadFile(file); + } + } +} + +export function dragOverHandler(ev) { + ev.preventDefault(); +} + +async function getBufferFromFile(fileEntry) { + + if (fileEntry instanceof ArrayBuffer) return fileEntry; + if (fileEntry instanceof String) return fileEntry; + + const name = fileEntry.fullPath || fileEntry.name; + const ext = name.split('.').pop(); + const readAsText = ext === 'mtlx'; + + if (debugFileHandling) console.log("reading ", fileEntry, "as text?", readAsText); + + if (debugFileHandling) console.log("getBufferFromFile", fileEntry); + const buffer = await new Promise((resolve, reject) => { + function readFile(file) { + var reader = new FileReader(); + reader.onloadend = function(e) { + if (debugFileHandling) console.log("loaded", "should be text?", readAsText, this.result); + resolve(this.result); + }; + + if (readAsText) + reader.readAsText(file); + else + reader.readAsArrayBuffer(file); + } + + if ("file" in fileEntry) { + fileEntry.file(function(file) { + readFile(file); + }, (e) => { + console.error("Error reading file ", e); + }); + } + else { + readFile(fileEntry); + } + }); + return buffer; +} + +async function handleFilesystemEntries(entries) { + const allFiles = []; + const fileIgnoreList = [ + '.gitignore', + 'README.md', + '.DS_Store', + ] + const dirIgnoreList = [ + '.git', + 'node_modules', + ] + + for (let entry of entries) { + if (debugFileHandling) console.log("file entry", entry) + if (entry.isFile) { + if (debugFileHandling) console.log("single file", entry); + if (fileIgnoreList.includes(entry.name)) { + continue; + } + allFiles.push(entry); + } + else if (entry.isDirectory) { + if (dirIgnoreList.includes(entry.name)) { + continue; + } + const files = await readDirectory(entry); + if (debugFileHandling) console.log("all files", files); + for (const file of files) { + if (fileIgnoreList.includes(file.name)) { + continue; + } + allFiles.push(file); + } + } + } + + const imageLoader = new THREE.ImageLoader(); + + // unpack zip files first + for (const fileEntry of allFiles) { + // special case: zip archives + if (fileEntry.fullPath.toLowerCase().endsWith('.zip')) { + await new Promise(async (resolve, reject) => { + const arrayBuffer = await getBufferFromFile(fileEntry); + + // use fflate to unpack them and add the files to the cache + fflate.unzip(new Uint8Array(arrayBuffer), (error, unzipped) => { + // push these files into allFiles + for (const [filePath, buffer] of Object.entries(unzipped)) { + + // mock FileEntry for easier usage downstream + const blob = new Blob([buffer]); + const newFileEntry = { + fullPath: "/" + filePath, + name: filePath.split('/').pop(), + file: (callback) => { + callback(blob); + }, + isFile: true, + }; + allFiles.push(newFileEntry); + } + + resolve(); + }); + }); + } + } + + // sort so mtlx files come first + allFiles.sort((a, b) => { + if (a.name.endsWith('.mtlx') && !b.name.endsWith('.mtlx')) { + return -1; + } + if (!a.name.endsWith('.mtlx') && b.name.endsWith('.mtlx')) { + return 1; + } + return 0; + }); + + if (debugFileHandling) console.log("all files", allFiles); + + // put all files in three' Cache + for (const fileEntry of allFiles) { + + const allowedFileTypes = [ + 'png', 'jpg', 'jpeg' + ]; + + const ext = fileEntry.fullPath.split('.').pop(); + if (!allowedFileTypes.includes(ext)) { + // console.log("skipping file", fileEntry.fullPath); + continue; + } + + const buffer = await getBufferFromFile(fileEntry); + const img = await imageLoader.loadAsync(URL.createObjectURL(new Blob([buffer]))); + if (debugFileHandling) console.log("caching file", fileEntry.fullPath, img); + THREE.Cache.add(fileEntry.fullPath, img); + } + + // TODO we could also allow dropping of multiple MaterialX files (or folders with them inside) + // and seed the dropdown from that. + // At that point, actually reading files and textures into memory should be deferred until they are actually used. + const rootFile = allFiles[0]; + THREE.Cache.add(rootFile.fullPath, await getBufferFromFile(rootFile)); + + if (debugFileHandling) console.log("CACHE", THREE.Cache.files); + + loadingCallback(rootFile); +} + +async function readDirectory(directory) { + let entries = []; + let getEntries = async (directory) => { + let dirReader = directory.createReader(); + await new Promise((resolve, reject) => { + dirReader.readEntries( + async (results) => { + if (results.length) { + // entries = entries.concat(results); + for (let entry of results) { + if (entry.isDirectory) { + await getEntries(entry); + } + else { + entries.push(entry); + } + } + } + resolve(); + }, + (error) => { + /* handle error — error is a FileError object */ + }, + )} + )}; + + await getEntries(directory); + return entries; +} + +async function testAndLoadFile(file) { + let ext = file.name.split('.').pop(); + if (debugFileHandling) console.log(file.name + ", " + file.size + ", " + ext); + + const arrayBuffer = await getBufferFromFile(file); + console.log(arrayBuffer) + + // mock a fileEntry and pass through the same loading logic + const newFileEntry = { + fullPath: "/" + file.name, + name: file.name.split('/').pop(), + isFile: true, + file: (callback) => { + callback(file); + } + }; + + handleFilesystemEntries([newFileEntry]); +} \ No newline at end of file diff --git a/javascript/MaterialXView/source/helper.js b/javascript/MaterialXView/source/helper.js index e8ffb9dcae..111dfd9b5d 100644 --- a/javascript/MaterialXView/source/helper.js +++ b/javascript/MaterialXView/source/helper.js @@ -20,8 +20,6 @@ const IMAGE_PATH_SEPARATOR = "/"; export function prepareEnvTexture(texture, capabilities) { const rgbaTexture = RGBToRGBA_Float(texture); - // RGBELoader sets flipY to true by default - rgbaTexture.flipY = false; rgbaTexture.wrapS = THREE.RepeatWrapping; rgbaTexture.anisotropy = capabilities.getMaxAnisotropy(); rgbaTexture.minFilter = THREE.LinearMipmapLinearFilter; diff --git a/javascript/MaterialXView/source/index.js b/javascript/MaterialXView/source/index.js index 424f63ec43..56e2e1f5a2 100644 --- a/javascript/MaterialXView/source/index.js +++ b/javascript/MaterialXView/source/index.js @@ -12,6 +12,7 @@ import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js'; import { GammaCorrectionShader } from 'three/examples/jsm/shaders/GammaCorrectionShader.js'; import { Viewer } from './viewer.js' +import { dropHandler, dragOverHandler, setLoadingCallback } from './dropHandling.js'; let renderer, composer, orbitControls; @@ -115,6 +116,20 @@ function init() console.error(Number.isInteger(err) ? this.getMx().getExceptionMessage(err) : err); }) + // allow dropping files and directories + document.addEventListener('drop', dropHandler, false); + document.addEventListener('dragover', dragOverHandler, false); + + setLoadingCallback(file => { + materialFilename = file.fullPath || file.name; + viewer.getEditor().clearFolders(); + viewer.getMaterial().loadMaterials(viewer, materialFilename); + viewer.getEditor().updateProperties(0.9); + viewer.getScene().setUpdateTransforms(); + }); + + // enable three.js Cache so that dropped files can reference each other + THREE.Cache.enabled = true; } function onWindowResize() diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index 0bc537faf0..d1adfd9ef4 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -589,6 +589,7 @@ export class Material // Set search path. Assumes images are relative to current file // location. + if (!materialFilename) materialFilename = "/"; const paths = materialFilename.split('/'); paths.pop(); const searchPath = paths.join('/'); diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 0d47cad5ed..d60a54cf3b 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,20 +1,28 @@ -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ - DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}" MESSAGE_NEVER - PATTERN "CMakeLists.txt" EXCLUDE - PATTERN "pbrlib_genosl_impl.*" EXCLUDE) - if (MATERIALX_OSL_LEGACY_CLOSURES) set(PBRLIB_SUFFIX "legacy") else() set(PBRLIB_SUFFIX "mtlx") endif() -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.${PBRLIB_SUFFIX}" - DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) +if(NOT SKBUILD) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ + DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}" + PATTERN "CMakeLists.txt" EXCLUDE + PATTERN "pbrlib_genosl_impl.*" EXCLUDE) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.${PBRLIB_SUFFIX}" + DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) +endif() -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ - DESTINATION "python/MaterialX/${MATERIALX_INSTALL_STDLIB_PATH}" - PATTERN "CMakeLists.txt" EXCLUDE - PATTERN "pbrlib_genosl_impl.*" EXCLUDE) -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.${PBRLIB_SUFFIX}" - DESTINATION "python/MaterialX/${MATERIALX_INSTALL_STDLIB_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) +set(MATERIALX_PYTHON_LIBRARIES_PATH "${MATERIALX_PYTHON_FOLDER_NAME}/${MATERIALX_INSTALL_STDLIB_PATH}") +if(SKBUILD) + set(MATERIALX_PYTHON_LIBRARIES_PATH "${SKBUILD_PLATLIB_DIR}/MaterialX/libraries") +endif() + +if(MATERIALX_BUILD_PYTHON) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ + DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}" + PATTERN "CMakeLists.txt" EXCLUDE + PATTERN "pbrlib_genosl_impl.*" EXCLUDE) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.${PBRLIB_SUFFIX}" + DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) +endif() diff --git a/libraries/bxdf/gltf_pbr.mtlx b/libraries/bxdf/gltf_pbr.mtlx index cb393fb82a..6654e63454 100644 --- a/libraries/bxdf/gltf_pbr.mtlx +++ b/libraries/bxdf/gltf_pbr.mtlx @@ -359,7 +359,7 @@ - + @@ -375,13 +375,10 @@ - - - - + @@ -422,7 +419,7 @@ - + @@ -434,9 +431,6 @@ - - - @@ -458,7 +452,7 @@ - + @@ -480,7 +474,7 @@ - + @@ -492,9 +486,6 @@ - - - @@ -516,7 +507,7 @@ - + @@ -538,7 +529,7 @@ - + @@ -550,9 +541,6 @@ - - - @@ -574,7 +562,7 @@ - + @@ -595,7 +583,7 @@ - + @@ -607,9 +595,6 @@ - - - @@ -631,7 +616,7 @@ - + @@ -648,7 +633,7 @@ - + @@ -660,9 +645,6 @@ - - - @@ -687,7 +669,7 @@ - + @@ -704,7 +686,7 @@ - + @@ -725,7 +707,7 @@ - + diff --git a/libraries/pbrlib/genosl/mx_blackbody.osl b/libraries/pbrlib/genosl/mx_blackbody.osl index 8b4de5ba9f..95951330f2 100644 --- a/libraries/pbrlib/genosl/mx_blackbody.osl +++ b/libraries/pbrlib/genosl/mx_blackbody.osl @@ -1,10 +1,10 @@ -void mx_blackbody(float temperature, output color color_value) +void mx_blackbody(float temp, output color color_value) { float xc, yc; float t, t2, t3, xc2, xc3; // if value outside valid range of approximation clamp to accepted temperature range - temperature = clamp(temperature, 1667.0, 25000.0); + float temperature = clamp(temp, 1667.0, 25000.0); t = 1000.0 / temperature; t2 = t * t; @@ -39,9 +39,10 @@ void mx_blackbody(float temperature, output color color_value) vector XYZ = vector(xc / yc, 1.0, (1 - xc - yc) / yc); /// XYZ to Rec.709 RGB colorspace conversion - matrix XYZ_to_RGB = matrix( 3.2406, -0.9689, 0.0557, - -1.5372, 1.8758, -0.2040, - -0.4986, 0.0415, 1.0570); + matrix XYZ_to_RGB = matrix( 3.2406, -0.9689, 0.0557, 0.0, + -1.5372, 1.8758, -0.2040, 0.0, + -0.4986, 0.0415, 1.0570, 0.0, + 0.0, 0.0, 0.0, 1.0); color_value = transform(XYZ_to_RGB, XYZ); color_value = max(color_value, vector(0.0)); diff --git a/libraries/stdlib/genglsl/mx_image_color3.glsl b/libraries/stdlib/genglsl/mx_image_color3.glsl index 802318f475..8c4c039554 100644 --- a/libraries/stdlib/genglsl/mx_image_color3.glsl +++ b/libraries/stdlib/genglsl/mx_image_color3.glsl @@ -2,13 +2,6 @@ void mx_image_color3(sampler2D tex_sampler, int layer, vec3 defaultval, vec2 texcoord, int uaddressmode, int vaddressmode, int filtertype, int framerange, int frameoffset, int frameendaction, vec2 uv_scale, vec2 uv_offset, out vec3 result) { - if (textureSize(tex_sampler, 0).x > 1) - { - vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); - result = texture(tex_sampler, uv).rgb; - } - else - { - result = defaultval; - } + vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); + result = texture(tex_sampler, uv).rgb; } diff --git a/libraries/stdlib/genglsl/mx_image_color4.glsl b/libraries/stdlib/genglsl/mx_image_color4.glsl index e74ad9445f..7541b9da04 100644 --- a/libraries/stdlib/genglsl/mx_image_color4.glsl +++ b/libraries/stdlib/genglsl/mx_image_color4.glsl @@ -2,13 +2,6 @@ void mx_image_color4(sampler2D tex_sampler, int layer, vec4 defaultval, vec2 texcoord, int uaddressmode, int vaddressmode, int filtertype, int framerange, int frameoffset, int frameendaction, vec2 uv_scale, vec2 uv_offset, out vec4 result) { - if (textureSize(tex_sampler, 0).x > 1) - { - vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); - result = texture(tex_sampler, uv); - } - else - { - result = defaultval; - } + vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); + result = texture(tex_sampler, uv); } diff --git a/libraries/stdlib/genglsl/mx_image_float.glsl b/libraries/stdlib/genglsl/mx_image_float.glsl index 9b831035d2..0a402a101c 100644 --- a/libraries/stdlib/genglsl/mx_image_float.glsl +++ b/libraries/stdlib/genglsl/mx_image_float.glsl @@ -2,13 +2,6 @@ void mx_image_float(sampler2D tex_sampler, int layer, float defaultval, vec2 texcoord, int uaddressmode, int vaddressmode, int filtertype, int framerange, int frameoffset, int frameendaction, vec2 uv_scale, vec2 uv_offset, out float result) { - if (textureSize(tex_sampler, 0).x > 1) - { - vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); - result = texture(tex_sampler, uv).r; - } - else - { - result = defaultval; - } + vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); + result = texture(tex_sampler, uv).r; } diff --git a/libraries/stdlib/genglsl/mx_image_vector2.glsl b/libraries/stdlib/genglsl/mx_image_vector2.glsl index 124cb09287..42a7235297 100644 --- a/libraries/stdlib/genglsl/mx_image_vector2.glsl +++ b/libraries/stdlib/genglsl/mx_image_vector2.glsl @@ -2,13 +2,6 @@ void mx_image_vector2(sampler2D tex_sampler, int layer, vec2 defaultval, vec2 texcoord, int uaddressmode, int vaddressmode, int filtertype, int framerange, int frameoffset, int frameendaction, vec2 uv_scale, vec2 uv_offset, out vec2 result) { - if (textureSize(tex_sampler, 0).x > 1) - { - vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); - result = texture(tex_sampler, uv).rg; - } - else - { - result = defaultval; - } + vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); + result = texture(tex_sampler, uv).rg; } diff --git a/libraries/stdlib/genglsl/mx_image_vector3.glsl b/libraries/stdlib/genglsl/mx_image_vector3.glsl index 840e60fe6f..d49eab735e 100644 --- a/libraries/stdlib/genglsl/mx_image_vector3.glsl +++ b/libraries/stdlib/genglsl/mx_image_vector3.glsl @@ -2,13 +2,6 @@ void mx_image_vector3(sampler2D tex_sampler, int layer, vec3 defaultval, vec2 texcoord, int uaddressmode, int vaddressmode, int filtertype, int framerange, int frameoffset, int frameendaction, vec2 uv_scale, vec2 uv_offset, out vec3 result) { - if (textureSize(tex_sampler, 0).x > 1) - { - vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); - result = texture(tex_sampler, uv).rgb; - } - else - { - result = defaultval; - } + vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); + result = texture(tex_sampler, uv).rgb; } diff --git a/libraries/stdlib/genglsl/mx_image_vector4.glsl b/libraries/stdlib/genglsl/mx_image_vector4.glsl index f4b61d83f0..c8bdc66fc4 100644 --- a/libraries/stdlib/genglsl/mx_image_vector4.glsl +++ b/libraries/stdlib/genglsl/mx_image_vector4.glsl @@ -2,13 +2,6 @@ void mx_image_vector4(sampler2D tex_sampler, int layer, vec4 defaultval, vec2 texcoord, int uaddressmode, int vaddressmode, int filtertype, int framerange, int frameoffset, int frameendaction, vec2 uv_scale, vec2 uv_offset, out vec4 result) { - if (textureSize(tex_sampler, 0).x > 1) - { - vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); - result = texture(tex_sampler, uv); - } - else - { - result = defaultval; - } + vec2 uv = mx_transform_uv(texcoord, uv_scale, uv_offset); + result = texture(tex_sampler, uv); } diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index bc1240e574..bb5e8edd1f 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -307,6 +307,7 @@ + @@ -324,6 +325,7 @@ + @@ -341,6 +343,7 @@ + @@ -358,6 +361,7 @@ + @@ -375,6 +379,7 @@ + @@ -392,6 +397,7 @@ + @@ -1083,12 +1089,131 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libraries/stdlib/stdlib_ng.mtlx b/libraries/stdlib/stdlib_ng.mtlx index f40001e14d..e031e72412 100644 --- a/libraries/stdlib/stdlib_ng.mtlx +++ b/libraries/stdlib/stdlib_ng.mtlx @@ -226,11 +226,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -242,7 +276,7 @@ - + @@ -254,7 +288,7 @@ - + @@ -346,11 +380,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -362,7 +430,7 @@ - + @@ -374,7 +442,7 @@ - + @@ -466,11 +534,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -482,7 +584,7 @@ - + @@ -494,7 +596,7 @@ - + @@ -586,11 +688,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -602,7 +738,7 @@ - + @@ -614,7 +750,7 @@ - + @@ -706,11 +842,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -722,7 +892,7 @@ - + @@ -734,7 +904,7 @@ - + @@ -826,11 +996,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -842,7 +1046,7 @@ - + @@ -854,7 +1058,7 @@ - + @@ -1246,13 +1450,9 @@ - - - - - - + + @@ -1380,49 +1580,788 @@ A 2D checkerboard pattern. --> - - - - - + + + + + + + + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..e674339900 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,78 @@ +[build-system] +# Use a fixed version because we use an experimental feature +# (a custom plugin) and for now that functionality has +# no compatibility promises. +requires = ["scikit-build-core==0.4.4"] +build-backend = "scikit_build_core.build" + +[project] +name = "MaterialX" +dynamic = ["version"] + +authors = [ + { name="Contributors to the MaterialX project", email="materialx-discussion@lists.aswf.io" }, +] +readme = "README.md" +requires-python = ">=3.6" + +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", +] + +[project.urls] +"Homepage" = "https://materialx.org" +"Source" = "https://github.com/AcademySoftwareFoundation/MaterialX" +"Bug Tracker" = "https://github.com/AcademySoftwareFoundation/MaterialX/issues" + +[project.scripts] +baketextures = "MaterialX._scripts.baketextures:main" +generateshader = "MaterialX._scripts.generateshader:main" +genmdl = "MaterialX._scripts.genmdl:main" +mxdoc = "MaterialX._scripts.mxdoc:main" +mxupdate = "MaterialX._scripts.mxupdate:main" +mxvalidate = "MaterialX._scripts.mxvalidate:main" +translateshader = "MaterialX._scripts.translateshader:main" +writenodegraphs = "MaterialX._scripts.writenodegraphs:main" + +[tool.scikit-build] +cmake.minimum-version = "3.18" +cmake.verbose = false +cmake.build-type = "Release" + +# Enable experimental features if any are available +# In this case we need custom local plugin to get +# the project version from cmake. +experimental = true +metadata.version.provider = "mtx_skbuild_plugin" +metadata.version.provider-path = "./python" + +# Uncoment when developing locally to enable inplace builds. +# build-dir = "build/" + +logging.level = "DEBUG" + +# Since the python package doesn't live in a standard directory +# in the source (i.e ./src or ./), we need to manually specify +# where the package is. +wheel.packages = ["python/MaterialX"] + +sdist.exclude = [ + "/build", + "/dist", + "/resources", + "/javascript", + "/documents", + "/.github", + "MANIFEST.in" +] + +[tool.scikit-build.cmake.define] +MATERIALX_BUILD_SHARED_LIBS = 'OFF' # Be explicit +MATERIALX_BUILD_PYTHON = 'ON' +MATERIALX_TEST_RENDER = 'OFF' +MATERIALX_WARNINGS_AS_ERRORS = 'ON' +MATERIALX_BUILD_TESTS = 'OFF' +# TODO: How could we harmonize this variable with SKBUILD? +MATERIALX_INSTALL_PYTHON = 'OFF' diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index e036c5abd5..da35a38b72 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,18 +1,25 @@ -set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in") -set(SETUP_PY "${CMAKE_INSTALL_PREFIX}/python/setup.py") - -configure_file(${SETUP_PY_IN} ${SETUP_PY}) +if(NOT SKBUILD) + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/MaterialX" DESTINATION "python" MESSAGE_NEVER) + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Scripts" DESTINATION "python" MESSAGE_NEVER) +endif() -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/MaterialX" DESTINATION "python" MESSAGE_NEVER) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Scripts" DESTINATION "python" MESSAGE_NEVER) +if(SKBUILD) + install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Scripts/" + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}/_scripts" + PATTERN "README.md" EXCLUDE + ) +endif() if(MATERIALX_PYTHON_OCIO_DIR) if(NOT EXISTS "${MATERIALX_PYTHON_OCIO_DIR}/config.ocio") message(WARNING "No file named config.ocio was found in the given OCIO directory.") endif() - install(DIRECTORY "${MATERIALX_PYTHON_OCIO_DIR}/" DESTINATION "python/MaterialX/config/" MESSAGE_NEVER) + install(DIRECTORY "${MATERIALX_PYTHON_OCIO_DIR}/" DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}/config/" MESSAGE_NEVER) endif() -if(MATERIALX_INSTALL_PYTHON AND PYTHON_EXECUTABLE) - install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} install clean --all)" MESSAGE_NEVER) +if(MATERIALX_INSTALL_PYTHON AND PYTHON_EXECUTABLE AND NOT SKBUILD) + set(SETUP_PY "${CMAKE_INSTALL_PREFIX}/python/setup.py") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in" "${SETUP_PY}") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} install clean --all)") endif() diff --git a/python/MaterialX/_scripts/README.md b/python/MaterialX/_scripts/README.md new file mode 100644 index 0000000000..f3586c5133 --- /dev/null +++ b/python/MaterialX/_scripts/README.md @@ -0,0 +1,2 @@ +This directory is empty buit it's used when packaging the Python library. +the files in ../../Scripts will be copied inside. diff --git a/python/MaterialX/_scripts/__init__.py b/python/MaterialX/_scripts/__init__.py new file mode 100644 index 0000000000..1217aefc79 --- /dev/null +++ b/python/MaterialX/_scripts/__init__.py @@ -0,0 +1 @@ +# Only required for entry-points. diff --git a/python/mtx_skbuild_plugin.py b/python/mtx_skbuild_plugin.py new file mode 100644 index 0000000000..56de6a9f53 --- /dev/null +++ b/python/mtx_skbuild_plugin.py @@ -0,0 +1,90 @@ +""" +This is a custom scikit-build-core plugin that will +fetch the MaterialX version from the CMake project. +""" +import os +import tempfile +import subprocess +from pathlib import Path +from typing import FrozenSet, Dict, Optional, Union, List + +from scikit_build_core.file_api.query import stateless_query +from scikit_build_core.file_api.reply import load_reply_dir + + +def dynamic_metadata( + fields: FrozenSet[str], + settings: Optional[Dict[str, object]] = None, +) -> Dict[str, Union[str, Dict[str, Optional[str]]]]: + print("mtx_skbuild_plugin: Computing MaterialX version from CMake...") + + if fields != {"version"}: + msg = "Only the 'version' field is supported" + raise ValueError(msg) + + if settings: + msg = "No inline configuration is supported" + raise ValueError(msg) + + current_dir = os.path.dirname(__file__) + + with tempfile.TemporaryDirectory() as tmpdir: + # We will use CMake's file API to get the version + # instead of parsing the CMakeLists files. + + # First generate the query folder so that CMake can generate replies. + reply_dir = stateless_query(Path(tmpdir)) + + # Run cmake (configure). CMake will generate a reply automatically. + try: + subprocess.run( + [ + "cmake", + "-S", + os.path.dirname(current_dir), + "-B", + tmpdir, + "-DMATERIALX_BUILD_SHARED_LIBS=OFF", + "-DMATERIALX_BUILD_PYTHON=OFF", + "-DMATERIALX_TEST_RENDER=OFF", + "-DMATERIALX_BUILD_TESTS=OFF", + "-DMATERIALX_INSTALL_PYTHON=OFF", + "-DMATERIALX_BUILD_RENDER=OFF", + ], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=True, + text=True, + ) + except subprocess.CalledProcessError as exc: + print(exc.stdout) + raise RuntimeError( + "Failed to configure project to get the version" + ) from exc + + # Get the generated replies. + index = load_reply_dir(reply_dir) + + # Get the version from the CMAKE_PROJECT_VERSION variable. + entries = [ + entry + for entry in index.reply.cache_v2.entries + if entry.name == "CMAKE_PROJECT_VERSION" + ] + + if not entries: + raise ValueError("Could not find MaterialX version from CMake project") + + if len(entries) > 1: + raise ValueError("More than one entry for CMAKE_PROJECT_VERSION found...") + + version = entries[0].value + print("mtx_skbuild_plugin: Computed version: {0}".format(version)) + + return {"version": version} + + +def get_requires_for_dynamic_metadata( + _settings: Optional[Dict[str, object]] = None, +) -> List[str]: + return ["cmake"] diff --git a/python/setup.py.in b/python/setup.py.in index dfe67330c2..072bafa968 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -14,4 +14,5 @@ setup(name='MaterialX', url='www.materialx.org', version='${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}', packages=['MaterialX'], - package_data={'MaterialX' : getRecursivePackageData('MaterialX')}) + package_data={'MaterialX' : getRecursivePackageData('MaterialX')}, + zip_safe = False) diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 5c1a433cf9..10212c95c2 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -1,2 +1,4 @@ -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ - DESTINATION "resources" MESSAGE_NEVER) +if(NOT SKBUILD) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ + DESTINATION "resources" MESSAGE_NEVER) +endif() diff --git a/resources/Materials/TestSuite/stdlib/nodegraph_inputs/top_level_input.mtlx b/resources/Materials/TestSuite/stdlib/nodegraph_inputs/top_level_input.mtlx new file mode 100644 index 0000000000..d92eae7f19 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/nodegraph_inputs/top_level_input.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/organization/organization.mtlx b/resources/Materials/TestSuite/stdlib/organization/organization.mtlx index 21154aecdd..0f4c024848 100644 --- a/resources/Materials/TestSuite/stdlib/organization/organization.mtlx +++ b/resources/Materials/TestSuite/stdlib/organization/organization.mtlx @@ -90,4 +90,14 @@ + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/procedural/linepattern.mtlx b/resources/Materials/TestSuite/stdlib/procedural/linepattern.mtlx new file mode 100644 index 0000000000..032abf129d --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/procedural/linepattern.mtlx @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/procedural/tiledshape.mtlx b/resources/Materials/TestSuite/stdlib/procedural/tiledshape.mtlx new file mode 100644 index 0000000000..69fd225f2c --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/procedural/tiledshape.mtlx @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/texture/image_default.mtlx b/resources/Materials/TestSuite/stdlib/texture/image_default.mtlx new file mode 100644 index 0000000000..89b99c3c39 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/texture/image_default.mtlx @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/MaterialXCore/CMakeLists.txt b/source/MaterialXCore/CMakeLists.txt index 37edf7929a..33e4fafdf4 100644 --- a/source/MaterialXCore/CMakeLists.txt +++ b/source/MaterialXCore/CMakeLists.txt @@ -1,25 +1,33 @@ +set(MATERIALX_MODULE_NAME MaterialXCore) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Generated.h.in ${CMAKE_CURRENT_BINARY_DIR}/Generated.h) file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_BINARY_DIR}/*.h") -add_library(MaterialXCore ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_CORE_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + set_target_properties( - MaterialXCore PROPERTIES - OUTPUT_NAME MaterialXCore${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" VERSION "${MATERIALX_LIBRARY_VERSION}" SOVERSION "${MATERIALX_MAJOR_VERSION}") target_link_libraries( - MaterialXCore + ${MATERIALX_MODULE_NAME} ${CMAKE_DL_LIBS}) -target_include_directories(MaterialXCore +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ @@ -27,14 +35,16 @@ target_include_directories(MaterialXCore PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXCore - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(FILES ${materialx_headers} - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXCore/) + install(FILES ${materialx_headers} + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXCore.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 5ec7044325..cf9587ecda 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -72,17 +72,29 @@ InterfaceElementPtr NodeDef::getImplementation(const string& target) const const TargetDefPtr targetDef = getDocument()->getTargetDef(target); const StringVec candidateTargets = targetDef ? targetDef->getMatchingTargets() : StringVec(); - // Search the candidate targets in order + // First, search for a target-specific match. for (const string& candidateTarget : candidateTargets) { for (InterfaceElementPtr interface : interfaces) { - if (targetStringsMatch(interface->getTarget(), candidateTarget)) + const std::string& interfaceTarget = interface->getTarget(); + if (!interfaceTarget.empty() && targetStringsMatch(interfaceTarget, candidateTarget)) { return interface; } } } + + // Then search for a generic match. + for (InterfaceElementPtr interface : interfaces) + { + // Look for interfaces without targets + const std::string& interfaceTarget = interface->getTarget(); + if (interfaceTarget.empty()) + { + return interface; + } + } return InterfaceElementPtr(); } diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 46d0552250..79297fa5a9 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -124,6 +124,7 @@ class Document::Cache for (ElementPtr elem : doc.lock()->traverseTree()) { const string& nodeName = elem->getAttribute(PortElement::NODE_NAME_ATTRIBUTE); + const string& nodeGraphName = elem->getAttribute(PortElement::NODE_GRAPH_ATTRIBUTE); const string& nodeString = elem->getAttribute(NodeDef::NODE_ATTRIBUTE); const string& nodeDefString = elem->getAttribute(InterfaceElement::NODE_DEF_ATTRIBUTE); @@ -135,6 +136,17 @@ class Document::Cache portElementMap.emplace(portElem->getQualifiedName(nodeName), portElem); } } + else + { + if (!nodeGraphName.empty()) + { + PortElementPtr portElem = elem->asA(); + if (portElem) + { + portElementMap.emplace(portElem->getQualifiedName(nodeGraphName), portElem); + } + } + } if (!nodeString.empty()) { NodeDefPtr nodeDef = elem->asA(); diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 8e43d9aa33..0e00bf596a 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -300,7 +300,7 @@ class MX_CORE_API Element : public std::enable_shared_from_this /// Return the element, if any, that this one directly inherits from. ElementPtr getInheritsFrom() const { - return resolveNameReference(getInheritString()); + return hasInheritString() ? resolveNameReference(getInheritString()) : nullptr; } /// Return true if this element has the given element as an inherited base, @@ -739,13 +739,13 @@ class MX_CORE_API Element : public std::enable_shared_from_this void copyContentFrom(const ConstElementPtr& source); /// Clear all attributes and descendants from this element. - void clearContent(); + virtual void clearContent(); /// Using the input name as a starting point, modify it to create a valid, /// unique name for a child element. string createValidChildName(string name) const { - name = createValidName(name); + name = name.empty() ? "_" : createValidName(name); while (_childMap.count(name)) { name = incrementName(name); diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index 3a93a384c2..65570ab6b6 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -305,7 +305,7 @@ InputPtr Input::getInterfaceInput() const { if (hasInterfaceName()) { - ConstNodeGraphPtr graph = getAncestorOfType(); + ConstGraphElementPtr graph = getAncestorOfType(); if (graph) { return graph->getInput(getInterfaceName()); @@ -611,6 +611,13 @@ ConstInterfaceElementPtr InterfaceElement::getDeclaration(const string&) const return InterfaceElementPtr(); } +void InterfaceElement::clearContent() +{ + _inputCount = 0; + _outputCount = 0; + TypedElement::clearContent(); +} + bool InterfaceElement::hasExactInputMatch(ConstInterfaceElementPtr declaration, string* message) const { for (InputPtr input : getActiveInputs()) diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index 94f6eddbaa..0773d5f836 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -639,6 +639,9 @@ class MX_CORE_API InterfaceElement : public TypedElement /// no declaration was found. virtual ConstInterfaceElementPtr getDeclaration(const string& target = EMPTY_STRING) const; + /// Clear all attributes and descendants from this element. + void clearContent() override; + /// Return true if this instance has an exact input match with the given /// declaration, where each input of this the instance corresponds to a /// declaration input of the same name and type. diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index 45524b116d..9596d905bc 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -439,9 +439,7 @@ vector GraphElement::topologicalSort() const } } - size_t visitCount = 0; vector result; - while (!childQueue.empty()) { // Pop the queue and add to topological order. @@ -467,14 +465,6 @@ vector GraphElement::topologicalSort() const } } } - - visitCount++; - } - - // Check if there was a cycle. - if (visitCount != children.size()) - { - throw ExceptionFoundCycle("Encountered a cycle in graph: " + getName()); } return result; @@ -738,6 +728,25 @@ InterfaceElementPtr NodeGraph::getImplementation() const return nodedef ? nodedef->getImplementation() : InterfaceElementPtr(); } +vector NodeGraph::getDownstreamPorts() const +{ + vector downstreamPorts; + for (PortElementPtr port : getDocument()->getMatchingPorts(getQualifiedName(getName()))) + { + ElementPtr node = port->getParent(); + ElementPtr graph = node ? node->getParent() : nullptr; + if (graph && graph->isA() && graph == getParent()) + { + downstreamPorts.push_back(port); + } + } + std::sort(downstreamPorts.begin(), downstreamPorts.end(), [](const ConstElementPtr& a, const ConstElementPtr& b) + { + return a->getName() > b->getName(); + }); + return downstreamPorts; +} + bool NodeGraph::validate(string* message) const { bool res = true; diff --git a/source/MaterialXCore/Node.h b/source/MaterialXCore/Node.h index a316b0eb6c..55846cf2e3 100644 --- a/source/MaterialXCore/Node.h +++ b/source/MaterialXCore/Node.h @@ -308,7 +308,6 @@ class MX_CORE_API GraphElement : public InterfaceElement /// Return a vector of all children (nodes and outputs) sorted in /// topological order. - /// @throws ExceptionFoundCycle if a cycle is encountered. vector topologicalSort() const; /// If not yet present, add a geometry node to this graph matching the given property @@ -358,6 +357,14 @@ class MX_CORE_API NodeGraph : public GraphElement /// none was found. InterfaceElementPtr getImplementation() const; + /// @} + /// @name Traversal + /// @{ + + /// Return a vector of all downstream ports that connect to this graph, ordered by + /// the names of the port elements. + vector getDownstreamPorts() const; + /// @} /// @name Utility /// @{ diff --git a/source/MaterialXCore/Types.h b/source/MaterialXCore/Types.h index 68f477ee04..5c64d0950a 100644 --- a/source/MaterialXCore/Types.h +++ b/source/MaterialXCore/Types.h @@ -592,9 +592,9 @@ class MX_CORE_API Matrix33 : public MatrixN float m20, float m21, float m22) : MatrixN(Uninit{}) { - _arr = { m00, m01, m02, - m10, m11, m12, - m20, m21, m22 }; + _arr = { RowArray{ m00, m01, m02 }, + RowArray{ m10, m11, m12 }, + RowArray{ m20, m21, m22 } }; } /// @name Matrix Operations @@ -663,10 +663,10 @@ class MX_CORE_API Matrix44 : public MatrixN float m30, float m31, float m32, float m33) : MatrixN(Uninit{}) { - _arr = { m00, m01, m02, m03, - m10, m11, m12, m13, - m20, m21, m22, m23, - m30, m31, m32, m33 }; + _arr = { RowArray{ m00, m01, m02, m03 }, + RowArray{ m10, m11, m12, m13 }, + RowArray{ m20, m21, m22, m23 }, + RowArray{ m30, m31, m32, m33 } }; } /// @name Matrix Operations diff --git a/source/MaterialXFormat/CMakeLists.txt b/source/MaterialXFormat/CMakeLists.txt index 940ef9662c..420149bae4 100644 --- a/source/MaterialXFormat/CMakeLists.txt +++ b/source/MaterialXFormat/CMakeLists.txt @@ -1,16 +1,24 @@ +set(MATERIALX_MODULE_NAME MaterialXFormat) + file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") assign_source_group("Source Files" ${materialx_source}) assign_source_group("Header Files" ${materialx_headers}) -add_library(MaterialXFormat ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_FORMAT_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + set_target_properties( - MaterialXFormat PROPERTIES - OUTPUT_NAME MaterialXFormat${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" @@ -18,26 +26,28 @@ set_target_properties( SOVERSION "${MATERIALX_MAJOR_VERSION}") target_link_libraries( - MaterialXFormat + ${MATERIALX_MODULE_NAME} MaterialXCore ${CMAKE_DL_LIBS}) -target_include_directories(MaterialXFormat +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXFormat - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXFormat/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXFormat.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXGenGlsl/CMakeLists.txt b/source/MaterialXGenGlsl/CMakeLists.txt index 2ddcb5475c..da497f9f88 100644 --- a/source/MaterialXGenGlsl/CMakeLists.txt +++ b/source/MaterialXGenGlsl/CMakeLists.txt @@ -1,16 +1,24 @@ +set(MATERIALX_MODULE_NAME MaterialXGenGlsl) + file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") assign_source_group("Source Files" ${materialx_source}) assign_source_group("Header Files" ${materialx_headers}) -add_library(MaterialXGenGlsl ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_GENGLSL_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + set_target_properties( - MaterialXGenGlsl PROPERTIES - OUTPUT_NAME MaterialXGenGlsl${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" @@ -18,27 +26,29 @@ set_target_properties( SOVERSION "${MATERIALX_MAJOR_VERSION}") target_link_libraries( - MaterialXGenGlsl + ${MATERIALX_MODULE_NAME} MaterialXGenShader MaterialXCore ${CMAKE_DL_LIBS}) -target_include_directories(MaterialXGenGlsl +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXGenGlsl - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXGenGlsl/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXGenGlsl.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXGenMdl/CMakeLists.txt b/source/MaterialXGenMdl/CMakeLists.txt index b73e674b7f..d9991843ce 100644 --- a/source/MaterialXGenMdl/CMakeLists.txt +++ b/source/MaterialXGenMdl/CMakeLists.txt @@ -1,16 +1,24 @@ +set(MATERIALX_MODULE_NAME MaterialXGenMdl) + file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") assign_source_group("Source Files" ${materialx_source}) assign_source_group("Header Files" ${materialx_headers}) -add_library(MaterialXGenMdl ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_GENMDL_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + set_target_properties( - MaterialXGenMdl PROPERTIES - OUTPUT_NAME MaterialXGenMdl${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" @@ -18,30 +26,32 @@ set_target_properties( SOVERSION "${MATERIALX_MAJOR_VERSION}") target_link_libraries( - MaterialXGenMdl + ${MATERIALX_MODULE_NAME} MaterialXGenShader MaterialXCore ${CMAKE_DL_LIBS}) -target_include_directories(MaterialXGenMdl +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXGenMdl - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXGenMdl/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/mdl - DESTINATION "${MATERIALX_INSTALL_MDL_MODULE_PATH}") + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/mdl + DESTINATION "${MATERIALX_INSTALL_MDL_MODULE_PATH}") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXGenMdl.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXGenMsl/CMakeLists.txt b/source/MaterialXGenMsl/CMakeLists.txt index 31d2599531..8d6d009f50 100644 --- a/source/MaterialXGenMsl/CMakeLists.txt +++ b/source/MaterialXGenMsl/CMakeLists.txt @@ -1,16 +1,24 @@ +set(MATERIALX_MODULE_NAME MaterialXGenMsl) + file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") assign_source_group("Source Files" ${materialx_source}) assign_source_group("Header Files" ${materialx_headers}) -add_library(MaterialXGenMsl ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_GENMSL_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + set_target_properties( - MaterialXGenMsl PROPERTIES - OUTPUT_NAME MaterialXGenMsl${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" @@ -18,27 +26,29 @@ set_target_properties( SOVERSION "${MATERIALX_MAJOR_VERSION}") target_link_libraries( - MaterialXGenMsl + ${MATERIALX_MODULE_NAME} MaterialXGenShader MaterialXCore ${CMAKE_DL_LIBS}) -target_include_directories(MaterialXGenMsl +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXGenMsl - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXGenMsl/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXGenMsl.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index 61a1c8f572..dcb0a3ed69 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -43,6 +43,8 @@ #include "MslResourceBindingContext.h" +#include + MATERIALX_NAMESPACE_BEGIN const string MslShaderGenerator::TARGET = "genmsl"; diff --git a/source/MaterialXGenOsl/CMakeLists.txt b/source/MaterialXGenOsl/CMakeLists.txt index 03e30de0c1..3cf7b93438 100644 --- a/source/MaterialXGenOsl/CMakeLists.txt +++ b/source/MaterialXGenOsl/CMakeLists.txt @@ -1,16 +1,24 @@ +set(MATERIALX_MODULE_NAME MaterialXGenOsl) + file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") assign_source_group("Source Files" ${materialx_source}) assign_source_group("Header Files" ${materialx_headers}) -add_library(MaterialXGenOsl ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_GENOSL_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + set_target_properties( - MaterialXGenOsl PROPERTIES - OUTPUT_NAME MaterialXGenOsl${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" @@ -18,28 +26,29 @@ set_target_properties( SOVERSION "${MATERIALX_MAJOR_VERSION}") target_link_libraries( - MaterialXGenOsl + ${MATERIALX_MODULE_NAME} MaterialXGenShader MaterialXCore ${CMAKE_DL_LIBS}) -target_include_directories(MaterialXGenOsl +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXGenOsl - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) - -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXGenOsl/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") +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) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXGenOsl.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXGenShader/CMakeLists.txt b/source/MaterialXGenShader/CMakeLists.txt index 231dda6e5c..1b9533e0a5 100644 --- a/source/MaterialXGenShader/CMakeLists.txt +++ b/source/MaterialXGenShader/CMakeLists.txt @@ -1,16 +1,24 @@ +set(MATERIALX_MODULE_NAME MaterialXGenShader) + file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") assign_source_group("Source Files" ${materialx_source}) assign_source_group("Header Files" ${materialx_headers}) -add_library(MaterialXGenShader ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_GENSHADER_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + set_target_properties( - MaterialXGenShader PROPERTIES - OUTPUT_NAME MaterialXGenShader${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" @@ -18,30 +26,32 @@ set_target_properties( SOVERSION "${MATERIALX_MAJOR_VERSION}") target_link_libraries( - MaterialXGenShader + ${MATERIALX_MODULE_NAME} MaterialXCore MaterialXFormat ${CMAKE_DL_LIBS}) -target_include_directories(MaterialXGenShader +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXGenShader - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXGenShader/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXGenShader.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../resources" - DESTINATION . MESSAGE_NEVER) + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../resources" + DESTINATION . MESSAGE_NEVER) +endif() diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index e6ad6eca29..8482659b34 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -1027,48 +1027,16 @@ void ShaderGraph::optimize(GenContext& context) } else if (node->hasClassification(ShaderNode::Classification::DOT)) { - // Dot nodes without modifiers can be elided by moving their connection downstream. + // Filename dot nodes must be elided so they do not create extra samplers. ShaderInput* in = node->getInput("in"); - if (in->getChannels().empty()) + if (in->getChannels().empty() && in->getType() == Type::FILENAME) { bypass(context, node, 0); ++numEdits; } } - else if (node->hasClassification(ShaderNode::Classification::IFELSE)) - { - // Check if we have a constant conditional expression - ShaderInput* intest = node->getInput("intest"); - if (!intest->getConnection()) - { - // Find which branch should be taken - ShaderInput* cutoff = node->getInput("cutoff"); - ValuePtr value = intest->getValue(); - const float intestValue = value ? value->asA() : 0.0f; - const int branch = (intestValue <= cutoff->getValue()->asA() ? 2 : 3); - - // Bypass the conditional using the taken branch - bypass(context, node, branch); - - ++numEdits; - } - } - else if (node->hasClassification(ShaderNode::Classification::SWITCH)) - { - // Check if we have a constant conditional expression - const ShaderInput* which = node->getInput("which"); - if (!which->getConnection()) - { - // Find which branch should be taken - ValuePtr value = which->getValue(); - const int branch = int(value == nullptr ? 0 : (which->getType() == Type::FLOAT ? value->asA() : value->asA())); - - // Bypass the conditional using the taken branch - bypass(context, node, branch); - - ++numEdits; - } - } + // Adding more nodes here requires them to have an input that is tagged + // "uniform" in the NodeDef or to handle very specific cases, like FILENAME. } if (numEdits > 0) @@ -1225,12 +1193,6 @@ void ShaderGraph::topologicalSort() } } } - - // Check if there was a cycle. - if (count != _nodeMap.size()) - { - throw ExceptionFoundCycle("Encountered a cycle in graph: " + getName()); - } } void ShaderGraph::setVariableNames(GenContext& context) diff --git a/source/MaterialXGenShader/ShaderGraph.h b/source/MaterialXGenShader/ShaderGraph.h index 4e30c4ae66..4117599c27 100644 --- a/source/MaterialXGenShader/ShaderGraph.h +++ b/source/MaterialXGenShader/ShaderGraph.h @@ -103,7 +103,6 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode void addDefaultGeomNode(ShaderInput* input, const GeomPropDef& geomprop, GenContext& context); /// Sort the nodes in topological order. - /// @throws ExceptionFoundCycle if a cycle is encountered. void topologicalSort(); /// Return an iterator for traversal upstream from the given output diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index c923e4be57..04551cb6d2 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -135,8 +135,6 @@ const ShaderNodePtr ShaderNode::NONE = createEmptyNode(); const string ShaderNode::CONSTANT = "constant"; const string ShaderNode::DOT = "dot"; const string ShaderNode::IMAGE = "image"; -const string ShaderNode::COMPARE = "compare"; -const string ShaderNode::SWITCH = "switch"; const string ShaderNode::SURFACESHADER = "surfaceshader"; const string ShaderNode::SCATTER_MODE = "scatter_mode"; const string ShaderNode::BSDF_R = "R"; @@ -292,14 +290,6 @@ ShaderNodePtr ShaderNode::create(const ShaderGraph* parent, const string& name, { newNode->_classification = Classification::TEXTURE | Classification::DOT; } - else if (nodeDef.getNodeString() == COMPARE) - { - newNode->_classification = Classification::TEXTURE | Classification::CONDITIONAL | Classification::IFELSE; - } - else if (nodeDef.getNodeString() == SWITCH) - { - newNode->_classification = Classification::TEXTURE | Classification::CONDITIONAL | Classification::SWITCH; - } // Third, check for file texture classification by group name else if (groupName == TEXTURE2D_GROUPNAME || groupName == TEXTURE3D_GROUPNAME) { @@ -381,7 +371,17 @@ void ShaderNode::initialize(const Node& node, const NodeDef& nodeDef, GenContext ShaderInput* input = getInput(nodeValue->getName()); if (input) { - input->setPath(nodeValue->getNamePath()); + string path = nodeValue->getNamePath(); + InputPtr nodeInput = nodeValue->asA(); + if (nodeInput) + { + InputPtr interfaceInput = nodeInput->getInterfaceInput(); + if (interfaceInput) + { + path = interfaceInput->getNamePath(); + } + } + input->setPath(path); } } diff --git a/source/MaterialXGenShader/ShaderNode.h b/source/MaterialXGenShader/ShaderNode.h index 30e3ab6d59..536e0adc1e 100644 --- a/source/MaterialXGenShader/ShaderNode.h +++ b/source/MaterialXGenShader/ShaderNode.h @@ -350,14 +350,11 @@ class MX_GENSHADER_API ShaderNode static const uint32_t VOLUME = 1 << 15; /// A volume shader node static const uint32_t LIGHT = 1 << 16; /// A light shader node static const uint32_t UNLIT = 1 << 17; /// An unlit surface shader node - // Specific conditional types - static const uint32_t IFELSE = 1 << 18; /// An if-else statement - static const uint32_t SWITCH = 1 << 19; /// A switch statement // Types based on nodegroup - static const uint32_t SAMPLE2D = 1 << 20; /// Can be sampled in 2D (uv space) - static const uint32_t SAMPLE3D = 1 << 21; /// Can be sampled in 3D (position) - static const uint32_t GEOMETRIC = 1 << 22; /// Geometric input - static const uint32_t DOT = 1 << 23; /// A dot node + static const uint32_t SAMPLE2D = 1 << 18; /// Can be sampled in 2D (uv space) + static const uint32_t SAMPLE3D = 1 << 19; /// Can be sampled in 3D (position) + static const uint32_t GEOMETRIC = 1 << 20; /// Geometric input + static const uint32_t DOT = 1 << 21; /// A dot node }; static const ShaderNodePtr NONE; @@ -365,8 +362,6 @@ class MX_GENSHADER_API ShaderNode static const string CONSTANT; static const string DOT; static const string IMAGE; - static const string COMPARE; - static const string SWITCH; static const string SURFACESHADER; static const string SCATTER_MODE; static const string BSDF_R; diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index 9e3fbccc40..2b28317ee2 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -17,13 +17,13 @@ namespace { -// the default node size is based off the of the size of the dot_color3 node using ed::getNodeSize() on that node +// Based on the dimensions of the dot_color3 node, computed by calling ed::getNodeSize const ImVec2 DEFAULT_NODE_SIZE = ImVec2(138, 116); const int DEFAULT_ALPHA = 255; const int FILTER_ALPHA = 50; -// Function based off ImRect_Expanded function from ImGui Node Editor blueprints-example.cpp +// Based on ImRect_Expanded function in ImGui Node Editor blueprints-example.cpp ImRect expandImRect(const ImRect& rect, float x, float y) { ImRect result = rect; @@ -34,10 +34,40 @@ ImRect expandImRect(const ImRect& rect, float x, float y) return result; } -// Get more user friendly node definition identifier. -// Will try and remove "ND_" prefix if it exists. Otherwise just returns -// the nodedef identifier. -std::string getNodeDefId(const std::string& val) +// Based on the splitter function in the ImGui Node Editor blueprints-example.cpp +static bool splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f) +{ + using namespace ImGui; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID("##Splitter"); + ImRect bb; + bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1)); + bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f); + return SplitterBehavior(bb, id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f); +} + +// Based on showLabel from ImGui Node Editor blueprints-example.cpp +auto showLabel = [](const char* label, ImColor color) +{ + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetTextLineHeight()); + auto size = ImGui::CalcTextSize(label); + + auto padding = ImGui::GetStyle().FramePadding; + auto spacing = ImGui::GetStyle().ItemSpacing; + + ImGui::SetCursorPos(ImGui::GetCursorPos() + ImVec2(spacing.x, -spacing.y)); + + auto rectMin = ImGui::GetCursorScreenPos() - padding; + auto rectMax = ImGui::GetCursorScreenPos() + size + padding; + + auto drawList = ImGui::GetWindowDrawList(); + drawList->AddRectFilled(rectMin, rectMax, color, size.y * 0.15f); + ImGui::TextUnformatted(label); +}; + +// Create a more user-friendly node definition name +std::string getUserNodeDefName(const std::string& val) { const std::string ND_PREFIX = "ND_"; std::string result = val; @@ -72,7 +102,8 @@ Graph::Graph(const std::string& materialFilename, _isCut(false), _autoLayout(false), _frameCount(INT_MIN), - _pinFilterType(mx::EMPTY_STRING) + _fontScale(1.0f), + _saveNodePositions(true) { loadStandardLibraries(); setPinColor(); @@ -84,7 +115,6 @@ Graph::Graph(const std::string& materialFilename, _geomFilter.push_back(".gltf"); _graphDoc = loadDocument(materialFilename); - _graphDoc->importLibrary(_stdLib); _initial = true; createNodeUIList(_stdLib); @@ -177,12 +207,16 @@ mx::DocumentPtr Graph::loadDocument(mx::FilePath filename) if (!filename.isEmpty()) { mx::readFromXmlFile(doc, filename, _searchPath, &readOptions); + doc->importLibrary(_stdLib); std::string message; if (!doc->validate(&message)) { std::cerr << "*** Validation warnings for " << filename.asString() << " ***" << std::endl; std::cerr << message << std::endl; } + + // Cache the currently loaded file + _materialFilename = filename; } } catch (mx::Exception& e) @@ -195,7 +229,6 @@ mx::DocumentPtr Graph::loadDocument(mx::FilePath filename) return doc; } -// populate nodes to add with input output group and nodegraph nodes which are not found in the stdlib void Graph::addExtraNodes() { if (!_graphDoc) @@ -203,10 +236,10 @@ void Graph::addExtraNodes() return; } - // clear any old nodes, if we previously used tab with another graph doc + // Clear any old nodes, if we previously used tab with another graph doc _extraNodes.clear(); - // get all types from the doc + // Get all types from the doc std::vector types; std::vector typeDefs = _graphDoc->getTypeDefs(); types.reserve(typeDefs.size()); @@ -215,7 +248,7 @@ void Graph::addExtraNodes() types.push_back(typeDef->getName()); } - // add input and output nodes for all types + // Add input and output nodes for all types for (const std::string& type : types) { std::string nodeName = "ND_input_" + type; @@ -224,16 +257,15 @@ void Graph::addExtraNodes() _extraNodes["Output Nodes"].push_back({ nodeName, type, "output" }); } - // add group node + // Add group node std::vector groupNode{ "ND_group", "", "group" }; _extraNodes["Group Nodes"].push_back(groupNode); - // add nodegraph node + // Add nodegraph node std::vector nodeGraph{ "ND_nodegraph", "", "nodegraph" }; _extraNodes["Node Graph"].push_back(nodeGraph); } -// return output pin needed to link the inputs and outputs ed::PinId Graph::getOutputPin(UiNodePtr node, UiNodePtr upNode, UiPinPtr input) { if (upNode->getNodeGraph() != nullptr) @@ -286,11 +318,11 @@ ed::PinId Graph::getOutputPin(UiNodePtr node, UiNodePtr upNode, UiPinPtr input) } } -// connect links via connected nodes in UiNodePtr void Graph::linkGraph() { _currLinks.clear(); - // start with bottom of graph + + // Start with bottom of graph for (UiNodePtr node : _graphNodes) { std::vector inputs = node->inputPins; @@ -298,20 +330,21 @@ void Graph::linkGraph() { for (size_t i = 0; i < inputs.size(); i++) { - // get upstream node for all inputs + // Get upstream node for all inputs std::string inputName = inputs[i]->_name; UiNodePtr inputNode = node->getConnectedNode(inputName); if (inputNode != nullptr) { Link link; - // getting the input connections for the current uiNode + + // Get the input connections for the current UiNode ax::NodeEditor::PinId id = inputs[i]->_pinId; inputs[i]->setConnected(true); int end = int(id.Get()); link._endAttr = end; - // get id number of output of node + // Get id number of output of node ed::PinId outputId = getOutputPin(node, inputNode, inputs[i]); int start = int(outputId.Get()); @@ -352,21 +385,16 @@ void Graph::linkGraph() } } -// connect all the links via the graph editor library void Graph::connectLinks() { - for (Link const& link : _currLinks) { - ed::Link(link.id, link._startAttr, link._endAttr); } } -// find link position in currLinks vector from link id int Graph::findLinkPosition(int id) { - int count = 0; for (size_t i = 0; i < _currLinks.size(); i++) { @@ -378,7 +406,7 @@ int Graph::findLinkPosition(int id) } return -1; } -// check if a node has already been assigned a position + bool Graph::checkPosition(UiNodePtr node) { if (node->getMxElement() != nullptr) @@ -390,7 +418,8 @@ bool Graph::checkPosition(UiNodePtr node) } return false; } -// calculate the total vertical space the node level takes up + +// Calculate the total vertical space the node level takes up float Graph::totalHeight(int level) { float total = 0.f; @@ -400,7 +429,8 @@ float Graph::totalHeight(int level) } return total; } -// set the y position of node based of the starting position and the nodes above it + +// Set the y-position of node based on the starting position and the nodes above it void Graph::setYSpacing(int level, float startingPos) { // set the y spacing for each node @@ -413,7 +443,7 @@ void Graph::setYSpacing(int level, float startingPos) } } -// calculate the average y position for a specific node level +// Calculate the average y-position for a specific node level float Graph::findAvgY(const std::vector& nodes) { // find the mid point of node level grou[ @@ -432,8 +462,8 @@ float Graph::findAvgY(const std::vector& nodes) void Graph::findYSpacing(float startY) { - // assume level 0 is set - // for each level find the average y position of the previous level to use as a spacing guide + // Assume level 0 is set + // For each level find the average y position of the previous level to use as a spacing guide int i = 0; for (std::pair> levelChunk : _levelMap) { @@ -441,7 +471,6 @@ void Graph::findYSpacing(float startY) { if (_levelMap[i][0]->_level > 0) { - int prevLevel = _levelMap[i].front()->_level - 1; float avgY = findAvgY(_levelMap[prevLevel]); float height = totalHeight(_levelMap[i].front()->_level); @@ -458,14 +487,13 @@ void Graph::findYSpacing(float startY) } } -// layout the x position by assigning the node levels based off its distance from the first node ImVec2 Graph::layoutPosition(UiNodePtr layoutNode, ImVec2 startingPos, bool initialLayout, int level) { if (checkPosition(layoutNode) && !_autoLayout) { for (UiNodePtr node : _graphNodes) { - // since nodegrpah nodes do not have any materialX info they are placed based off their conneced node + // Since nodegraph nodes do not have MaterialX info they are placed based on their connected node if (node->getNodeGraph() != nullptr) { std::vector outputCon = node->getOutputConnections(); @@ -478,7 +506,7 @@ ImVec2 Graph::layoutPosition(UiNodePtr layoutNode, ImVec2 startingPos, bool init } else { - // don't set position of group nodes + // Don't set position of group nodes if (node->getMessage().empty()) { if (node->getMxElement()->hasAttribute("xpos")) @@ -506,7 +534,7 @@ ImVec2 Graph::layoutPosition(UiNodePtr layoutNode, ImVec2 startingPos, bool init { if (layoutNode->_level < level) { - // remove the old instance of the node from the map + // Remove the old instance of the node from the map int levelNum = 0; int removeNum = -1; for (UiNodePtr levelNode : _levelMap[layoutNode->_level]) @@ -533,7 +561,7 @@ ImVec2 Graph::layoutPosition(UiNodePtr layoutNode, ImVec2 startingPos, bool init auto it = _levelMap.find(layoutNode->_level); if (it != _levelMap.end()) { - // key already exists add to it + // Key already exists so add to it bool nodeFound = false; for (UiNodePtr node : it->second) { @@ -550,30 +578,31 @@ ImVec2 Graph::layoutPosition(UiNodePtr layoutNode, ImVec2 startingPos, bool init } else { - // insert new vector into key + // Insert new vector into key std::vector newValue = { layoutNode }; _levelMap.insert({ layoutNode->_level, newValue }); } std::vector pins = layoutNode->inputPins; if (initialLayout) { - // check number of inputs that are connected to node + // Check number of inputs that are connected to node if (layoutNode->getInputConnect() > 0) { - // not top of node graph stop recursion + // Not top of node graph so stop recursion if (pins.size() != 0 && layoutNode->getInput() == nullptr) { for (size_t i = 0; i < pins.size(); i++) { - // get upstream node for all inputs + // Get upstream node for all inputs newPos = startingPos; UiNodePtr nextNode = layoutNode->getConnectedNode(pins[i]->_name); if (nextNode) { - startingPos.x = (1200.f - ((layoutNode->_level) * 350)) * _fontScale; + startingPos.x = (1200.f - ((layoutNode->_level) * 250)) * _fontScale; ed::SetNodePosition(layoutNode->getId(), startingPos); layoutNode->setPos(ImVec2(startingPos)); - // call layout position on upstream node with newPos as -140 to the left of current node + + // Call layout position on upstream node with newPos to the left of current node layoutPosition(nextNode, ImVec2(newPos.x, startingPos.y), initialLayout, layoutNode->_level + 1); } } @@ -581,9 +610,10 @@ ImVec2 Graph::layoutPosition(UiNodePtr layoutNode, ImVec2 startingPos, bool init } else { - startingPos.x = (1200.f - ((layoutNode->_level) * 350)) * _fontScale; + startingPos.x = (1200.f - ((layoutNode->_level) * 250)) * _fontScale; layoutNode->setPos(ImVec2(startingPos)); - // set current node position + + // Set current node position ed::SetNodePosition(layoutNode->getId(), ImVec2(startingPos)); } } @@ -591,10 +621,9 @@ ImVec2 Graph::layoutPosition(UiNodePtr layoutNode, ImVec2 startingPos, bool init } } -// extra layout pass for inputs and nodes that do not attach to an output node void Graph::layoutInputs() { - // layout inputs after other nodes so that they can be all in a line on far left side of node graph + // Layout inputs after other nodes so that they can be all in a line on far left side of node graph if (_levelMap.begin() != _levelMap.end()) { int levelCount = -1; @@ -613,7 +642,6 @@ void Graph::layoutInputs() startingPos.y += ed::GetNodeSize(uiNode->getId()).y; startingPos.y += 23; } - // accoutning for extra nodes like in gltf else if (uiNode->getOutputConnections().size() == 0 && (uiNode->getNode() != nullptr)) { if (uiNode->getNode()->getCategory() != mx::SURFACE_MATERIAL_NODE_STRING) @@ -625,7 +653,6 @@ void Graph::layoutInputs() } } -// reutrn pin color based on the type of the value of that pin void Graph::setPinColor() { _pinColor.insert(std::make_pair("integer", ImColor(255, 255, 28, 255))); @@ -644,8 +671,8 @@ void Graph::setPinColor() _pinColor.insert(std::make_pair("BSDF", ImColor(10, 181, 150, 255))); _pinColor.insert(std::make_pair("EDF", ImColor(255, 50, 100, 255))); _pinColor.insert(std::make_pair("VDF", ImColor(0, 100, 151, 255))); - _pinColor.insert(std::make_pair("surfaceshader", ImColor(150, 255, 255, 255))); - _pinColor.insert(std::make_pair("material", ImColor(255, 255, 255, 255))); + _pinColor.insert(std::make_pair(mx::SURFACE_SHADER_TYPE_STRING, ImColor(150, 255, 255, 255))); + _pinColor.insert(std::make_pair(mx::MATERIAL_TYPE_STRING, ImColor(255, 255, 255, 255))); _pinColor.insert(std::make_pair(mx::DISPLACEMENT_SHADER_TYPE_STRING, ImColor(155, 50, 100, 255))); _pinColor.insert(std::make_pair(mx::VOLUME_SHADER_TYPE_STRING, ImColor(155, 250, 100, 255))); _pinColor.insert(std::make_pair(mx::LIGHT_SHADER_TYPE_STRING, ImColor(100, 150, 100, 255))); @@ -662,28 +689,9 @@ void Graph::setPinColor() _pinColor.insert(std::make_pair("stringarray", ImColor(120, 180, 100))); } -// based off of showLabel from ImGui Node Editor blueprints-example.cpp -auto showLabel = [](const char* label, ImColor color) -{ - ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetTextLineHeight()); - auto size = ImGui::CalcTextSize(label); - - auto padding = ImGui::GetStyle().FramePadding; - auto spacing = ImGui::GetStyle().ItemSpacing; - - ImGui::SetCursorPos(ImGui::GetCursorPos() + ImVec2(spacing.x, -spacing.y)); - - auto rectMin = ImGui::GetCursorScreenPos() - padding; - auto rectMax = ImGui::GetCursorScreenPos() + size + padding; - - auto drawList = ImGui::GetWindowDrawList(); - drawList->AddRectFilled(rectMin, rectMax, color, size.y * 0.15f); - ImGui::TextUnformatted(label); -}; - void Graph::selectMaterial(UiNodePtr uiNode) { - // find renderable element that correspond with material uiNode + // Find renderable element that corresponds with material UiNode std::vector elems = mx::findRenderableElements(_graphDoc); mx::TypedElementPtr typedElem = nullptr; for (mx::TypedElementPtr elem : elems) @@ -698,13 +706,17 @@ void Graph::selectMaterial(UiNodePtr uiNode) _renderer->setMaterial(typedElem); } -// set the node to display in render veiw based off the selected node or nodegraph void Graph::setRenderMaterial(UiNodePtr node) { - // set render node right away is node is a material - if (node->getNode() && node->getNode()->getType() == "material") + // For now only surface shaders and materials are considered renderable. + // This can be adjusted as desired to include being able to use outputs, + // and / a sub-graph in the nodegraph. + const mx::StringSet RENDERABLE_TYPES = { mx::MATERIAL_TYPE_STRING, mx::SURFACE_SHADER_TYPE_STRING }; + + // Set render node right away is node is renderable + if (node->getNode() && RENDERABLE_TYPES.count(node->getNode()->getType())) { - // only set new render node if different material has been selected + // Only set new render node if different material has been selected if (_currRenderNode != node) { _currRenderNode = node; @@ -712,55 +724,124 @@ void Graph::setRenderMaterial(UiNodePtr node) _renderer->setMaterialCompilation(true); } } + + // Traverse downstream looking for the first renderable element. else { - // continue downstream using output connections until a material node is found - std::vector outNodes = node->getOutputConnections(); - if (outNodes.size() > 0) + mx::NodePtr mtlxNode = node->getNode(); + mx::NodeGraphPtr mtlxNodeGraph = node->getNodeGraph(); + mx::OutputPtr mtlxOutput = node->getOutput(); + if (mtlxOutput) { - if (outNodes[0]->getNode()) + mx::ElementPtr parent = mtlxOutput->getParent(); + if (parent->isA()) + mtlxNodeGraph = parent->asA(); + else if (parent->isA()) + mtlxNode = parent->asA(); + } + mx::StringSet testPaths; + if (mtlxNode) + { + mx::ElementPtr parent = mtlxNode->getParent(); + if (parent->isA()) { - if (outNodes[0]->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING) + // There is no logic to support traversing from inside a functional graph + // to it's instance and hence downstream so skip this from consideration. + // The closest approach would be to "flatten" all definitions to compound graphs. + mx::NodeGraphPtr parentGraph = parent->asA(); + if (parentGraph->getNodeDef()) { - std::vector shaderOut = outNodes[0]->getOutputConnections(); - if (shaderOut.size() > 0) + return; + } + } + testPaths.insert(mtlxNode->getNamePath()); + } + else if (mtlxNodeGraph) + { + testPaths.insert(mtlxNodeGraph->getNamePath()); + } + + mx::NodePtr foundNode = nullptr; + while (!testPaths.empty() && !foundNode) + { + mx::StringSet nextPaths; + for (const std::string& testPath : testPaths) + { + mx::ElementPtr testElem = _graphDoc->getDescendant(testPath); + mx::NodePtr testNode = testElem->asA(); + std::vector downstreamPorts; + if (testNode) + { + downstreamPorts = testNode->getDownstreamPorts(); + } + else + { + mx::NodeGraphPtr testGraph = testElem->asA(); + if (testGraph) { - if (shaderOut[0]) + downstreamPorts = testGraph->getDownstreamPorts(); + } + } + + // Test all downstream ports. If the port's node is renderable + // then stop searching. + for (mx::PortElementPtr downstreamPort : downstreamPorts) + { + mx::ElementPtr parent = downstreamPort->getParent(); + if (parent) + { + mx::NodePtr downstreamNode = parent->asA(); + if (downstreamNode) { - if (shaderOut[0]->getNode()->getType() == "material") + mx::NodeDefPtr nodeDef = downstreamNode->getNodeDef(); + if (nodeDef) { - if (_currRenderNode != shaderOut[0]) + if (RENDERABLE_TYPES.count(nodeDef->getType())) { - _currRenderNode = shaderOut[0]; - _frameCount = ImGui::GetFrameCount(); - _renderer->setMaterialCompilation(true); + foundNode = downstreamNode; + break; } } } + if (!foundNode) + { + nextPaths.insert(parent->getNamePath()); + } } - else - { - _currRenderNode = nullptr; - } } - else if (outNodes[0]->getNode()->getType() == mx::MATERIAL_TYPE_STRING) + if (foundNode) + { + break; + } + } + + // Set up next set of nodes to search downstream + testPaths = nextPaths; + } + + // Update rendering. If found use that node, otherwise + // use the current fallback of using the first renderable node. + if (foundNode) + { + for (auto uiNode : _graphNodes) + { + if (uiNode->getNode() == foundNode) { - if (_currRenderNode != outNodes[0]) + if (_currRenderNode != uiNode) { - _currRenderNode = outNodes[0]; + _currRenderNode = uiNode; _frameCount = ImGui::GetFrameCount(); _renderer->setMaterialCompilation(true); } + break; } } - else - { - _currRenderNode = nullptr; - } } else { _currRenderNode = nullptr; + _frameCount = ImGui::GetFrameCount(); + _renderer->setMaterialCompilation(true); } } } @@ -768,38 +849,15 @@ void Graph::setRenderMaterial(UiNodePtr node) void Graph::updateMaterials(mx::InputPtr input, mx::ValuePtr value) { std::string renderablePath; - mx::TypedElementPtr renderableElem; - std::vector elems = mx::findRenderableElements(_graphDoc); - - size_t num = 0; - int num2 = 0; - for (mx::TypedElementPtr elem : elems) + if (_currRenderNode) { - renderableElem = elem; - mx::NodePtr node = elem->asA(); - if (node) + if (_currRenderNode->getNode()) { - if (_currRenderNode) - { - if (node->getName() == _currRenderNode->getName()) - { - renderablePath = renderableElem->getNamePath(); - break; - } - } - else - { - renderablePath = renderableElem->getNamePath(); - } + renderablePath = _currRenderNode->getNode()->getNamePath(); } - else + else if (_currRenderNode->getOutput()) { - renderablePath = renderableElem->getNamePath(); - if (num2 == 2) - { - break; - } - num2++; + renderablePath = _currRenderNode->getOutput()->getNamePath(); } } @@ -821,42 +879,37 @@ void Graph::updateMaterials(mx::InputPtr input, mx::ValuePtr value) else { std::string name = input->getNamePath(); - // need to use exact interface name in order for input - mx::InputPtr interfaceInput = findInput(input, input->getName()); - if (interfaceInput) - { - name = interfaceInput->getNamePath(); - } + // Note that if there is a topogical change due to // this value change or a transparency change, then // this is not currently caught here. - _renderer->getMaterials()[num]->modifyUniform(name, value); + _renderer->getMaterials()[0]->modifyUniform(name, value); } } } -// set the value of the selected node constants in the node property editor + void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIProperties& uiProperties) { - std::string inName = !uiProperties.uiName.empty() ? uiProperties.uiName : input->getName(); ImGui::PushItemWidth(-1); mx::ValuePtr minVal = uiProperties.uiMin; mx::ValuePtr maxVal = uiProperties.uiMax; - // if input is a float set the float slider Ui to the value + // If input is a float set the float slider UI to the value if (input->getType() == "float") { mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - // updates the value to the default for new nodes + // Update the value to the default for new nodes float prev = val->asA(), temp = val->asA(); float min = minVal ? minVal->asA() : 0.f; float max = maxVal ? maxVal->asA() : 100.f; float speed = (max - min) / 1000.0f; ImGui::DragFloat("##hidelabel", &temp, speed, min, max); - // set input value and update materials if different from previous value + + // Set input value and update materials if different from previous value if (prev != temp) { addNodeInput(_currUiNode, input); @@ -875,7 +928,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert int max = maxVal ? maxVal->asA() : 100; float speed = (max - min) / 100.0f; ImGui::DragInt("##hidelabel", &temp, speed, min, max); - // set input value and update materials if different from previous value + + // Set input value and update materials if different from previous value if (prev != temp) { addNodeInput(_currUiNode, input); @@ -899,7 +953,7 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert ImGui::SameLine(); ImGui::ColorEdit3("##color", &temp[0], ImGuiColorEditFlags_NoInputs); - // set input value and update materials if different from previous value + // Set input value and update materials if different from previous value if (prev != temp) { addNodeInput(_currUiNode, input); @@ -921,9 +975,11 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert ImGui::DragFloat4("##hidelabel", &temp[0], speed, min, max); ImGui::PopItemWidth(); ImGui::SameLine(); - // color edit for the color picker to the right of the color floats + + // Color edit for the color picker to the right of the color floats ImGui::ColorEdit4("##color", &temp[0], ImGuiColorEditFlags_NoInputs); - // set input value and update materials if different from previous value + + // Set input value and update materials if different from previous value if (temp != prev) { addNodeInput(_currUiNode, input); @@ -942,7 +998,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; ImGui::DragFloat2("##hidelabel", &temp[0], speed, min, max); - // set input value and update materials if different from previous value + + // Set input value and update materials if different from previous value if (prev != temp) { addNodeInput(_currUiNode, input); @@ -961,7 +1018,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; ImGui::DragFloat3("##hidelabel", &temp[0], speed, min, max); - // set input value and update materials if different from previous value + + // Set input value and update materials if different from previous value if (prev != temp) { addNodeInput(_currUiNode, input); @@ -980,7 +1038,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; ImGui::DragFloat4("##hidelabel", &temp[0], speed, min, max); - // set input value and update materials if different from previous value + + // Set input value and update materials if different from previous value if (prev != temp) { addNodeInput(_currUiNode, input); @@ -996,7 +1055,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert { std::string prev = val->asA(), temp = val->asA(); ImGui::InputText("##constant", &temp); - // set input value and update materials if different from previous value + + // Set input value and update materials if different from previous value if (prev != temp) { addNodeInput(_currUiNode, input); @@ -1014,10 +1074,12 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert std::string temp = val->asA(), prev = val->asA(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.15f, .15f, .15f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.2f, .4f, .6f, 1.0f)); - // browser button to select new file + + // Browser button to select new file ImGui::PushItemWidth(-100); if (ImGui::Button("Browse")) { + _fileDialogImageInputName = input->getName(); _fileDialogImage.setTitle("Node Input Dialog"); _fileDialogImage.open(); _fileDialogImage.setTypeFilters(_imageFilter); @@ -1028,19 +1090,21 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert ImGui::PopStyleColor(); ImGui::PopStyleColor(); - // create and load document from selected file - if (_fileDialogImage.hasSelected()) + // Create and load document from selected file + if (_fileDialogImage.hasSelected() && _fileDialogImageInputName == input->getName()) { - // set the new filename to the complete file path + // Set the new filename to the complete file path mx::FilePath fileName = _fileDialogImage.getSelected(); temp = fileName; - // need to set the file prefix for the input to "" so that it can find the new file + + // Need to clear the file prefix so that it can find the new file input->setAttribute(input->FILE_PREFIX_ATTRIBUTE, ""); _fileDialogImage.clearSelected(); _fileDialogImage.setTypeFilters(std::vector()); + _fileDialogImageInputName = ""; } - // set input value and update materials if different from previous value + // Set input value and update materials if different from previous value if (prev != temp) { addNodeInput(_currUiNode, input); @@ -1057,7 +1121,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert { bool prev = val->asA(), temp = val->asA(); ImGui::Checkbox("", &temp); - // set input value and update materials if different from previous value + + // Set input value and update materials if different from previous value if (prev != temp) { addNodeInput(_currUiNode, input); @@ -1069,13 +1134,14 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert ImGui::PopItemWidth(); } -// build the initial graph of a loaded mtlx document including shader, material and nodegraph node + void Graph::setUiNodeInfo(UiNodePtr node, const std::string& type, const std::string& category) { node->setType(type); node->setCategory(category); ++_graphTotalSize; - // create pins + + // Create pins if (node->getNodeGraph()) { std::vector outputs = node->getNodeGraph()->getOutputs(); @@ -1155,14 +1221,13 @@ void Graph::setUiNodeInfo(UiNodePtr node, const std::string& type, const std::st _graphNodes.push_back(std::move(node)); } -// Generate node UI from nodedefs. void Graph::createNodeUIList(mx::DocumentPtr doc) { _nodesToAdd.clear(); const std::string EXTRA_GROUP_NAME = "extra"; for (mx::NodeDefPtr nodeDef : doc->getNodeDefs()) { - // nodeDef is the key for the map + // NodeDef is the key for the map std::string group = nodeDef->getNodeGroup(); if (group.empty()) { @@ -1178,7 +1243,6 @@ void Graph::createNodeUIList(mx::DocumentPtr doc) addExtraNodes(); } -// build the UiNode node graph based off of loading a document void Graph::buildUiBaseGraph(mx::DocumentPtr doc) { std::vector nodeGraphs = doc->getNodeGraphs(); @@ -1194,7 +1258,8 @@ void Graph::buildUiBaseGraph(mx::DocumentPtr doc) _newLinks.clear(); _currPins.clear(); _graphTotalSize = 1; - // creating uiNodes for nodes that belong to the document so they are not in a nodegraph + + // Create UiNodes for nodes that belong to the document so they are not in a nodegraph for (mx::NodePtr node : docNodes) { if (!includeElement(node)) @@ -1204,7 +1269,8 @@ void Graph::buildUiBaseGraph(mx::DocumentPtr doc) currNode->setNode(node); setUiNodeInfo(currNode, node->getType(), node->getCategory()); } - // creating uiNodes for the nodegraph + + // Create UiNodes for the nodegraph for (mx::NodeGraphPtr nodeGraph : nodeGraphs) { if (!includeElement(nodeGraph)) @@ -1230,7 +1296,8 @@ void Graph::buildUiBaseGraph(mx::DocumentPtr doc) currNode->setOutput(output); setUiNodeInfo(currNode, output->getType(), output->getCategory()); } - // creating edges for nodegraphs + + // Create edges for nodegraphs for (mx::NodeGraphPtr graph : nodeGraphs) { for (mx::InputPtr input : graph->getActiveInputs()) @@ -1256,7 +1323,8 @@ void Graph::buildUiBaseGraph(mx::DocumentPtr doc) } } } - // creating edges for surface and material nodes + + // Create edges for surface and material nodes for (mx::NodePtr node : docNodes) { mx::NodeDefPtr nD = node->getNodeDef(node->getName()); @@ -1291,7 +1359,6 @@ void Graph::buildUiBaseGraph(mx::DocumentPtr doc) } if (upNum != -1) { - UiEdge newEdge = UiEdge(_graphNodes[upNum], _graphNodes[downNum], input); if (!edgeExists(newEdge)) { @@ -1304,11 +1371,10 @@ void Graph::buildUiBaseGraph(mx::DocumentPtr doc) } } } -// build the UiNode node graph based off of diving into a node graph node + void Graph::buildUiNodeGraph(const mx::NodeGraphPtr& nodeGraphs) { - - // clear all values so that ids can start with 0 or 1 + // Clear all values so that ids can start with 0 or 1 _graphNodes.clear(); _currLinks.clear(); _currEdge.clear(); @@ -1319,12 +1385,10 @@ void Graph::buildUiNodeGraph(const mx::NodeGraphPtr& nodeGraphs) { mx::NodeGraphPtr nodeGraph = nodeGraphs; std::vector children = nodeGraph->topologicalSort(); - // Write out all nodes. - mx::NodeDefPtr nodeDef = nodeGraph->getNodeDef(); mx::NodeDefPtr currNodeDef; - // create input nodes + // Create input nodes if (nodeDef) { std::vector inputs = nodeDef->getActiveInputs(); @@ -1337,7 +1401,7 @@ void Graph::buildUiNodeGraph(const mx::NodeGraphPtr& nodeGraphs) } } - // search node graph children to create uiNodes + // Search node graph children to create uiNodes for (mx::ElementPtr elem : children) { mx::NodePtr node = elem->asA(); @@ -1410,10 +1474,9 @@ void Graph::buildUiNodeGraph(const mx::NodeGraphPtr& nodeGraphs) } int upNode = findNode(upName, upstreamType); int downNode = findNode(downName, downstreamType); - if (downNode > 0 && upNode > 0 && - _graphNodes[downNode]->getOutput() != nullptr) + if (downNode > 0 && upNode > 0 && _graphNodes[downNode]->getOutput()) { - // creating edges for the output nodes + // Create edges for the output nodes UiEdge newEdge = UiEdge(_graphNodes[upNode], _graphNodes[downNode], nullptr); if (!edgeExists(newEdge)) { @@ -1448,7 +1511,7 @@ void Graph::buildUiNodeGraph(const mx::NodeGraphPtr& nodeGraphs) std::vector ins = upstreamNode->getActiveInputs(); for (mx::InputPtr input : ins) { - // connecting input nodes + // Connect input nodes if (input->hasInterfaceName()) { std::string interfaceName = input->getInterfaceName(); @@ -1474,7 +1537,7 @@ void Graph::buildUiNodeGraph(const mx::NodeGraphPtr& nodeGraphs) } } - // second pass to catch all of the connections that arent part of an output + // Second pass to catch all of the connections that arent part of an output for (mx::ElementPtr elem : children) { mx::NodePtr node = elem->asA(); @@ -1543,7 +1606,6 @@ void Graph::buildUiNodeGraph(const mx::NodeGraphPtr& nodeGraphs) } } -// return node position in _graphNodes based off node name and type to account for input/output UiNodes with same names as mx Nodes int Graph::findNode(const std::string& name, const std::string& type) { int count = 0; @@ -1573,13 +1635,12 @@ int Graph::findNode(const std::string& name, const std::string& type) return -1; } -// set position of pasted nodes based off of original node position void Graph::positionPasteBin(ImVec2 pos) { ImVec2 totalPos = ImVec2(0, 0); ImVec2 avgPos = ImVec2(0, 0); - // get average position of original nodes + // Get average position of original nodes for (auto pasteNode : _copiedNodes) { ImVec2 origPos = ed::GetNodePosition(pasteNode.first->getId()); @@ -1589,7 +1650,7 @@ void Graph::positionPasteBin(ImVec2 pos) avgPos.x = totalPos.x / (int) _copiedNodes.size(); avgPos.y = totalPos.y / (int) _copiedNodes.size(); - // get offset from clciked position + // Get offset from clicked position ImVec2 offset = ImVec2(0, 0); offset.x = pos.x - avgPos.x; offset.y = pos.y - avgPos.y; @@ -1605,11 +1666,12 @@ void Graph::positionPasteBin(ImVec2 pos) ed::SetNodePosition(pasteNode.second->getId(), newPos); } } + void Graph::createEdge(UiNodePtr upNode, UiNodePtr downNode, mx::InputPtr connectingInput) { if (downNode->getOutput()) { - // creating edges for the output nodes + // Create edges for the output nodes UiEdge newEdge = UiEdge(upNode, downNode, nullptr); if (!edgeExists(newEdge)) { @@ -1674,6 +1736,7 @@ void Graph::copyUiNode(UiNodePtr node) _copiedNodes[node] = copyNode; _graphNodes.push_back(copyNode); } + void Graph::copyNodeGraph(UiNodePtr origGraph, UiNodePtr copyGraph) { copyGraph->getNodeGraph()->copyContentFrom(origGraph->getNodeGraph()); @@ -1684,6 +1747,7 @@ void Graph::copyNodeGraph(UiNodePtr origGraph, UiNodePtr copyGraph) input->setName(newName); } } + void Graph::copyInputs() { for (std::map::iterator iter = _copiedNodes.begin(); iter != _copiedNodes.end(); ++iter) @@ -1695,19 +1759,18 @@ void Graph::copyInputs() { if (origNode->getConnectedNode(pin->_name) && !_ctrlClick) { - // if original node is connected check if connect node is in copied nodes + // If original node is connected check if connect node is in copied nodes if (_copiedNodes.find(origNode->getConnectedNode(pin->_name)) != _copiedNodes.end()) { - // set copy node connected to the value at this key - // create an edge + // Set copy node connected to the value at this key createEdge(_copiedNodes[origNode->getConnectedNode(pin->_name)], copyNode, copyNode->inputPins[count]->_input); UiNodePtr upNode = _copiedNodes[origNode->getConnectedNode(pin->_name)]; if (copyNode->getNode() || copyNode->getNodeGraph()) { - mx::InputPtr connectingInput = nullptr; copyNode->inputPins[count]->_input->copyContentFrom(pin->_input); - // update value to be empty + + // Update value to be empty if (copyNode->getNode() && copyNode->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING) { if (upNode->getOutput()) @@ -1721,7 +1784,6 @@ void Graph::copyInputs() } else { - // node graph if (upNode->getNodeGraph()) { ed::PinId outputId = getOutputPin(copyNode, upNode, copyNode->inputPins[count]); @@ -1761,7 +1823,7 @@ void Graph::copyInputs() copyNode->getOutput()->setConnectedNode(upNode->getNode()); } - // update input node num and output connections + // Update input node num and output connections copyNode->setInputNodeNum(1); upNode->setOutputConnection(copyNode); } @@ -1781,12 +1843,13 @@ void Graph::copyInputs() } } } -// add node to graphNodes based off of node def information + void Graph::addNode(const std::string& category, const std::string& name, const std::string& type) { mx::NodePtr node = nullptr; std::vector matchingNodeDefs; - // create document or node graph is there is not already one + + // Create document or node graph is there is not already one if (category == "output") { std::string outName = ""; @@ -1803,7 +1866,8 @@ void Graph::addNode(const std::string& category, const std::string& name, const { std::string inName = ""; mx::InputPtr newIn = nullptr; - // add input as child of correct parent and create valid name + + // Add input as child of correct parent and create valid name inName = _currGraphElem->createValidChildName(name); newIn = _currGraphElem->addInput(inName, type); auto inputNode = std::make_shared(inName, int(++_graphTotalSize)); @@ -1815,20 +1879,23 @@ void Graph::addNode(const std::string& category, const std::string& name, const else if (category == "group") { auto groupNode = std::make_shared(name, int(++_graphTotalSize)); - // set message of group uinode in order to identify it as such + + // Set message of group UiNode in order to identify it as such groupNode->setMessage("Comment"); setUiNodeInfo(groupNode, type, "group"); - // create ui portions of group node + + // Create ui portions of group node buildGroupNode(_graphNodes.back()); return; } else if (category == "nodegraph") { - // create new mx::NodeGraph and set as current node graph + // Create new mx::NodeGraph and set as current node graph _graphDoc->addNodeGraph(); std::string nodeGraphName = _graphDoc->getNodeGraphs().back()->getName(); auto nodeGraphNode = std::make_shared(nodeGraphName, int(++_graphTotalSize)); - // set mx::Nodegraph as node graph for uiNode + + // Set mx::Nodegraph as node graph for uiNode nodeGraphNode->setNodeGraph(_graphDoc->getNodeGraphs().back()); setUiNodeInfo(nodeGraphNode, type, "nodegraph"); @@ -1839,9 +1906,8 @@ void Graph::addNode(const std::string& category, const std::string& name, const matchingNodeDefs = _graphDoc->getMatchingNodeDefs(category); for (mx::NodeDefPtr nodedef : matchingNodeDefs) { - std::string nodedefName = nodedef->getName(); - std::string sub = getNodeDefId(nodedefName); - if (sub == name) + std::string userNodeDefName = getUserNodeDefName(nodedef->getName()); + if (userNodeDefName == name) { node = _currGraphElem->addNodeInstance(nodedef, _currGraphElem->createValidChildName(name)); } @@ -1854,17 +1920,16 @@ void Graph::addNode(const std::string& category, const std::string& name, const int countDef = 0; for (size_t i = 0; i < matchingNodeDefs.size(); i++) { - // use substring of name in order to remove ND_ - std::string nodedefName = matchingNodeDefs[i]->getName(); - std::string sub = getNodeDefId(nodedefName); - if (sub == name) + std::string userNodeDefName = getUserNodeDefName(matchingNodeDefs[i]->getName()); + if (userNodeDefName == name) { num = countDef; } countDef++; } std::vector defInputs = matchingNodeDefs[num]->getActiveInputs(); - // adding inputs to ui node as pins so that we can later add them to the node if necessary + + // Add inputs to UiNode as pins so that we can later add them to the node if necessary auto newNode = std::make_shared(node->getName(), int(++_graphTotalSize)); newNode->setCategory(category); newNode->setType(type); @@ -1892,7 +1957,7 @@ void Graph::addNode(const std::string& category, const std::string& name, const updateMaterials(); } } -// return node pos + int Graph::getNodeId(ed::PinId pinId) { for (UiPinPtr pin : _currPins) @@ -1905,7 +1970,6 @@ int Graph::getNodeId(ed::PinId pinId) return -1; } -// return pin based off of UiPin id UiPinPtr Graph::getPin(ed::PinId pinId) { for (UiPinPtr pin : _currPins) @@ -1919,8 +1983,7 @@ UiPinPtr Graph::getPin(ed::PinId pinId) return nullPin; } -// This function is based off of the pin icon function in the ImGui Node Editor blueprints-example.cpp -void Graph::DrawPinIcon(std::string type, bool connected, int alpha) +void Graph::drawPinIcon(std::string type, bool connected, int alpha) { ax::Drawing::IconType iconType = ax::Drawing::IconType::Flow; ImColor color = ImColor(0, 0, 0, 255); @@ -1934,7 +1997,6 @@ void Graph::DrawPinIcon(std::string type, bool connected, int alpha) ax::Widgets::Icon(ImVec2(24, 24), iconType, connected, color, ImColor(32, 32, 32, alpha)); } -// This function is based off of the comment node in the ImGui Node Editor blueprints-example.cpp void Graph::buildGroupNode(UiNodePtr node) { const float commentAlpha = 0.75f; @@ -1991,12 +2053,14 @@ void Graph::buildGroupNode(UiNodePtr node) } ed::EndGroupHint(); } + bool Graph::readOnly() { - // if the sources are not the same then the current graph cannot be modified + // If the sources are not the same then the current graph cannot be modified return _currGraphElem->getActiveSourceUri() != _graphDoc->getActiveSourceUri(); } -mx::InputPtr Graph::findInput(mx::InputPtr nodeInput, std::string name) + +mx::InputPtr Graph::findInput(mx::InputPtr nodeInput, const std::string& name) { if (_isNodeGraph) { @@ -2008,7 +2072,6 @@ mx::InputPtr Graph::findInput(mx::InputPtr nodeInput, std::string name) { if (input->getInterfaceInput()) { - if (input->getInterfaceInput() == nodeInput) { return input; @@ -2040,18 +2103,6 @@ mx::InputPtr Graph::findInput(mx::InputPtr nodeInput, std::string name) } return nullptr; } -// This function is based off the splitter function in the ImGui Node Editor blueprints-example.cpp -static bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f) -{ - using namespace ImGui; - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiID id = window->GetID("##Splitter"); - ImRect bb; - bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1)); - bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f); - return SplitterBehavior(bb, id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f); -} void Graph::drawOutputPins(UiNodePtr node, const std::string& longestInputLabel) { @@ -2075,11 +2126,11 @@ void Graph::drawOutputPins(UiNodePtr node, const std::string& longestInputLabel) bool connected = pin->getConnected(); if (!_pinFilterType.empty()) { - DrawPinIcon(pin->_type, connected, _pinFilterType == pin->_type ? DEFAULT_ALPHA : FILTER_ALPHA); + drawPinIcon(pin->_type, connected, _pinFilterType == pin->_type ? DEFAULT_ALPHA : FILTER_ALPHA); } else { - DrawPinIcon(pin->_type, connected, DEFAULT_ALPHA); + drawPinIcon(pin->_type, connected, DEFAULT_ALPHA); } ed::EndPin(); @@ -2096,16 +2147,16 @@ void Graph::drawInputPin(UiPinPtr pin) { if (_pinFilterType == pin->_type) { - DrawPinIcon(pin->_type, connected, DEFAULT_ALPHA); + drawPinIcon(pin->_type, connected, DEFAULT_ALPHA); } else { - DrawPinIcon(pin->_type, connected, FILTER_ALPHA); + drawPinIcon(pin->_type, connected, FILTER_ALPHA); } } else { - DrawPinIcon(pin->_type, connected, DEFAULT_ALPHA); + drawPinIcon(pin->_type, connected, DEFAULT_ALPHA); } ImGui::PopID(); ed::EndPin(); @@ -2126,7 +2177,7 @@ std::vector Graph::createNodes(bool nodegraph) } else { - // color for output pin + // Color for output pin std::string outputType; if (node->getNode() != nullptr) { @@ -2180,8 +2231,8 @@ std::vector Graph::createNodes(bool nodegraph) } } drawOutputPins(node, longestInputLabel); - // set color of output pin + // Set color of output pin if (node->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING) { if (node->getOutputConnections().size() > 0) @@ -2241,16 +2292,16 @@ std::vector Graph::createNodes(bool nodegraph) { if (_pinFilterType == pin->_type) { - DrawPinIcon(pin->_type, true, DEFAULT_ALPHA); + drawPinIcon(pin->_type, true, DEFAULT_ALPHA); } else { - DrawPinIcon(pin->_type, true, FILTER_ALPHA); + drawPinIcon(pin->_type, true, FILTER_ALPHA); } } else { - DrawPinIcon(pin->_type, true, DEFAULT_ALPHA); + drawPinIcon(pin->_type, true, DEFAULT_ALPHA); } ImGui::SameLine(); @@ -2311,16 +2362,16 @@ std::vector Graph::createNodes(bool nodegraph) { if (_pinFilterType == pin->_type) { - DrawPinIcon(pin->_type, true, DEFAULT_ALPHA); + drawPinIcon(pin->_type, true, DEFAULT_ALPHA); } else { - DrawPinIcon(pin->_type, true, FILTER_ALPHA); + drawPinIcon(pin->_type, true, FILTER_ALPHA); } } else { - DrawPinIcon(pin->_type, true, DEFAULT_ALPHA); + drawPinIcon(pin->_type, true, DEFAULT_ALPHA); } ImGui::SameLine(); ImGui::TextUnformatted("input"); @@ -2377,7 +2428,6 @@ std::vector Graph::createNodes(bool nodegraph) return outputNum; } -// add mx::InputPtr to node based off of input pin void Graph::addNodeInput(UiNodePtr node, mx::InputPtr& input) { if (node->getNode()) @@ -2433,165 +2483,211 @@ void Graph::setDefaults(mx::InputPtr input) } } -// add link to nodegraph and set up connections between UiNodes and MaterialX Nodes to update shader -void Graph::AddLink(ed::PinId inputPinId, ed::PinId outputPinId) +void Graph::addLink(ed::PinId inputPinId, ed::PinId outputPinId) { int end_attr = int(outputPinId.Get()); int start_attr = int(inputPinId.Get()); UiPinPtr inputPin = getPin(outputPinId); UiPinPtr outputPin = getPin(inputPinId); - if (inputPinId && outputPinId && (outputPin->_type == inputPin->_type)) + + if (!inputPin || !outputPin) { - if (inputPin->_connected == false) + ed::RejectNewItem(); + return; + } + + // Perform type check + bool typesMatch = (outputPin->_type == inputPin->_type); + if (!typesMatch) + { + ed::RejectNewItem(); + showLabel("Invalid connection due to mismatched types", ImColor(50, 50, 50, 255)); + return; + } + + if (inputPin->_connected == false) + { + int upNode = getNodeId(inputPinId); + int downNode = getNodeId(outputPinId); + UiNodePtr uiDownNode = _graphNodes[downNode]; + UiNodePtr uiUpNode = _graphNodes[upNode]; + if (!uiDownNode || !uiUpNode) { - int upNode = getNodeId(inputPinId); - int downNode = getNodeId(outputPinId); + ed::RejectNewItem(); + return; + } - // make sure there is an implementation for node - const mx::ShaderGenerator& shadergen = _renderer->getGenContext().getShaderGenerator(); + // make sure there is an implementation for node + const mx::ShaderGenerator& shadergen = _renderer->getGenContext().getShaderGenerator(); + + // Prevent direct connecting from input to output + if (uiDownNode->getInput() && uiUpNode->getOutput()) + { + ed::RejectNewItem(); + showLabel("Direct connections between inputs and outputs is invalid", ImColor(50, 50, 50, 255)); + return; + } - // Find the implementation for this nodedef if not an input or output uinode - if (_graphNodes[downNode]->getInput() && _isNodeGraph) + // Find the implementation for this nodedef if not an input or output uinode + if (uiDownNode->getInput() && _isNodeGraph) + { + ed::RejectNewItem(); + showLabel("Cannot connect to inputs inside of graph", ImColor(50, 50, 50, 255)); + return; + } + else if (uiUpNode->getNode()) + { + mx::ShaderNodeImplPtr impl = shadergen.getImplementation(*_graphNodes[upNode]->getNode()->getNodeDef(), _renderer->getGenContext()); + if (!impl) { ed::RejectNewItem(); - showLabel("Cannot connect to inputs inside of graph", ImColor(50, 50, 50, 255)); + showLabel("Invalid Connection: Node does not have an implementation", ImColor(50, 50, 50, 255)); return; } - else if (_graphNodes[upNode]->getNode()) - { - mx::ShaderNodeImplPtr impl = shadergen.getImplementation(*_graphNodes[upNode]->getNode()->getNodeDef(), _renderer->getGenContext()); - if (!impl) - { - ed::RejectNewItem(); - showLabel("Invalid Connection: Node does not have an implementation", ImColor(50, 50, 50, 255)); - return; - } - } + } - if (ed::AcceptNewItem()) - { - // Since we accepted new link, lets add one to our list of links. - Link link; - link._startAttr = start_attr; - link._endAttr = end_attr; - _currLinks.push_back(link); - _frameCount = ImGui::GetFrameCount(); - _renderer->setMaterialCompilation(true); + if (ed::AcceptNewItem()) + { + // Since we accepted new link, lets add one to our list of links. + Link link; + link._startAttr = start_attr; + link._endAttr = end_attr; + _currLinks.push_back(link); + _frameCount = ImGui::GetFrameCount(); + _renderer->setMaterialCompilation(true); - if (_graphNodes[downNode]->getNode() || _graphNodes[downNode]->getNodeGraph()) + if (uiDownNode->getNode() || uiDownNode->getNodeGraph()) + { + mx::InputPtr connectingInput = nullptr; + for (UiPinPtr pin : uiDownNode->inputPins) { - mx::InputPtr connectingInput = nullptr; - for (UiPinPtr pin : _graphNodes[downNode]->inputPins) + if (pin->_pinId == outputPinId) { - if (pin->_pinId == outputPinId) + addNodeInput(uiDownNode, pin->_input); + // update value to be empty + if (uiDownNode->getNode() && uiDownNode->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING) { - addNodeInput(_graphNodes[downNode], pin->_input); - // update value to be empty - if (_graphNodes[downNode]->getNode() && _graphNodes[downNode]->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING) + if (uiUpNode->getOutput() != nullptr) { - if (_graphNodes[upNode]->getOutput() != nullptr) - { - pin->_input->setConnectedOutput(_graphNodes[upNode]->getOutput()); - } - else if (_graphNodes[upNode]->getInput() != nullptr) - { - pin->_input->setInterfaceName(_graphNodes[upNode]->getName()); - } - else + pin->_input->setConnectedOutput(uiUpNode->getOutput()); + } + else if (uiUpNode->getInput() != nullptr) + { + pin->_input->setInterfaceName(uiUpNode->getName()); + } + else + { + // node graph + if (uiUpNode->getNodeGraph() != nullptr) { - // node graph - if (_graphNodes[upNode]->getNodeGraph() != nullptr) + for (UiPinPtr outPin : uiUpNode->outputPins) { - for (UiPinPtr outPin : _graphNodes[upNode]->outputPins) + // set pin connection to correct output + if (outPin->_pinId == inputPinId) { - // set pin connection to correct output - if (outPin->_pinId == inputPinId) - { - mx::OutputPtr outputs = _graphNodes[upNode]->getNodeGraph()->getOutput(outPin->_name); - pin->_input->setConnectedOutput(outputs); - } + mx::OutputPtr outputs = uiUpNode->getNodeGraph()->getOutput(outPin->_name); + pin->_input->setConnectedOutput(outputs); } } - else - { - pin->_input->setConnectedNode(_graphNodes[upNode]->getNode()); - } } + else + { + pin->_input->setConnectedNode(uiUpNode->getNode()); + } + } + } + else + { + if (uiUpNode->getInput()) + { + pin->_input->setInterfaceName(uiUpNode->getName()); } else { - if (_graphNodes[upNode]->getInput()) + if (uiUpNode->getNode()) { - - pin->_input->setInterfaceName(_graphNodes[upNode]->getName()); - } - else - { - if (_graphNodes[upNode]->getNode()) + mx::NodePtr upstreamNode = _graphNodes[upNode]->getNode(); + mx::NodeDefPtr upstreamNodeDef = upstreamNode->getNodeDef(); + bool isMultiOutput = upstreamNodeDef ? upstreamNodeDef->getOutputs().size() > 1 : false; + + // This is purely to avoid adding a reference to an update node only 1 output, + // as currently validation consides adding this an error. Otherwise + // it will add an "output" attribute all the time. + if (!isMultiOutput) { - pin->_input->setConnectedNode(_graphNodes[upNode]->getNode()); + pin->_input->setConnectedNode(uiUpNode->getNode()); } - else if (_graphNodes[upNode]->getNodeGraph()) + else { for (UiPinPtr outPin : _graphNodes[upNode]->outputPins) { // set pin connection to correct output if (outPin->_pinId == inputPinId) { - mx::OutputPtr outputs = _graphNodes[upNode]->getNodeGraph()->getOutput(outPin->_name); + mx::OutputPtr outputs = uiUpNode->getNode()->getOutput(outPin->_name); + if (!outputs) + { + outputs = uiUpNode->getNode()->addOutput(outPin->_name, pin->_input->getType()); + } pin->_input->setConnectedOutput(outputs); } } } } + else if (uiUpNode->getNodeGraph()) + { + for (UiPinPtr outPin : uiUpNode->outputPins) + { + // set pin connection to correct output + if (outPin->_pinId == inputPinId) + { + mx::OutputPtr outputs = uiUpNode->getNodeGraph()->getOutput(outPin->_name); + pin->_input->setConnectedOutput(outputs); + } + } + } } - - pin->setConnected(true); - pin->_input->removeAttribute(mx::ValueElement::VALUE_ATTRIBUTE); - connectingInput = pin->_input; - break; } + + pin->setConnected(true); + pin->_input->removeAttribute(mx::ValueElement::VALUE_ATTRIBUTE); + connectingInput = pin->_input; + break; } - // create new edge and set edge information - createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); } - else if (_graphNodes[downNode]->getOutput() != nullptr) - { - mx::InputPtr connectingInput = nullptr; - _graphNodes[downNode]->getOutput()->setConnectedNode(_graphNodes[upNode]->getNode()); + // create new edge and set edge information + createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); + } + else if (_graphNodes[downNode]->getOutput() != nullptr) + { + mx::InputPtr connectingInput = nullptr; + _graphNodes[downNode]->getOutput()->setConnectedNode(_graphNodes[upNode]->getNode()); - // create new edge and set edge information - createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); - } - else + // create new edge and set edge information + createEdge(_graphNodes[upNode], _graphNodes[downNode], connectingInput); + } + else + { + // create new edge and set edge info + UiEdge newEdge = UiEdge(_graphNodes[upNode], _graphNodes[downNode], nullptr); + if (!edgeExists(newEdge)) { - // create new edge and set edge info - UiEdge newEdge = UiEdge(_graphNodes[upNode], _graphNodes[downNode], nullptr); - if (!edgeExists(newEdge)) - { - _graphNodes[downNode]->edges.push_back(newEdge); - _currEdge.push_back(newEdge); + _graphNodes[downNode]->edges.push_back(newEdge); + _currEdge.push_back(newEdge); - // update input node num and output connections - _graphNodes[downNode]->setInputNodeNum(1); - _graphNodes[upNode]->setOutputConnection(_graphNodes[downNode]); - } + // update input node num and output connections + _graphNodes[downNode]->setInputNodeNum(1); + _graphNodes[upNode]->setOutputConnection(_graphNodes[downNode]); } } } - else - { - ed::RejectNewItem(); - } } else { ed::RejectNewItem(); - showLabel("Invalid Connection due to Mismatch Types", ImColor(50, 50, 50, 255)); } } -// remove node edge based of off connecting input void Graph::removeEdge(int downNode, int upNode, UiPinPtr pin) { int num = _graphNodes[downNode]->getEdgeIndex(_graphNodes[upNode]->getId(), pin); @@ -2607,9 +2703,7 @@ void Graph::removeEdge(int downNode, int upNode, UiPinPtr pin) } } - // downNode set node num -1 _graphNodes[downNode]->setInputNodeNum(-1); - // upNode remove outputconnection _graphNodes[upNode]->removeOutputConnection(_graphNodes[downNode]->getName()); } @@ -2617,8 +2711,8 @@ void Graph::deleteLinkInfo(int startAttr, int endAttr) { int upNode = getNodeId(startAttr); int downNode = getNodeId(endAttr); - // change input so that is default val - // change informtion of actual mx::Node + + // Change input to default value if (_graphNodes[downNode]->getNode()) { mx::NodeDefPtr nodeDef = _graphNodes[downNode]->getNode()->getNodeDef(_graphNodes[downNode]->getNode()->getName()); @@ -2639,14 +2733,18 @@ void Graph::deleteLinkInfo(int startAttr, int endAttr) } if (_graphNodes[upNode]->getInput()) { - // remove interface value in order to set the default of the input + // Remove interface value in order to set the default of the input pin->_input->removeAttribute(mx::ValueElement::INTERFACE_NAME_ATTRIBUTE); setDefaults(pin->_input); setDefaults(_graphNodes[upNode]->getInput()); } + // Remove any output reference + pin->_input->removeAttribute(mx::PortElement::OUTPUT_ATTRIBUTE); + pin->setConnected(false); - // if a value exists update the input with it + + // If a value exists update the input with it if (val) { pin->_input->setValueString(val->getValueString()); @@ -2656,7 +2754,7 @@ void Graph::deleteLinkInfo(int startAttr, int endAttr) } else if (_graphNodes[downNode]->getNodeGraph()) { - // set default values for nodegraph node pins ie nodegraph inputs + // Set default values for nodegraph node pins ie nodegraph inputs mx::NodeDefPtr nodeDef = _graphNodes[downNode]->getNodeGraph()->getNodeDef(); for (UiPinPtr pin : _graphNodes[downNode]->inputPins) { @@ -2687,7 +2785,7 @@ void Graph::deleteLinkInfo(int startAttr, int endAttr) } } } -// delete link from currLink vector and remove any connections in UiNode or MaterialX Nodes to update shader + void Graph::deleteLink(ed::LinkId deletedLinkId) { // If you agree that link can be deleted, accept deletion. @@ -2696,10 +2794,11 @@ void Graph::deleteLink(ed::LinkId deletedLinkId) _renderer->setMaterialCompilation(true); _frameCount = ImGui::GetFrameCount(); int link_id = int(deletedLinkId.Get()); + // Then remove link from your data. int pos = findLinkPosition(link_id); - // link start -1 equals node num + // Link start -1 equals node num Link currLink = _currLinks[pos]; deleteLinkInfo(currLink._startAttr, currLink._endAttr); _currLinks.erase(_currLinks.begin() + pos); @@ -2708,7 +2807,7 @@ void Graph::deleteLink(ed::LinkId deletedLinkId) void Graph::deleteNode(UiNodePtr node) { - // delete link + // Delete link for (UiPinPtr inputPin : node->inputPins) { UiNodePtr upNode = node->getConnectedNode(inputPin->_name); @@ -2716,7 +2815,8 @@ void Graph::deleteNode(UiNodePtr node) { upNode->removeOutputConnection(node->getName()); int num = node->getEdgeIndex(upNode->getId(), inputPin); - // erase edge between node and up node + + // Erase edge between node and up node if (num != -1) { if (node->edges.size() == 1) @@ -2733,7 +2833,7 @@ void Graph::deleteNode(UiNodePtr node) if (node->outputPins.size() > 0) { - // update downNode info + // Update downNode info for (UiPinPtr pin : node->outputPins.front()->getConnections()) { mx::ValuePtr val; @@ -2741,7 +2841,7 @@ void Graph::deleteNode(UiNodePtr node) { mx::NodeDefPtr nodeDef = pin->_pinNode->getNode()->getNodeDef(pin->_pinNode->getNode()->getName()); val = nodeDef->getActiveInput(pin->_input->getName())->getValue(); - if (pin->_pinNode->getNode()->getType() == "surfaceshader") + if (pin->_pinNode->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING) { pin->_input->setConnectedOutput(nullptr); } @@ -2782,19 +2882,19 @@ void Graph::deleteNode(UiNodePtr node) } pin->_pinNode->setInputNodeNum(-1); - // not really necessary since it will be deleted + + // Not really necessary since it will be deleted node->removeOutputConnection(pin->_pinNode->getName()); } } - // remove from NodeGraph - // all link information is handled in delete link which is called before this + // Remove from NodeGraph + // All link information is handled in delete link which is called before this int nodeNum = findNode(node->getId()); _currGraphElem->removeChild(node->getName()); _graphNodes.erase(_graphNodes.begin() + nodeNum); } -// create pins for outputs/inputs added while inside the node graph void Graph::addNodeGraphPins() { for (UiNodePtr node : _graphNodes) @@ -2893,18 +2993,34 @@ void Graph::clearGraph() _renderer->updateMaterials(nullptr); } -void Graph::loadGraphFromFile() +void Graph::loadGraphFromFile(bool prompt) { - // deselect node before loading new file - if (_currUiNode != nullptr) + // Deselect node before loading new file + if (_currUiNode) { ed::DeselectNode(_currUiNode->getId()); _currUiNode = nullptr; } - _fileDialog.setTitle("Open File"); - _fileDialog.setTypeFilters(_mtlxFilter); - _fileDialog.open(); + if (prompt || _materialFilename.isEmpty()) + { + _fileDialog.setTitle("Open File"); + _fileDialog.setTypeFilters(_mtlxFilter); + _fileDialog.open(); + } + else + { + _graphDoc = loadDocument(_materialFilename); + + // Rebuild the UI + _initial = true; + buildUiBaseGraph(_graphDoc); + _currGraphElem = _graphDoc; + _prevUiNode = nullptr; + + _renderer->setDocument(_graphDoc); + _renderer->updateMaterials(nullptr); + } } void Graph::saveGraphToFile() @@ -2930,15 +3046,18 @@ void Graph::graphButtons() { if (ImGui::BeginMenu("File")) { - // buttons for loading and saving a .mtlx - // new Material button + // Buttons for loading and saving a .mtlx if (ImGui::MenuItem("New", "Ctrl-N")) { clearGraph(); } else if (ImGui::MenuItem("Open", "Ctrl-O")) { - loadGraphFromFile(); + loadGraphFromFile(true); + } + else if (ImGui::MenuItem("Reload", "Ctrl-R")) + { + loadGraphFromFile(false); } else if (ImGui::MenuItem("Save", "Ctrl-S")) { @@ -2965,6 +3084,12 @@ void Graph::graphButtons() ImGui::EndMenu(); } + if (ImGui::BeginMenu("Options")) + { + ImGui::Checkbox("Save Node Positions", &_saveNodePositions); + ImGui::EndMenu(); + } + if (ImGui::Button("Help")) { ImGui::OpenPopup("Help"); @@ -2984,23 +3109,28 @@ void Graph::graphButtons() { if (ImGui::IsKeyReleased(ImGuiKey_O)) { - loadGraphFromFile(); + loadGraphFromFile(true); } else if (ImGui::IsKeyReleased(ImGuiKey_N)) { clearGraph(); } + else if (ImGui::IsKeyReleased(ImGuiKey_R)) + { + loadGraphFromFile(false); + } else if (ImGui::IsKeyReleased(ImGuiKey_S)) { saveGraphToFile(); } } - // split window into panes for NodeEditor + // Split window into panes for NodeEditor static float leftPaneWidth = 375.0f; static float rightPaneWidth = 750.0f; - Splitter(true, 4.0f, &leftPaneWidth, &rightPaneWidth, 20.0f, 20.0f); - // create back button and graph hiearchy name display + splitter(true, 4.0f, &leftPaneWidth, &rightPaneWidth, 20.0f, 20.0f); + + // Create back button and graph hierarchy name display ImGui::Indent(leftPaneWidth + 15.f); if (ImGui::Button("<")) { @@ -3024,20 +3154,21 @@ void Graph::graphButtons() ImGui::Unindent(leftPaneWidth + 15.f); ImGui::PopStyleColor(); ImGui::NewLine(); - // creating two windows using splitter + + // Create two windows using splitter float paneWidth = (leftPaneWidth - 2.0f); ImGui::BeginChild("Selection", ImVec2(paneWidth, 0)); ImVec2 windowPos = ImGui::GetWindowPos(); - // renderView window + + // RenderView window ImVec2 wsize = ImVec2((float) _renderer->getViewWidth(), (float) _renderer->getViewHeight()); float aspectRatio = _renderer->getPixelRatio(); ImVec2 screenSize = ImVec2(paneWidth, paneWidth / aspectRatio); _renderer->setViewWidth((int) screenSize[0]); _renderer->setViewHeight((int) screenSize[1]); - if (_renderer != nullptr) + if (_renderer) { - glEnable(GL_FRAMEBUFFER_SRGB); _renderer->getViewCamera()->setViewportSize(mx::Vector2(screenSize[0], screenSize[1])); GLuint64 my_image_texture = _renderer->_textureID; @@ -3047,19 +3178,20 @@ void Graph::graphButtons() } ImGui::Separator(); - // property editor for current nodes + // Property editor for current nodes propertyEditor(); ImGui::EndChild(); ImGui::SameLine(0.0f, 12.0f); handleRenderViewInputs(windowPos, screenSize[0], screenSize[1]); } + void Graph::propertyEditor() { ImGui::Text("Node Property Editor"); if (_currUiNode) { - // set and edit name + // Set and edit name ImGui::Text("Name: "); ImGui::SameLine(); std::string original = _currUiNode->getName(); @@ -3095,9 +3227,7 @@ void Graph::propertyEditor() { if (temp != original) { - std::string name = _currUiNode->getInput()->getParent()->createValidChildName(temp); - std::vector downstreamNodes = _currUiNode->getOutputConnections(); for (UiNodePtr nodes : downstreamNodes) { @@ -3157,7 +3287,8 @@ void Graph::propertyEditor() ImGui::Text("Category:"); ImGui::SameLine(); - // change button color to match background + + // Change button color to match background ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.096f, .096f, .096f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.1f, .1f, .1f, 1.0f)); if (_currUiNode->getNode()) @@ -3202,7 +3333,8 @@ void Graph::propertyEditor() mx::getUIProperties(input->_input, mx::EMPTY_STRING, uiProperties); std::string inputLabel = !uiProperties.uiName.empty() ? uiProperties.uiName : input->_input->getName(); mx::OutputPtr out = input->_input->getConnectedOutput(); - // setting comment help box + + // Set comment help box ImGui::PushID(int(input->_pinId.Get())); ImGui::Text("%s", inputLabel.c_str()); mx::InputPtr tempInt = _currUiNode->getNode()->getNodeDef()->getActiveInput(input->_input->getName()); @@ -3218,7 +3350,7 @@ void Graph::propertyEditor() } docString += "\t \n"; - // setting constant sliders for input values + // Set constant sliders for input values ImGui::TableNextColumn(); if (!input->getConnected()) { @@ -3265,13 +3397,13 @@ void Graph::propertyEditor() mx::getUIProperties(mxinput, mx::EMPTY_STRING, uiProperties); std::string inputLabel = !uiProperties.uiName.empty() ? uiProperties.uiName : mxinput->getName(); - // setting comment help box + // Set comment help box ImGui::PushID(int(inputs[i]->_pinId.Get())); ImGui::Text("%s", inputLabel.c_str()); ImGui::TableNextColumn(); - // setting constant sliders for input values + // Set constant sliders for input values if (!inputs[i]->getConnected()) { setConstant(_currUiNode, inputs[i]->_input, uiProperties); @@ -3324,7 +3456,7 @@ void Graph::propertyEditor() mx::getUIProperties(mxinput, mx::EMPTY_STRING, uiProperties); std::string inputLabel = !uiProperties.uiName.empty() ? uiProperties.uiName : mxinput->getName(); - // setting comment help box + // Set comment help box ImGui::PushID(int(input->_pinId.Get())); ImGui::Text("%s", inputLabel.c_str()); @@ -3368,7 +3500,6 @@ void Graph::propertyEditor() } } -// Helper to display basic user controls. void Graph::showHelp() const { ImGui::Text("MATERIALX GRAPH EDITOR HELP"); @@ -3431,11 +3562,13 @@ void Graph::addNodePopup(bool cursor) } ImGui::InputText("##input", input, sizeof(input)); std::string subs(input); - // input string length - // filter extra nodes - includes inputs, outputs, groups, and node graphs + + // Input string length + // Filter extra nodes - includes inputs, outputs, groups, and node graphs + const std::string NODEGRAPH_ENTRY = "Node Graph"; for (std::unordered_map>>::iterator it = _extraNodes.begin(); it != _extraNodes.end(); ++it) { - // filter out list of nodes + // Filter out list of nodes if (subs.size() > 0) { ImGui::SetNextWindowSizeConstraints(ImVec2(250.0f, 300.0f), ImVec2(-1.0f, 500.0f)); @@ -3443,14 +3576,21 @@ void Graph::addNodePopup(bool cursor) { std::string str(it->second[i][0]); std::string nodeName = it->second[i][0]; - // allow spaces to be used to search for node names + + // Disallow creating nested nodegraphs + if (_isNodeGraph && it->first == NODEGRAPH_ENTRY) + { + continue; + } + + // Allow spaces to be used to search for node names std::replace(subs.begin(), subs.end(), ' ', '_'); if (str.find(subs) != std::string::npos) { - if (ImGui::MenuItem(getNodeDefId(nodeName).c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) + if (ImGui::MenuItem(getUserNodeDefName(nodeName).c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) { - addNode(it->second[i][2], getNodeDefId(nodeName), it->second[i][1]); + addNode(it->second[i][2], getUserNodeDefName(nodeName), it->second[i][1]); _addNewNode = true; memset(input, '\0', sizeof(input)); } @@ -3466,9 +3606,9 @@ void Graph::addNodePopup(bool cursor) for (size_t j = 0; j < it->second.size(); j++) { std::string name = it->second[j][0]; - if (ImGui::MenuItem(getNodeDefId(name).c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) + if (ImGui::MenuItem(getUserNodeDefName(name).c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) { - addNode(it->second[j][2], getNodeDefId(name), it->second[j][1]); + addNode(it->second[j][2], getUserNodeDefName(name), it->second[j][1]); _addNewNode = true; } } @@ -3476,10 +3616,11 @@ void Graph::addNodePopup(bool cursor) } } } - // filter nodedefs and add to menu if matches filter + + // Filter nodedefs and add to menu if matches filter for (std::unordered_map>::iterator it = _nodesToAdd.begin(); it != _nodesToAdd.end(); ++it) { - // filter out list of nodes + // Filter out list of nodes if (subs.size() > 0) { ImGui::SetNextWindowSizeConstraints(ImVec2(250.0f, 300.0f), ImVec2(-1.0f, 500.0f)); @@ -3489,7 +3630,7 @@ void Graph::addNodePopup(bool cursor) std::string nodeName = it->second[i]->getName(); if (str.find(subs) != std::string::npos) { - std::string val = getNodeDefId(nodeName); + std::string val = getUserNodeDefName(nodeName); if (ImGui::MenuItem(val.c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) { addNode(it->second[i]->getNodeString(), val, it->second[i]->getType()); @@ -3508,7 +3649,7 @@ void Graph::addNodePopup(bool cursor) for (size_t i = 0; i < it->second.size(); i++) { std::string name = it->second[i]->getName(); - std::string val = getNodeDefId(name); + std::string val = getUserNodeDefName(name); if (ImGui::MenuItem(val.c_str()) || (ImGui::IsItemFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Enter))) { addNode(it->second[i]->getNodeString(), val, it->second[i]->getType()); @@ -3524,6 +3665,7 @@ void Graph::addNodePopup(bool cursor) open_AddPopup = false; } } + void Graph::searchNodePopup(bool cursor) { const bool open_search = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && ImGui::IsKeyDown(ImGuiKey_F) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl); @@ -3547,7 +3689,6 @@ void Graph::searchNodePopup(bool cursor) if (std::string(input).size() > 0) { - for (UiNodePtr node : _graphNodes) { if (node->getName().find(std::string(input)) != std::string::npos) @@ -3581,7 +3722,6 @@ void Graph::readOnlyPopup() } } -// compiling shaders message void Graph::shaderPopup() { if (_renderer->getMaterialCompilation()) @@ -3601,7 +3741,6 @@ void Graph::shaderPopup() } } -// allow for camera manipulation of render view window void Graph::handleRenderViewInputs(ImVec2 minValue, float width, float height) { ImVec2 mousePos = ImGui::GetMousePos(); @@ -3645,14 +3784,15 @@ void Graph::handleRenderViewInputs(ImVec2 minValue, float width, float height) { _renderer->setKeyEvent(ImGuiKey_KeypadSubtract); } - // scrolling not possible if open or save file dialog is open + + // Scrolling not possible if open or save file dialog is open if (scrollAmt != 0 && !_fileDialogSave.isOpened() && !_fileDialog.isOpened() && !_fileDialogGeom.isOpened()) { _renderer->setScrollEvent(scrollAmt); } } } -// sets up graph editor + void Graph::drawGraph(ImVec2 mousePos) { if (_searchNodeId > 0) @@ -3663,7 +3803,8 @@ void Graph::drawGraph(ImVec2 mousePos) } bool TextCursor = false; - // center imgui window and setting size + + // Center imgui window and set size ImGuiIO& io2 = ImGui::GetIO(); ImGui::SetNextWindowSize(io2.DisplaySize); ImGui::SetNextWindowPos(ImVec2(io2.DisplaySize.x * 0.5f, io2.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); @@ -3676,7 +3817,8 @@ void Graph::drawGraph(ImVec2 mousePos) ed::Begin("My Editor"); { ed::Suspend(); - // set up pop ups for adding a node when tab is pressed + + // Set up popups for adding a node when tab is pressed ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f)); ImGui::SetNextWindowSizeConstraints(ImVec2(250.0f, 300.0f), ImVec2(-1.0f, 500.0f)); addNodePopup(TextCursor); @@ -3686,7 +3828,7 @@ void Graph::drawGraph(ImVec2 mousePos) ed::Resume(); - // Gathering selected nodes / links - from ImGui Node Editor blueprints-example.cpp + // Gather selected nodes / links - from ImGui Node Editor blueprints-example.cpp std::vector selectedNodes; std::vector selectedLinks; selectedNodes.resize(ed::GetSelectedObjectCount()); @@ -3702,29 +3844,23 @@ void Graph::drawGraph(ImVec2 mousePos) _ctrlClick = true; } - // setting current node based off of selected node + // Set current node based off of selected node if (selectedNodes.size() > 0) { int graphPos = findNode(int(selectedNodes[0].Get())); if (graphPos > -1) { - // only selected not if its not the same as previously selected + // Only selected if its not the same as previously selected if (!_prevUiNode || (_prevUiNode->getName() != _graphNodes[graphPos]->getName())) { _currUiNode = _graphNodes[graphPos]; - // update render material if needed + + // Update render material if needed if (_currUiNode->getNode()) - { - if (_currUiNode->getNode()->getType() == mx::SURFACE_SHADER_TYPE_STRING || _currUiNode->getNode()->getType() == mx::MATERIAL_TYPE_STRING) - { - setRenderMaterial(_currUiNode); - } - } - else if (_currUiNode->getNodeGraph()) { setRenderMaterial(_currUiNode); } - else if (_currUiNode->getOutput()) + else if (_currUiNode->getNodeGraph() || _currUiNode->getOutput()) { setRenderMaterial(_currUiNode); } @@ -3733,7 +3869,7 @@ void Graph::drawGraph(ImVec2 mousePos) } } - // check if keyboard shortcuts for copy/cut/paste have been used + // Check if keyboard shortcuts for copy/cut/paste have been used if (ed::BeginShortcut()) { if (ed::AcceptCopy()) @@ -3753,7 +3889,8 @@ void Graph::drawGraph(ImVec2 mousePos) if (!readOnly()) { _copiedNodes.clear(); - // same as copy but remove from graphNodes + + // Same as copy but remove from graphNodes for (ed::NodeId selected : selectedNodes) { int pos = findNode((int) selected.Get()); @@ -3786,40 +3923,44 @@ void Graph::drawGraph(ImVec2 mousePos) } } - // set y position of first node + // Set y-position of first node std::vector outputNum = createNodes(_isNodeGraph); - // address copy information if applicable and relink graph if a new node has been added + // Address copy information if applicable and relink graph if a new node has been added if (_addNewNode) { copyInputs(); linkGraph(); ImVec2 canvasPos = ed::ScreenToCanvas(mousePos); - // place the copied nodes or the individual new nodes - if ((int) _copiedNodes.size() > 0) + + // Place the copied nodes or the individual new nodes + if (!_copiedNodes.empty()) { positionPasteBin(canvasPos); } - else + else if (!_graphNodes.empty()) { ed::SetNodePosition(_graphNodes.back()->getId(), canvasPos); } _copiedNodes.clear(); _addNewNode = false; } - // layout and link graph during the initial call of drawGraph() + + // Layout and link graph during the initial call of drawGraph if (_initial || _autoLayout) { _currLinks.clear(); float y = 0.f; _levelMap = std::unordered_map>(); - // start layout with output or material nodes since layout algorithm works right to left + + // Start layout with output or material nodes since layout algorithm works right to left for (int outN : outputNum) { layoutPosition(_graphNodes[outN], ImVec2(1200.f, y), true, 0); y += 350; } - // if there are no output or material nodes but the nodes have position layout each individual node + + // If there are no output or material nodes but the nodes have position layout each individual node if (_graphNodes.size() > 0) { @@ -3834,7 +3975,8 @@ void Graph::drawGraph(ImVec2 mousePos) linkGraph(); findYSpacing(0.f); layoutInputs(); - // automatically frame node graph upon loading + + // Automatically frame node graph upon loading ed::NavigateToContent(); } if (_delete) @@ -3844,13 +3986,15 @@ void Graph::drawGraph(ImVec2 mousePos) _delete = false; } connectLinks(); - // set to false after intial layout so that nodes can be moved + + // Set to false after intial layout so that nodes can be moved _initial = false; _autoLayout = false; - // delete selected nodes and their links if delete key is pressed or if the shortcut for cut is used + + // Delete selected nodes and their links if delete key is pressed + // or if the shortcut for cut is used if (ImGui::IsKeyReleased(ImGuiKey_Delete) || _isCut) { - if (selectedNodes.size() > 0) { _frameCount = ImGui::GetFrameCount(); @@ -3880,24 +4024,25 @@ void Graph::drawGraph(ImVec2 mousePos) _isCut = false; } - // start the session with content centered + // Start the session with content centered if (ImGui::GetFrameCount() == 2) { ed::NavigateToContent(0.0f); } - // hotkey to frame selected node(s) + // Hotkey to frame selected node(s) if (ImGui::IsKeyReleased(ImGuiKey_F) && !_fileDialogSave.isOpened()) { ed::NavigateToSelection(); } - // go back up from inside a subgraph + // Go back up from inside a subgraph if (ImGui::IsKeyReleased(ImGuiKey_U) && (!ImGui::IsPopupOpen("add node")) && (!ImGui::IsPopupOpen("search")) && !_fileDialogSave.isOpened()) { upNodeGraph(); } - // adding new link + + // Add new link if (ed::BeginCreate()) { ed::PinId inputPinId, outputPinId, filterPinId; @@ -3905,7 +4050,7 @@ void Graph::drawGraph(ImVec2 mousePos) { if (!readOnly()) { - AddLink(inputPinId, outputPinId); + addLink(inputPinId, outputPinId); } else { @@ -3925,7 +4070,8 @@ void Graph::drawGraph(ImVec2 mousePos) _pinFilterType = mx::EMPTY_STRING; } ed::EndCreate(); - // deleting link + + // Delete link if (ed::BeginDelete()) { ed::LinkId deletedLinkId; @@ -3944,7 +4090,7 @@ void Graph::drawGraph(ImVec2 mousePos) ed::EndDelete(); } - // diving into a node that has a subgraph + // Dive into a node that has a subgraph ed::NodeId clickedNode = ed::GetDoubleClickedNode(); if (clickedNode.Get() > 0) { @@ -3952,9 +4098,9 @@ void Graph::drawGraph(ImVec2 mousePos) { if (_currUiNode->getNode() != nullptr) { - mx::InterfaceElementPtr impl = _currUiNode->getNode()->getImplementation(); - // only dive if current node is a node graph + + // Only dive if current node is a node graph if (impl && impl->isA()) { savePosition(); @@ -4022,22 +4168,21 @@ void Graph::drawGraph(ImVec2 mousePos) ed::Suspend(); _fileDialogSave.display(); - // saving file + + // Save file if (_fileDialogSave.hasSelected()) { - std::string message; if (!_graphDoc->validate(&message)) { std::cerr << "*** Validation warnings for " << _materialFilename.getBaseName() << " ***" << std::endl; std::cerr << message; } - std::string fileName = _fileDialogSave.getSelected(); - mx::FilePath name = _fileDialogSave.getSelected(); + _materialFilename = _fileDialogSave.getSelected(); ed::Resume(); savePosition(); - writeText(fileName, name); + saveDocument(_materialFilename); _fileDialogSave.clearSelected(); } else @@ -4049,7 +4194,8 @@ void Graph::drawGraph(ImVec2 mousePos) ImGui::End(); _fileDialog.display(); - // create and load document from selected file + + // Create and load document from selected file if (_fileDialog.hasSelected()) { mx::FilePath fileName = _fileDialog.getSelected(); @@ -4057,7 +4203,6 @@ void Graph::drawGraph(ImVec2 mousePos) std::string graphName = fileName.getBaseName(); _currGraphName.push_back(graphName.substr(0, graphName.length() - 5)); _graphDoc = loadDocument(fileName); - _graphDoc->importLibrary(_stdLib); _initial = true; buildUiBaseGraph(_graphDoc); @@ -4081,7 +4226,6 @@ void Graph::drawGraph(ImVec2 mousePos) _fileDialogImage.display(); } -// return node location in graphNodes vector based off of node id int Graph::findNode(int nodeId) { int count = 0; @@ -4096,7 +4240,6 @@ int Graph::findNode(int nodeId) return -1; } -// find a link based on an attribute id std::vector Graph::findLinkId(int id) { std::vector ids; @@ -4109,7 +4252,7 @@ std::vector Graph::findLinkId(int id) } return ids; } -// check if current edge is already in edge vector + bool Graph::edgeExists(UiEdge newEdge) { if (_currEdge.size() > 0) @@ -4145,7 +4288,6 @@ bool Graph::edgeExists(UiEdge newEdge) return false; } -// check if a link exists in currLink vector bool Graph::linkExists(Link newLink) { for (const auto& link : _currLinks) @@ -4154,7 +4296,6 @@ bool Graph::linkExists(Link newLink) { if (link._endAttr == newLink._endAttr) { - // link exists return true; } } @@ -4162,7 +4303,6 @@ bool Graph::linkExists(Link newLink) { if (link._endAttr == newLink._startAttr) { - // link exists return true; } } @@ -4170,12 +4310,11 @@ bool Graph::linkExists(Link newLink) return false; } -// set materialX attribute positions for nodes which changed pos void Graph::savePosition() { for (UiNodePtr node : _graphNodes) { - if (node->getMxElement() != nullptr) + if (node->getMxElement()) { ImVec2 pos = ed::GetNodePosition(node->getId()); pos.x /= DEFAULT_NODE_SIZE.x; @@ -4189,14 +4328,27 @@ void Graph::savePosition() } } } -void Graph::writeText(std::string fileName, mx::FilePath filePath) +void Graph::saveDocument(mx::FilePath filePath) { if (filePath.getExtension() != mx::MTLX_EXTENSION) { filePath.addExtension(mx::MTLX_EXTENSION); } + mx::DocumentPtr writeDoc = _graphDoc; + + // If requested, create a modified version of the document for saving. + if (!_saveNodePositions) + { + writeDoc = _graphDoc->copy(); + for (mx::ElementPtr elem : writeDoc->traverseTree()) + { + elem->removeAttribute("xpos"); + elem->removeAttribute("ypos"); + } + } + mx::XmlWriteOptions writeOptions; writeOptions.elementPredicate = getElementPredicate(); - mx::writeToXmlFile(_graphDoc, filePath, &writeOptions); + mx::writeToXmlFile(writeDoc, filePath, &writeOptions); } diff --git a/source/MaterialXGraphEditor/Graph.h b/source/MaterialXGraphEditor/Graph.h index 68140cdaae..8c76f0f68d 100644 --- a/source/MaterialXGraphEditor/Graph.h +++ b/source/MaterialXGraphEditor/Graph.h @@ -60,105 +60,160 @@ class Graph private: mx::ElementPredicate getElementPredicate() const; void loadStandardLibraries(); + + // Generate node UI from nodedefs void createNodeUIList(mx::DocumentPtr doc); + + // Build UiNode nodegraph upon loading a document void buildUiBaseGraph(mx::DocumentPtr doc); + + // Build UiNode node graph upon diving into a nodegraph node void buildUiNodeGraph(const mx::NodeGraphPtr& nodeGraphs); + + // Based on the comment node in the ImGui Node Editor blueprints-example.cpp. void buildGroupNode(UiNodePtr node); - // handling link information + // Connect links via connected nodes in UiNodePtr void linkGraph(); + + // Connect all links via the graph editor library void connectLinks(); + + // Find link position in current links vector from link id int findLinkPosition(int id); + + // Find link from attribute id std::vector findLinkId(int attrId); + + // Check if link exists in the current link vector bool linkExists(Link newLink); - void AddLink(ed::PinId inputPinId, ed::PinId outputPinId); + + // Add link to nodegraph and set up connections between UiNodes and + // MaterialX Nodes to update shader + void addLink(ed::PinId inputPinId, ed::PinId outputPinId); + + // Delete link from current link vector and remove any connections in + // UiNode or MaterialX Nodes to update shader void deleteLink(ed::LinkId deletedLinkId); + void deleteLinkInfo(int startAtrr, int endAttr); - // functions for the layout of the nodes + // Layout the x-position by assigning the node levels based on its distance from the first node ImVec2 layoutPosition(UiNodePtr node, ImVec2 pos, bool initialLayout, int level); + + // Extra layout pass for inputs and nodes that do not attach to an output node void layoutInputs(); + void findYSpacing(float startPos); float totalHeight(int level); void setYSpacing(int level, float startingPos); float findAvgY(const std::vector& nodes); - // pin information + // Return pin color based on the type of the value of that pin void setPinColor(); - void DrawPinIcon(std::string type, bool connected, int alpha); + + // Based on the pin icon function in the ImGui Node Editor blueprints-example.cpp + void drawPinIcon(std::string type, bool connected, int alpha); + UiPinPtr getPin(ed::PinId id); void drawInputPin(UiPinPtr pin); + + // Return output pin needed to link the inputs and outputs ed::PinId getOutputPin(UiNodePtr node, UiNodePtr inputNode, UiPinPtr input); + void drawOutputPins(UiNodePtr node, const std::string& longestInputLabel); + + // Create pins for outputs/inputs added while inside the node graph void addNodeGraphPins(); - // UiNode functions std::vector createNodes(bool nodegraph); int getNodeId(ed::PinId pinId); + + // Find node location in graph nodes vector from node id int findNode(int nodeId); + + // Return node position in _graphNodes from node name and type to account for + // input/output UiNodes with same names as MaterialX nodes int findNode(const std::string& name, const std::string& type); + + // Add node to graphNodes based on nodedef information void addNode(const std::string& category, const std::string& name, const std::string& type); + void deleteNode(UiNodePtr node); + + // Build the initial graph of a loaded document including shader, material and nodegraph node void setUiNodeInfo(UiNodePtr node, const std::string& type, const std::string& category); - // UiEdge functions + // Check if edge exists in edge vector bool edgeExists(UiEdge edge); + void createEdge(UiNodePtr upNode, UiNodePtr downNode, mx::InputPtr connectingInput); + + // Remove node edge based on connecting input void removeEdge(int downNode, int upNode, UiPinPtr pin); - void writeText(std::string filename, mx::FilePath filePath); + void saveDocument(mx::FilePath filePath); + + // Set position attributes for nodes which changed position void savePosition(); + + // Check if node has already been assigned a position bool checkPosition(UiNodePtr node); + // Add input pointer to node based on input pin void addNodeInput(UiNodePtr node, mx::InputPtr& input); - mx::InputPtr findInput(mx::InputPtr input, std::string name); - // travel up from inside a node graph + mx::InputPtr findInput(mx::InputPtr input, const std::string& name); void upNodeGraph(); - // property editor information + // Set the value of the selected node constants in the node property editor void setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIProperties& uiProperties); + void propertyEditor(); void setDefaults(mx::InputPtr input); - // set up Ui information for add node popup + // Setup UI information for add node popup void addExtraNodes(); - // copy and paste functions void copyInputs(); + + // Set position of pasted nodes based on original node position void positionPasteBin(ImVec2 pos); + void copyNodeGraph(UiNodePtr origGraph, UiNodePtr copyGraph); void copyUiNode(UiNodePtr node); - // renderview window and buttons void graphButtons(); - // popup information void addNodePopup(bool cursor); void searchNodePopup(bool cursor); bool readOnly(); void readOnlyPopup(); + + // Compiling shaders message void shaderPopup(); - // modifying materials void updateMaterials(mx::InputPtr input = nullptr, mx::ValuePtr value = nullptr); void selectMaterial(UiNodePtr node); + + // Allow for camera manipulation of render view window void handleRenderViewInputs(ImVec2 minValue, float width, float height); + + // Set the node to display in render view based on selected node or nodegraph void setRenderMaterial(UiNodePtr node); - // File I/O void clearGraph(); - void loadGraphFromFile(); + void loadGraphFromFile(bool prompt); void saveGraphToFile(); void loadGeometry(); + void showHelp() const; + + private: mx::StringVec _geomFilter; mx::StringVec _mtlxFilter; mx::StringVec _imageFilter; - // Help - void showHelp() const; - RenderViewPtr _renderer; // document and intializing information @@ -214,7 +269,7 @@ class Graph FileDialog _fileDialogSave; FileDialog _fileDialogImage; FileDialog _fileDialogGeom; - + std::string _fileDialogImageInputName; bool _isNodeGraph; @@ -236,7 +291,10 @@ class Graph std::string _pinFilterType; // DPI scaling for fonts - float _fontScale = 1.0f; + float _fontScale; + + // Options + bool _saveNodePositions; }; #endif diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index faf48f543a..176014ba65 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -159,7 +159,6 @@ RenderView::RenderView(mx::DocumentPtr doc, _genContext(mx::GlslShaderGenerator::create()), _unitRegistry(mx::UnitConverterRegistry::create()), _splitByUdims(true), - _mergeMaterials(false), _materialCompilation(false), _renderTransparency(true), _renderDoubleSided(true), @@ -410,18 +409,15 @@ void RenderView::updateMaterials(mx::TypedElementPtr typedElem) // Clear user data on the generator. _genContext.clearUserData(); - // Clear materials if merging is not requested. - if (!_mergeMaterials) + // Clear materials. + for (mx::MeshPartitionPtr geom : _geometryList) { - for (mx::MeshPartitionPtr geom : _geometryList) + if (_materialAssignments.count(geom)) { - if (_materialAssignments.count(geom)) - { - assignMaterial(geom, nullptr); - } + assignMaterial(geom, nullptr); } - _materials.clear(); } + _materials.clear(); std::vector newMaterials; try @@ -434,10 +430,19 @@ void RenderView::updateMaterials(mx::TypedElementPtr typedElem) // Apply direct lights. applyDirectLights(_document); - //// Check for any udim set. + // Check for any udim set. mx::ValuePtr udimSetValue = _document->getGeomPropValue(mx::UDIM_SET_PROPERTY); - //// Create new materials. + // Skip material nodes without upstream shaders. + mx::NodePtr node = typedElem ? typedElem->asA() : nullptr; + if (node && + node->getCategory() == mx::SURFACE_MATERIAL_NODE_STRING && + mx::getShaderNodes(node).empty()) + { + typedElem = nullptr; + } + + // Create new materials. if (!typedElem) { std::vector elems = mx::findRenderableElements(_document); @@ -451,8 +456,7 @@ void RenderView::updateMaterials(mx::TypedElementPtr typedElem) mx::NodePtr materialNode = nullptr; if (typedElem) { - mx::NodePtr node = typedElem->asA(); - materialNode = node && node->getType() == mx::MATERIAL_TYPE_STRING ? node : nullptr; + materialNode = node; if (udimSetValue && udimSetValue->isA()) { for (const std::string& udim : udimSetValue->asA()) @@ -551,14 +555,11 @@ void RenderView::updateMaterials(mx::TypedElementPtr typedElem) // Apply fallback assignments. mx::GlslMaterialPtr fallbackMaterial = newMaterials[0]; - if (!_mergeMaterials || fallbackMaterial->getUdim().empty()) + for (mx::MeshPartitionPtr geom : _geometryList) { - for (mx::MeshPartitionPtr geom : _geometryList) + if (!_materialAssignments[geom]) { - if (!_materialAssignments[geom]) - { - assignMaterial(geom, fallbackMaterial); - } + assignMaterial(geom, fallbackMaterial); } } @@ -720,7 +721,7 @@ void RenderView::loadEnvironmentLight() envIrradianceMap = _imageHandler->acquireImage(envIrradiancePath); // If not found, then generate an irradiance map via spherical harmonics. - if (envIrradianceMap == _imageHandler->getInvalidImage()) + if (envIrradianceMap == _imageHandler->getZeroImage()) { mx::Sh3ColorCoeffs shIrradiance = mx::projectEnvironment(envRadianceMap, true); envIrradianceMap = mx::renderEnvironment(shIrradiance, IRRADIANCE_MAP_WIDTH, IRRADIANCE_MAP_HEIGHT); diff --git a/source/MaterialXGraphEditor/RenderView.h b/source/MaterialXGraphEditor/RenderView.h index e931be9592..354e898ce1 100644 --- a/source/MaterialXGraphEditor/RenderView.h +++ b/source/MaterialXGraphEditor/RenderView.h @@ -145,11 +145,6 @@ class RenderView return _materialAssignments; } - bool getMergeMaterials() - { - return _mergeMaterials; - } - std::vector getMaterials() { return _materials; @@ -323,7 +318,6 @@ class RenderView bool _splitByUdims; // Material options - bool _mergeMaterials; bool _materialCompilation; // Unit options diff --git a/source/MaterialXRender/CMakeLists.txt b/source/MaterialXRender/CMakeLists.txt index d0a50232cd..52d07e688e 100644 --- a/source/MaterialXRender/CMakeLists.txt +++ b/source/MaterialXRender/CMakeLists.txt @@ -1,3 +1,5 @@ +set(MATERIALX_MODULE_NAME MaterialXRender) + include_directories( ${EXTERNAL_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../) @@ -18,12 +20,18 @@ if(UNIX) add_compile_options(-Wno-unused-function) endif() -add_library(MaterialXRender ${materialx_source} ${materialx_headers} ${materialx_inlined}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers} ${materialx_inlined}) add_definitions(-DMATERIALX_RENDER_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + target_link_libraries( - MaterialXRender + ${MATERIALX_MODULE_NAME} MaterialXGenShader ${CMAKE_DL_LIBS}) @@ -33,7 +41,7 @@ if(MATERIALX_BUILD_OIIO) find_package(OpenImageIO REQUIRED) if(OPENIMAGEIO_FOUND) include_directories(${OPENIMAGEIO_INCLUDE_DIR}) - target_link_libraries(MaterialXRender ${OPENIMAGEIO_LIBRARIES}) + target_link_libraries(${MATERIALX_MODULE_NAME} ${OPENIMAGEIO_LIBRARIES}) # Also needed by MaterialXTest: set(OPENIMAGEIO_FOUND "${OPENIMAGEIO_FOUND}" PARENT_SCOPE) set(OPENIMAGEIO_INCLUDE_DIR "${OPENIMAGEIO_INCLUDE_DIR}" PARENT_SCOPE) @@ -44,25 +52,27 @@ if(MATERIALX_BUILD_OIIO) endif() set_target_properties( - MaterialXRender PROPERTIES - OUTPUT_NAME MaterialXRender${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" VERSION "${MATERIALX_LIBRARY_VERSION}" SOVERSION "${MATERIALX_MAJOR_VERSION}") -install(TARGETS MaterialXRender - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXRender/ MESSAGE_NEVER - FILES_MATCHING - PATTERN "*.h*" - PATTERN "*.inl") + 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}/MaterialXRender.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXRender/External/OpenImageIO/FindOpenImageIO.cmake b/source/MaterialXRender/External/OpenImageIO/FindOpenImageIO.cmake index 4fab4f9814..6c1b1682d6 100644 --- a/source/MaterialXRender/External/OpenImageIO/FindOpenImageIO.cmake +++ b/source/MaterialXRender/External/OpenImageIO/FindOpenImageIO.cmake @@ -45,6 +45,13 @@ find_library ( OPENIMAGEIO_LIBRARY HINTS ${OPENIMAGEIO_ROOT_DIR}/lib PATH_SUFFIXES lib64 lib PATHS "${OPENIMAGEIO_ROOT_DIR}/lib" ) + +find_library ( OPENIMAGEIO_UTIL_LIBRARY + NAMES OpenImageIO_Util${OIIO_LIBNAME_SUFFIX} + HINTS ${OPENIMAGEIO_ROOT_DIR}/lib + PATH_SUFFIXES lib64 lib + PATHS "${OPENIMAGEIO_ROOT_DIR}/lib" ) + find_path ( OPENIMAGEIO_INCLUDE_DIR NAMES OpenImageIO/imageio.h HINTS ${OPENIMAGEIO_ROOT_DIR}/include @@ -66,7 +73,7 @@ if (EXISTS "${OIIO_VERSION_HEADER}") set (OPENIMAGEIO_VERSION "${OPENIMAGEIO_VERSION_MAJOR}.${OPENIMAGEIO_VERSION_MINOR}.${OPENIMAGEIO_VERSION_PATCH}") endif () -set ( OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARY}) +set ( OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARY} ${OPENIMAGEIO_UTIL_LIBRARY}) get_filename_component (OPENIMAGEIO_LIBRARY_DIRS "${OPENIMAGEIO_LIBRARY}" DIRECTORY CACHE) if (NOT OpenImageIO_FIND_QUIETLY) diff --git a/source/MaterialXRender/ImageHandler.cpp b/source/MaterialXRender/ImageHandler.cpp index bc43b617ff..d54a18fedd 100644 --- a/source/MaterialXRender/ImageHandler.cpp +++ b/source/MaterialXRender/ImageHandler.cpp @@ -56,9 +56,6 @@ ImageHandler::ImageHandler(ImageLoaderPtr imageLoader) { addLoader(imageLoader); _zeroImage = createUniformImage(2, 2, 4, Image::BaseType::UINT8, Color4(0.0f)); - - // Generated shaders interpret 1x1 textures as invalid images. - _invalidImage = createUniformImage(1, 1, 4, Image::BaseType::UINT8, Color4(0.0f)); } void ImageHandler::addLoader(ImageLoaderPtr loader) @@ -118,7 +115,7 @@ bool ImageHandler::saveImage(const FilePath& filePath, return false; } -ImagePtr ImageHandler::acquireImage(const FilePath& filePath) +ImagePtr ImageHandler::acquireImage(const FilePath& filePath, const Color4& defaultColor) { // Resolve the input filepath. FilePath resolvedFilePath = filePath; @@ -142,9 +139,12 @@ ImagePtr ImageHandler::acquireImage(const FilePath& filePath) return image; } - // No valid image was found, so cache the sentinel invalid image. - cacheImage(resolvedFilePath, _invalidImage); - return _invalidImage; + // No valid image was found, so generate a uniform texture with the given default color. + // TODO: This step assumes that the missing image and its default color are in the same + // color space, which is not always the case. + ImagePtr defaultImage = createUniformImage(1, 1, 4, Image::BaseType::UINT8, defaultColor); + cacheImage(resolvedFilePath, defaultImage); + return defaultImage; } bool ImageHandler::bindImage(ImagePtr, const ImageSamplingProperties&) @@ -189,7 +189,7 @@ ImageVec ImageHandler::getReferencedImages(ConstDocumentPtr doc) if (file) { ImagePtr image = acquireImage(file->getResolvedValueString()); - if (image && image != _invalidImage) + if (image) { imageVec.push_back(image); } @@ -214,14 +214,6 @@ ImagePtr ImageHandler::loadImage(const FilePath& filePath) } if (image) { - // Generated shaders interpret 1x1 textures as invalid images, so valid 1x1 - // images must be resized. - if (image->getWidth() == 1 && image->getHeight() == 1) - { - image = createUniformImage(2, 2, image->getChannelCount(), - image->getBaseType(), image->getTexelColor(0, 0)); - } - return image; } } @@ -288,23 +280,23 @@ void ImageSamplingProperties::setProperties(const string& fileNameUniform, root = root.substr(0, pos); } - const string uaddressmodeStr = root + UADDRESS_MODE_SUFFIX; - const ShaderPort* port = uniformBlock.find(uaddressmodeStr); + const ShaderPort* port = uniformBlock.find(root + UADDRESS_MODE_SUFFIX); ValuePtr intValue = port ? port->getValue() : nullptr; uaddressMode = ImageSamplingProperties::AddressMode(intValue && intValue->isA() ? intValue->asA() : INVALID_MAPPED_INT_VALUE); - const string vaddressmodeStr = root + VADDRESS_MODE_SUFFIX; - port = uniformBlock.find(vaddressmodeStr); + port = uniformBlock.find(root + VADDRESS_MODE_SUFFIX); intValue = port ? port->getValue() : nullptr; vaddressMode = ImageSamplingProperties::AddressMode(intValue && intValue->isA() ? intValue->asA() : INVALID_MAPPED_INT_VALUE); - const string filtertypeStr = root + FILTER_TYPE_SUFFIX; - port = uniformBlock.find(filtertypeStr); + port = uniformBlock.find(root + FILTER_TYPE_SUFFIX); intValue = port ? port->getValue() : nullptr; filterType = ImageSamplingProperties::FilterType(intValue && intValue->isA() ? intValue->asA() : INVALID_MAPPED_INT_VALUE); - const string defaultColorStr = root + DEFAULT_COLOR_SUFFIX; - port = uniformBlock.find(defaultColorStr); + port = uniformBlock.find(root + DEFAULT_COLOR_SUFFIX); + if (!port) + { + port = uniformBlock.find(root + DEFAULT_COLOR_SUFFIX + "_cm_in"); + } ValuePtr colorValue = port ? port->getValue() : nullptr; if (colorValue) { diff --git a/source/MaterialXRender/ImageHandler.h b/source/MaterialXRender/ImageHandler.h index ee1fe127c4..c744eb2f6a 100644 --- a/source/MaterialXRender/ImageHandler.h +++ b/source/MaterialXRender/ImageHandler.h @@ -188,7 +188,7 @@ class MX_RENDER_API ImageHandler /// found in the cache, then each image loader will be applied in turn. /// @param filePath File path of the image. /// @return On success, a shared pointer to the acquired image. - ImagePtr acquireImage(const FilePath& filePath); + ImagePtr acquireImage(const FilePath& filePath, const Color4& defaultColor = Color4(0.0f)); /// Bind an image for rendering. /// @param image The image to bind. @@ -247,13 +247,6 @@ class MX_RENDER_API ImageHandler return _zeroImage; } - /// Return the sentinel invalid image, representing images that cannot be loaded - /// and should be replaced with their declared default value. - ImagePtr getInvalidImage() const - { - return _invalidImage; - } - /// Acquire all images referenced by the given document, and return the /// images in a vector. ImageVec getReferencedImages(ConstDocumentPtr doc); @@ -278,7 +271,6 @@ class MX_RENDER_API ImageHandler FileSearchPath _searchPath; StringResolverPtr _resolver; ImagePtr _zeroImage; - ImagePtr _invalidImage; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXRender/ShaderRenderer.cpp b/source/MaterialXRender/ShaderRenderer.cpp index a5e81d1f68..3bba62795e 100644 --- a/source/MaterialXRender/ShaderRenderer.cpp +++ b/source/MaterialXRender/ShaderRenderer.cpp @@ -25,17 +25,26 @@ const float DEFAULT_FAR_PLANE = 100.0f; // ShaderRenderer methods // -ShaderRenderer::ShaderRenderer(unsigned int width, unsigned int height, Image::BaseType baseType) : +ShaderRenderer::ShaderRenderer(unsigned int width, unsigned int height, Image::BaseType baseType, MatrixConvention matrixConvention) : _width(width), _height(height), - _baseType(baseType) + _baseType(baseType), + _matrixConvention(matrixConvention) { // Initialize a default camera. float fH = std::tan(DEFAULT_FIELD_OF_VIEW / 360.0f * PI) * DEFAULT_NEAR_PLANE; float fW = fH * 1.0f; _camera = Camera::create(); _camera->setViewMatrix(Camera::createViewMatrix(DEFAULT_EYE_POSITION, DEFAULT_TARGET_POSITION, DEFAULT_UP_VECTOR)); - _camera->setProjectionMatrix(Camera::createPerspectiveMatrix(-fW, fW, -fH, fH, DEFAULT_NEAR_PLANE, DEFAULT_FAR_PLANE)); + + if (_matrixConvention == ShaderRenderer::MatrixConvention::Metal) + { + _camera->setProjectionMatrix(Camera::createPerspectiveMatrixZP(-fW, fW, -fH, fH, DEFAULT_NEAR_PLANE, DEFAULT_FAR_PLANE)); + } + else // MatrixConvention::OpenGL (default) + { + _camera->setProjectionMatrix(Camera::createPerspectiveMatrix(-fW, fW, -fH, fH, DEFAULT_NEAR_PLANE, DEFAULT_FAR_PLANE)); + } } void ShaderRenderer::createProgram(ShaderPtr) @@ -50,4 +59,9 @@ void ShaderRenderer::setSize(unsigned int, unsigned int) { } +void ShaderRenderer::updateUniform(const string&, ConstValuePtr) +{ + throw ExceptionRenderError("Update uniform is not yet supported"); +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXRender/ShaderRenderer.h b/source/MaterialXRender/ShaderRenderer.h index 2c6f5fbf87..c1cfbecfa0 100644 --- a/source/MaterialXRender/ShaderRenderer.h +++ b/source/MaterialXRender/ShaderRenderer.h @@ -30,6 +30,12 @@ using ShaderRendererPtr = std::shared_ptr; class MX_RENDER_API ShaderRenderer { public: + /// Viewing API matrix conventions designation (default to OpenGL). + enum class MatrixConvention + { + OpenGL = 0, + Metal = 1 + }; /// A map with name and source code for each shader stage. using StageMap = StringMap; @@ -104,6 +110,9 @@ class MX_RENDER_API ShaderRenderer /// Validate inputs for the program. virtual void validateInputs() { } + /// Update the program with value of the uniform. + virtual void updateUniform(const string& name, ConstValuePtr value); + /// Set the size of the rendered image. virtual void setSize(unsigned int width, unsigned int height); @@ -123,13 +132,16 @@ class MX_RENDER_API ShaderRenderer /// @} protected: - ShaderRenderer(unsigned int width, unsigned int height, Image::BaseType baseType); + ShaderRenderer(unsigned int width, unsigned int height, Image::BaseType baseType, + MatrixConvention matrixConvention = MatrixConvention::OpenGL); protected: unsigned int _width; unsigned int _height; Image::BaseType _baseType; + MatrixConvention _matrixConvention; + CameraPtr _camera; ImageHandlerPtr _imageHandler; GeometryHandlerPtr _geometryHandler; diff --git a/source/MaterialXRenderGlsl/CMakeLists.txt b/source/MaterialXRenderGlsl/CMakeLists.txt index ddab96c318..cb2f3c27c2 100644 --- a/source/MaterialXRenderGlsl/CMakeLists.txt +++ b/source/MaterialXRenderGlsl/CMakeLists.txt @@ -1,3 +1,5 @@ +set(MATERIALX_MODULE_NAME MaterialXRenderGlsl) + file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.c*") file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") @@ -34,12 +36,18 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wno-deprecated-declarations) endif() -add_library(MaterialXRenderGlsl ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_RENDERGLSL_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + if(MATERIALX_BUILD_SHARED_LIBS) - target_compile_definitions(MaterialXRenderGlsl PUBLIC GLAD_GLAPI_EXPORT PRIVATE GLAD_GLAPI_EXPORT_BUILD) + target_compile_definitions(${MATERIALX_MODULE_NAME} PUBLIC GLAD_GLAPI_EXPORT PRIVATE GLAD_GLAPI_EXPORT_BUILD) endif() set(COMMON_LIBRARIES @@ -50,19 +58,19 @@ set(COMMON_LIBRARIES if(WIN32) if(MSVC) target_link_libraries( - MaterialXRenderGlsl + ${MATERIALX_MODULE_NAME} ${COMMON_LIBRARIES} Opengl32) elseif(MINGW) target_link_libraries( - MaterialXRenderGlsl + ${MATERIALX_MODULE_NAME} ${COMMON_LIBRARIES} Opengl32 gdi32) endif() elseif(APPLE) target_link_libraries( - MaterialXRenderGlsl + ${MATERIALX_MODULE_NAME} ${COMMON_LIBRARIES} ${OPENGL_LIBRARIES} "-framework Foundation" @@ -70,7 +78,7 @@ elseif(APPLE) "-framework Metal") elseif(UNIX) target_link_libraries( - MaterialXRenderGlsl + ${MATERIALX_MODULE_NAME} ${COMMON_LIBRARIES} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} @@ -78,30 +86,32 @@ elseif(UNIX) endif() set_target_properties( - MaterialXRenderGlsl PROPERTIES - OUTPUT_NAME MaterialXRenderGlsl${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" VERSION "${MATERIALX_LIBRARY_VERSION}" SOVERSION "${MATERIALX_MAJOR_VERSION}") -target_include_directories(MaterialXRenderGlsl +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXRenderGlsl - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXRenderGlsl/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXRenderGlsl.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index ef7a0ed0c2..ce4582d44f 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -209,7 +209,7 @@ ImagePtr GlslMaterial::bindImage(const FilePath& filePath, const std::string& un imageHandler->setFilenameResolver(resolver); // Acquire the given image. - ImagePtr image = imageHandler->acquireImage(filePath); + ImagePtr image = imageHandler->acquireImage(filePath, samplingProperties.defaultColor); if (!image) { return nullptr; diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index a60997716a..900cac0ef1 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -491,7 +491,7 @@ ImagePtr GlslProgram::bindTexture(unsigned int uniformType, int uniformLocation, uniformType >= GL_SAMPLER_1D && uniformType <= GL_SAMPLER_CUBE) { // Acquire the image. - ImagePtr image = imageHandler->acquireImage(filePath); + ImagePtr image = imageHandler->acquireImage(filePath, samplingProperties.defaultColor); if (imageHandler->bindImage(image, samplingProperties)) { GLTextureHandlerPtr textureHandler = std::static_pointer_cast(imageHandler); diff --git a/source/MaterialXRenderGlsl/GlslRenderer.cpp b/source/MaterialXRenderGlsl/GlslRenderer.cpp index e81ded996e..374305f32f 100644 --- a/source/MaterialXRenderGlsl/GlslRenderer.cpp +++ b/source/MaterialXRenderGlsl/GlslRenderer.cpp @@ -25,7 +25,7 @@ GlslRendererPtr GlslRenderer::create(unsigned int width, unsigned int height, Im } GlslRenderer::GlslRenderer(unsigned int width, unsigned int height, Image::BaseType baseType) : - ShaderRenderer(width, height, baseType), + ShaderRenderer(width, height, baseType, MatrixConvention::OpenGL), _initialized(false), _screenColor(DEFAULT_SCREEN_COLOR_LIN_REC709) { @@ -119,6 +119,16 @@ void GlslRenderer::validateInputs() _program->getAttributesList(); } +void GlslRenderer::updateUniform(const string& name, ConstValuePtr value) +{ + if (!_program->bind()) + { + return; + } + + _program->bindUniform(name, value); +} + void GlslRenderer::setSize(unsigned int width, unsigned int height) { if (_context->makeCurrent()) diff --git a/source/MaterialXRenderGlsl/GlslRenderer.h b/source/MaterialXRenderGlsl/GlslRenderer.h index 8538fe2208..9ea121aec9 100644 --- a/source/MaterialXRenderGlsl/GlslRenderer.h +++ b/source/MaterialXRenderGlsl/GlslRenderer.h @@ -79,6 +79,9 @@ class MX_RENDERGLSL_API GlslRenderer : public ShaderRenderer /// Validate inputs for the program void validateInputs() override; + /// 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; diff --git a/source/MaterialXRenderHw/CMakeLists.txt b/source/MaterialXRenderHw/CMakeLists.txt index 85ef13c55c..dfd262a3ae 100644 --- a/source/MaterialXRenderHw/CMakeLists.txt +++ b/source/MaterialXRenderHw/CMakeLists.txt @@ -1,8 +1,12 @@ +set(MATERIALX_MODULE_NAME MaterialXRenderHw) + 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) find_library(COCOA_FRAMEWORK Cocoa) +endif() file(GLOB materialx_source_oc "${CMAKE_CURRENT_SOURCE_DIR}/*.m") message("Objective C files: " ${materialx_source_oc}) set_source_files_properties(${materialx_source_oc} PROPERTIES @@ -20,26 +24,37 @@ endif() assign_source_group("Source Files" ${materialx_source}) assign_source_group("Header Files" ${materialx_headers}) -add_library(MaterialXRenderHw ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_RENDERHW_EXPORTS) +if(APPLE AND NOT MATERIALX_BUILD_IOS) +set(CMAKE_DL_LIBS +${CMAKE_DL_LIBS} +"-framework Cocoa") +endif() + +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + if(MSVC) target_link_libraries( - MaterialXRenderHw + ${MATERIALX_MODULE_NAME} MaterialXRender ${CMAKE_DL_LIBS}) elseif(APPLE) target_link_libraries( - MaterialXRenderHw + ${MATERIALX_MODULE_NAME} MaterialXRender ${CMAKE_DL_LIBS} "-framework Foundation" - "-framework Cocoa" "-framework Metal") elseif(UNIX) target_link_libraries( - MaterialXRenderHw + ${MATERIALX_MODULE_NAME} MaterialXRender ${CMAKE_DL_LIBS} ${X11_LIBRARIES} @@ -47,30 +62,32 @@ elseif(UNIX) endif() set_target_properties( - MaterialXRenderHw PROPERTIES - OUTPUT_NAME MaterialXRenderHw${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" VERSION "${MATERIALX_LIBRARY_VERSION}" SOVERSION "${MATERIALX_MAJOR_VERSION}") -target_include_directories(MaterialXRenderHw +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXRenderHw - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXRenderHw/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXRenderHw.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXRenderHw/SimpleWindowIOS.cpp b/source/MaterialXRenderHw/SimpleWindowIOS.cpp new file mode 100644 index 0000000000..1d4189b2ab --- /dev/null +++ b/source/MaterialXRenderHw/SimpleWindowIOS.cpp @@ -0,0 +1,40 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#if defined(__APPLE__) + +#ifdef TARGET_OS_IOS + +#include + +MATERIALX_NAMESPACE_BEGIN + +SimpleWindow::SimpleWindow() : + _width(0), + _height(0) +{ + // Give a unique identifier to this window. + static unsigned int windowCount = 1; + _id = windowCount; + windowCount++; +} + +bool SimpleWindow::initialize(const char* title, + unsigned int width, unsigned int height, + void* /*applicationShell*/) +{ + _windowWrapper = WindowWrapper::create(nullptr); + return true; +} + +SimpleWindow::~SimpleWindow() +{ +} + +MATERIALX_NAMESPACE_END + +#endif + +#endif diff --git a/source/MaterialXRenderHw/SimpleWindowMac.cpp b/source/MaterialXRenderHw/SimpleWindowMac.cpp index 1cf070ac74..a04d1f49ae 100644 --- a/source/MaterialXRenderHw/SimpleWindowMac.cpp +++ b/source/MaterialXRenderHw/SimpleWindowMac.cpp @@ -5,6 +5,8 @@ #if defined(__APPLE__) +#ifndef TARGET_OS_IOS + #include #include @@ -42,3 +44,5 @@ SimpleWindow::~SimpleWindow() MATERIALX_NAMESPACE_END #endif + +#endif diff --git a/source/MaterialXRenderHw/WindowCocoaWrappers.m b/source/MaterialXRenderHw/WindowCocoaWrappers.m index c73de77810..a012966a8f 100644 --- a/source/MaterialXRenderHw/WindowCocoaWrappers.m +++ b/source/MaterialXRenderHw/WindowCocoaWrappers.m @@ -5,6 +5,8 @@ #if defined (__APPLE__) +#ifndef TARGET_OS_IOS + #import #import #import @@ -72,3 +74,5 @@ void NSUtilDisposeWindow(void* pWindow) } #endif + +#endif diff --git a/source/MaterialXRenderHw/WindowWrapper.cpp b/source/MaterialXRenderHw/WindowWrapper.cpp index 315960fb2b..654498d5cd 100644 --- a/source/MaterialXRenderHw/WindowWrapper.cpp +++ b/source/MaterialXRenderHw/WindowWrapper.cpp @@ -84,8 +84,12 @@ WindowWrapper::WindowWrapper(ExternalWindowHandle externalHandle, DisplayHandle display) { _externalHandle = externalHandle; +#ifndef TARGET_OS_IOS // Cache a pointer to the window. _internalHandle = NSUtilGetView(externalHandle); +#else + _internalHandle = nullptr; +#endif } WindowWrapper::~WindowWrapper() diff --git a/source/MaterialXRenderMsl/CMakeLists.txt b/source/MaterialXRenderMsl/CMakeLists.txt index 5ad50ea2cc..4d5e286463 100644 --- a/source/MaterialXRenderMsl/CMakeLists.txt +++ b/source/MaterialXRenderMsl/CMakeLists.txt @@ -1,3 +1,5 @@ +set(MATERIALX_MODULE_NAME MaterialXRenderMsl) + file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.m*") file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") @@ -9,8 +11,10 @@ if(POLICY CMP0072) endif() if(APPLE) +if(NOT MATERIALX_BUILD_IOS) find_library(COCOA_FRAMEWORK Cocoa) find_package(OpenGL REQUIRED) +endif() file(GLOB_RECURSE materialx_source_oc "${CMAKE_CURRENT_SOURCE_DIR}/*.m") message("Objective C files: " ${materialx_source_oc}) set_source_files_properties(${materialx_source_oc} PROPERTIES @@ -34,7 +38,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wno-deprecated-declarations) endif() -add_library(MaterialXRenderMsl ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_RENDERMSL_EXPORTS) @@ -42,23 +46,28 @@ set(COMMON_LIBRARIES MaterialXRenderHw MaterialXGenMsl ${CMAKE_DL_LIBS}) + +if(APPLE AND NOT MATERIALX_BUILD_IOS) +set(COMMON_LIBRARIES + ${COMMON_LIBRARIES} + "-framework Cocoa") +endif() if(MSVC) target_link_libraries( - MaterialXRenderMsl + ${MATERIALX_MODULE_NAME} ${COMMON_LIBRARIES} Opengl32) elseif(APPLE) target_link_libraries( - MaterialXRenderMsl + ${MATERIALX_MODULE_NAME} ${COMMON_LIBRARIES} ${OPENGL_LIBRARIES} "-framework Foundation" - "-framework Cocoa" "-framework Metal") elseif(UNIX) target_link_libraries( - MaterialXRenderMsl + ${MATERIALX_MODULE_NAME} ${COMMON_LIBRARIES} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} @@ -66,29 +75,31 @@ elseif(UNIX) endif() set_target_properties( - MaterialXRenderMsl PROPERTIES - OUTPUT_NAME MaterialXRenderMsl${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" VERSION "${MATERIALX_LIBRARY_VERSION}" SOVERSION "${MATERIALX_MAJOR_VERSION}") -target_include_directories(MaterialXRenderMsl +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXRenderMsl - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXRenderMsl/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXRenderMsl.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm index 7e9cd38adc..66fc0462f2 100644 --- a/source/MaterialXRenderMsl/MslMaterial.mm +++ b/source/MaterialXRenderMsl/MslMaterial.mm @@ -199,7 +199,7 @@ imageHandler->setFilenameResolver(resolver); // Acquire the given image. - return imageHandler->acquireImage(filePath); + return imageHandler->acquireImage(filePath, samplingProperties.defaultColor); } void MslMaterial::bindLighting(LightHandlerPtr lightHandler, diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm index 84a615fd61..4f8378ae46 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm @@ -542,7 +542,7 @@ int GetStrideOfMetalType(MTLDataType type) { // Acquire the image. string error; - ImagePtr image = imageHandler->acquireImage(filePath); + ImagePtr image = imageHandler->acquireImage(filePath, samplingProperties.defaultColor); imageHandler->bindImage(image, samplingProperties); return bindTexture(renderCmdEncoder, uniformLocation, image, imageHandler); } diff --git a/source/MaterialXRenderMsl/MslRenderer.h b/source/MaterialXRenderMsl/MslRenderer.h index bf968078fe..ca87d9dd3e 100644 --- a/source/MaterialXRenderMsl/MslRenderer.h +++ b/source/MaterialXRenderMsl/MslRenderer.h @@ -82,6 +82,9 @@ class MX_RENDERMSL_API MslRenderer : public ShaderRenderer /// Validate inputs for the program void validateInputs() override; + /// 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; @@ -126,9 +129,6 @@ class MX_RENDERMSL_API MslRenderer : public ShaderRenderer protected: MslRenderer(unsigned int width, unsigned int height, Image::BaseType baseType); - - virtual void updateViewInformation(); - virtual void updateWorldInformation(); void triggerProgrammaticCapture(); void stopProgrammaticCapture(); @@ -146,11 +146,6 @@ class MX_RENDERMSL_API MslRenderer : public ShaderRenderer bool _initialized; - const Vector3 _eye; - const Vector3 _center; - const Vector3 _up; - float _objectScale; - SimpleWindowPtr _window; Color3 _screenColor; }; diff --git a/source/MaterialXRenderMsl/MslRenderer.mm b/source/MaterialXRenderMsl/MslRenderer.mm index f6de188b2f..f5e794c2b3 100644 --- a/source/MaterialXRenderMsl/MslRenderer.mm +++ b/source/MaterialXRenderMsl/MslRenderer.mm @@ -14,13 +14,6 @@ MATERIALX_NAMESPACE_BEGIN -const float PI = std::acos(-1.0f); - -// View information -const float FOV_PERSP = 45.0f; // degrees -const float NEAR_PLANE_PERSP = 0.05f; -const float FAR_PLANE_PERSP = 100.0f; - // // MslRenderer methods // @@ -36,20 +29,14 @@ } MslRenderer::MslRenderer(unsigned int width, unsigned int height, Image::BaseType baseType) : - ShaderRenderer(width, height, baseType), + ShaderRenderer(width, height, baseType, MatrixConvention::Metal), _initialized(false), - _eye(0.0f, 0.0f, 3.0f), - _center(0.0f, 0.0f, 0.0f), - _up(0.0f, 1.0f, 0.0f), - _objectScale(1.0f), _screenColor(DEFAULT_SCREEN_COLOR_LIN_REC709) { _program = MslProgram::create(); _geometryHandler = GeometryHandler::create(); _geometryHandler->addLoader(TinyObjLoader::create()); - - _camera = Camera::create(); } void MslRenderer::initialize(RenderContextHandle) @@ -137,6 +124,11 @@ _program->getAttributesList(); } +void MslRenderer::updateUniform(const string& name, ConstValuePtr value) +{ + _program->bindUniform(name, value); +} + void MslRenderer::createFrameBuffer(bool encodeSrgb) { _framebuffer = MetalFramebuffer::create(_device, @@ -160,20 +152,6 @@ } -void MslRenderer::updateViewInformation() -{ - float fH = std::tan(FOV_PERSP / 360.0f * PI) * NEAR_PLANE_PERSP; - float fW = fH * 1.0f; - - _camera->setViewMatrix(Camera::createViewMatrix(_eye, _center, _up)); - _camera->setProjectionMatrix(Camera::createPerspectiveMatrixZP(-fW, fW, -fH, fH, NEAR_PLANE_PERSP, FAR_PLANE_PERSP)); -} - -void MslRenderer::updateWorldInformation() -{ - _camera->setWorldMatrix(Matrix44::createScale(Vector3(_objectScale))); -} - void MslRenderer::triggerProgrammaticCapture() { MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager]; @@ -217,9 +195,6 @@ [renderCmdEncoder setCullMode:MTLCullModeBack]; - - updateViewInformation(); - updateWorldInformation(); try { diff --git a/source/MaterialXRenderOsl/CMakeLists.txt b/source/MaterialXRenderOsl/CMakeLists.txt index a4ffa81235..ac1de93d2e 100644 --- a/source/MaterialXRenderOsl/CMakeLists.txt +++ b/source/MaterialXRenderOsl/CMakeLists.txt @@ -1,16 +1,24 @@ +set(MATERIALX_MODULE_NAME MaterialXRenderOsl) + file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") assign_source_group("Source Files" ${materialx_source}) assign_source_group("Header Files" ${materialx_headers}) -add_library(MaterialXRenderOsl ${materialx_source} ${materialx_headers}) +add_library(${MATERIALX_MODULE_NAME} ${materialx_source} ${materialx_headers}) add_definitions(-DMATERIALX_RENDEROSL_EXPORTS) +# 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) + target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + set_target_properties( - MaterialXRenderOsl PROPERTIES - OUTPUT_NAME MaterialXRenderOsl${MATERIALX_LIBNAME_SUFFIX} + ${MATERIALX_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}" @@ -18,26 +26,28 @@ set_target_properties( SOVERSION "${MATERIALX_MAJOR_VERSION}") target_link_libraries( - MaterialXRenderOsl + ${MATERIALX_MODULE_NAME} MaterialXRender ${CMAKE_DL_LIBS}) -target_include_directories(MaterialXRenderOsl +target_include_directories(${MATERIALX_MODULE_NAME} PUBLIC $ $ PRIVATE ${EXTERNAL_INCLUDE_DIRS}) -install(TARGETS MaterialXRenderOsl - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) +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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/MaterialXRenderOsl/ MESSAGE_NEVER - FILES_MATCHING PATTERN "*.h*") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER + FILES_MATCHING PATTERN "*.h*") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/MaterialXRenderOsl.pdb" - DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" + DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) +endif() diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp index 2477d9f486..655ec5b7fb 100644 --- a/source/MaterialXTest/MaterialXCore/Node.cpp +++ b/source/MaterialXTest/MaterialXCore/Node.cpp @@ -136,6 +136,24 @@ TEST_CASE("Node", "[node]") REQUIRE(doc->getOutputs().empty()); } +TEST_CASE("Node inputCount repro", "[node]") +{ + // Create a document. + mx::DocumentPtr doc = mx::createDocument(); + mx::NodePtr constant = doc->addNode("constant"); + constant->setInputValue("value", 0.5f); + + // Check that input count is correct after clearContent + constant->clearContent(); + CHECK(constant->getInputCount() == 0); + + // Check that validate succeeds after clear and rebuild + constant->setType("float"); + mx::OutputPtr output = doc->addOutput(mx::EMPTY_STRING, "float"); + output->setConnectedNode(constant); + CHECK(doc->validate()); +} + TEST_CASE("Flatten", "[nodegraph]") { // Read an example containing graph-based custom nodes. diff --git a/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm b/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm index f33e793690..248d458542 100644 --- a/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm +++ b/source/MaterialXTest/MaterialXRenderMsl/RenderMsl.mm @@ -78,7 +78,7 @@ void runBake(mx::DocumentPtr doc, const mx::FileSearchPath& imageSearchPath, con void MslShaderRenderTester::loadAdditionalLibraries(mx::DocumentPtr document, GenShaderUtil::TestSuiteOptions& options) { - mx::FilePath lightDir = mx::FilePath::getCurrentPath() / mx::FilePath("resources/Materials/TestSuite/lights"); + mx::FilePath lightDir = mx::getDefaultDataSearchPath().find("resources/Materials/TestSuite/lights"); for (const auto& lightFile : options.lightFiles) { loadLibrary(lightDir / mx::FilePath(lightFile), document); @@ -135,6 +135,7 @@ void runBake(mx::DocumentPtr doc, const mx::FileSearchPath& imageSearchPath, con mx::StbImageLoaderPtr stbLoader = mx::StbImageLoader::create(); mx::ImageHandlerPtr imageHandler = _renderer->createImageHandler(stbLoader); + imageHandler->setSearchPath(mx::getDefaultDataSearchPath()); #if defined(MATERIALX_BUILD_OIIO) mx::OiioImageLoaderPtr oiioLoader = mx::OiioImageLoader::create(); imageHandler->addLoader(oiioLoader); @@ -179,6 +180,7 @@ void runBake(mx::DocumentPtr doc, const mx::FileSearchPath& imageSearchPath, con std::cout << "Validating MSL rendering for: " << doc->getSourceUri() << std::endl; mx::ScopedTimer totalMSLTime(&profileTimes.languageTimes.totalTime); + mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); const mx::ShaderGenerator& shadergen = context.getShaderGenerator(); @@ -277,7 +279,7 @@ void runBake(mx::DocumentPtr doc, const mx::FileSearchPath& imageSearchPath, con { if (!testOptions.renderGeometry.isAbsolute()) { - geomPath = mx::FilePath::getCurrentPath() / mx::FilePath("resources/Geometry") / testOptions.renderGeometry; + geomPath = searchPath.find("resources/Geometry") / testOptions.renderGeometry; } else { @@ -286,7 +288,7 @@ void runBake(mx::DocumentPtr doc, const mx::FileSearchPath& imageSearchPath, con } else { - geomPath = mx::FilePath::getCurrentPath() / mx::FilePath("resources/Geometry/sphere.obj"); + geomPath = searchPath.find("resources/Geometry/sphere.obj"); } if (!geomHandler->hasGeometry(geomPath)) @@ -373,7 +375,7 @@ void runBake(mx::DocumentPtr doc, const mx::FileSearchPath& imageSearchPath, con { { mx::ScopedTimer renderTimer(&profileTimes.languageTimes.renderTime); - _renderer->getImageHandler()->setSearchPath(imageSearchPath); + _renderer->getImageHandler()->setSearchPath(mx::getDefaultDataSearchPath()); _renderer->setSize(static_cast(testOptions.renderSize[0]), static_cast(testOptions.renderSize[1])); _renderer->render(); } @@ -456,18 +458,10 @@ void runBake(mx::DocumentPtr doc, const mx::FileSearchPath& imageSearchPath, con TEST_CASE("Render: MSL TestSuite", "[rendermsl]") { - MslShaderRenderTester renderTester(mx::MslShaderGenerator::create()); - - const mx::FilePath testRootPath = mx::FilePath::getCurrentPath() / mx::FilePath("resources/Materials/TestSuite"); - const mx::FilePath testRootPath2 = mx::FilePath::getCurrentPath() / mx::FilePath("resources/Materials/Examples/StandardSurface"); - const mx::FilePath testRootPath3 = mx::FilePath::getCurrentPath() / mx::FilePath("resources/Materials/Examples/UsdPreviewSurface"); - mx::FilePathVec testRootPaths; - testRootPaths.push_back(testRootPath); - testRootPaths.push_back(testRootPath2); - testRootPaths.push_back(testRootPath3); - - mx::FilePath optionsFilePath = testRootPath / mx::FilePath("_options.mtlx"); + mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); + mx::FilePath optionsFilePath = searchPath.find("resources/Materials/TestSuite/_options.mtlx"); + MslShaderRenderTester renderTester(mx::MslShaderGenerator::create()); renderTester.validate(optionsFilePath); } diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index ecbb4352fc..6346658d07 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -474,7 +474,7 @@ void Viewer::loadEnvironmentLight() } // Look for an irradiance map using an expected filename convention. - mx::ImagePtr envIrradianceMap = _imageHandler->getInvalidImage(); + mx::ImagePtr envIrradianceMap = _imageHandler->getZeroImage(); if (!_normalizeEnvironment && !_splitDirectLight) { mx::FilePath envIrradiancePath = _envRadianceFilename.getParentPath() / IRRADIANCE_MAP_FOLDER / _envRadianceFilename.getBaseName(); @@ -482,7 +482,7 @@ void Viewer::loadEnvironmentLight() } // If not found, then generate an irradiance map via spherical harmonics. - if (envIrradianceMap == _imageHandler->getInvalidImage()) + if (envIrradianceMap == _imageHandler->getZeroImage()) { if (_generateReferenceIrradiance) { diff --git a/source/PyMaterialX/PyMaterialXCore/CMakeLists.txt b/source/PyMaterialX/PyMaterialXCore/CMakeLists.txt index dfc2aefac0..9f3d2291c0 100644 --- a/source/PyMaterialX/PyMaterialXCore/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXCore/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -24,4 +22,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXCore - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXCore/PyInterface.cpp b/source/PyMaterialX/PyMaterialXCore/PyInterface.cpp index 2a4645d3b6..2e9b264381 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyInterface.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyInterface.cpp @@ -93,6 +93,7 @@ void bindPyInterface(py::module& mod) .def("getDefaultVersion", &mx::InterfaceElement::getDefaultVersion) .def("getDeclaration", &mx::InterfaceElement::getDeclaration, py::arg("target") = mx::EMPTY_STRING) + .def("clearContent", &mx::InterfaceElement::clearContent) .def("hasExactInputMatch", &mx::InterfaceElement::hasExactInputMatch, py::arg("declaration"), py::arg("message") = nullptr) BIND_INTERFACE_TYPE_INSTANCE(integer, int) diff --git a/source/PyMaterialX/PyMaterialXCore/PyNode.cpp b/source/PyMaterialX/PyMaterialXCore/PyNode.cpp index 704cda7589..55448dee80 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyNode.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyNode.cpp @@ -59,6 +59,7 @@ void bindPyNode(py::module& mod) .def("addInterfaceName", &mx::NodeGraph::addInterfaceName) .def("removeInterfaceName", &mx::NodeGraph::removeInterfaceName) .def("modifyInterfaceName", &mx::NodeGraph::modifyInterfaceName) + .def("getDownstreamPorts", &mx::NodeGraph::getDownstreamPorts) .def_readonly_static("CATEGORY", &mx::NodeGraph::CATEGORY); py::class_(mod, "Backdrop") diff --git a/source/PyMaterialX/PyMaterialXFormat/CMakeLists.txt b/source/PyMaterialX/PyMaterialXFormat/CMakeLists.txt index 9566e792fd..095b3eb087 100644 --- a/source/PyMaterialX/PyMaterialXFormat/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXFormat/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -25,4 +23,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXFormat - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXGenGlsl/CMakeLists.txt b/source/PyMaterialX/PyMaterialXGenGlsl/CMakeLists.txt index b65ef857a4..24266712fd 100644 --- a/source/PyMaterialX/PyMaterialXGenGlsl/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXGenGlsl/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -25,4 +23,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXGenGlsl - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXGenMdl/CMakeLists.txt b/source/PyMaterialX/PyMaterialXGenMdl/CMakeLists.txt index a1bc225a4f..328a2439ed 100644 --- a/source/PyMaterialX/PyMaterialXGenMdl/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXGenMdl/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -24,4 +22,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXGenMdl - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXGenMsl/CMakeLists.txt b/source/PyMaterialX/PyMaterialXGenMsl/CMakeLists.txt index 88e21687bc..33dec7319a 100644 --- a/source/PyMaterialX/PyMaterialXGenMsl/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXGenMsl/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -25,4 +23,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXGenMsl - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXGenOsl/CMakeLists.txt b/source/PyMaterialX/PyMaterialXGenOsl/CMakeLists.txt index 5d30769b4d..65b0dabe67 100644 --- a/source/PyMaterialX/PyMaterialXGenOsl/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXGenOsl/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -25,4 +23,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXGenOsl - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXGenShader/CMakeLists.txt b/source/PyMaterialX/PyMaterialXGenShader/CMakeLists.txt index 13c01b3351..5bee142c24 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXGenShader/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -26,4 +24,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXGenShader - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXRender/CMakeLists.txt b/source/PyMaterialX/PyMaterialXRender/CMakeLists.txt index a050cb6aa3..2617a0b392 100644 --- a/source/PyMaterialX/PyMaterialXRender/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXRender/CMakeLists.txt @@ -17,8 +17,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -28,4 +26,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXRender - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXRender/PyImageHandler.cpp b/source/PyMaterialX/PyMaterialXRender/PyImageHandler.cpp index 7ece49d60b..d261bc7306 100644 --- a/source/PyMaterialX/PyMaterialXRender/PyImageHandler.cpp +++ b/source/PyMaterialX/PyMaterialXRender/PyImageHandler.cpp @@ -41,7 +41,8 @@ void bindPyImageHandler(py::module& mod) .def("addLoader", &mx::ImageHandler::addLoader) .def("saveImage", &mx::ImageHandler::saveImage, py::arg("filePath"), py::arg("image"), py::arg("verticalFlip") = false) - .def("acquireImage", &mx::ImageHandler::acquireImage) + .def("acquireImage", &mx::ImageHandler::acquireImage, + py::arg("filePath"), py::arg("defaultColor") = mx::Color4(0.0f)) .def("bindImage", &mx::ImageHandler::bindImage) .def("unbindImage", &mx::ImageHandler::unbindImage) .def("unbindImages", &mx::ImageHandler::unbindImages) @@ -54,6 +55,5 @@ void bindPyImageHandler(py::module& mod) py::arg("image") = nullptr) .def("clearImageCache", &mx::ImageHandler::clearImageCache) .def("getZeroImage", &mx::ImageHandler::getZeroImage) - .def("getInvalidImage", &mx::ImageHandler::getInvalidImage) .def("getReferencedImages", &mx::ImageHandler::getReferencedImages); } diff --git a/source/PyMaterialX/PyMaterialXRender/PyShaderRenderer.cpp b/source/PyMaterialX/PyMaterialXRender/PyShaderRenderer.cpp index c67238dea5..94c0d49cee 100644 --- a/source/PyMaterialX/PyMaterialXRender/PyShaderRenderer.cpp +++ b/source/PyMaterialX/PyMaterialXRender/PyShaderRenderer.cpp @@ -25,6 +25,7 @@ void bindPyShaderRenderer(py::module& mod) .def("createProgram", static_cast(&mx::ShaderRenderer::createProgram)) .def("createProgram", static_cast(&mx::ShaderRenderer::createProgram)) .def("validateInputs", &mx::ShaderRenderer::validateInputs) + .def("updateUniform", &mx::ShaderRenderer::updateUniform) .def("setSize", &mx::ShaderRenderer::setSize) .def("render", &mx::ShaderRenderer::render); diff --git a/source/PyMaterialX/PyMaterialXRenderGlsl/CMakeLists.txt b/source/PyMaterialX/PyMaterialXRenderGlsl/CMakeLists.txt index a29cdc5c1e..a0b04ddbda 100644 --- a/source/PyMaterialX/PyMaterialXRenderGlsl/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXRenderGlsl/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -27,4 +25,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXRenderGlsl - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXRenderMsl/CMakeLists.txt b/source/PyMaterialX/PyMaterialXRenderMsl/CMakeLists.txt index ec562fe8cf..04c6d95e3c 100644 --- a/source/PyMaterialX/PyMaterialXRenderMsl/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXRenderMsl/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -27,4 +25,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXRenderMsl - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") diff --git a/source/PyMaterialX/PyMaterialXRenderOsl/CMakeLists.txt b/source/PyMaterialX/PyMaterialXRenderOsl/CMakeLists.txt index 4777b13e7b..c0b83948a9 100644 --- a/source/PyMaterialX/PyMaterialXRenderOsl/CMakeLists.txt +++ b/source/PyMaterialX/PyMaterialXRenderOsl/CMakeLists.txt @@ -14,8 +14,6 @@ set_target_properties( COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}" - VERSION "${MATERIALX_LIBRARY_VERSION}" - SOVERSION "${MATERIALX_MAJOR_VERSION}" DEBUG_POSTFIX "${MATERIALX_PYTHON_DEBUG_POSTFIX}") target_link_libraries( @@ -25,4 +23,4 @@ target_link_libraries( PRIVATE ${CMAKE_DL_LIBS}) install(TARGETS PyMaterialXRenderOsl - DESTINATION "python/MaterialX") + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}") From 03d2bc22361c482d6bcb3107c2698b8778eefad2 Mon Sep 17 00:00:00 2001 From: ld-kerley <154285602+ld-kerley@users.noreply.github.com> Date: Tue, 23 Jan 2024 11:37:23 -0800 Subject: [PATCH 04/20] Rename atan2 inputs in 1.39 (#1659) Renaming the input ports to align correctly with the spec: * `in1` -> `iny` * `in2` -> `inx` Add upgrade code to migrate port names found in documents. --- .../Specification/MaterialX.Specification.md | 2 +- .../stdlib/genglsl/stdlib_genglsl_impl.mtlx | 8 +++---- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 8 +++---- .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 8 +++---- .../stdlib/genosl/stdlib_genosl_impl.mtlx | 8 +++---- libraries/stdlib/stdlib_defs.mtlx | 16 ++++++------- python/Scripts/genmdl.py | 10 ++++---- resources/Lights/envmap_shader.mtlx | 4 ++-- .../Materials/TestSuite/stdlib/math/trig.mtlx | 16 ++++++------- source/MaterialXCore/Document.cpp | 24 +++++++++++++++++++ .../MaterialXGenMdl/mdl/materialx/stdlib.mdl | 24 +++++++++---------- 11 files changed, 76 insertions(+), 52 deletions(-) diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 4b99956fb4..0ef9146c5d 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -1148,7 +1148,7 @@ Math nodes have one or two spatially-varying inputs, and are used to perform a m -* **`atan2`**: the arctangent of the expression (iny/inx); the output will be expressed in radians. If both `in1` and `in2` are provided, they must be the same type. +* **`atan2`**: the arctangent of the expression (iny/inx); the output will be expressed in radians. If both `iny` and `inx` are provided, they must be the same type. * `iny` (float or vectorN): the value or nodename for the "y" input; default is 0.0. * `inx` (float or vectorN): the value or nodename for the "x" input; default is 1.0. diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index 90d3120bd7..912d6d9f37 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -340,25 +340,25 @@ - + - + - + - + diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index ab0d776936..34d6e9aae3 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -343,28 +343,28 @@ - + - + - + - + diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index fcab8fd69d..5c61f9a979 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -341,25 +341,25 @@ - + - + - + - + diff --git a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx index 1ba22ef6a3..0c1235e4fc 100644 --- a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -343,25 +343,25 @@ - + - + - + - + diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index bb5e8edd1f..96a4f3b776 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -1999,8 +1999,8 @@ - - + + @@ -2024,8 +2024,8 @@ - - + + @@ -2049,8 +2049,8 @@ - - + + @@ -2074,8 +2074,8 @@ - - + + diff --git a/python/Scripts/genmdl.py b/python/Scripts/genmdl.py index f42add0425..ac46e7af6c 100644 --- a/python/Scripts/genmdl.py +++ b/python/Scripts/genmdl.py @@ -165,13 +165,13 @@ def _writeOperatorFunc(file, outputType, arg1, functionName, arg2): else: file.write(INDENT + 'return ' + arg1 + ' ' + functionName + ' ' + arg2 + ';\n') -def _writeTwoArgumentFunc(file, outputType, functionName): +def _writeTwoArgumentFunc(file, outputType, functionName, arg1="mxp_in1", arg2="mxp_in2"): if outputType == 'color4': - file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(mxp_in1), mk_float4(mxp_in2)));\n') + file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(' + arg1 + '), mk_float4(' + arg2 + ')));\n') elif outputType == 'color': - file.write(INDENT + 'return color(' + functionName + '(float3(mxp_in1), float3(mxp_in2)));\n') + file.write(INDENT + 'return color(' + functionName + '(float3(' + arg1 + '), float3(' + arg2 + ')));\n') else: - file.write(INDENT + 'return ' + functionName + '(mxp_in1, mxp_in2);\n') + file.write(INDENT + 'return ' + functionName + '(' + arg1 + ', ' + arg2 + ');\n') def _writeThreeArgumentFunc(file, outputType, functionName, arg1, arg2, arg3): if outputType == 'color4': @@ -661,7 +661,7 @@ def main(): _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) wroteImplementation = True elif nodeCategory == 'atan2': - _writeTwoArgumentFunc(file, outputType, '::math::'+nodeCategory) + _writeTwoArgumentFunc(file, outputType, '::math::'+nodeCategory, arg1=mxp_iny, arg2=mxp_inx) wroteImplementation = True elif nodeCategory == 'sqrt': _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) diff --git a/resources/Lights/envmap_shader.mtlx b/resources/Lights/envmap_shader.mtlx index 8c9c6ec0f5..235b1a2ab9 100644 --- a/resources/Lights/envmap_shader.mtlx +++ b/resources/Lights/envmap_shader.mtlx @@ -15,8 +15,8 @@ - - + + diff --git a/resources/Materials/TestSuite/stdlib/math/trig.mtlx b/resources/Materials/TestSuite/stdlib/math/trig.mtlx index 7e0702796f..5c52983757 100644 --- a/resources/Materials/TestSuite/stdlib/math/trig.mtlx +++ b/resources/Materials/TestSuite/stdlib/math/trig.mtlx @@ -188,29 +188,29 @@ - - + + - - + + - - + + - - + + diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 9fe55537ac..f19f0fcb61 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -1419,6 +1419,30 @@ void Document::upgradeVersion() removeNode(top->getName()); } } + + NodePtr node = elem->asA(); + if (!node) + { + continue; + } + const string& nodeCategory = node->getCategory(); + if (nodeCategory == "atan2") + { + // rename input ports + // "in1" -> "iny" + // "in2" -> "inx" + + auto input1 = node->getInput("in1"); + if (input1) + { + input1->setName("iny"); + } + auto input2 = node->getInput("in2"); + if (input2) + { + input2->setName("inx"); + } + } } removeNodeDef("ND_thin_film_bsdf"); diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl index bce4a44ea5..b83417521f 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl @@ -1513,14 +1513,14 @@ export float mx_acos_float( } export float mx_atan2_float( - float mxp_in1 = float(1.0), - float mxp_in2 = float(0.0) + float mxp_iny = float(1.0), + float mxp_inx = float(0.0) ) [[ anno::description("Node Group: math") ]] { - return ::math::atan2(mxp_in1, mxp_in2); + return ::math::atan2(mxp_iny, mxp_inx); } export float2 mx_sin_vector2( @@ -1574,14 +1574,14 @@ export float2 mx_acos_vector2( } export float2 mx_atan2_vector2( - float2 mxp_in1 = float2(1.0, 1.0), - float2 mxp_in2 = float2(0.0, 0.0) + float2 mxp_iny = float2(1.0, 1.0), + float2 mxp_inx = float2(0.0, 0.0) ) [[ anno::description("Node Group: math") ]] { - return ::math::atan2(mxp_in1, mxp_in2); + return ::math::atan2(mxp_iny, mxp_inx); } export float3 mx_sin_vector3( @@ -1635,14 +1635,14 @@ export float3 mx_acos_vector3( } export float3 mx_atan2_vector3( - float3 mxp_in1 = float3(1.0, 1.0, 1.0), - float3 mxp_in2 = float3(0.0, 0.0, 0.0) + float3 mxp_iny = float3(1.0, 1.0, 1.0), + float3 mxp_inx = float3(0.0, 0.0, 0.0) ) [[ anno::description("Node Group: math") ]] { - return ::math::atan2(mxp_in1, mxp_in2); + return ::math::atan2(mxp_iny, mxp_inx); } export float4 mx_sin_vector4( @@ -1696,14 +1696,14 @@ export float4 mx_acos_vector4( } export float4 mx_atan2_vector4( - float4 mxp_in1 = float4(1.0, 1.0, 1.0, 1.0), - float4 mxp_in2 = float4(0.0, 0.0, 0.0, 0.0) + float4 mxp_iny = float4(1.0, 1.0, 1.0, 1.0), + float4 mxp_inx = float4(0.0, 0.0, 0.0, 0.0) ) [[ anno::description("Node Group: math") ]] { - return ::math::atan2(mxp_in1, mxp_in2); + return ::math::atan2(mxp_iny, mxp_inx); } export float mx_sqrt_float( From f4c84a6a86bed48cefc341ebe0ea9680ef237111 Mon Sep 17 00:00:00 2001 From: ld-kerley <154285602+ld-kerley@users.noreply.github.com> Date: Sun, 28 Jan 2024 12:12:30 -0800 Subject: [PATCH 05/20] Upgrade switch node to ten inputs in 1.39 (#1660) Also added an upgrade function, which may need some closer attention. The upgrade function attempts to retain the behavior from 1.38 where any value of which that is above the accepted range that would previously been served the default (in1) value. A which value of 6 would have previously return in1, but now it would return one of the newly added inputs. To retain the previous renderer image, the document upgrader sets the value of which to the default of 0. --- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 24 ++-- libraries/stdlib/stdlib_defs.mtlx | 60 +++++++++ source/MaterialXCore/Document.cpp | 22 ++++ .../MaterialXGenMdl/mdl/materialx/stdlib.mdl | 120 ++++++++++++++++++ .../MaterialXGenShader/Nodes/SwitchNode.cpp | 6 +- 5 files changed, 217 insertions(+), 15 deletions(-) diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index 1157fa2e3c..5d1fce0813 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -639,19 +639,19 @@ - - - - - - + + + + + + - - - - - - + + + + + + diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index cfe3e80b3f..0f8ff43177 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -3902,6 +3902,11 @@ + + + + + @@ -3911,6 +3916,11 @@ + + + + + @@ -3920,6 +3930,11 @@ + + + + + @@ -3929,6 +3944,11 @@ + + + + + @@ -3938,6 +3958,11 @@ + + + + + @@ -3947,6 +3972,11 @@ + + + + + @@ -3956,6 +3986,11 @@ + + + + + @@ -3965,6 +4000,11 @@ + + + + + @@ -3974,6 +4014,11 @@ + + + + + @@ -3983,6 +4028,11 @@ + + + + + @@ -3992,6 +4042,11 @@ + + + + + @@ -4001,6 +4056,11 @@ + + + + + diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index f19f0fcb61..565f391da3 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -1443,6 +1443,28 @@ void Document::upgradeVersion() input2->setName("inx"); } } + else if (nodeCategory == "switch") + { + // previously we only had 5 inputs, and any value of "which" outside of the valid range of inputs would default to the + // first input. To retain backwards image compatibility we need to revert any value of "which" that is now a valid value + // ie 6,7,8,9,10, to the value of the default, ie. 1. + // NOTE : this won't catch the case if there is something connected upstream in to the 'which' port. Open to suggestions + // on how to handle this. + + auto which = node->getInput("which"); + if (which && which->hasValue()) + { + auto whichValue = which->getValue(); + if (whichValue->isA() && whichValue->asA() >= 5) + { + which->setValue(0); + } + else if (whichValue->isA() && whichValue->asA() >= 5) + { + which->setValue(0.0); + } + } + } } removeNodeDef("ND_thin_film_bsdf"); diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl index 53f9fddbd4..edc1aa17cb 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl @@ -3607,6 +3607,11 @@ export float mx_switch_float( float mxp_in3 = float(0.0), float mxp_in4 = float(0.0), float mxp_in5 = float(0.0), + float mxp_in6 = float(0.0), + float mxp_in7 = float(0.0), + float mxp_in8 = float(0.0), + float mxp_in9 = float(0.0), + float mxp_in10 = float(0.0), float mxp_which = float(0.0) ) [[ @@ -3620,6 +3625,11 @@ export float mx_switch_float( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3631,6 +3641,11 @@ export color mx_switch_color3( color mxp_in3 = color(0.0, 0.0, 0.0), color mxp_in4 = color(0.0, 0.0, 0.0), color mxp_in5 = color(0.0, 0.0, 0.0), + color mxp_in6 = color(0.0, 0.0, 0.0), + color mxp_in7 = color(0.0, 0.0, 0.0), + color mxp_in8 = color(0.0, 0.0, 0.0), + color mxp_in9 = color(0.0, 0.0, 0.0), + color mxp_in10 = color(0.0, 0.0, 0.0), float mxp_which = float(0.0) ) [[ @@ -3644,6 +3659,11 @@ export color mx_switch_color3( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3655,6 +3675,11 @@ export color4 mx_switch_color4( color4 mxp_in3 = mk_color4(0.0, 0.0, 0.0, 0.0), color4 mxp_in4 = mk_color4(0.0, 0.0, 0.0, 0.0), color4 mxp_in5 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in6 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in7 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in8 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in9 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in10 = mk_color4(0.0, 0.0, 0.0, 0.0), float mxp_which = float(0.0) ) [[ @@ -3668,6 +3693,11 @@ export color4 mx_switch_color4( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3679,6 +3709,11 @@ export float2 mx_switch_vector2( float2 mxp_in3 = float2(0.0, 0.0), float2 mxp_in4 = float2(0.0, 0.0), float2 mxp_in5 = float2(0.0, 0.0), + float2 mxp_in6 = float2(0.0, 0.0), + float2 mxp_in7 = float2(0.0, 0.0), + float2 mxp_in8 = float2(0.0, 0.0), + float2 mxp_in9 = float2(0.0, 0.0), + float2 mxp_in10 = float2(0.0, 0.0), float mxp_which = float(0.0) ) [[ @@ -3692,6 +3727,11 @@ export float2 mx_switch_vector2( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3703,6 +3743,11 @@ export float3 mx_switch_vector3( float3 mxp_in3 = float3(0.0, 0.0, 0.0), float3 mxp_in4 = float3(0.0, 0.0, 0.0), float3 mxp_in5 = float3(0.0, 0.0, 0.0), + float3 mxp_in6 = float3(0.0, 0.0, 0.0), + float3 mxp_in7 = float3(0.0, 0.0, 0.0), + float3 mxp_in8 = float3(0.0, 0.0, 0.0), + float3 mxp_in9 = float3(0.0, 0.0, 0.0), + float3 mxp_in10 = float3(0.0, 0.0, 0.0), float mxp_which = float(0.0) ) [[ @@ -3716,6 +3761,11 @@ export float3 mx_switch_vector3( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3727,6 +3777,11 @@ export float4 mx_switch_vector4( float4 mxp_in3 = float4(0.0, 0.0, 0.0, 0.0), float4 mxp_in4 = float4(0.0, 0.0, 0.0, 0.0), float4 mxp_in5 = float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in6 = float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in7 = float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in8 = float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in9 = float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in10 = float4(0.0, 0.0, 0.0, 0.0), float mxp_which = float(0.0) ) [[ @@ -3740,6 +3795,11 @@ export float4 mx_switch_vector4( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3751,6 +3811,11 @@ export float mx_switch_floatI( float mxp_in3 = float(0.0), float mxp_in4 = float(0.0), float mxp_in5 = float(0.0), + float mxp_in6 = float(0.0), + float mxp_in7 = float(0.0), + float mxp_in8 = float(0.0), + float mxp_in9 = float(0.0), + float mxp_in10 = float(0.0), int mxp_which = int(0) ) [[ @@ -3764,6 +3829,11 @@ export float mx_switch_floatI( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3775,6 +3845,11 @@ export color mx_switch_color3I( color mxp_in3 = color(0.0, 0.0, 0.0), color mxp_in4 = color(0.0, 0.0, 0.0), color mxp_in5 = color(0.0, 0.0, 0.0), + color mxp_in6 = color(0.0, 0.0, 0.0), + color mxp_in7 = color(0.0, 0.0, 0.0), + color mxp_in8 = color(0.0, 0.0, 0.0), + color mxp_in9 = color(0.0, 0.0, 0.0), + color mxp_in10 = color(0.0, 0.0, 0.0), int mxp_which = int(0) ) [[ @@ -3788,6 +3863,11 @@ export color mx_switch_color3I( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3799,6 +3879,11 @@ export color4 mx_switch_color4I( color4 mxp_in3 = mk_color4(0.0, 0.0, 0.0, 0.0), color4 mxp_in4 = mk_color4(0.0, 0.0, 0.0, 0.0), color4 mxp_in5 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in6 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in7 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in8 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in9 = mk_color4(0.0, 0.0, 0.0, 0.0), + color4 mxp_in10 = mk_color4(0.0, 0.0, 0.0, 0.0), int mxp_which = int(0) ) [[ @@ -3812,6 +3897,11 @@ export color4 mx_switch_color4I( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3823,6 +3913,11 @@ export float2 mx_switch_vector2I( float2 mxp_in3 = float2(0.0, 0.0), float2 mxp_in4 = float2(0.0, 0.0), float2 mxp_in5 = float2(0.0, 0.0), + float2 mxp_in6 = float2(0.0, 0.0), + float2 mxp_in7 = float2(0.0, 0.0), + float2 mxp_in8 = float2(0.0, 0.0), + float2 mxp_in9 = float2(0.0, 0.0), + float2 mxp_in10 = float2(0.0, 0.0), int mxp_which = int(0) ) [[ @@ -3836,6 +3931,11 @@ export float2 mx_switch_vector2I( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3847,6 +3947,11 @@ export float3 mx_switch_vector3I( float3 mxp_in3 = float3(0.0, 0.0, 0.0), float3 mxp_in4 = float3(0.0, 0.0, 0.0), float3 mxp_in5 = float3(0.0, 0.0, 0.0), + float3 mxp_in6 = float3(0.0, 0.0, 0.0), + float3 mxp_in7 = float3(0.0, 0.0, 0.0), + float3 mxp_in8 = float3(0.0, 0.0, 0.0), + float3 mxp_in9 = float3(0.0, 0.0, 0.0), + float3 mxp_in10 = float3(0.0, 0.0, 0.0), int mxp_which = int(0) ) [[ @@ -3860,6 +3965,11 @@ export float3 mx_switch_vector3I( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; @@ -3871,6 +3981,11 @@ export float4 mx_switch_vector4I( float4 mxp_in3 = float4(0.0, 0.0, 0.0, 0.0), float4 mxp_in4 = float4(0.0, 0.0, 0.0, 0.0), float4 mxp_in5 = float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in6= float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in7 = float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in8 = float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in9 = float4(0.0, 0.0, 0.0, 0.0), + float4 mxp_in10 = float4(0.0, 0.0, 0.0, 0.0), int mxp_which = int(0) ) [[ @@ -3884,6 +3999,11 @@ export float4 mx_switch_vector4I( case 2: returnValue=mxp_in3; break; case 3: returnValue=mxp_in4; break; case 4: returnValue=mxp_in5; break; + case 5: returnValue=mxp_in6; break; + case 6: returnValue=mxp_in7; break; + case 7: returnValue=mxp_in8; break; + case 8: returnValue=mxp_in9; break; + case 9: returnValue=mxp_in10; break; default: returnValue=mxp_in1; break; } return returnValue; diff --git a/source/MaterialXGenShader/Nodes/SwitchNode.cpp b/source/MaterialXGenShader/Nodes/SwitchNode.cpp index 66273cbdc6..f244854e47 100644 --- a/source/MaterialXGenShader/Nodes/SwitchNode.cpp +++ b/source/MaterialXGenShader/Nodes/SwitchNode.cpp @@ -11,7 +11,7 @@ MATERIALX_NAMESPACE_BEGIN -const StringVec SwitchNode::INPUT_NAMES = { "in1", "in2", "in3", "in4", "in5", "which" }; +const StringVec SwitchNode::INPUT_NAMES = { "in1", "in2", "in3", "in4", "in5", "in6", "in7", "in8", "in9", "in10" }; ShaderNodeImplPtr SwitchNode::create() { @@ -29,10 +29,10 @@ void SwitchNode::emitFunctionCall(const ShaderNode& node, GenContext& context, S shadergen.emitOutput(node.getOutput(), true, true, context, stage); shadergen.emitLineEnd(stage); - const ShaderInput* which = node.getInput(INPUT_NAMES[5]); + const ShaderInput* which = node.getInput("which"); // Process the branches of the switch node - for (int branch = 0; branch < 5; ++branch) + for (int branch = 0; branch < 10; ++branch) { const ShaderInput* input = node.getInput(INPUT_NAMES[branch]); if (!input) From 779f3464f90abcb98aa57bcea7d97a1f23ad1b14 Mon Sep 17 00:00:00 2001 From: ld-kerley <154285602+ld-kerley@users.noreply.github.com> Date: Tue, 30 Jan 2024 20:55:44 -0800 Subject: [PATCH 06/20] Rename ND_normalmap to ND_normalmap_float in 1.39 (#1677) Renaming ND_normalmap -> ND_normalmap_float Added upgrade mechanism to handle the node definition rename. --- libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx | 3 +-- libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx | 2 +- libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx | 2 +- libraries/stdlib/genosl/stdlib_genosl_impl.mtlx | 2 +- libraries/stdlib/stdlib_defs.mtlx | 2 +- source/MaterialXCore/Document.cpp | 6 ++++++ 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index b7aa172d9c..cd01323852 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -42,10 +42,9 @@ - + - diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index 5d1fce0813..e250cbaf75 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -44,7 +44,7 @@ - + diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index 3ef9c8ff26..016bec4a73 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -42,7 +42,7 @@ - + diff --git a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx index 9b13d1ef2c..63fee9fd56 100644 --- a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -44,7 +44,7 @@ - + diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 0f8ff43177..3a8933c3c4 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -2497,7 +2497,7 @@ Node: Transform a normal vector from object or tangent space into "world" space. --> - + diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 565f391da3..abf02aecb7 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -1426,6 +1426,7 @@ void Document::upgradeVersion() continue; } const string& nodeCategory = node->getCategory(); + const string& nodeDef = node->getNodeDefString(); if (nodeCategory == "atan2") { // rename input ports @@ -1465,6 +1466,11 @@ void Document::upgradeVersion() } } } + else if (nodeDef == "ND_normalmap") + { + // ND_normalmap was renamed to ND_normalmap_float + node->setNodeDefString("ND_normalmap_float"); + } } removeNodeDef("ND_thin_film_bsdf"); From 678de80bee7ac547c52950ac631a2102bc67915c Mon Sep 17 00:00:00 2001 From: ld-kerley <154285602+ld-kerley@users.noreply.github.com> Date: Sat, 10 Feb 2024 16:05:12 -0800 Subject: [PATCH 07/20] Remove arrayappend node definition (#1707) The arrayappend node has been removed from the 1.39 specification, so we're removing it from the codebase. This node has never been implemented in any shader generator or application (we think), so it should be safe to remove without any upgrade functionality. --- libraries/stdlib/stdlib_defs.mtlx | 86 ------------------- .../MaterialXGenGlsl/GenGlsl.cpp | 2 +- .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 2 +- .../MaterialXTest/MaterialXGenMsl/GenMsl.cpp | 2 +- .../MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 2 +- .../MaterialXGenShader/GenShaderUtil.cpp | 1 - 6 files changed, 4 insertions(+), 91 deletions(-) diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 3a8933c3c4..b142458e7e 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -2593,92 +2593,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -