From 967d4c2f5c5d563f10c0b7fcd8fb7e19e6369768 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 29 Oct 2024 14:44:23 -0700 Subject: [PATCH 01/20] Reduce verbosity of unit tests (#2091) This changelist reduces the verbosity of our unit tests for element equivalence, focusing on REQUIRE statements to provide coverage. --- .../MaterialXTest/MaterialXCore/Document.cpp | 64 ------------------- 1 file changed, 64 deletions(-) diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index 94f8b98708..ae7623084e 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -10,8 +10,6 @@ #include #include -#include - namespace mx = MaterialX; TEST_CASE("Document", "[document]") @@ -123,16 +121,6 @@ TEST_CASE("Document", "[document]") REQUIRE(doc->validate()); } -void printDifferences(const mx::ElementEquivalenceResultVec& results, const std::string& label) -{ - for (const mx::ElementEquivalenceResult& result : results) - { - std::cout << label << ": " << "Element: " << result.path1 << - ", Element: " << result.path2 << ", Difference Type: " << result.differenceType - << ", Value: " << result.attributeName << std::endl; - } -} - TEST_CASE("Document equivalence", "[document]") { mx::DocumentPtr doc = mx::createDocument(); @@ -224,44 +212,18 @@ TEST_CASE("Document equivalence", "[document]") // Check skipping all value compares options.skipValueComparisons = true; bool equivalent = doc->isEquivalent(doc2, options, &results); - if (equivalent) - { - std::cout << "Unexpected skip value equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } - else - { - printDifferences(results, "Expected value differences"); - } REQUIRE(!equivalent); // Check attibute values options.skipValueComparisons = false; results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Unexpected value difference"); - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(equivalent); unsigned int currentPrecision = mx::Value::getFloatPrecision(); // This will compare 0.012345608 versus: 1, 0.012345611 for input10 options.precision = 8; equivalent = doc->isEquivalent(doc2, options); - if (equivalent) - { - std::cout << "Unexpected precision equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } - else - { - printDifferences(results, "Expected precision difference"); - } REQUIRE(!equivalent); options.precision = currentPrecision; @@ -274,12 +236,6 @@ TEST_CASE("Document equivalence", "[document]") floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, "100.0"); } equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Unexpected filtering differences"); - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(equivalent); for (mx::InputPtr floatInput : floatInputs) { @@ -293,16 +249,6 @@ TEST_CASE("Document equivalence", "[document]") mismatchElement->setName("mismatch_color4"); results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Expected name mismatch differences"); - } - else - { - std::cout << "Unexpected name match equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(!equivalent); mismatchElement->setName(previousName); results.clear(); @@ -320,15 +266,5 @@ TEST_CASE("Document equivalence", "[document]") nodeGraph2->setNodeDefString("ND_mygraph"); results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Expected functional graph differences"); - } - else - { - std::cout << "Unexpected functional graph equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(!equivalent); } From 9d875a817f17dac5d8b3ad2b388cdfdee5c6eb6a Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:10:33 -0700 Subject: [PATCH 02/20] Initial implementation of structs in MaterialX (#1831) This PR introduces support for custom structs types. Custom structs are defined using the `typedef` element. ``` ``` `member` elements are used to define the members of the custom struct. The `value` here is the default value used if no initializer is specified. --- .../JsMaterialX/JsMaterialXCore/JsValue.cpp | 2 +- source/MaterialXCore/Definition.cpp | 8 + source/MaterialXCore/Definition.h | 11 +- source/MaterialXCore/Element.cpp | 16 + source/MaterialXCore/Element.h | 14 +- source/MaterialXCore/Exception.h | 8 + source/MaterialXCore/Value.cpp | 73 ++++- source/MaterialXCore/Value.h | 81 ++++- source/MaterialXGenGlsl/GlslSyntax.cpp | 37 +++ source/MaterialXGenGlsl/GlslSyntax.h | 14 + .../mdl/materialx/stdlib_1_8.mdl | 20 ++ source/MaterialXGenOsl/OslShaderGenerator.cpp | 9 +- source/MaterialXGenShader/ShaderGenerator.cpp | 41 +++ source/MaterialXGenShader/ShaderGenerator.h | 6 + source/MaterialXGenShader/ShaderNode.cpp | 4 +- source/MaterialXGenShader/Syntax.cpp | 65 ++++ source/MaterialXGenShader/Syntax.h | 32 ++ source/MaterialXGenShader/TypeDesc.cpp | 129 +++++++- source/MaterialXGenShader/TypeDesc.h | 79 ++++- source/MaterialXGraphEditor/RenderView.cpp | 3 + source/MaterialXRender/Util.cpp | 2 +- source/MaterialXRenderGlsl/GlslMaterial.cpp | 2 +- source/MaterialXRenderGlsl/GlslProgram.cpp | 120 ++++--- source/MaterialXRenderGlsl/GlslProgram.h | 4 +- source/MaterialXRenderMsl/MslMaterial.mm | 2 +- .../MslPipelineStateObject.h | 4 +- .../MslPipelineStateObject.mm | 296 +++++++++++------- source/MaterialXTest/MaterialXCore/Node.cpp | 6 +- .../MaterialXGenShader/GenShaderUtil.cpp | 5 + source/MaterialXView/Viewer.cpp | 3 + .../PyMaterialX/PyMaterialXCore/PyValue.cpp | 6 +- .../PyShaderGenerator.cpp | 2 + 32 files changed, 903 insertions(+), 201 deletions(-) diff --git a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp index d0ddba7e17..5e45ef16cd 100644 --- a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp +++ b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp @@ -47,7 +47,7 @@ EMSCRIPTEN_BINDINGS(value) .function("copy", &mx::Value::copy, ems::pure_virtual()) .function("getTypeString", &mx::Value::getTypeString) .function("getValueString", &mx::Value::getValueString) - .class_function("createValueFromStrings", &mx::Value::createValueFromStrings) + BIND_CLASS_FUNC("createValueFromStrings", mx::Value, createValueFromStrings, 2, 3, stRef, stRef, mx::ConstTypeDefPtr) .class_function("setFloatFormat", &mx::Value::setFloatFormat) .class_function("setFloatPrecision", &mx::Value::setFloatPrecision) .class_function("getFloatFormat", &mx::Value::getFloatFormat) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 22c111f03c..da6c3ca3af 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -196,4 +196,12 @@ vector UnitTypeDef::getUnitDefs() const return unitDefs; } +ValuePtr AttributeDef::getValue() const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType())); +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXCore/Definition.h b/source/MaterialXCore/Definition.h index 6498f21c89..0ce7761b6d 100644 --- a/source/MaterialXCore/Definition.h +++ b/source/MaterialXCore/Definition.h @@ -423,11 +423,11 @@ class MX_CORE_API TargetDef : public TypedElement /// @class Member /// A member element within a TypeDef. -class MX_CORE_API Member : public TypedElement +class MX_CORE_API Member : public ValueElement { public: Member(ElementPtr parent, const string& name) : - TypedElement(parent, CATEGORY, name) + ValueElement(parent, CATEGORY, name) { } virtual ~Member() { } @@ -625,12 +625,7 @@ class MX_CORE_API AttributeDef : public TypedElement /// /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getValue() const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getValueString(), getType()); - } + ValuePtr getValue() const; /// @} /// @name Elements diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index af47a6a2ba..648d7df000 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -638,6 +638,22 @@ string ValueElement::getResolvedValueString(StringResolverPtr resolver) const return resolver->resolve(getValueString(), getType()); } +ValuePtr ValueElement::getValue() const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType())); +} + +ValuePtr ValueElement::getResolvedValue(StringResolverPtr resolver) const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getResolvedValueString(resolver), getType(), getDocument()->getTypeDef(getType())); +} + ValuePtr ValueElement::getDefaultValue() const { ConstElementPtr parent = getParent(); diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index a80bc3a49f..fb4bbe07ce 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -1037,12 +1037,7 @@ class MX_CORE_API ValueElement : public TypedElement /// /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getValue() const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getValueString(), getType()); - } + ValuePtr getValue() const; /// Return the resolved value of an element as a generic value object, which /// may be queried to access its data. @@ -1052,12 +1047,7 @@ class MX_CORE_API ValueElement : public TypedElement /// will be created at this scope and applied to the return value. /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getResolvedValueString(resolver), getType()); - } + ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const; /// Return the default value for this element as a generic value object, which /// may be queried to access its data. diff --git a/source/MaterialXCore/Exception.h b/source/MaterialXCore/Exception.h index 4fc0c728ec..4cf51f1cd5 100644 --- a/source/MaterialXCore/Exception.h +++ b/source/MaterialXCore/Exception.h @@ -50,6 +50,14 @@ class MX_CORE_API Exception : public std::exception string _msg; }; +/// @class ExceptionTypeError +/// An exception that is thrown when a type mismatch is encountered. +class MX_CORE_API ExceptionTypeError : public Exception +{ + public: + using Exception::Exception; +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXCore/Value.cpp b/source/MaterialXCore/Value.cpp index 68da4b5b9d..bb70aa04ae 100644 --- a/source/MaterialXCore/Value.cpp +++ b/source/MaterialXCore/Value.cpp @@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 // +#include +#include #include #include @@ -267,12 +269,18 @@ template ValuePtr TypedValue::createFromString(const string& value) // Value methods // -ValuePtr Value::createValueFromStrings(const string& value, const string& type) +ValuePtr Value::createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef) { CreatorMap::iterator it = _creatorMap.find(type); if (it != _creatorMap.end()) return it->second(value); + if (typeDef && !typeDef->getMembers().empty()) + { + // If we're given a TypeDef pointer that has child members, then we can create a new AggregateValue. + return AggregateValue::createAggregateValueFromString(value, type, typeDef); + } + return TypedValue::createFromString(value); } @@ -291,6 +299,69 @@ template const T& Value::asA() const return typedVal->getData(); } +template <> +MX_CORE_API bool Value::isA() const +{ + return dynamic_cast(this) != nullptr; +} + +template <> +MX_CORE_API const AggregateValue& Value::asA() const +{ + const AggregateValue* typedVal = dynamic_cast(this); + if (!typedVal) + { + throw ExceptionTypeError("Incorrect type specified for value"); + } + return *typedVal; +} + +string AggregateValue::getValueString() const +{ + if (_data.empty()) + return EMPTY_STRING; + + std::string result = "{"; + std::string separator = ""; + for (const auto& val : _data) + { + result += separator + val->getValueString(); + separator = ";"; + } + result += "}"; + + return result; +} + +AggregateValuePtr AggregateValue::createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDef) +{ + StringVec subValues = parseStructValueString(value); + + AggregateValuePtr result = AggregateValue::createAggregateValue(type); + const auto& members = typeDef->getMembers(); + + if (subValues.size() != members.size()) + { + std::stringstream ss; + ss << "Wrong number of initializers - expect " << members.size(); + throw Exception(ss.str()); + } + + auto doc = typeDef->getDocument(); + for (size_t i = 0; i < members.size(); ++i) + { + const auto& member = members[i]; + + // This will return nullptr if the type is not a listed typedef. + ConstTypeDefPtr subTypeDef = doc->getTypeDef(members[i]->getType()); + + // Calling Value::createValueFromStrings() here allows support for recursively nested structs. + result->appendValue(Value::createValueFromStrings(subValues[i], member->getType(), subTypeDef)); + } + + return result; +} + ScopedFloatFormatting::ScopedFloatFormatting(Value::FloatFormat format, int precision) : _format(Value::getFloatFormat()), _precision(Value::getFloatPrecision()) diff --git a/source/MaterialXCore/Value.h b/source/MaterialXCore/Value.h index 764a0ccc01..4dae4ab135 100644 --- a/source/MaterialXCore/Value.h +++ b/source/MaterialXCore/Value.h @@ -24,21 +24,22 @@ using BoolVec = vector; using FloatVec = vector; class Value; +class AggregateValue; /// A shared pointer to a Value using ValuePtr = shared_ptr; /// A shared pointer to a const Value using ConstValuePtr = shared_ptr; -template class TypedValue; +/// A shared pointer to an Aggregate Value +using AggregateValuePtr = shared_ptr; +/// A shared pointer to a const Aggregate Value +using ConstAggregateValuePtr = shared_ptr; -/// @class ExceptionTypeError -/// An exception that is thrown when a type mismatch is encountered. -class MX_CORE_API ExceptionTypeError : public Exception -{ - public: - using Exception::Exception; -}; +class TypeDef; +using ConstTypeDefPtr = shared_ptr; + +template class TypedValue; /// A generic, discriminated value, whose type may be queried dynamically. class MX_CORE_API Value @@ -73,7 +74,7 @@ class MX_CORE_API Value /// Create a new value instance from value and type strings. /// @return A shared pointer to a typed value, or an empty shared pointer /// if the conversion to the given data type cannot be performed. - static ValuePtr createValueFromStrings(const string& value, const string& type); + static ValuePtr createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef = nullptr); /// Create a deep copy of the value. virtual ValuePtr copy() const = 0; @@ -193,6 +194,68 @@ template class MX_CORE_API TypedValue : public Value T _data; }; +/// A subclass for aggregate values with multiple members +class MX_CORE_API AggregateValue : public Value +{ + public: + AggregateValue(const string& typeName) : + _typeName(typeName) + { + } + virtual ~AggregateValue() { } + + /// Create a deep copy of the value. + ValuePtr copy() const override + { + auto result = createAggregateValue(_typeName); + for (const auto& val : _data) + { + result->appendValue(val->copy()); + } + return result; + } + + /// Append a member value to the aggregate. + void appendValue(ConstValuePtr valuePtr) + { + _data.emplace_back(valuePtr); + } + + const vector& getMembers() const + { + return _data; + } + + /// Query an indexed member value from the aggregate. + ConstValuePtr getMemberValue(size_t index) const + { + return _data[index]; + } + + /// Return type string. + const string& getTypeString() const override { return _typeName; } + + /// Return value string. + string getValueString() const override; + + // + // Static helper methods + // + + /// Create a new value from an object of any valid MaterialX type. + static AggregateValuePtr createAggregateValue(const string& typeName) + { + return std::make_shared(typeName); + } + + static AggregateValuePtr createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDefPtr); + + private: + const string _typeName; + + vector _data; +}; + /// @class ScopedFloatFormatting /// An RAII class for controlling the float formatting of values. class MX_CORE_API ScopedFloatFormatting diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp index f91305f1a6..651a4ab5ff 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.cpp +++ b/source/MaterialXGenGlsl/GlslSyntax.cpp @@ -375,4 +375,41 @@ bool GlslSyntax::remapEnumeration(const string& value, TypeDesc type, const stri return true; } +StructTypeSyntaxPtr GlslSyntax::createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const +{ + return std::make_shared( + this, + structTypeName, + defaultValue, + uniformDefaultValue, + typeAlias, + typeDefinition); +} + +string GlslStructTypeSyntax::getValue(const Value& value, bool /* uniform */) const +{ + const AggregateValue& aggValue = static_cast(value); + + string result = aggValue.getTypeString() + "("; + + string separator = ""; + for (const auto& memberValue : aggValue.getMembers()) + { + result += separator; + separator = ","; + + auto memberTypeName = memberValue->getTypeString(); + auto memberTypeDesc = TypeDesc::get(memberTypeName); + + // Recursively use the syntax to generate the output, so we can supported nested structs. + result += _parentSyntax->getValue(memberTypeDesc, *memberValue, true); + } + + result += ")"; + + return result; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/GlslSyntax.h b/source/MaterialXGenGlsl/GlslSyntax.h index 8408534e7e..1e82e354bd 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.h +++ b/source/MaterialXGenGlsl/GlslSyntax.h @@ -45,6 +45,20 @@ class MX_GENGLSL_API GlslSyntax : public Syntax static const StringVec VEC2_MEMBERS; static const StringVec VEC3_MEMBERS; static const StringVec VEC4_MEMBERS; + + protected: + StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const override; +}; + +/// Specialization of TypeSyntax for aggregate types. +class MX_GENGLSL_API GlslStructTypeSyntax : public StructTypeSyntax +{ + public: + using StructTypeSyntax::StructTypeSyntax; + + string getValue(const Value& value, bool uniform) const override; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl index bef1e430d4..bb6eaf157a 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl @@ -441,3 +441,23 @@ export float3 mx_viewdirection_vector3( ::state::coordinate_object, internal_space_direction)); } + + +export float3 mx_extractGroup( + uniform texcoordGroup_struct in = {{0.1,0.1},{0.2,0.2},{0.3,0.3}}, + uniform int index = 0 +) + [[ + anno::description("Node Group: experimental") + ]] +{ + result = in.st_0.ss; + + if (index == 1) + result = in.st_1.ss; + else if (index == 2) + result = in.st_2.ss; + + return result; +} + diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index f29719a39b..d0d9d96cba 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -510,10 +511,10 @@ void OslShaderGenerator::emitMetadata(const ShaderPort* port, ShaderStage& stage { static const std::unordered_map UI_WIDGET_METADATA = { - { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("filename", Type::STRING.getName())) }, - { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("checkBox", Type::STRING.getName())) } + { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("filename")) }, + { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("checkBox")) } }; static const std::set METADATA_TYPE_BLACKLIST = diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index 6c23382f81..398232bf39 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -344,6 +344,47 @@ ShaderNodeImplPtr ShaderGenerator::getImplementation(const NodeDef& nodedef, Gen return impl; } +/// Load any struct type definitions from the document in to the type cache. +void ShaderGenerator::loadStructTypeDefs(const DocumentPtr& doc) +{ + for (const auto& mxTypeDef : doc->getTypeDefs()) + { + const auto& typeDefName = mxTypeDef->getName(); + const auto& members = mxTypeDef->getMembers(); + + // If we don't have any member children then we're not going to consider ourselves a struct. + if (members.empty()) + continue; + + StructTypeDesc newStructTypeDesc; + for (const auto& member : members) + { + auto memberName = member->getName(); + auto memberTypeName = member->getType(); + auto memberType = TypeDesc::get(memberTypeName); + auto memberDefaultValue = member->getValueString(); + + newStructTypeDesc.addMember(memberName, memberType, memberDefaultValue); + } + + auto structIndex = StructTypeDesc::emplace_back(newStructTypeDesc); + + TypeDesc structTypeDesc(typeDefName, TypeDesc::BASETYPE_STRUCT, TypeDesc::SEMANTIC_NONE, 1, structIndex); + + TypeDescRegistry(structTypeDesc, typeDefName); + + StructTypeDesc::get(structIndex).setTypeDesc(TypeDesc::get(typeDefName)); + } + + _syntax->registerStructTypeDescSyntax(); +} + +/// Clear any struct type definitions loaded +void ShaderGenerator::clearStructTypeDefs() +{ + StructTypeDesc::clear(); +} + namespace { diff --git a/source/MaterialXGenShader/ShaderGenerator.h b/source/MaterialXGenShader/ShaderGenerator.h index fa60a4d63e..a2f54fec2e 100644 --- a/source/MaterialXGenShader/ShaderGenerator.h +++ b/source/MaterialXGenShader/ShaderGenerator.h @@ -191,6 +191,12 @@ class MX_GENSHADER_API ShaderGenerator return _tokenSubstitutions; } + /// Load any struct type definitions from the document in to the type cache. + void loadStructTypeDefs(const DocumentPtr& doc); + + /// Clear any struct type definitions loaded + void clearStructTypeDefs(); + /// Register metadata that should be exported to the generated shaders. /// Supported metadata includes standard UI attributes like "uiname", "uifolder", /// "uimin", "uimax", etc. diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index 4e90fcbb2d..d52810ffc4 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -437,7 +437,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) const string& attrValue = nodeDef.getAttribute(nodedefAttr); if (!attrValue.empty()) { - ValuePtr value = Value::createValueFromStrings(attrValue, metadataEntry->type.getName()); + ValuePtr value = metadataEntry->type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; @@ -472,7 +472,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) if (!attrValue.empty()) { const TypeDesc type = metadataEntry->type != Type::NONE ? metadataEntry->type : input->getType(); - ValuePtr value = Value::createValueFromStrings(attrValue, type.getName()); + ValuePtr value = type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index 661aa41660..b8eed3e9b8 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -190,6 +190,36 @@ bool Syntax::remapEnumeration(const string&, TypeDesc, const string&, std::pair< return false; } +void Syntax::registerStructTypeDescSyntax() +{ + for (const auto& typeName : StructTypeDesc::getStructTypeNames()) + { + const auto& typeDesc = TypeDesc::get(typeName); + const auto& structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); + + string structTypeName = typeName; + string defaultValue = typeName + "( "; + string uniformDefaultValue = EMPTY_STRING; + string typeAlias = EMPTY_STRING; + string typeDefinition = "struct " + structTypeName + " { "; + + for (const auto& x : structTypeDesc.getMembers()) + { + string memberName = x._name; + string memberType = x._typeDesc.getName(); + string memberDefaultValue = x._defaultValueStr; + + defaultValue += memberDefaultValue + ", "; + typeDefinition += memberType + " " + memberName + "; "; + } + + typeDefinition += " };"; + defaultValue += " )"; + + registerTypeSyntax(typeDesc, createStructSyntax(structTypeName, defaultValue, uniformDefaultValue, typeAlias, typeDefinition)); + } +} + const StringVec TypeSyntax::EMPTY_MEMBERS; TypeSyntax::TypeSyntax(const string& name, const string& defaultValue, const string& uniformDefaultValue, @@ -246,4 +276,39 @@ string AggregateTypeSyntax::getValue(const Value& value, bool /*uniform*/) const return valueString.empty() ? valueString : getName() + "(" + valueString + ")"; } +StructTypeSyntax::StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias, const string& typeDefinition, const StringVec& members) : + TypeSyntax(name, defaultValue, uniformDefaultValue, typeAlias, typeDefinition, members), _parentSyntax(parentSyntax) +{ +} + +string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const +{ + const AggregateValue& aggValue = static_cast(value); + + auto typeDesc = TypeDesc::get(aggValue.getTypeString()); + auto structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); + + string result = "{"; + + string separator = ""; + for (const auto& memberValue : aggValue.getMembers()) + { + result += separator; + separator = ";"; + + auto memberTypeName = memberValue->getTypeString(); + auto memberTypeDesc = TypeDesc::get(memberTypeName); + + // Recursively use the syntax to generate the output, so we can support nested structs. + const string valueStr = _parentSyntax->getValue(memberTypeDesc, *memberValue, true); + + result += valueStr; + } + + result += "}"; + + return result; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/Syntax.h b/source/MaterialXGenShader/Syntax.h index a4bb7e49b5..6f16633b59 100644 --- a/source/MaterialXGenShader/Syntax.h +++ b/source/MaterialXGenShader/Syntax.h @@ -20,6 +20,7 @@ MATERIALX_NAMESPACE_BEGIN class Syntax; class TypeSyntax; +class StructTypeSyntax; class TypeDesc; class ShaderPort; @@ -29,6 +30,8 @@ using SyntaxPtr = shared_ptr; using ConstSyntaxPtr = shared_ptr; /// Shared pointer to a TypeSyntax using TypeSyntaxPtr = shared_ptr; +/// Shared pointer to a StructTypeSyntax +using StructTypeSyntaxPtr = shared_ptr; /// Map holding identifier names and a counter for /// creating unique names from them. @@ -67,6 +70,8 @@ class MX_GENSHADER_API Syntax /// Multiple calls will add to the internal set of tokens. void registerInvalidTokens(const StringMap& tokens); + virtual void registerStructTypeDescSyntax(); + /// Returns a set of names that are reserved words for this language syntax. const StringSet& getReservedWords() const { return _reservedWords; } @@ -199,6 +204,19 @@ class MX_GENSHADER_API Syntax /// Protected constructor Syntax(); + virtual StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const + { + return std::make_shared( + this, + structTypeName, + defaultValue, + uniformDefaultValue, + typeAlias, + typeDefinition); + } + vector _typeSyntaxes; std::unordered_map _typeSyntaxIndexByType; @@ -292,6 +310,20 @@ class MX_GENSHADER_API AggregateTypeSyntax : public TypeSyntax string getValue(const Value& value, bool uniform) const override; }; +/// Specialization of TypeSyntax for aggregate types. +class MX_GENSHADER_API StructTypeSyntax : public TypeSyntax +{ + public: + StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias = EMPTY_STRING, const string& typeDefinition = EMPTY_STRING, + const StringVec& members = EMPTY_MEMBERS); + + string getValue(const Value& value, bool uniform) const override; + + protected: + const Syntax* _parentSyntax; +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp index 1267caf14d..5d51680211 100644 --- a/source/MaterialXGenShader/TypeDesc.cpp +++ b/source/MaterialXGenShader/TypeDesc.cpp @@ -5,7 +5,7 @@ #include -#include +#include MATERIALX_NAMESPACE_BEGIN @@ -28,6 +28,16 @@ TypeDescNameMap& typeNameMap() return map; } +using StructTypeDescStorage = vector; +StructTypeDescStorage& structTypeStorage() +{ + // TODO: Our use of the singleton pattern for TypeDescMap and StructTypeDestStorage + // is not thread-safe, and we should consider replacing this with thread-local + // data in the GenContext object. + static StructTypeDescStorage storage; + return storage; +} + } // anonymous namespace const string TypeDesc::NONE_TYPE_NAME = "none"; @@ -46,7 +56,52 @@ TypeDesc TypeDesc::get(const string& name) return it != types.end() ? it->second : Type::NONE; } -TypeDescRegistry::TypeDescRegistry(TypeDesc type, const std::string& name) +void TypeDesc::remove(const string& name) +{ + TypeDescNameMap& typenames = typeNameMap(); + + TypeDescMap& types = typeMap(); + + auto it = types.find(name); + if (it == types.end()) + return; + + typenames.erase(it->second.typeId()); + types.erase(it); +} + +ValuePtr TypeDesc::createValueFromStrings(const string& value) const +{ + ValuePtr newValue = Value::createValueFromStrings(value, getName()); + if (!isStruct()) + return newValue; + + // Value::createValueFromStrings() can only create a valid Value for a struct if it is passed + // the optional TypeDef argument, otherwise it just returns a "string" typed Value. + // So if this is a struct type we need to create a new AggregateValue. + + StringVec subValues = parseStructValueString(value); + + AggregateValuePtr result = AggregateValue::createAggregateValue(getName()); + auto structTypeDesc = StructTypeDesc::get(getStructIndex()); + const auto& members = structTypeDesc.getMembers(); + + if (subValues.size() != members.size()) + { + std::stringstream ss; + ss << "Wrong number of initializers - expect " << members.size(); + throw ExceptionShaderGenError(ss.str()); + } + + for (size_t i = 0; i < members.size(); ++i) + { + result->appendValue( members[i]._typeDesc.createValueFromStrings(subValues[i])); + } + + return result; +} + +TypeDescRegistry::TypeDescRegistry(TypeDesc type, const string& name) { TypeDescMap& types = typeMap(); TypeDescNameMap& typenames = typeNameMap(); @@ -86,4 +141,74 @@ TYPEDESC_REGISTER_TYPE(MATERIAL, "material") } // namespace Type +// +// StructTypeDesc methods +// + +void StructTypeDesc::addMember(const string& name, TypeDesc type, string defaultValueStr) +{ + _members.emplace_back(StructTypeDesc::StructMemberTypeDesc(name, type, defaultValueStr)); +} + +vector StructTypeDesc::getStructTypeNames() +{ + StructTypeDescStorage& structs = structTypeStorage(); + vector structNames; + for (const auto& x : structs) + { + structNames.emplace_back(x.typeDesc().getName()); + } + return structNames; +} + +StructTypeDesc& StructTypeDesc::get(unsigned int index) +{ + StructTypeDescStorage& structs = structTypeStorage(); + return structs[index]; +} + +uint16_t StructTypeDesc::emplace_back(StructTypeDesc structTypeDesc) +{ + StructTypeDescStorage& structs = structTypeStorage(); + if (structs.size() >= std::numeric_limits::max()) + { + throw ExceptionShaderGenError("Maximum number of custom struct types has been exceeded."); + } + uint16_t index = static_cast(structs.size()); + structs.emplace_back(structTypeDesc); + return index; +} + +void StructTypeDesc::clear() +{ + StructTypeDescStorage& structs = structTypeStorage(); + for (const auto& structType: structs) + { + // Need to add typeID to structTypeDesc - and use it here to reference back to typeDesc obj and remove it. + TypeDesc::remove(structType.typeDesc().getName()); + } + structs.clear(); +} + +const string& StructTypeDesc::getName() const +{ + return _typedesc.getName(); +} + +const vector& StructTypeDesc::getMembers() const +{ + return _members; +} + +TypeDesc createStructTypeDesc(std::string_view name) +{ + return {name, TypeDesc::BASETYPE_STRUCT}; +} + +void registerStructTypeDesc(std::string_view name) +{ + auto structTypeDesc = createStructTypeDesc(name); + TypeDescRegistry register_struct(structTypeDesc, string(name)); +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index 1a537b7e58..95d2851915 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -10,6 +10,7 @@ /// Type descriptor for a MaterialX data type. #include +#include #include @@ -61,14 +62,21 @@ class MX_GENSHADER_API TypeDesc /// Empty constructor. constexpr TypeDesc() noexcept : - _id(0), _basetype(BASETYPE_NONE), _semantic(SEMANTIC_NONE), _size(0) { } + _id(0), + _basetype(BASETYPE_NONE), + _semantic(SEMANTIC_NONE), + _size(0), + _structIndex(0) + { + } /// Constructor. - constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1) noexcept : + constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1, uint16_t structIndex = 0) noexcept : _id(constexpr_hash(name)), // Note: We only store the hash to keep the class size minimal. _basetype(basetype), _semantic(semantic), - _size(size) + _size(size), + _structIndex(structIndex) { } @@ -112,6 +120,12 @@ class MX_GENSHADER_API TypeDesc /// Return true if the type represents a closure. bool isClosure() const { return (_semantic == SEMANTIC_CLOSURE || _semantic == SEMANTIC_SHADER || _semantic == SEMANTIC_MATERIAL); } + /// Return true if the type represents a struct. + bool isStruct() const { return _basetype == BASETYPE_STRUCT; } + + /// Return the index for the struct member information in StructTypeDesc, the result is invalid if `isStruct()` returns false. + uint16_t getStructIndex() const { return _structIndex; } + /// Equality operator bool operator==(TypeDesc rhs) const { @@ -143,8 +157,14 @@ class MX_GENSHADER_API TypeDesc /// If no type is found Type::NONE is returned. static TypeDesc get(const string& name); + /// Remove a type description by name, if it exists. + static void remove(const string& name); + static const string NONE_TYPE_NAME; + /// Create a Value from a string for a given typeDesc + ValuePtr createValueFromStrings(const string& value) const; + private: /// Simple constexpr hash function, good enough for the small set of short strings that /// are used for our data type names. @@ -157,6 +177,7 @@ class MX_GENSHADER_API TypeDesc uint8_t _basetype; uint8_t _semantic; uint16_t _size; + uint16_t _structIndex; }; /// @class TypeDescRegistry @@ -208,6 +229,58 @@ TYPEDESC_DEFINE_TYPE(MATERIAL, "material", TypeDesc::BASETYPE_NONE, TypeDesc::SE } // namespace Type + +/// @class StructTypeDesc +/// A type descriptor for MaterialX struct types. +/// +/// All types need to have a type descriptor registered in order for shader generators +/// to know about the type. If the type represented is of basetype=BASETYPE_STRUCT then +/// the type also needs to have an associated StructTypeDesc that describes the members +/// of the struct. +/// +class MX_GENSHADER_API StructTypeDesc +{ + public: + struct StructMemberTypeDesc + { + StructMemberTypeDesc(string name, TypeDesc typeDesc, string defaultValueStr) : + _name(name), _typeDesc(typeDesc), _defaultValueStr(defaultValueStr) + { + } + string _name; + TypeDesc _typeDesc; + string _defaultValueStr; + }; + + /// Empty constructor. + StructTypeDesc() noexcept{} + + void addMember(const string& name, TypeDesc type, string defaultValueStr); + void setTypeDesc(TypeDesc typedesc) { _typedesc = typedesc; } + + /// Return a type description by index. + static StructTypeDesc& get(unsigned int index); + static vector getStructTypeNames(); + static uint16_t emplace_back(StructTypeDesc structTypeDesc); + static void clear(); + + TypeDesc typeDesc() const { return _typedesc; } + + const string& getName() const; + + const vector& getMembers() const; + + private: + TypeDesc _typedesc; + vector _members; +}; + +class MX_GENSHADER_API StructTypeDescRegistry +{ + public: + StructTypeDescRegistry(); +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index dbc9b4f980..92cd8f07c7 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -630,6 +630,9 @@ void RenderView::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Register struct type definitions + context.getShaderGenerator().loadStructTypeDefs(_document); } void RenderView::drawContents() diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index 881f1b7eea..00fdc65381 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -170,7 +170,7 @@ unsigned int getUIProperties(InputPtr input, const string& target, UIProperties& else { valueString += val; - uiProperties.enumerationValues.push_back(Value::createValueFromStrings(valueString, input->getType())); + uiProperties.enumerationValues.push_back(typeDesc.createValueFromStrings(valueString)); valueString.clear(); index = 0; } diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index 788af713b2..064ab898ff 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -360,7 +360,7 @@ void GlslMaterial::modifyUniform(const std::string& path, ConstValuePtr value, s { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index b2ca0aa66e..b63e1faecc 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -508,7 +508,7 @@ ImagePtr GlslProgram::bindTexture(unsigned int uniformType, int uniformLocation, return nullptr; } -MaterialX::ValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -946,47 +946,87 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - int glType = mapTypeToOpenGLType(v->getType()); - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - - // Ignore types which are unsupported in GLSL. - if (glType == Input::INVALID_OPENGL_TYPE) - { - continue; - } + const auto& variablePath = v->getPath(); + const auto& variableUnit = v->getUnit(); + const auto& variableColorspace = v->getColorSpace(); + const auto& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt != _uniformList.end()) + const auto populateUniformInput = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue) -> void { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->unit = v->getUnit(); - input->colorspace = v->getColorSpace(); - input->value = v->getValue(); - if (input->gltype == glType) - { - input->typeString = v->getType().getName(); - } - else + auto populateUniformInput_impl = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". Unit: \"" + (!v->getUnit().empty() ? v->getUnit() : "") - + "\". Colorspace: \"" + (!v->getColorSpace().empty() ? v->getColorSpace() : "") - + "\". GLType: " + std::to_string(mapTypeToOpenGLType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + if (!typedesc.isStruct()) + { + // Handle non-struct types + int glType = mapTypeToOpenGLType(typedesc); + + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } + + // Ignore types which are unsupported in GLSL. + if (glType == Input::INVALID_OPENGL_TYPE) + { + return; + } + + auto inputIt = _uniformList.find(variableName); + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->unit = variableUnit; + input->colorspace = variableColorspace; + input->value = variableValue; + if (input->gltype == glType) + { + input->typeString = typedesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + typedesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". Unit: \"" + (!variableUnit.empty() ? variableUnit : "") + + "\". Colorspace: \"" + (!variableColorspace.empty() ? variableColorspace : "") + + "\". GLType: " + std::to_string(glType)); + uniformTypeMismatchFound = true; + } + } + } + else + { + // If we're a struct - we need to loop over each member + auto structTypeDesc = StructTypeDesc::get(typedesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& member = members[i]; + auto memberTypeDesc = member._typeDesc; + auto memberVariableName = variableName + "." + member._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(memberTypeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(typedesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1100,12 +1140,12 @@ const GlslProgram::InputMap& GlslProgram::updateAttributesList() if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; diff --git a/source/MaterialXRenderGlsl/GlslProgram.h b/source/MaterialXRenderGlsl/GlslProgram.h index 7d58dbaca7..4addd7d54b 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.h +++ b/source/MaterialXRenderGlsl/GlslProgram.h @@ -102,7 +102,7 @@ class MX_RENDERGLSL_API GlslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) @@ -223,7 +223,7 @@ class MX_RENDERGLSL_API GlslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(unsigned int uniformType, int uniformLocation, const FilePath& filePath, diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm index 311d84acee..eb13ea7900 100644 --- a/source/MaterialXRenderMsl/MslMaterial.mm +++ b/source/MaterialXRenderMsl/MslMaterial.mm @@ -318,7 +318,7 @@ { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.h b/source/MaterialXRenderMsl/MslPipelineStateObject.h index b335e29af5..a823662f5f 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.h +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.h @@ -99,7 +99,7 @@ class MX_RENDERMSL_API MslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) @@ -256,7 +256,7 @@ class MX_RENDERMSL_API MslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(id renderCmdEncoder, diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm index 2d5685646f..470fa549b2 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm @@ -235,12 +235,12 @@ int GetStrideOfMetalType(MTLDataType type) if (_shader->hasAttribute(HW::ATTR_TRANSPARENT)) { - psoDesc.colorAttachments[0].blendingEnabled = YES; - psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + psoDesc.colorAttachments[0].blendingEnabled = YES; + psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; psoDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; _alphaBlendingEnabled = true; @@ -265,12 +265,12 @@ int GetStrideOfMetalType(MTLDataType type) if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; @@ -566,8 +566,8 @@ int GetStrideOfMetalType(MTLDataType type) return nullptr; } -MaterialX::ValuePtr MslProgram::findUniformValue(const string& uniformName, - const MslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr MslProgram::findUniformValue(const string& uniformName, + const MslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -925,31 +925,54 @@ int GetStrideOfMetalType(MTLDataType type) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { - for (MTLStructMember* member in arg.bufferStructType.members) - { - std::string uboObjectName = std::string(arg.name.UTF8String); - std::string memberName = member.name.UTF8String; - std::string uboDotMemberName = uboObjectName + "." + memberName; + const auto uboObjectName = string(arg.name.UTF8String); - InputPtr inputPtr = std::make_shared(arg.index, member.dataType, arg.bufferDataSize, EMPTY_STRING); - _uniformList[uboDotMemberName] = inputPtr; - _globalUniformNameList[memberName] = uboDotMemberName; - - if (MTLArrayType* arrayMember = member.arrayType) + const auto addUniformToList = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix) -> void + { + auto addUniformToList_impl = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix, auto& addUniformToList_ref) -> void { - for (int i = 0; i < arrayMember.arrayLength; ++i) + auto memberName = memberNamePrefix + member.name.UTF8String; + + if (MTLStructType* structMember = member.structType) { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + for (MTLStructMember* subMember in structMember.members) { - std::string memberNameDotSubmember = memberName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - std::string uboDotMemberNameDotSubmemberName = uboObjectName + "." + memberNameDotSubmember; + auto namePrefix = memberName + "."; + addUniformToList_ref(subMember, subMember.argumentIndex, subMember.offset, namePrefix, addUniformToList_ref); + } + } + else + { + auto uboDotMemberName = uboObjectName + "." + memberName; + + InputPtr inputPtr = std::make_shared(index, member.dataType, size, EMPTY_STRING); + this->_uniformList[uboDotMemberName] = inputPtr; + this->_globalUniformNameList[memberName] = uboDotMemberName; - InputPtr inputPtr = std::make_shared(ArrayOfStructMember.argumentIndex, ArrayOfStructMember.dataType, ArrayOfStructMember.offset, EMPTY_STRING); - _uniformList[uboDotMemberNameDotSubmemberName] = inputPtr; - _globalUniformNameList[memberNameDotSubmember] = uboDotMemberNameDotSubmemberName; + if (MTLArrayType* arrayMember = member.arrayType) + { + for (int i = 0; i < arrayMember.arrayLength; ++i) + { + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + auto namePrefix = memberName + "[" + std::to_string(i) + "]."; + addUniformToList_ref(ArrayOfStructMember, ArrayOfStructMember.argumentIndex, ArrayOfStructMember.offset, namePrefix, addUniformToList_ref); + } + } } } - } + }; + + return addUniformToList_impl(member, index, size, memberNamePrefix, addUniformToList_impl); + }; + + for (MTLStructMember* member in arg.bufferStructType.members) + { + addUniformToList(member, arg.index, arg.bufferDataSize, ""); } } @@ -1006,55 +1029,90 @@ int GetStrideOfMetalType(MTLDataType type) for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - MTLDataType resourceType = mapTypeToMetalType(v->getType()); - - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - // Ignore types which are unsupported in MSL. - if (resourceType == MTLDataTypeNone) - { - continue; - } + const string& variablePath = v->getPath(); + const string& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt == _uniformList.end()) + const auto populateUniformInput = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue) -> void { - if (v->getType() == Type::FILENAME) + auto populateUniformInput_impl = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - inputIt = _uniformList.find(TEXTURE_NAME(v->getVariable())); - } - else - { - inputIt = _uniformList.find(uniforms.getInstance() + "." + v->getVariable()); - } - } + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } - if (inputIt != _uniformList.end()) - { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->value = v->getValue(); - if (input->resourceType == resourceType) - { - input->typeString = v->getType().getName(); - } - else - { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". resourceType: " + std::to_string(mapTypeToMetalType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + MTLDataType resourceType = mapTypeToMetalType(variableTypeDesc); + // Ignore types which are unsupported in MSL. + if (resourceType == MTLDataTypeNone) + { + return; + } + + if (!variableTypeDesc.isStruct()) + { + auto inputIt = _uniformList.find(variableName); + + if (inputIt == _uniformList.end()) { + if(variableTypeDesc == Type::FILENAME) + { + inputIt = _uniformList.find(TEXTURE_NAME(variableName)); + } + else + { + inputIt = _uniformList.find(uniforms.getInstance() + "." + variableName); + } + } + + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->value = variableValue; + if (input->resourceType == resourceType) + { + input->typeString = variableTypeDesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + variableTypeDesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". resourceType: " + std::to_string(mapTypeToMetalType(variableTypeDesc)) + ); + uniformTypeMismatchFound = true; + } + } + } + else + { + auto structTypeDesc = StructTypeDesc::get(variableTypeDesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& structMember = members[i]; + auto memberVariableName = variableName+"."+structMember._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(structMember._typeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(variableTypeDesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1231,7 +1289,7 @@ int GetStrideOfMetalType(MTLDataType type) return false; }; - auto setValue = [](MaterialX::ValuePtr value, std::vector& data, size_t offset) + auto setValue = [](MaterialX::ConstValuePtr value, std::vector& data, size_t offset) { if (value->getTypeString() == "float") { @@ -1307,7 +1365,7 @@ throw ExceptionRenderError( { if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - MaterialX::ValuePtr value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; + auto value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; if (value) { setValue(value, uniformBufferData, member.offset); @@ -1332,39 +1390,60 @@ throw ExceptionRenderError( if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - auto uniformInfo = _uniformList.find(uniformName); - if (uniformInfo != _uniformList.end()) - { - MaterialX::ValuePtr value = uniformInfo->second->value; - if (value) - { - setValue(value, uniformBufferData, member.offset); - } - } - else - { - } - } - - if (MTLArrayType* arrayMember = member.arrayType) - { - for (int i = 0; i < arrayMember.arrayLength; ++i) + const auto setUniformValue = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset ) -> void { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + auto setUniformValue_impl = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset, auto &setUniformValue_ref ) -> void { - string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - - auto uniformInfo = _uniformList.find(uniformNameSubArray); - if (uniformInfo != _uniformList.end()) + if(MTLArrayType* arrayMember = member.arrayType) { - MaterialX::ValuePtr value = uniformInfo->second->value; - if (value) + for(int i = 0; i < arrayMember.arrayLength; ++i) { - setValue(value, uniformBufferData, member.offset + i * arrayMember.stride + ArrayOfStructMember.offset); + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; + auto uniformInfo = _uniformList.find(uniformNameSubArray); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset + i * arrayMember.stride + ArrayOfStructMember.offset); + } + } + } } } - } - } + else if (MTLStructType* structMember = member.structType) + { + // this code does not support struct recursion yet.... + for (MTLStructMember* subMember in structMember.members) + { + string subUniformName = uniformName+"."+subMember.name.UTF8String; + setUniformValue_ref(subMember, subUniformName, uniformBufferData, offset+subMember.offset, setUniformValue_ref); + } + } + else + { + auto uniformInfo = _uniformList.find(uniformName); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset); + } + } + } + }; + + return setUniformValue_impl(member, uniformName, uniformBufferData, offset, setUniformValue_impl); + }; + + setUniformValue(member, uniformName, uniformBufferData, member.offset); } } @@ -1415,14 +1494,15 @@ throw ExceptionRenderError( // A "filename" is not indicative of type, so just return a 2d sampler. return MTLDataTypeTexture; } - else if (type == Type::BSDF || - type == Type::MATERIAL || + else if (type == Type::BSDF || + type == Type::MATERIAL || type == Type::DISPLACEMENTSHADER || - type == Type::EDF || - type == Type::VDF || - type == Type::SURFACESHADER || - type == Type::LIGHTSHADER || - type == Type::VOLUMESHADER) + type == Type::EDF || + type == Type::VDF || + type == Type::SURFACESHADER || + type == Type::LIGHTSHADER || + type == Type::VOLUMESHADER || + type.isStruct()) return MTLDataTypeStruct; return MTLDataTypeNone; diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp index ef746bfe05..f3ce7d40de 100644 --- a/source/MaterialXTest/MaterialXCore/Node.cpp +++ b/source/MaterialXTest/MaterialXCore/Node.cpp @@ -159,12 +159,12 @@ TEST_CASE("Node", "[node]") REQUIRE(typeDef->getMembers().size() == scalarCount); // Reference the custom type. - std::string d65("400.0,82.75,500.0,109.35,600.0,90.01,700.0,71.61,800.0,59.45"); + std::string d65("{400;82.75;500;109.35;600;90.01;700;71.61;800;59.45}"); constant->setInputValue("value", d65, "spectrum"); REQUIRE(constant->getInput("value")->getType() == "spectrum"); REQUIRE(constant->getInput("value")->getValueString() == d65); - REQUIRE(constant->getInputValue("value")->isA()); - REQUIRE(constant->getInputValue("value")->asA() == d65); + REQUIRE(constant->getInputValue("value")->isA()); + REQUIRE(constant->getInputValue("value")->asA().getValueString() == d65); // Validate the document. REQUIRE(doc->validate()); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 4a8e61645a..78da7e50f3 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -649,6 +649,9 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons addColorManagement(); addUnitSystem(); + // Register struct typedefs from the library files. + _shaderGenerator->loadStructTypeDefs(_dependLib); + // Test suite setup addSkipFiles(); @@ -705,6 +708,8 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons preprocessDocument(doc); _shaderGenerator->registerShaderMetadata(doc, context); + _shaderGenerator->loadStructTypeDefs(doc); + // For each new file clear the implementation cache. // Since the new file might contain implementations with names // colliding with implementations in previous test cases. diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 24aea1eb42..c4c69bb812 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -1769,6 +1769,9 @@ void Viewer::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Initialize the struct typedefs from the stdlib + context.getShaderGenerator().loadStructTypeDefs(_stdLib); } void Viewer::loadStandardLibraries() diff --git a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp index 501f9d5f04..c36bd6c288 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp @@ -6,6 +6,7 @@ #include #include +#include #define BIND_TYPE_INSTANCE(NAME, T) \ py::class_, std::shared_ptr< mx::TypedValue >, mx::Value>(mod, "TypedValue_" #NAME) \ @@ -22,7 +23,10 @@ void bindPyValue(py::module& mod) py::class_(mod, "Value") .def("getValueString", &mx::Value::getValueString) .def("getTypeString", &mx::Value::getTypeString) - .def_static("createValueFromStrings", &mx::Value::createValueFromStrings); + .def_static("createValueFromStrings", &mx::Value::createValueFromStrings, + py::arg("value"), + py::arg("type"), + py::arg("typeDefPtr") = nullptr); BIND_TYPE_INSTANCE(integer, int) BIND_TYPE_INSTANCE(boolean, bool) diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp index b952bd4651..0c8a086e58 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp @@ -22,5 +22,7 @@ void bindPyShaderGenerator(py::module& mod) .def("setUnitSystem", &mx::ShaderGenerator::setUnitSystem) .def("getUnitSystem", &mx::ShaderGenerator::getUnitSystem) .def("getTokenSubstitutions", &mx::ShaderGenerator::getTokenSubstitutions) + .def("loadStructTypeDefs", &mx::ShaderGenerator::loadStructTypeDefs) + .def("clearStructTypeDefs", &mx::ShaderGenerator::clearStructTypeDefs) .def("registerShaderMetadata", &mx::ShaderGenerator::registerShaderMetadata); } From ed450e82de41a9a5d4273c49babfdb37b18b922e Mon Sep 17 00:00:00 2001 From: Chris Rydalch Date: Tue, 29 Oct 2024 18:12:58 -0500 Subject: [PATCH 03/20] Move unimplemented Worley noise features to proposals doc (#2090) The *period* and *metric* parameters are not yet implemented. --- documents/Specification/MaterialX.Proposals.md | 18 ++++++++++++++++++ .../Specification/MaterialX.Specification.md | 4 ---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/documents/Specification/MaterialX.Proposals.md b/documents/Specification/MaterialX.Proposals.md index b96c688f25..d387d28718 100644 --- a/documents/Specification/MaterialX.Proposals.md +++ b/documents/Specification/MaterialX.Proposals.md @@ -188,7 +188,25 @@ We have a standard 3d fractal noise, but a 2d variant would be useful as well. * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for input coordinate repeated at that step. Default is 0, meaning the noise is not periodic. * `in` (float): the 1D coordinate at which the noise is evaluated. + +Expanded 2D Worley noise to support different distance metrics and periodicity. + +* **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). + * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + + + +Expanded 3D Worley noise to support different distance metrics and periodicity. + +* **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). + * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + +#### Periodic Noises + +In #1201 it was decided that separate periodic versions of all of the noises is preferred to adding it to the existing noises. ### Shape Nodes diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index 070587340c..65027694d8 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -887,16 +887,12 @@ Standard Noise nodes: * **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `texcoord` (vector2): the 2D position at which the noise is evaluated. Default is to use the first set of texture coordinates. * **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. From b330fd7ade12811aa4a39096bef3b986841d67bb Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:37:10 -0700 Subject: [PATCH 04/20] Removing MDL struct test function (#2099) Removing MDL struct test function incorrectly included in #1831. --- .../mdl/materialx/stdlib_1_8.mdl | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl index bb6eaf157a..bef1e430d4 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl @@ -441,23 +441,3 @@ export float3 mx_viewdirection_vector3( ::state::coordinate_object, internal_space_direction)); } - - -export float3 mx_extractGroup( - uniform texcoordGroup_struct in = {{0.1,0.1},{0.2,0.2},{0.3,0.3}}, - uniform int index = 0 -) - [[ - anno::description("Node Group: experimental") - ]] -{ - result = in.st_0.ss; - - if (index == 1) - result = in.st_1.ss; - else if (index == 2) - result = in.st_2.ss; - - return result; -} - From 1b2852e1db52fc52ba5f845b784a2c46d909ef2d Mon Sep 17 00:00:00 2001 From: Lee Kerley <154285602+ld-kerley@users.noreply.github.com> Date: Thu, 31 Oct 2024 09:33:36 -0700 Subject: [PATCH 05/20] Simplify the MetalTexture abstraction (#2095) `mx_texture.metal` is used to provide an abstraction to the texture code when being called from GLSL code. There are a few functions in the interface of this abstraction that do not appear to be used anywhere. This PR proposes removing them, as a precursor to other upcoming texture work. I'm proposing this as a separate PR to make things easier to review. All of the MSL unit tests pass. --- libraries/stdlib/genmsl/lib/mx_texture.metal | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/libraries/stdlib/genmsl/lib/mx_texture.metal b/libraries/stdlib/genmsl/lib/mx_texture.metal index 479a8836bf..7e90b60686 100644 --- a/libraries/stdlib/genmsl/lib/mx_texture.metal +++ b/libraries/stdlib/genmsl/lib/mx_texture.metal @@ -2,13 +2,8 @@ struct MetalTexture { texture2d tex; sampler s; - int get_width() { return tex.get_width(); } - int get_height() { return tex.get_height(); } - int get_num_mip_levels() { return tex.get_num_mip_levels(); } }; -int get_width(MetalTexture mtlTex) { return mtlTex.get_width(); } - float4 texture(MetalTexture mtlTex, float2 uv) { return mtlTex.tex.sample(mtlTex.s, uv); @@ -21,10 +16,5 @@ float4 textureLod(MetalTexture mtlTex, float2 uv, float lod) int2 textureSize(MetalTexture mtlTex, int mipLevel) { - return int2(mtlTex.get_width(), mtlTex.get_height()); -} - -int texture_mips(MetalTexture mtlTex) -{ - return mtlTex.tex.get_num_mip_levels(); + return int2(mtlTex.tex.get_width(), mtlTex.tex.get_height()); } From 65862ed56e9fd82dc2771bf3d371e16a1a1e30d3 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 31 Oct 2024 12:05:37 -0700 Subject: [PATCH 06/20] Clarifications to UsdPreviewSurface (#2100) - Set the shading model version to 2.5, reflecting the alignment of this graph definition with the 2.5 specification for UsdPreviewSurface (https://openusd.org/release/spec_usdpreviewsurface.html). - Add UI names for shading model inputs. - Update doc string letter case. --- libraries/bxdf/usd_preview_surface.mtlx | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index a521c756bc..4abdb91d9f 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -6,21 +6,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + From 4339aaa83480693c1bf4d5b54e1cf614654dd507 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 31 Oct 2024 17:12:44 -0700 Subject: [PATCH 07/20] Improvements to the MaterialX Viewer (#2101) - Replace raw pointers with NanoGUI references to improve application robustness. - Allow UI names to be displayed without a corresponding UI folder. --- source/MaterialXRender/Util.cpp | 2 +- source/MaterialXView/Editor.cpp | 103 ++++++++-------- source/MaterialXView/Editor.h | 20 ++-- source/MaterialXView/Viewer.cpp | 204 +++++++++++++++----------------- source/MaterialXView/Viewer.h | 36 +++--- 5 files changed, 179 insertions(+), 186 deletions(-) diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index 00fdc65381..c206514412 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -318,7 +318,7 @@ void createUIPropertyGroups(DocumentPtr doc, const VariableBlock& block, UIPrope // Prepend a parent label for unlabeled node inputs. ElementPtr parent = pair.first->getParent(); - if (item.ui.uiFolder.empty() && parent && parent->isA()) + if (item.ui.uiName.empty() && parent && parent->isA()) { item.label = parent->getName() + pathSeparator + item.label; } diff --git a/source/MaterialXView/Editor.cpp b/source/MaterialXView/Editor.cpp index abba9ce10e..6d64c55b30 100644 --- a/source/MaterialXView/Editor.cpp +++ b/source/MaterialXView/Editor.cpp @@ -18,11 +18,11 @@ namespace class EditorColorPicker : public ng::ColorPicker { public: - EditorColorPicker(ng::Widget* parent, const ng::Color& color) : + EditorColorPicker(ng::ref parent, const ng::Color& color) : ng::ColorPicker(parent, color) { - ng::Popup* popup = this->popup(); - ng::Widget* floatGroup = new ng::Widget(popup); + ng::ref popup = this->popup(); + ng::ref floatGroup = new ng::Widget(popup); auto layout = new ng::GridLayout(ng::Orientation::Horizontal, 2, ng::Alignment::Middle, 2, 2); layout->set_col_alignment({ ng::Alignment::Fill, ng::Alignment::Fill }); @@ -60,7 +60,7 @@ class EditorColorPicker : public ng::ColorPicker protected: // Additional numeric entry / feedback widgets - ng::FloatBox* _colorWidgets[4]; + ng::ref> _colorWidgets[4]; }; } // anonymous namespace @@ -70,10 +70,6 @@ class EditorColorPicker : public ng::ColorPicker // PropertyEditor::PropertyEditor() : - _window(nullptr), - _container(nullptr), - _gridLayout2(nullptr), - _gridLayout3(nullptr), _visible(false), _fileDialogsForImages(true) { @@ -81,7 +77,7 @@ PropertyEditor::PropertyEditor() : void PropertyEditor::create(Viewer& parent) { - ng::Window* parentWindow = parent.getWindow(); + ng::ref parentWindow = parent.getWindow(); // Remove the window associated with the form. // This is done by explicitly creating and owning the window @@ -110,7 +106,7 @@ void PropertyEditor::create(Viewer& parent) _window->set_position(previousPosition); _window->set_visible(_visible); - ng::VScrollPanel* scroll_panel = new ng::VScrollPanel(_window); + ng::ref scroll_panel = new ng::VScrollPanel(_window); scroll_panel->set_fixed_height(300); _container = new ng::Widget(scroll_panel); _container->set_layout(new ng::GroupLayout(1, 1, 1, 1)); @@ -127,7 +123,7 @@ void PropertyEditor::create(Viewer& parent) } void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable) + ng::ref container, Viewer* viewer, bool editable) { const mx::UIProperties& ui = item.ui; mx::ValuePtr value = item.variable->getValue(); @@ -148,9 +144,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!group.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); - ng::Label* groupLabel = new ng::Label(twoColumns, group); + ng::ref groupLabel = new ng::Label(twoColumns, group); groupLabel->set_font_size(20); groupLabel->set_font("sans-bold"); new ng::Label(twoColumns, ""); @@ -187,11 +183,11 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st const size_t valueIndex = indexInEnumeration(); if (INVALID_INDEX != valueIndex) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(static_cast(valueIndex)); @@ -215,7 +211,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st } else { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -252,9 +248,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Float widget else if (value->isA()) { - ng::Widget* threeColumns = new ng::Widget(container); + ng::ref threeColumns = new ng::Widget(container); threeColumns->set_layout(_gridLayout3); - ng::FloatBox* floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) + ng::ref> floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) { mx::MaterialPtr material = viewer->getSelectedMaterial(); if (material) @@ -269,12 +265,12 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Boolean widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); bool v = value->asA(); new ng::Label(twoColumns, label); - ng::CheckBox* boolVar = new ng::CheckBox(twoColumns, ""); + ng::ref boolVar = new ng::CheckBox(twoColumns, ""); boolVar->set_checked(v); boolVar->set_font_size(15); boolVar->set_callback([path, viewer](bool v) @@ -290,7 +286,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color3 input. Can map to a combo box if an enumeration else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); // Determine if there is an enumeration for this @@ -312,7 +308,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Create a combo box. The items are the enumerations in order. if (index >= 0) { - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(index); @@ -353,7 +349,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -376,7 +372,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 2 widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector2 v = value->asA(); @@ -415,7 +411,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 3 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector3 v = value->asA(); @@ -470,7 +466,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector4 v = value->asA(); @@ -542,16 +538,17 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st std::string v = value->asA(); if (!v.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); if (item.variable->getType() == mx::Type::FILENAME) { new ng::Label(twoColumns, label); - ng::Button* buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); + ng::ref buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); buttonVar->set_enabled(editable); buttonVar->set_font_size(15); - buttonVar->set_callback([buttonVar, path, viewer]() + auto buttonVarPtr = buttonVar.get(); + buttonVar->set_callback([buttonVarPtr, path, viewer]() { mx::MaterialPtr material = viewer->getSelectedMaterial(); mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; @@ -572,7 +569,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!filename.empty()) { uniform->setValue(mx::Value::createValue(filename)); - buttonVar->set_caption(mx::FilePath(filename).getBaseName()); + buttonVarPtr->set_caption(mx::FilePath(filename).getBaseName()); viewer->perform_layout(); } } @@ -583,7 +580,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st else { new ng::Label(twoColumns, label); - ng::TextBox* stringVar = new ng::TextBox(twoColumns, v); + ng::ref stringVar = new ng::TextBox(twoColumns, v); stringVar->set_fixed_size({ 100, 20 }); stringVar->set_font_size(15); stringVar->set_callback([path, viewer](const std::string& v) @@ -629,14 +626,12 @@ void PropertyEditor::updateContents(Viewer* viewer) } if (!shaderName.empty() && shaderName != "surface") { - ng::Widget* twoColumns = new ng::Widget(_container); + ng::ref twoColumns = new ng::Widget(_container); twoColumns->set_layout(_gridLayout2); - ng::Widget* threeColumns = new ng::Widget(_container); - threeColumns->set_layout(_gridLayout3); - ng::Label* modelLabel = new ng::Label(twoColumns, "Shading Model"); + ng::ref modelLabel = new ng::Label(twoColumns, "Shading Model"); modelLabel->set_font_size(20); modelLabel->set_font("sans-bold"); - ng::Label* nameLabel = new ng::Label(twoColumns, shaderName); + ng::ref nameLabel = new ng::Label(twoColumns, shaderName); nameLabel->set_font_size(20); } } @@ -688,15 +683,15 @@ void PropertyEditor::updateContents(Viewer* viewer) viewer->perform_layout(); } -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value(value); - ng::FloatBox* box = new ng::FloatBox(parent, value); + ng::ref> box = new ng::FloatBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -734,29 +729,31 @@ ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& la } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value(value); + boxPtr->set_value(value); callback(value); }); - box->set_callback([slider, callback](float value) + box->set_callback([sliderPtr, callback](float value) { - slider->set_value(value); + sliderPtr->set_value(value); callback(value); }); return box; } -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value((float) value); - ng::IntBox* box = new ng::IntBox(parent, value); + ng::ref> box = new ng::IntBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -794,14 +791,16 @@ ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, i } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value((int) value); + boxPtr->set_value((int) value); callback((int) value); }); - box->set_callback([slider, callback](int value) + box->set_callback([sliderPtr, callback](int value) { - slider->set_value((float) value); + sliderPtr->set_value((float) value); callback(value); }); diff --git a/source/MaterialXView/Editor.h b/source/MaterialXView/Editor.h index b1fb4a3ade..b99f1f160c 100644 --- a/source/MaterialXView/Editor.h +++ b/source/MaterialXView/Editor.h @@ -39,7 +39,7 @@ class PropertyEditor } } - ng::Window* getWindow() + ng::ref getWindow() { return _window; } @@ -47,19 +47,19 @@ class PropertyEditor protected: void create(Viewer& parent); void addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable); + ng::ref container, Viewer* viewer, bool editable); - ng::Window* _window; - ng::Widget* _container; - ng::GridLayout* _gridLayout2; - ng::GridLayout* _gridLayout3; + ng::ref _window; + ng::ref _container; + ng::ref _gridLayout2; + ng::ref _gridLayout3; bool _visible; bool _fileDialogsForImages; }; -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback = nullptr); -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback); +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback = nullptr); +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback); #endif // MATERIALXVIEW_EDITOR_H diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index c4c69bb812..46d03a1665 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -158,7 +158,6 @@ Viewer::Viewer(const std::string& materialFilename, const mx::Color3& screenColor) : ng::Screen(ng::Vector2i(screenWidth, screenHeight), "MaterialXView", true, false, true, true, USE_FLOAT_BUFFER, 4, 0), - _window(nullptr), _materialFilename(materialFilename), _meshFilename(meshFilename), _envRadianceFilename(envRadianceFilename), @@ -184,11 +183,7 @@ Viewer::Viewer(const std::string& materialFilename, _shadowSoftness(1), _ambientOcclusionGain(0.6f), _selectedGeom(0), - _geomLabel(nullptr), - _geometrySelectionBox(nullptr), _selectedMaterial(0), - _materialLabel(nullptr), - _materialSelectionBox(nullptr), _identityCamera(mx::Camera::create()), _viewCamera(mx::Camera::create()), _envCamera(mx::Camera::create()), @@ -232,9 +227,6 @@ Viewer::Viewer(const std::string& materialFilename, _bakeHeight(0), _bakeDocumentPerMaterial(false), _frameTiming(false), - _timingLabel(nullptr), - _timingPanel(nullptr), - _timingText(nullptr), _avgFrameTime(0.0) { // Resolve input filenames, taking both the provided search path and @@ -295,11 +287,11 @@ void Viewer::initialize() _imageHandler->setSearchPath(_searchPath); // Initialize user interfaces. - createLoadMeshInterface(_window, "Load Mesh"); - createLoadMaterialsInterface(_window, "Load Material"); - createLoadEnvironmentInterface(_window, "Load Environment"); - createPropertyEditorInterface(_window, "Property Editor"); - createAdvancedSettings(_window); + createLoadMeshInterface((ng::ref) _window, "Load Mesh"); + createLoadMaterialsInterface((ng::ref) _window, "Load Material"); + createLoadEnvironmentInterface((ng::ref) _window, "Load Environment"); + createPropertyEditorInterface((ng::ref) _window, "Property Editor"); + createAdvancedSettings((ng::ref) _window); // Create geometry selection box. _geomLabel = new ng::Label(_window, "Select Geometry"); @@ -562,9 +554,9 @@ mx::ElementPredicate Viewer::getElementPredicate() }; } -void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMeshInterface(ng::ref parent, const std::string& label) { - ng::Button* meshButton = new ng::Button(parent, label); + ng::ref meshButton = new ng::Button(parent, label); meshButton->set_icon(FA_FOLDER); meshButton->set_tooltip("Load a new geometry in the OBJ or glTF format."); meshButton->set_callback([this]() @@ -590,9 +582,9 @@ void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) }); } -void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_FOLDER); materialButton->set_tooltip("Load a material document in the MTLX format."); materialButton->set_callback([this]() @@ -608,9 +600,9 @@ void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& label) +void Viewer::createLoadEnvironmentInterface(ng::ref parent, const std::string& label) { - ng::Button* envButton = new ng::Button(parent, label); + ng::ref envButton = new ng::Button(parent, label); envButton->set_icon(FA_FOLDER); envButton->set_tooltip("Load a lat-long environment light in the HDR format."); envButton->set_callback([this]() @@ -634,9 +626,9 @@ void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& l }); } -void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createSaveMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_SAVE); materialButton->set_tooltip("Save a material document in the MTLX format."); materialButton->set_callback([this]() @@ -664,9 +656,9 @@ void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& label) +void Viewer::createPropertyEditorInterface(ng::ref parent, const std::string& label) { - ng::Button* editorButton = new ng::Button(parent, label); + ng::ref editorButton = new ng::Button(parent, label); editorButton->set_flags(ng::Button::ToggleButton); editorButton->set_tooltip("View or edit properties of the current material."); editorButton->set_change_callback([this](bool state) @@ -676,40 +668,38 @@ void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& la }); } -void Viewer::createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel) +void Viewer::createDocumentationInterface(ng::ref parent) { - ng::GridLayout* documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, - ng::Alignment::Minimum, 13, 5); + ng::ref documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, + ng::Alignment::Minimum, 13, 5); documentationLayout->set_row_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); - ng::Widget* documentationGroup = new ng::Widget(parent); + ng::ref documentationGroup = new ng::Widget(parent); documentationGroup->set_layout(documentationLayout); - ng::Label* documentationLabel = new ng::Label(documentationGroup, "Documentation"); + ng::ref documentationLabel = new ng::Label(documentationGroup, "Documentation"); documentationLabel->set_font_size(20); documentationLabel->set_font("sans-bold"); - ng::Button* shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); - shortcutsButton->set_flags(ng::Button::ToggleButton); - shortcutsButton->set_icon(FA_CARET_RIGHT); - shortcutsButton->set_fixed_width(230); + _shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); + _shortcutsButton->set_flags(ng::Button::ToggleButton); + _shortcutsButton->set_icon(FA_CARET_RIGHT); + _shortcutsButton->set_fixed_width(230); - ng::Widget* shortcutsTable = new ng::Widget(documentationGroup); - shortcutsTable->set_layout(new ng::GroupLayout(13)); - shortcutsTable->set_visible(false); + _shortcutsTable = new ng::Widget(documentationGroup); + _shortcutsTable->set_layout(new ng::GroupLayout(13)); + _shortcutsTable->set_visible(false); - // recompute layout when showing/hiding shortcuts. - shortcutsButton->set_change_callback([this, scrollPanel, shortcutsButton, - shortcutsTable](bool state) + // Recompute layout when showing/hiding shortcuts. + _shortcutsButton->set_change_callback([this](bool state) { - shortcutsTable->set_visible(state); - shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); - scrollPanel->set_scroll(state ? 0.73f : 1.0f); + _shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); + _shortcutsTable->set_visible(state); perform_layout(); }); // 2 cell layout for (key, description) pair. - ng::GridLayout* gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, - ng::Alignment::Minimum, 2, 2); + ng::ref gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, + ng::Alignment::Minimum, 2, 2); gridLayout2->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); const std::vector> KEYBOARD_SHORTCUTS = @@ -741,73 +731,73 @@ void Viewer::createDocumentationInterface(Widget* parent, ng::VScrollPanel* scro for (const auto& shortcut : KEYBOARD_SHORTCUTS) { - ng::Widget* twoColumns = new ng::Widget(shortcutsTable); + ng::ref twoColumns = new ng::Widget(_shortcutsTable); twoColumns->set_layout(gridLayout2); - ng::Label* keyLabel = new ng::Label(twoColumns, shortcut.first); + ng::ref keyLabel = new ng::Label(twoColumns, shortcut.first); keyLabel->set_font("sans-bold"); keyLabel->set_font_size(16); keyLabel->set_fixed_width(40); - ng::Label* descriptionLabel = new ng::Label(twoColumns, shortcut.second); + ng::ref descriptionLabel = new ng::Label(twoColumns, shortcut.second); descriptionLabel->set_font_size(16); descriptionLabel->set_fixed_width(160); } } -void Viewer::createAdvancedSettings(Widget* parent) +void Viewer::createAdvancedSettings(ng::ref parent) { - ng::PopupButton* advancedButton = new ng::PopupButton(parent, "Advanced Settings"); + ng::ref advancedButton = new ng::PopupButton(parent, "Advanced Settings"); advancedButton->set_icon(FA_TOOLS); advancedButton->set_chevron_icon(-1); advancedButton->set_tooltip("Asset and rendering options."); - ng::Popup* advancedPopupParent = advancedButton->popup(); + ng::ref advancedPopupParent = advancedButton->popup(); advancedPopupParent->set_layout(new ng::GroupLayout()); - ng::VScrollPanel* scrollPanel = new ng::VScrollPanel(advancedPopupParent); + ng::ref scrollPanel = new ng::VScrollPanel(advancedPopupParent); scrollPanel->set_fixed_height(500); - ng::Widget* advancedPopup = new ng::Widget(scrollPanel); + ng::ref advancedPopup = new ng::Widget(scrollPanel); advancedPopup->set_layout(new ng::BoxLayout(ng::Orientation::Vertical)); - ng::Widget* settingsGroup = new ng::Widget(advancedPopup); + ng::ref settingsGroup = new ng::Widget(advancedPopup); settingsGroup->set_layout(new ng::GroupLayout(13)); - ng::Label* viewLabel = new ng::Label(settingsGroup, "Viewing Options"); + ng::ref viewLabel = new ng::Label(settingsGroup, "Viewing Options"); viewLabel->set_font_size(20); viewLabel->set_font("sans-bold"); - ng::CheckBox* drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); + ng::ref drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); drawEnvironmentBox->set_checked(_drawEnvironment); drawEnvironmentBox->set_callback([this](bool enable) { _drawEnvironment = enable; }); - ng::CheckBox* outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); + ng::ref outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); outlineSelectedGeometryBox->set_checked(_outlineSelection); outlineSelectedGeometryBox->set_callback([this](bool enable) { _outlineSelection = enable; }); - ng::Label* renderLabel = new ng::Label(settingsGroup, "Render Options"); + ng::ref renderLabel = new ng::Label(settingsGroup, "Render Options"); renderLabel->set_font_size(20); renderLabel->set_font("sans-bold"); - ng::CheckBox* transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); + ng::ref transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); transparencyBox->set_checked(_renderTransparency); transparencyBox->set_callback([this](bool enable) { _renderTransparency = enable; }); - ng::CheckBox* doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); + ng::ref doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); doubleSidedBox->set_checked(_renderDoubleSided); doubleSidedBox->set_callback([this](bool enable) { _renderDoubleSided = enable; }); - ng::CheckBox* importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); + ng::ref importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); importanceSampleBox->set_checked(_genContext.getOptions().hwSpecularEnvironmentMethod == mx::SPECULAR_ENVIRONMENT_FIS); _lightHandler->setUsePrefilteredMap(_genContext.getOptions().hwSpecularEnvironmentMethod != mx::SPECULAR_ENVIRONMENT_FIS); importanceSampleBox->set_callback([this](bool enable) @@ -820,7 +810,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); + ng::ref refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); refractionBox->set_checked(_genContext.getOptions().hwTransmissionRenderMethod == mx::TRANSMISSION_REFRACTION); refractionBox->set_callback([this](bool enable) { @@ -831,14 +821,14 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); + ng::ref refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); refractionSidedBox->set_checked(_lightHandler->getRefractionTwoSided()); refractionSidedBox->set_callback([this](bool enable) { _lightHandler->setRefractionTwoSided(enable); }); - ng::CheckBox* shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); + ng::ref shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); shaderInterfaceBox->set_checked(_genContext.getOptions().shaderInterfaceType == mx::SHADER_INTERFACE_REDUCED); shaderInterfaceBox->set_callback([this](bool enable) { @@ -846,11 +836,11 @@ void Viewer::createAdvancedSettings(Widget* parent) setShaderInterfaceType(interfaceType); }); - Widget* albedoGroup = new Widget(settingsGroup); + ng::ref albedoGroup = new Widget(settingsGroup); albedoGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(albedoGroup, "Albedo Method:"); mx::StringVec albedoOptions = { "Analytic", "Table", "MC" }; - ng::ComboBox* albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); + ng::ref albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); albedoBox->set_chevron_icon(-1); albedoBox->set_selected_index((int) _genContext.getOptions().hwDirectionalAlbedoMethod ); albedoBox->set_callback([this](int index) @@ -877,7 +867,7 @@ void Viewer::createAdvancedSettings(Widget* parent) } }); - Widget* sampleGroup = new Widget(settingsGroup); + ng::ref sampleGroup = new Widget(settingsGroup); sampleGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(sampleGroup, "Environment Samples:"); mx::StringVec sampleOptions; @@ -887,7 +877,7 @@ void Viewer::createAdvancedSettings(Widget* parent) sampleOptions.push_back(std::to_string(i)); m_process_events = true; } - ng::ComboBox* sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); + ng::ref sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); sampleBox->set_chevron_icon(-1); sampleBox->set_selected_index((int)std::log2(_lightHandler->getEnvSampleCount() / MIN_ENV_SAMPLE_COUNT) / 2); sampleBox->set_callback([this](int index) @@ -895,30 +885,30 @@ void Viewer::createAdvancedSettings(Widget* parent) _lightHandler->setEnvSampleCount(MIN_ENV_SAMPLE_COUNT * (int) std::pow(4, index)); }); - ng::Label* lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); + ng::ref lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); lightingLabel->set_font_size(20); lightingLabel->set_font("sans-bold"); - ng::CheckBox* directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); + ng::ref directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); directLightingBox->set_checked(_lightHandler->getDirectLighting()); directLightingBox->set_callback([this](bool enable) { _lightHandler->setDirectLighting(enable); }); - ng::CheckBox* indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); + ng::ref indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); indirectLightingBox->set_checked(_lightHandler->getIndirectLighting()); indirectLightingBox->set_callback([this](bool enable) { _lightHandler->setIndirectLighting(enable); }); - ng::Widget* lightRotationRow = new ng::Widget(settingsGroup); + ng::ref lightRotationRow = new ng::Widget(settingsGroup); lightRotationRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties ui; ui.uiMin = mx::Value::createValue(0.0f); ui.uiMax = mx::Value::createValue(360.0f); - ng::FloatBox* lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", + ng::ref> lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", _lightRotation, &ui, [this](float value) { _lightRotation = value; @@ -926,11 +916,11 @@ void Viewer::createAdvancedSettings(Widget* parent) }); lightRotationBox->set_editable(true); - ng::Label* shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); + ng::ref shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); shadowingLabel->set_font_size(20); shadowingLabel->set_font("sans-bold"); - ng::CheckBox* shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); + ng::ref shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); shadowMapBox->set_checked(_genContext.getOptions().hwShadowMap); shadowMapBox->set_callback([this](bool enable) { @@ -938,7 +928,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); + ng::ref ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); ambientOcclusionBox->set_checked(_genContext.getOptions().hwAmbientOcclusion); ambientOcclusionBox->set_callback([this](bool enable) { @@ -946,23 +936,23 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::Widget* ambientOcclusionGainRow = new ng::Widget(settingsGroup); + ng::ref ambientOcclusionGainRow = new ng::Widget(settingsGroup); ambientOcclusionGainRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", + ng::ref> ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", _ambientOcclusionGain, nullptr, [this](float value) { _ambientOcclusionGain = value; }); ambientOcclusionGainBox->set_editable(true); - ng::Label* sceneLabel = new ng::Label(settingsGroup, "Scene Options"); + ng::ref sceneLabel = new ng::Label(settingsGroup, "Scene Options"); sceneLabel->set_font_size(20); sceneLabel->set_font("sans-bold"); - Widget* unitGroup = new Widget(settingsGroup); + ng::ref unitGroup = new Widget(settingsGroup); unitGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(unitGroup, "Distance Unit:"); - ng::ComboBox* distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); + ng::ref distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); distanceUnitBox->set_fixed_size(ng::Vector2i(100, 20)); distanceUnitBox->set_chevron_icon(-1); if (_distanceUnitConverter) @@ -986,68 +976,68 @@ void Viewer::createAdvancedSettings(Widget* parent) m_process_events = true; }); - ng::Label* meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); + ng::ref meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); meshLoading->set_font_size(20); meshLoading->set_font("sans-bold"); - ng::CheckBox* splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); + ng::ref splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); splitUdimsBox->set_checked(_splitByUdims); splitUdimsBox->set_callback([this](bool enable) { _splitByUdims = enable; }); - ng::Label* materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); + ng::ref materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); materialLoading->set_font_size(20); materialLoading->set_font("sans-bold"); - ng::CheckBox* mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); + ng::ref mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); mergeMaterialsBox->set_checked(_mergeMaterials); mergeMaterialsBox->set_callback([this](bool enable) { _mergeMaterials = enable; }); - ng::CheckBox* showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); + ng::ref showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); showInputsBox->set_checked(_showAllInputs); showInputsBox->set_callback([this](bool enable) { _showAllInputs = enable; }); - ng::CheckBox* flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); + ng::ref flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); flattenBox->set_checked(_flattenSubgraphs); flattenBox->set_callback([this](bool enable) { _flattenSubgraphs = enable; }); - ng::Label* envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); + ng::ref envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); envLoading->set_font_size(20); envLoading->set_font("sans-bold"); - ng::CheckBox* normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); + ng::ref normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); normalizeEnvBox->set_checked(_normalizeEnvironment); normalizeEnvBox->set_callback([this](bool enable) { _normalizeEnvironment = enable; }); - ng::CheckBox* splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); + ng::ref splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); splitDirectLightBox->set_checked(_splitDirectLight); splitDirectLightBox->set_callback([this](bool enable) { _splitDirectLight = enable; }); - ng::Label* translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); + ng::ref translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); translationLabel->set_font_size(20); translationLabel->set_font("sans-bold"); - ng::Widget* targetShaderGroup = new ng::Widget(settingsGroup); + ng::ref targetShaderGroup = new ng::Widget(settingsGroup); targetShaderGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(targetShaderGroup, "Target Shader"); - ng::TextBox* targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); + ng::ref targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); targetShaderBox->set_callback([this](const std::string& choice) { _targetShader = choice; @@ -1056,46 +1046,46 @@ void Viewer::createAdvancedSettings(Widget* parent) targetShaderBox->set_font_size(16); targetShaderBox->set_editable(true); - ng::Label* textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); + ng::ref textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); textureLabel->set_font_size(20); textureLabel->set_font("sans-bold"); - ng::CheckBox* bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); + ng::ref bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); bakeHdrBox->set_checked(_bakeHdr); bakeHdrBox->set_callback([this](bool enable) { _bakeHdr = enable; }); - ng::CheckBox* bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); + ng::ref bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); bakeAverageBox->set_checked(_bakeAverage); bakeAverageBox->set_callback([this](bool enable) { _bakeAverage = enable; }); - ng::CheckBox* bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); + ng::ref bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); bakeOptimized->set_checked(_bakeOptimize); bakeOptimized->set_callback([this](bool enable) { _bakeOptimize = enable; }); - ng::CheckBox* bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); + ng::ref bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); bakeDocumentPerMaterial->set_checked(_bakeDocumentPerMaterial); bakeDocumentPerMaterial->set_callback([this](bool enable) { _bakeDocumentPerMaterial = enable; }); - ng::Label* wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); + ng::ref wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); wedgeLabel->set_font_size(20); wedgeLabel->set_font("sans-bold"); - ng::Widget* wedgeNameGroup = new ng::Widget(settingsGroup); + ng::ref wedgeNameGroup = new ng::Widget(settingsGroup); wedgeNameGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(wedgeNameGroup, "Property Name"); - ng::TextBox* wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); + ng::ref wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); wedgeNameBox->set_callback([this](const std::string& choice) { _wedgePropertyName = choice; @@ -1104,12 +1094,12 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeNameBox->set_font_size(16); wedgeNameBox->set_editable(true); - ng::Widget* wedgeMinGroup = new ng::Widget(settingsGroup); + ng::ref wedgeMinGroup = new ng::Widget(settingsGroup); wedgeMinGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeProp; wedgeProp.uiSoftMin = mx::Value::createValue(0.0f); wedgeProp.uiSoftMax = mx::Value::createValue(1.0f); - ng::FloatBox* wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", + ng::ref> wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMin = value; @@ -1117,9 +1107,9 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMinBox->set_value(0.0); wedgeMinBox->set_editable(true); - ng::Widget* wedgeMaxGroup = new ng::Widget(settingsGroup); + ng::ref wedgeMaxGroup = new ng::Widget(settingsGroup); wedgeMaxGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", + ng::ref> wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMax = value; @@ -1127,13 +1117,13 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMaxBox->set_value(1.0); wedgeMaxBox->set_editable(true); - ng::Widget* wedgeCountGroup = new ng::Widget(settingsGroup); + ng::ref wedgeCountGroup = new ng::Widget(settingsGroup); wedgeCountGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeCountProp; wedgeCountProp.uiMin = mx::Value::createValue(1); wedgeCountProp.uiSoftMax = mx::Value::createValue(8); wedgeCountProp.uiStep = mx::Value::createValue(1); - ng::IntBox* wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", + ng::ref> wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", _wedgeImageCount, &wedgeCountProp, [this](int value) { _wedgeImageCount = value; @@ -1141,7 +1131,7 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeCountBox->set_value(8); wedgeCountBox->set_editable(true); - createDocumentationInterface(advancedPopup, scrollPanel); + createDocumentationInterface(advancedPopup); } void Viewer::updateGeometrySelections() @@ -2441,7 +2431,7 @@ void Viewer::updateCameras() void Viewer::updateDisplayedProperties() { _propertyEditor.updateContents(this); - createSaveMaterialsInterface(_propertyEditor.getWindow(), "Save Material"); + createSaveMaterialsInterface((ng::ref) _propertyEditor.getWindow(), "Save Material"); perform_layout(); } diff --git a/source/MaterialXView/Viewer.h b/source/MaterialXView/Viewer.h index 08712f3c78..8f0257e1e1 100644 --- a/source/MaterialXView/Viewer.h +++ b/source/MaterialXView/Viewer.h @@ -179,7 +179,7 @@ class Viewer : public ng::Screen } // Return the underlying NanoGUI window. - ng::Window* getWindow() const + ng::ref getWindow() const { return _window; } @@ -283,13 +283,13 @@ class Viewer : public ng::Screen void updateMaterialSelectionUI(); void updateDisplayedProperties(); - void createLoadMeshInterface(Widget* parent, const std::string& label); - void createLoadMaterialsInterface(Widget* parent, const std::string& label); - void createLoadEnvironmentInterface(Widget* parent, const std::string& label); - void createSaveMaterialsInterface(Widget* parent, const std::string& label); - void createPropertyEditorInterface(Widget* parent, const std::string& label); - void createAdvancedSettings(Widget* parent); - void createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel); + void createLoadMeshInterface(ng::ref parent, const std::string& label); + void createLoadMaterialsInterface(ng::ref parent, const std::string& label); + void createLoadEnvironmentInterface(ng::ref parent, const std::string& label); + void createSaveMaterialsInterface(ng::ref parent, const std::string& label); + void createPropertyEditorInterface(ng::ref parent, const std::string& label); + void createAdvancedSettings(ng::ref parent); + void createDocumentationInterface(ng::ref parent); // Return the ambient occlusion image, if any, associated with the given material. mx::ImagePtr getAmbientOcclusionImage(mx::MaterialPtr material); @@ -318,7 +318,7 @@ class Viewer : public ng::Screen void setShaderInterfaceType(mx::ShaderInterfaceType interfaceType); private: - ng::Window* _window; + ng::ref _window; RenderPipelinePtr _renderPipeline; mx::FilePath _materialFilename; @@ -380,15 +380,15 @@ class Viewer : public ng::Screen // Geometry selections std::vector _geometryList; size_t _selectedGeom; - ng::Label* _geomLabel; - ng::ComboBox* _geometrySelectionBox; + ng::ref _geomLabel; + ng::ref _geometrySelectionBox; // Material selections std::vector _materials; mx::MaterialPtr _wireMaterial; size_t _selectedMaterial; - ng::Label* _materialLabel; - ng::ComboBox* _materialSelectionBox; + ng::ref _materialLabel; + ng::ref _materialSelectionBox; PropertyEditor _propertyEditor; // Material assignments @@ -475,11 +475,15 @@ class Viewer : public ng::Screen // Frame timing bool _frameTiming; - ng::Label* _timingLabel; - ng::Widget* _timingPanel; - ng::TextBox* _timingText; + ng::ref _timingLabel; + ng::ref _timingPanel; + ng::ref _timingText; mx::ScopedTimer _frameTimer; double _avgFrameTime; + + // Documentation UI + ng::ref _shortcutsButton; + ng::ref _shortcutsTable; }; extern const mx::Vector3 DEFAULT_CAMERA_POSITION; From bef88b9f528cff361ecfcd2c52afb3359836aeb7 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 2 Nov 2024 14:59:16 -0700 Subject: [PATCH 08/20] Extend Chiang tests across languages (#2104) This changelist extends testing of Chiang Hair BSDF nodes across shading languages, allowing render comparisons to include the complete Examples and TestSuite folders. In order to avoid shader compilation errors, placeholder OSL implementations of these nodes have been added, and these should be replaced with accurate implementations once they are supported. --- libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl | 7 +++++++ libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx | 12 ++++++++++++ .../bsdf/{hair_bsdf.mtlx => chiang_hair_bsdf.mtlx} | 0 ...aceshader.mtlx => chiang_hair_surfaceshader.mtlx} | 0 source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp | 7 +------ source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 2 -- source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 6 +----- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 2 -- 8 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl rename resources/Materials/TestSuite/pbrlib/bsdf/{hair_bsdf.mtlx => chiang_hair_bsdf.mtlx} (100%) rename resources/Materials/TestSuite/pbrlib/surfaceshader/{hair_surfaceshader.mtlx => chiang_hair_surfaceshader.mtlx} (100%) diff --git a/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl new file mode 100644 index 0000000000..002bdc3044 --- /dev/null +++ b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl @@ -0,0 +1,7 @@ +void mx_chiang_hair_roughness(float longitudinal, float azimuthal, float scale_TT, float scale_TRT, output vector2 roughness_R, output vector2 roughness_TT, output vector2 roughness_TRT) +{ + // TODO: Write OSL implementation of this node. + roughness_R = vector2(0.0, 0.0); + roughness_TT = vector2(0.0, 0.0); + roughness_TRT = vector2(0.0, 0.0); +} diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx index d3849a5ddb..beac984518 100644 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx +++ b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx @@ -22,6 +22,9 @@ + + + @@ -71,4 +74,13 @@ + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx similarity index 100% rename from resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx rename to resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx similarity index 100% rename from resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx rename to resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp index 414bc3dd5d..b0309ea44d 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp @@ -84,12 +84,7 @@ TEST_CASE("GenShader: MSL Implementation Check", "[genmsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); - generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); - generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); - generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 34); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 30); } TEST_CASE("GenShader: MSL Unique Names", "[genmsl]") diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h index 692c283fda..7c96279d8b 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h @@ -43,8 +43,6 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester void addSkipFiles() override { - _skipFiles.insert("hair_bsdf.mtlx"); - _skipFiles.insert("hair_surfaceshader.mtlx"); } void setupDependentLibraries() override diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp index c89f9ab19d..612d134753 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp @@ -89,12 +89,8 @@ TEST_CASE("GenShader: OSL Implementation Check", "[genosl]") generatorSkipNodeTypes.insert("light"); mx::StringSet generatorSkipNodeDefs; - generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); - generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); - generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); - generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 35); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31); } TEST_CASE("GenShader: OSL Unique Names", "[genosl]") diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h index f02f750d26..959c12d48b 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h @@ -45,8 +45,6 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester void addSkipFiles() override { - _skipFiles.insert("hair_bsdf.mtlx"); - _skipFiles.insert("hair_surfaceshader.mtlx"); } // Ignore light shaders in the document for OSL From 20383ae3e721d93b6dce981b09475c4e2e524989 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 13 Nov 2024 17:05:33 -0800 Subject: [PATCH 09/20] Update deprecated Xcode in CI (#2114) This changelist updates a deprecated version of Xcode in our GitHub CI. --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c11603dd70..b2d5f182bf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,10 +68,10 @@ jobs: cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON python: 3.9 - - name: MacOS_Xcode_14_Python311 + - name: MacOS_Xcode_15_Python311 os: macos-14 compiler: xcode - compiler_version: "14.3" + compiler_version: "15.1" python: 3.11 static_analysis: ON cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON From 65dbd3937db8093011b825e9e5bf0b9ae9757abf Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Thu, 14 Nov 2024 10:31:09 -0500 Subject: [PATCH 10/20] Skip comments in functional equivalence tests (#2110) Skip `comment` blocks when checking for functional equivalency as they should not affect the comparison. --- source/MaterialXCore/Element.cpp | 22 ++++++++++++++++--- .../MaterialXTest/MaterialXCore/Document.cpp | 8 +++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 648d7df000..043d6f4092 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -426,9 +426,25 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& } } - // Compare children. - const vector& children = getChildren(); - const vector& rhsChildren = rhs->getChildren(); + // Compare all child elements that affect functional equivalence. + vector children; + for (ElementPtr child : getChildren()) + { + if (child->getCategory() == CommentElement::CATEGORY) + { + continue; + } + children.push_back(child); + } + vector rhsChildren; + for (ElementPtr child : rhs->getChildren()) + { + if (child->getCategory() == CommentElement::CATEGORY) + { + continue; + } + rhsChildren.push_back(child); + } if (children.size() != rhsChildren.size()) { if (results) diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index ae7623084e..f3a207fc84 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -150,6 +150,9 @@ TEST_CASE("Document equivalence", "[document]") unsigned int index = 0; mx::ElementPtr child = doc->addNodeGraph("mygraph"); mx::NodeGraphPtr graph = child->asA(); + // Add comment block at the start of the first doc to check skipping + mx::ElementPtr comment = doc->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 1"); for (auto it = inputMap.begin(); it != inputMap.end(); ++it) { const std::string inputType = (*it).first; @@ -205,6 +208,11 @@ TEST_CASE("Document equivalence", "[document]") input->setName("input_" + inputType); } } + // Add comment blocks at end of second doc to check value and count checks + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 2"); + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 3"); mx::ElementEquivalenceOptions options; mx::ElementEquivalenceResultVec results; From a368aac8ccc4f8cf7a9d1d5189826b040eced893 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Sat, 16 Nov 2024 18:27:38 -0500 Subject: [PATCH 11/20] Cleanup options for equivalence testing (#2115) User facing naming changes for the functional equivalence API. There are no logic changes. --- source/MaterialXCore/Element.cpp | 12 +++--- source/MaterialXCore/Element.h | 37 +++++++++---------- .../MaterialXTest/MaterialXCore/Document.cpp | 12 +++--- .../PyMaterialX/PyMaterialXCore/PyElement.cpp | 8 ++-- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 043d6f4092..3bede2fe74 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -396,14 +396,14 @@ bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& StringVec rhsAttributeNames = rhs->getAttributeNames(); // Filter out any attributes specified in the options. - const StringSet& skipAttributes = options.skipAttributes; - if (!skipAttributes.empty()) + const StringSet& attributeExclusionList = options.attributeExclusionList; + if (!attributeExclusionList.empty()) { attributeNames.erase(std::remove_if(attributeNames.begin(), attributeNames.end(), - [&skipAttributes](const string& attr) { return skipAttributes.find(attr) != skipAttributes.end(); }), + [&attributeExclusionList](const string& attr) { return attributeExclusionList.find(attr) != attributeExclusionList.end(); }), attributeNames.end()); rhsAttributeNames.erase(std::remove_if(rhsAttributeNames.begin(), rhsAttributeNames.end(), - [&skipAttributes](const string& attr) { return skipAttributes.find(attr) != skipAttributes.end(); }), + [&attributeExclusionList](const string& attr) { return attributeExclusionList.find(attr) != attributeExclusionList.end(); }), rhsAttributeNames.end()); } @@ -714,7 +714,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr { // Perform value comparisons bool performedValueComparison = false; - if (!options.skipValueComparisons) + if (options.performValueComparisons) { const StringSet uiAttributes = { @@ -724,7 +724,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr }; // Get precision and format options - ScopedFloatFormatting fmt(options.format, options.precision); + ScopedFloatFormatting fmt(options.floatFormat, options.floatPrecision); ConstValueElementPtr rhsValueElement = rhs->asA(); diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index fb4bbe07ce..05eb2235f3 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -1389,34 +1389,33 @@ class MX_CORE_API ElementEquivalenceOptions public: ElementEquivalenceOptions() { - format = Value::getFloatFormat(); - precision = Value::getFloatPrecision(); - skipAttributes = {}; - skipValueComparisons = false; + performValueComparisons = true; + floatFormat = Value::getFloatFormat(); + floatPrecision = Value::getFloatPrecision(); + attributeExclusionList = {}; }; ~ElementEquivalenceOptions() { } - /// Floating point format option for floating point value comparisons - Value::FloatFormat format; + /// Perform value comparisons as opposed to literal string comparisons. + /// Default is true. + bool performValueComparisons; - /// Floating point precision option for floating point value comparisons - int precision; + /// Floating point format to use for floating point value comparisons + Value::FloatFormat floatFormat; - /// Attribute filtering options. By default all attributes are considered. - /// Name, category attributes cannot be skipped. + /// Floating point precision to use for floating point value comparisons + int floatPrecision; + + /// Specifies the set of attributes that should be excluded when performing a comparison. + /// By default all attributes are considered. Name and category attributes cannot be excluded. /// - /// For example UI attribute comparision be skipped by setting: - /// skipAttributes = { + /// For example, to exclude UI and documentation attributes from consideration the follow may be set: + /// attributeExclusionList = { /// ValueElement::UI_MIN_ATTRIBUTE, ValueElement::UI_MAX_ATTRIBUTE, /// ValueElement::UI_SOFT_MIN_ATTRIBUTE, ValueElement::UI_SOFT_MAX_ATTRIBUTE, /// ValueElement::UI_STEP_ATTRIBUTE, Element::XPOS_ATTRIBUTE, - /// Element::YPOS_ATTRIBUTE }; - StringSet skipAttributes; - - /// Do not perform any value comparisions. Instead perform exact string comparisons for attributes - /// Default is false. The operator==() method can be used instead as it always performs - /// a strict comparison. Default is false. - bool skipValueComparisons; + /// Element::YPOS_ATTRIBUTE, Element::DOC_ATTRIBUTE }; + StringSet attributeExclusionList; }; /// @class ExceptionOrphanedElement diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index f3a207fc84..b593969ccb 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -217,27 +217,27 @@ TEST_CASE("Document equivalence", "[document]") mx::ElementEquivalenceOptions options; mx::ElementEquivalenceResultVec results; - // Check skipping all value compares - options.skipValueComparisons = true; + // Check that this fails when not performing value comparisons + options.performValueComparisons = false; bool equivalent = doc->isEquivalent(doc2, options, &results); REQUIRE(!equivalent); // Check attibute values - options.skipValueComparisons = false; + options.performValueComparisons = true; results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); REQUIRE(equivalent); unsigned int currentPrecision = mx::Value::getFloatPrecision(); // This will compare 0.012345608 versus: 1, 0.012345611 for input10 - options.precision = 8; + options.floatPrecision = 8; equivalent = doc->isEquivalent(doc2, options); REQUIRE(!equivalent); - options.precision = currentPrecision; + options.floatPrecision = currentPrecision; // Check attribute filtering of inputs results.clear(); - options.skipAttributes = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; + options.attributeExclusionList = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; for (mx::InputPtr floatInput : floatInputs) { floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, "0.9"); diff --git a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp index cb70d04704..004fa0a670 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp @@ -224,10 +224,10 @@ void bindPyElement(py::module& mod) .def_readwrite("attributeName", &mx::ElementEquivalenceResult::attributeName); py::class_(mod, "ElementEquivalenceOptions") - .def_readwrite("format", &mx::ElementEquivalenceOptions::format) - .def_readwrite("precision", &mx::ElementEquivalenceOptions::precision) - .def_readwrite("skipAttributes", &mx::ElementEquivalenceOptions::skipAttributes) - .def_readwrite("skipValueComparisons", &mx::ElementEquivalenceOptions::skipValueComparisons) + .def_readwrite("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) + .def_readwrite("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) + .def_readwrite("floatPrecision", &mx::ElementEquivalenceOptions::floatPrecision) + .def_readwrite("attributeExclusionList", &mx::ElementEquivalenceOptions::attributeExclusionList) .def(py::init<>()); py::class_(mod, "StringResolver") From a3a7744f3e7a290b4d029ea60452f4bab8a9496f Mon Sep 17 00:00:00 2001 From: krohmerNV <42233792+krohmerNV@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:48:00 +0100 Subject: [PATCH 12/20] MDL 1.9 updates (#2102) add new version to GenMDL and remove uniform restriction from material IOR Minor updates: - improve MDL printing by adding named parameters - handle 1-element mixes (basically scale) above layers - improve blur and height to normal to return something meaningful (before totally broken) - improve non-material outputs that can be rendered, e.g. float3x3 and float4x4 - preparations for MDL 1.10 - remove shader parameters from the public MDL material interface. backsurfaceshader and displacementshader showed up with default values only after recent upstream changes --- .../pbrlib/genmdl/pbrlib_genmdl_impl.mtlx | 6 +- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 2 +- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 89 +++- source/MaterialXGenMdl/MdlShaderGenerator.h | 9 +- .../Nodes/ClosureLayerNodeMdl.cpp | 45 ++ .../Nodes/ClosureLayerNodeMdl.h | 7 + .../MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp | 13 +- .../MaterialXGenMdl/mdl/materialx/pbrlib.mdl | 10 +- .../mdl/materialx/pbrlib_1_6.mdl | 34 +- .../mdl/materialx/pbrlib_1_9.mdl | 372 +++++++++++++++++ .../mdl/materialx/sampling.mdl | 19 +- .../MaterialXGenMdl/mdl/materialx/stdlib.mdl | 10 +- .../mdl/materialx/stdlib_1_9.mdl | 387 ++++++++++++++++++ .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 22 +- 14 files changed, 961 insertions(+), 64 deletions(-) create mode 100644 source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl create mode 100644 source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index c8f23958ae..45f83f164a 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -2,7 +2,7 @@ - + @@ -11,13 +11,13 @@ - + - + diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index 51566463aa..b190937c41 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -695,7 +695,7 @@ - + diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index 76cd7587fd..71db0d7cf4 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -52,9 +52,11 @@ const string IMPORT_ALL = " import *"; const string MDL_VERSION_1_6 = "1.6"; const string MDL_VERSION_1_7 = "1.7"; const string MDL_VERSION_1_8 = "1.8"; +const string MDL_VERSION_1_9 = "1.9"; const string MDL_VERSION_SUFFIX_1_6 = "1_6"; const string MDL_VERSION_SUFFIX_1_7 = "1_7"; const string MDL_VERSION_SUFFIX_1_8 = "1_8"; +const string MDL_VERSION_SUFFIX_1_9 = "1_9"; } // anonymous namespace @@ -191,6 +193,27 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G emitLineBreak(stage); } + // Emit shader inputs that have been filtered during printing of the public interface + const string uniformPrefix = _syntax->getUniformQualifier() + " "; + for (ShaderGraphInputSocket* inputSocket : graph.getInputSockets()) + { + if (inputSocket->getConnections().size() && + (inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL)) + { + const string& qualifier = inputSocket->isUniform() || inputSocket->getType() == Type::FILENAME + ? uniformPrefix + : EMPTY_STRING; + const string& type = _syntax->getTypeName(inputSocket->getType()); + + emitLineBegin(stage); + emitString(qualifier + type + " " + inputSocket->getVariable() + " = ", stage); + emitString(_syntax->getDefaultValue(inputSocket->getType(), true), stage); + emitLineEnd(stage, true); + } + } + // Emit all texturing nodes. These are inputs to any // closure/shader nodes and need to be emitted first. emitFunctionCalls(graph, context, stage, ShaderNode::Classification::TEXTURE); @@ -215,6 +238,7 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G const string result = getUpstreamResult(outputSocket, context); const TypeDesc outputType = outputSocket->getType(); + // Try to return some meaningful color in case the output is not a material if (graph.hasClassification(ShaderNode::Classification::TEXTURE)) { if (outputType == Type::DISPLACEMENTSHADER) @@ -229,7 +253,25 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G else { emitLine("float3 displacement__ = float3(0.0)", stage); - emitLine("color finalOutput__ = mk_color3(" + result + ")", stage); + std::string finalOutput = "mk_color3(0.0)"; + if (outputType == Type::BOOLEAN) + finalOutput = result + " ? mk_color3(0.0, 1.0, 0.0) : mk_color3(1.0, 0.0, 0.0)"; + else if (outputType == Type::INTEGER) + finalOutput = "mk_color3(" + result + " / 100)"; // arbitrary + else if (outputType == Type::FLOAT) + finalOutput = "mk_color3(" + result + ")"; + else if (outputType == Type::VECTOR2) + finalOutput = "mk_color3(" + result + ".x, " + result + ".y, 0.0)"; + else if (outputType == Type::VECTOR3) + finalOutput = "mk_color3(" + result + ")"; + else if (outputType == Type::COLOR3) + finalOutput = result; + else if (outputType == Type::COLOR4) + finalOutput = result + ".rgb"; + else if (outputType == Type::MATRIX33 || outputType == Type::MATRIX44) + finalOutput = "mk_color3(" + result + "[0][0], " + result + "[1][1], " + result + "[2][2])"; + + emitLine("color finalOutput__ = " + finalOutput, stage); } // End shader body @@ -527,6 +569,13 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen // and are editable by users. if (inputSocket->getConnections().size() && graph->isEditable(*inputSocket)) { + if (inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL) + { + continue; + } + inputs->add(inputSocket->getSelf()); } } @@ -537,7 +586,7 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen outputs->add(outputSocket->getSelf()); } - // MDL does not allow varying data connected to transmission IOR. + // MDL does not allow varying data connected to transmission IOR until MDL 1.9. // We must find all uses of transmission IOR and make sure we don't // have a varying connection to it. If a varying connection is found // we break that connection and revert to using default value on that @@ -552,8 +601,14 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen // this fix will disconnect the transmission IOR on the inside, but // still support the connection to reflection IOR. // - if (graph->hasClassification(ShaderNode::Classification::SHADER) || - graph->hasClassification(ShaderNode::Classification::CLOSURE)) + GenMdlOptions::MdlVersion version = getMdlVersion(context); + bool uniformIorRequired = + version == GenMdlOptions::MdlVersion::MDL_1_6 || + version == GenMdlOptions::MdlVersion::MDL_1_7 || + version == GenMdlOptions::MdlVersion::MDL_1_8; + if (uniformIorRequired && ( + graph->hasClassification(ShaderNode::Classification::SHADER) || + graph->hasClassification(ShaderNode::Classification::CLOSURE))) { // Find dependencies on transmission IOR. std::set graphsWithIorDependency; @@ -641,10 +696,15 @@ void MdlShaderGenerator::emitShaderInputs(const DocumentPtr doc, const VariableB } } -void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const +GenMdlOptions::MdlVersion MdlShaderGenerator::getMdlVersion(GenContext& context) const { GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); - GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; + return options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; +} + +void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const +{ + GenMdlOptions::MdlVersion version = getMdlVersion(context); emitLineBegin(stage); emitString("mdl ", stage); @@ -656,19 +716,22 @@ void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& case GenMdlOptions::MdlVersion::MDL_1_7: emitString(MDL_VERSION_1_7, stage); break; + case GenMdlOptions::MdlVersion::MDL_1_8: + emitString(MDL_VERSION_1_8, stage); + break; default: - // GenMdlOptions::MdlVersion::MDL_1_8 + // GenMdlOptions::MdlVersion::MDL_1_9 // GenMdlOptions::MdlVersion::MDL_LATEST - emitString(MDL_VERSION_1_8, stage); + emitString(MDL_VERSION_1_9, stage); break; } emitLineEnd(stage, true); } + const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& context) const { - GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); - GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; + GenMdlOptions::MdlVersion version = getMdlVersion(context); switch (version) { @@ -676,10 +739,12 @@ const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& contex return MDL_VERSION_SUFFIX_1_6; case GenMdlOptions::MdlVersion::MDL_1_7: return MDL_VERSION_SUFFIX_1_7; + case GenMdlOptions::MdlVersion::MDL_1_8: + return MDL_VERSION_SUFFIX_1_8; default: - // GenMdlOptions::MdlVersion::MDL_1_8 + // GenMdlOptions::MdlVersion::MDL_1_9 // GenMdlOptions::MdlVersion::MDL_LATEST - return MDL_VERSION_SUFFIX_1_8; + return MDL_VERSION_SUFFIX_1_9; } } diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.h b/source/MaterialXGenMdl/MdlShaderGenerator.h index 3a24bcf87d..ef88fbc453 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.h +++ b/source/MaterialXGenMdl/MdlShaderGenerator.h @@ -25,7 +25,8 @@ class MX_GENMDL_API GenMdlOptions : public GenUserData MDL_1_6, MDL_1_7, MDL_1_8, - MDL_LATEST = MDL_1_8 + MDL_1_9, + MDL_LATEST = MDL_1_9 }; /// Create MDL code generator options with default values. @@ -76,7 +77,11 @@ class MX_GENMDL_API MdlShaderGenerator : public ShaderGenerator /// Map of code snippets for geomprops in MDL. static const std::unordered_map GEOMPROP_DEFINITIONS; - /// Add the MDL file header containing the version number of the generated module.. + /// Get the selected MDL target language version number from the context option. + /// If not set, the latest version supported by GenMdl is returned. + GenMdlOptions::MdlVersion getMdlVersion(GenContext& context) const; + + /// Add the MDL file header containing the version number of the generated module. void emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const; /// Add the version number suffix appended to MDL modules that use versions. diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index e3484b0171..8949ae6cc0 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -16,6 +16,10 @@ MATERIALX_NAMESPACE_BEGIN const string StringConstantsMdl::TOP = "top"; const string StringConstantsMdl::BASE = "base"; +const string StringConstantsMdl::FG = "fg"; +const string StringConstantsMdl::BG = "bg"; +const string StringConstantsMdl::MIX = "mix"; +const string StringConstantsMdl::TOP_WEIGHT = "top_weight"; ShaderNodeImplPtr ClosureLayerNodeMdl::create() { @@ -101,6 +105,7 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // Transport the base bsdf further than one layer ShaderNode* baseReceiverNode = top; + ShaderNode* mixTopWeightNode = nullptr; while (true) { // If the top node is again a layer, we don't want to override the base @@ -111,6 +116,26 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& } else { + // TODO is there a more efficient way to check if the node is a mix_bsdf? + std::string name = top->getImplementation().getName(); + if (name == "IM_mix_bsdf_genmdl") + { + // handle one special case: the top node is a mix where either fg or bg is empty + // so basically a scale factor + ShaderOutput* fgOutput = top->getInput(StringConstantsMdl::FG)->getConnection(); + ShaderOutput* bgOutput = top->getInput(StringConstantsMdl::BG)->getConnection(); + ShaderOutput* mixOutput = top->getInput(StringConstantsMdl::MIX)->getConnection(); + ShaderNode* fg = fgOutput ? fgOutput->getNode() : nullptr; + ShaderNode* bg = bgOutput ? bgOutput->getNode() : nullptr; + ShaderNode* mix = mixOutput ? mixOutput->getNode() : nullptr; + if ((fg && !bg) || (!fg && bg)) + { + baseReceiverNode = fg ? fg : bg; // take the node that is valid + top = baseReceiverNode; + mixTopWeightNode = mix; + } + break; + } // we stop at elemental bsdfs // TODO handle mix, add, and multiply break; @@ -150,6 +175,11 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // base BSDF connection and output variable name from the // layer operator itself. topNodeBaseInput->makeConnection(base->getOutput()); + if (mixTopWeightNode) + { + ShaderInput* topNodeTopWeightInput = baseReceiverNode->getInput(StringConstantsMdl::TOP_WEIGHT); + topNodeTopWeightInput->makeConnection(mixTopWeightNode->getOutput()); + } ScopedSetVariableName setVariable(output->getVariable(), top->getOutput()); // Make the call. @@ -171,6 +201,21 @@ void LayerableNodeMdl::addInputs(ShaderNode& node, GenContext& /*context*/) cons { // Add the input to hold base layer BSDF. node.addInput(StringConstantsMdl::BASE, Type::BSDF); + + // Set the top level weight default to 1.0 + ShaderInput* topWeightNode = node.addInput(StringConstantsMdl::TOP_WEIGHT, Type::FLOAT); + ValuePtr value = TypedValue::createValue(1.0f); + topWeightNode->setValue(value); +} + +bool LayerableNodeMdl::isEditable(const ShaderInput& input) const +{ + if (input.getName() == StringConstantsMdl::BASE || + input.getName() == StringConstantsMdl::TOP_WEIGHT) + { + return false; + } + return BASE::isEditable(input); } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h index bced5cfac1..8b6f987287 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h @@ -23,6 +23,10 @@ class MX_GENMDL_API StringConstantsMdl /// String constants static const string TOP; ///< layer parameter name of the top component static const string BASE; ///< layer parameter name of the base component + static const string FG; ///< mix parameter name of the foreground + static const string BG; ///< mix parameter name of the background + static const string MIX; ///< mix parameter name of the amount + static const string TOP_WEIGHT; ///< mix amount forwarded into layer top component }; /// Closure layer node implementation for MDL. @@ -40,11 +44,14 @@ class MX_GENMDL_API ClosureLayerNodeMdl : public ShaderNodeImpl /// Note, not all elemental bsdfs support this kind of transformation. class MX_GENMDL_API LayerableNodeMdl : public SourceCodeNodeMdl { + using BASE = SourceCodeNodeMdl; + public: virtual ~LayerableNodeMdl() = default; static ShaderNodeImplPtr create(); void addInputs(ShaderNode& node, GenContext&) const override; + bool isEditable(const ShaderInput& input) const override; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp index 6477cd9ae8..dd0444d129 100644 --- a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp @@ -59,12 +59,17 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex // Emit calls for the closure dependencies upstream from this node. shadergen.emitDependentFunctionCalls(node, context, stage, ShaderNode::Classification::CLOSURE); - // Check if transmission IOR is used for this shader. + // Check if transmission IOR is used for this shader for MDL versions before 1.9. // MDL only supports a single transmission IOR per material and // it is given as an input on the 'material' constructor. // So if used we must forward this value/connection to the surface // constructor. It's set as an extra input below. - const ShaderInput* ior = findTransmissionIOR(node); + GenMdlOptions::MdlVersion version = shadergen.getMdlVersion(context); + bool uniformIorRequired = + version == GenMdlOptions::MdlVersion::MDL_1_6 || + version == GenMdlOptions::MdlVersion::MDL_1_7 || + version == GenMdlOptions::MdlVersion::MDL_1_8; + const ShaderInput* ior = uniformIorRequired ? findTransmissionIOR(node) : nullptr; shadergen.emitLineBegin(stage); @@ -79,6 +84,9 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex for (ShaderInput* input : node.getInputs()) { shadergen.emitString(delim, stage); + shadergen.emitString("mxp_", stage); + shadergen.emitString(input->getName(), stage); + shadergen.emitString(": ", stage); shadergen.emitInput(input, context, stage); delim = ", "; } @@ -87,6 +95,7 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex { // Emit the extra input for transmission IOR. shadergen.emitString(delim, stage); + shadergen.emitString("mxp_transmission_ior: ", stage); shadergen.emitInput(ior, context, stage); } diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl index 0c11ce3744..789b4cfa77 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl @@ -16,15 +16,15 @@ // MDL implementation of all types and nodes of // MaterialX Physically-Based Shading Nodes -// Document v1.37 REV2, July 16, 2019 (Revised October 17, 2019) +// Document version 1.39, June 29, 2024 // see www.materialx.org // in -// NVIDIA Material Definition Language 1.8 +// NVIDIA Material Definition Language 1.9 // Language Specification -// Document version 1.8.2, May 24, 2023 +// Document version 1.9.2, September 16, 2024 // www.nvidia.com/mdl -mdl 1.8; +mdl 1.9; // forward the latest version -export using .::pbrlib_1_8 import *; +export using .::pbrlib_1_9 import *; diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl index e70f849920..64102d6c27 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl @@ -82,7 +82,8 @@ export material mx_oren_nayar_diffuse_bsdf( float mxp_weight = 1.0, color mxp_color = color(0.18), float mxp_roughness = 0.0, - float3 mxp_normal = state::normal() + float3 mxp_normal = state::normal(), + uniform bool mxp_energy_compensation = false [[ anno::unused() ]] // MDL 1.10 ) [[ anno::usage( "materialx:bsdf") ]] @@ -152,7 +153,8 @@ export material mx_dielectric_bsdf( float3 mxp_tangent = state::texture_tangent_u(0), uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, - material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix float mxp_thinfilm_thickness = 0.0, float mxp_thinfilm_ior = 1.0 ) [[ @@ -174,8 +176,8 @@ export material mx_dielectric_bsdf( layer: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect), base: mxp_base.surface.scattering, @@ -186,8 +188,8 @@ export material mx_dielectric_bsdf( layer: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_transmit), normal: mxp_normal); @@ -200,8 +202,8 @@ export material mx_dielectric_bsdf( base: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect_transmit)), normal: mxp_normal); @@ -258,12 +260,13 @@ export material mx_conductor_bsdf( ) ); -// TODO MDL 1.8 +// MDL 1.8 // * will add support for thin film above a color_custom_curve_layer node until then, thin_film will have no effect // * thin_film(thickness: 0.0, ior: < 1.0) will be handled properly export material mx_generalized_schlick_bsdf( float mxp_weight = 1.0, color mxp_color0 = color(1.0), + color mxp_color82 = color(1.0), // MDL 1.10 color mxp_color90 = color(1.0), float mxp_exponent = 5.0, float2 mxp_roughness = float2(0.05), @@ -271,7 +274,8 @@ export material mx_generalized_schlick_bsdf( float3 mxp_tangent = state::texture_tangent_u(0), uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, - material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix float mxp_thinfilm_thickness = 0.0, float mxp_thinfilm_ior = 1.0 ) [[ @@ -283,8 +287,8 @@ export material mx_generalized_schlick_bsdf( bsdf ggx_model_R = df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: color(1.0), - multiscatter_tint: color(1.0), + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect); @@ -302,7 +306,7 @@ export material mx_generalized_schlick_bsdf( layer: mxp_scatter_mode == mx_scatter_mode_T ? df::color_custom_curve_layer( normal_reflectivity: mxp_color0, - grazing_reflectivity: mxp_color90, + grazing_reflectivity: mxp_color82 * mxp_color90, exponent: mxp_exponent, layer: bsdf(), base: ggx_model_T, @@ -312,7 +316,7 @@ export material mx_generalized_schlick_bsdf( ior: color(coatIor), base: df::color_custom_curve_layer( normal_reflectivity: mxp_color0, - grazing_reflectivity: mxp_color90, + grazing_reflectivity: mxp_color82 * mxp_color90, exponent: mxp_exponent, layer: ggx_model_R, base: mxp_scatter_mode == mx_scatter_mode_R @@ -440,7 +444,7 @@ export material mx_chiang_hair_bsdf( float mxp_cuticle_angle = 0.5, float3 mxp_absorption_coefficient = float3(0.0), // TODO: MDL's chiang_hair BSDF has no support user tangent vector - float3 mxp_curve_direction = state::texture_tangent_u(0) + float3 mxp_curve_direction = state::texture_tangent_u(0) [[ anno::unused() ]] ) [[ anno::usage( "materialx:bsdf") ]] diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl new file mode 100644 index 0000000000..e8654380d3 --- /dev/null +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// MDL implementation of all types and nodes of +// MaterialX Physically-Based Shading Nodes +// Document version 1.39, June 29, 2024 +// see www.materialx.org +// in +// NVIDIA Material Definition Language 1.9 +// Language Specification +// Document version 1.9.2, September 16, 2024 +// www.nvidia.com/mdl + +mdl 1.9; + +import ::anno::*; +import ::df::*; +import ::math::*; +import ::state::*; + +import .::core::*; + +// Changes since MDL 1.8 +// - lift the restriction of uniform IORs + +// forward unchanged definitions from the previous versions +export using .::pbrlib_1_6 import mx_scatter_mode; +export using .::pbrlib_1_6 import mx_map_scatter_mode; +export using .::pbrlib_1_6 import mx_oren_nayar_diffuse_bsdf; +export using .::pbrlib_1_6 import mx_burley_diffuse_bsdf; +export using .::pbrlib_1_6 import mx_translucent_bsdf; +export using .::pbrlib_1_6 import mx_subsurface_bsdf; +export using .::pbrlib_1_6 import mx_thin_film_bsdf; +export using .::pbrlib_1_6 import mx_chiang_hair_bsdf; +export using .::pbrlib_1_6 import mx_uniform_edf; +export using .::pbrlib_1_6 import mx_conical_edf; +export using .::pbrlib_1_6 import mx_measured_edf; +export using .::pbrlib_1_6 import mx_absorption_vdf; +export using .::pbrlib_1_6 import mx_anisotropic_vdf; +export using .::pbrlib_1_6 import mx_light; +export using .::pbrlib_1_6 import mx_displacement_float; +export using .::pbrlib_1_6 import mx_displacement_vector3; +export using .::pbrlib_1_6 import volume_mix_return; +export using .::pbrlib_1_6 import volume_mix; +export using .::pbrlib_1_6 import mx_multiply_bsdf_color3; +export using .::pbrlib_1_6 import mx_multiply_bsdf_float; +export using .::pbrlib_1_6 import mx_multiply_edf_color3; +export using .::pbrlib_1_6 import mx_multiply_edf_float; +export using .::pbrlib_1_6 import mx_multiply_vdf_color3; +export using .::pbrlib_1_6 import mx_multiply_vdf_float; +export using .::pbrlib_1_6 import mx_roughness_anisotropy; +export using .::pbrlib_1_6 import mx_roughness_dual; +export using .::pbrlib_1_6 import mx_blackbody; +export using .::pbrlib_1_6 import mx_artistic_ior__result; +export using .::pbrlib_1_6 import mx_artistic_ior; +export using .::pbrlib_1_6 import mx_deon_hair_absorption_from_melanin; +export using .::pbrlib_1_6 import mx_chiang_hair_absorption_from_color; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness__result; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness; + +export using .::pbrlib_1_7 import mx_sheen_bsdf; +export using .::pbrlib_1_7 import mx_add_bsdf; +export using .::pbrlib_1_7 import mx_add_edf; +export using .::pbrlib_1_7 import mx_mix_edf; +export using .::pbrlib_1_7 import mx_add_vdf; +export using .::pbrlib_1_7 import mx_generalized_schlick_edf; +export using .::pbrlib_1_7 import mx_volume; + +export material mx_mix_bsdf( + material mxp_fg = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_bg = material() [[ anno::usage( "materialx:bsdf") ]], + float mxp_mix = 0.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float mix = math::saturate(mxp_mix); + volume_mix_return v = volume_mix( + mxp_fg.volume.scattering_coefficient, mix, + mxp_bg.volume.scattering_coefficient, (1.0f - mix)); +} in material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mix, + layer: mxp_fg.surface.scattering, + base: mxp_bg.surface.scattering + ) + ), + // we need to carry volume properties along for SSS + ior: mix * mxp_fg.ior + (1.0f - mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component(v.mix_weight1, mxp_fg.volume.scattering), + df::vdf_component(1.0 - v.mix_weight1, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: v.scattering_coefficient + ) +); + +export material mx_mix_vdf( + material mxp_fg = material() [[ anno::usage( "materialx:vdf") ]], + material mxp_bg = material() [[ anno::usage( "materialx:vdf") ]], + float mxp_mix = 0.0 +) [[ + anno::usage( "materialx:vdf") +]] += let { + float mix = math::saturate(mxp_mix); + volume_mix_return v = volume_mix( + mxp_fg.volume.scattering_coefficient, mix, + mxp_bg.volume.scattering_coefficient, (1.0f - mix)); +} in material( + ior: mix * mxp_fg.ior + (1.0f - mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component( v.mix_weight1, mxp_fg.volume.scattering), + df::vdf_component( 1.0 - v.mix_weight1, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: v.scattering_coefficient + ) +); + +// helper to compute ior for generalized_schlick +color mx_f0_to_ior(color F0) +{ + float3 sqrtF0 = math::sqrt(math::clamp(float3(F0), 0.01, 0.99)); + return color((float3(1.0) + sqrtF0) / (float3(1.0) - sqrtF0)); +} + +export material mx_generalized_schlick_bsdf( + float mxp_weight = 1.0, + color mxp_color0 = color(1.0), + color mxp_color82 = color(1.0), // MDL 1.10 + color mxp_color90 = color(1.0), + float mxp_exponent = 5.0, + float2 mxp_roughness = float2(0.05), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + bsdf ggx_model_R = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect); + + bsdf ggx_model_T = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_transmit); + +} in material( + surface: material_surface( + scattering: df::unbounded_mix( + df::bsdf_component[]( + df::bsdf_component( + mxp_weight, + mxp_scatter_mode == mx_scatter_mode_T + ? df::color_custom_curve_layer( + normal_reflectivity: mxp_color0, + grazing_reflectivity: mxp_color82 * mxp_color90, + exponent: mxp_exponent, + layer: bsdf(), + base: ggx_model_T, + normal: mxp_normal) + : df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: df::color_custom_curve_layer( + normal_reflectivity: mxp_color0, + grazing_reflectivity: mxp_color82 * mxp_color90, + exponent: mxp_exponent, + layer: ggx_model_R, + base: mxp_scatter_mode == mx_scatter_mode_R + ? mxp_base.surface.scattering + : ggx_model_T, + normal: mxp_normal)) + ), + df::bsdf_component( + 1.0 - mxp_weight, + mxp_base.surface.scattering) + ) + ) + ), + ior: mx_f0_to_ior(mxp_color0), + // we need to carry volume properties along for SSS + volume: mxp_base.volume +); + + +// TODO MDL 1.8 +// * will add support for thin film above a color_custom_curve_layer node until then, thin_film will have no effect +// * thin_film(thickness: 0.0, ior: < 1.0) will be handled properly +export material mx_dielectric_bsdf( + float mxp_weight = 1.0, + color mxp_tint = color(1.0), + float mxp_ior = 1.5, + float2 mxp_roughness = float2(0.0), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + float grazing_refl = math::max((1.0 - math::average(mxp_roughness)), 0.0); + float root_r = (mxp_ior-1)/(mxp_ior+1); + bsdf bsdf_R = df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + // fresnel layer has issues if base is a diffuse transmission, use custom curve for now + // this will break thin_film but improves standard_surface with diffuse transmission + base: df::custom_curve_layer( + normal_reflectivity: root_r*root_r, + grazing_reflectivity: grazing_refl, + weight: mxp_weight, + layer: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect), + base: mxp_base.surface.scattering, + normal: mxp_normal)); + + bsdf bsdf_T = df::weighted_layer( + weight: mxp_weight, + layer: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_transmit), + normal: mxp_normal); + + bsdf bsdf_RT = df::weighted_layer( + weight: mxp_weight, + layer: df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect_transmit)), + normal: mxp_normal); + + bsdf bsdf_selected = (mxp_scatter_mode == mx_scatter_mode_R) ? bsdf_R : + ((mxp_scatter_mode == mx_scatter_mode_T) ? bsdf_T : bsdf_RT); +} in material( + surface: material_surface( + scattering: bsdf_selected + ), + // we need to carry volume properties along for SSS + ior: color(mxp_ior), + volume: mxp_base.volume +); + +export material mx_conductor_bsdf( + float mxp_weight = 1.0, + color mxp_ior = color(0.18, 0.42, 1.37), + color mxp_extinction = color(3.42, 2.35, 1.77), + float2 mxp_roughness = float2(0.0), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + bsdf ggx_model = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0), + multiscatter_tint: color(1.0), + tangent_u: mxp_tangent); + bsdf conductor = df::fresnel_factor( + ior: mxp_ior, + extinction_coefficient: mxp_extinction, + base: ggx_model); + bsdf thin_film_conductor = df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: conductor); +} in material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mxp_weight, + layer: thin_film_conductor, + normal: mxp_normal + ) + ), + ior: mxp_ior, +); + +// Shader Nodes + +// NOTE: The MDL material with thin_walled == false uses the same material_surface +// properties for the front- and backface, the material will not be black +// from the backside as mandated by the MaterialX spec. +export material mx_surface( + material mxp_bsdf = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_edf = material() [[ anno::usage( "materialx:edf") ]], + float mxp_opacity = 1.0, + uniform bool mxp_thin_walled = false, + float mxp_transmission_ior = 0.0 // extra parameter for setting transmission IOR +) [[ + anno::usage( "materialx:surfaceshader") +]] += let { + bsdf bsdf_node = mxp_bsdf.surface.scattering; + material_emission edf_node = mxp_edf.surface.emission; + // we need to carry volume properties along for SSS + material_volume bsdf_volume = mxp_bsdf.volume; +} in material( + thin_walled: mxp_thin_walled, + surface: material_surface( + scattering: bsdf_node, + emission: edf_node + ), + ior: mxp_transmission_ior > 0.0 ? color(mxp_transmission_ior) : mxp_bsdf.ior, + volume: bsdf_volume, + geometry: material_geometry( + cutout_opacity: mxp_opacity + ) +); diff --git a/source/MaterialXGenMdl/mdl/materialx/sampling.mdl b/source/MaterialXGenMdl/mdl/materialx/sampling.mdl index 1809503653..15228efeca 100644 --- a/source/MaterialXGenMdl/mdl/materialx/sampling.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/sampling.mdl @@ -5,7 +5,9 @@ mdl 1.6; +import ::anno::*; import ::math::*; +import ::state::*; import .::core::*; @@ -15,14 +17,14 @@ export const int MX_MAX_SAMPLE_COUNT = 49; export const int MX_WEIGHT_ARRAY_SIZE = 84; // This is not available in MDL so just use a "small" number -float2 dFdx(float2 uv) +float2 dFdx(float2 uv [[anno::unused()]]) { - return uv+0.0001; + return float2(0.001, 0); } -float2 dFdy(float2 uv) +float2 dFdy(float2 uv [[anno::unused()]]) { - return uv+0.0001; + return float2(0, 0.001); } // @@ -49,11 +51,10 @@ export float2 mx_compute_sample_size_uv(float2 uv, float filterSize, float filte // export float3 mx_normal_from_samples_sobel(float[9] S, float scale) { - float nx = S[0] - S[2] + (2.0*S[3]) - (2.0*S[5]) + S[6] - S[8]; - float ny = S[0] + (2.0*S[1]) + S[2] - S[6] - (2.0*S[7]) - S[8]; - float nz = scale * ::math::sqrt(1.0 - nx*nx - ny*ny); - float3 norm = ::math::normalize(float3(nx, ny, nz)); - return (norm + 1.0) * 0.5; + float nx = S[0] - S[2] + (2.0*S[3]) - (2.0*S[5]) + S[6] - S[8]; + float ny = S[0] + (2.0*S[1]) + S[2] - S[6] - (2.0*S[7]) - S[8]; + float3 norm = math::normalize(float3(nx * scale, ny * scale, 0.125)); + return (norm + 1.0) * 0.5; } // Kernel weights for box filter diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl index 79ed3dff4f..a23c0150ed 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl @@ -4,15 +4,15 @@ // // MDL implementation of all Standard Source Nodes of // MaterialX: An Open Standard for Network-Based CG Object Looks -// Document v1.37 REV2, January 19, 2020 +// Document version 1.39, September 15, 2024 // www.materialx.org // in -// NVIDIA Material Definition Language 1.7 +// NVIDIA Material Definition Language 1.9 // Language Specification -// Document version 1.7.2, January 17, 2022 +// Document version 1.9.2, September 16, 2024 // www.nvidia.com/mdl -mdl 1.8; +mdl 1.9; // forward the latest version -export using .::stdlib_1_8 import *; +export using .::stdlib_1_9 import *; diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl new file mode 100644 index 0000000000..549287c5b7 --- /dev/null +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl @@ -0,0 +1,387 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// +// MDL implementation of all Standard Source Nodes of +// MaterialX: An Open Standard for Network-Based CG Object Looks +// Document version 1.39, September 15, 2024 +// www.materialx.org +// in +// NVIDIA Material Definition Language 1.9 +// Language Specification +// Document version 1.9.2, September 16, 2024 +// www.nvidia.com/mdl + +mdl 1.9; + +import ::anno::*; +import ::df::*; +import ::math::*; +import ::scene::*; +import ::state::*; + +import .::core::*; +import .::noise::*; +import .::hsv::*; + +// Changes since MDL 1.8 +// - lift the restriction of uniform IORs + +// forward unchanged definitions from the previous version +export using .::stdlib_1_7 import mx_surfacematerial; +export using .::stdlib_1_7 import mx_surface_unlit; +export using .::stdlib_1_7 import mx_image_float; +export using .::stdlib_1_7 import mx_image_color3; +export using .::stdlib_1_7 import mx_image_color4; +export using .::stdlib_1_7 import mx_image_vector2; +export using .::stdlib_1_7 import mx_image_vector3; +export using .::stdlib_1_7 import mx_image_vector4; +export using .::stdlib_1_7 import mx_constant_float; +export using .::stdlib_1_7 import mx_constant_color3; +export using .::stdlib_1_7 import mx_constant_color4; +export using .::stdlib_1_7 import mx_constant_vector2; +export using .::stdlib_1_7 import mx_constant_vector3; +export using .::stdlib_1_7 import mx_constant_vector4; +export using .::stdlib_1_7 import mx_constant_boolean; +export using .::stdlib_1_7 import mx_constant_integer; +export using .::stdlib_1_7 import mx_constant_matrix33; +export using .::stdlib_1_7 import mx_constant_matrix44; +export using .::stdlib_1_7 import mx_constant_string; +export using .::stdlib_1_7 import mx_constant_filename; +export using .::stdlib_1_7 import mx_ramplr_float; +export using .::stdlib_1_7 import mx_ramplr_color3; +export using .::stdlib_1_7 import mx_ramplr_color4; +export using .::stdlib_1_7 import mx_ramplr_vector2; +export using .::stdlib_1_7 import mx_ramplr_vector3; +export using .::stdlib_1_7 import mx_ramplr_vector4; +export using .::stdlib_1_7 import mx_ramptb_float; +export using .::stdlib_1_7 import mx_ramptb_color3; +export using .::stdlib_1_7 import mx_ramptb_color4; +export using .::stdlib_1_7 import mx_ramptb_vector2; +export using .::stdlib_1_7 import mx_ramptb_vector3; +export using .::stdlib_1_7 import mx_ramptb_vector4; +export using .::stdlib_1_7 import mx_splitlr_float; +export using .::stdlib_1_7 import mx_splitlr_color3; +export using .::stdlib_1_7 import mx_splitlr_color4; +export using .::stdlib_1_7 import mx_splitlr_vector2; +export using .::stdlib_1_7 import mx_splitlr_vector3; +export using .::stdlib_1_7 import mx_splitlr_vector4; +export using .::stdlib_1_7 import mx_splittb_float; +export using .::stdlib_1_7 import mx_splittb_color3; +export using .::stdlib_1_7 import mx_splittb_color4; +export using .::stdlib_1_7 import mx_splittb_vector2; +export using .::stdlib_1_7 import mx_splittb_vector3; +export using .::stdlib_1_7 import mx_splittb_vector4; +export using .::stdlib_1_7 import mx_position_vector3; +export using .::stdlib_1_7 import mx_normal_vector3; +export using .::stdlib_1_7 import mx_tangent_vector3; +export using .::stdlib_1_7 import mx_bitangent_vector3; +export using .::stdlib_1_7 import mx_texcoord_vector2; +export using .::stdlib_1_7 import mx_texcoord_vector3; +export using .::stdlib_1_7 import mx_geomcolor_float; +export using .::stdlib_1_7 import mx_geomcolor_color3; +export using .::stdlib_1_7 import mx_geomcolor_color4; +export using .::stdlib_1_7 import mx_ambientocclusion_float; +export using .::stdlib_1_7 import mx_frame_float; +export using .::stdlib_1_7 import mx_time_float; +export using .::stdlib_1_7 import mx_modulo_color3; +export using .::stdlib_1_7 import mx_modulo_color4; +export using .::stdlib_1_7 import mx_modulo_color3FA; +export using .::stdlib_1_7 import mx_modulo_color4FA; +export using .::stdlib_1_7 import mx_invert_color4; +export using .::stdlib_1_7 import mx_invert_color4FA; +export using .::stdlib_1_7 import mx_absval_color4; +export using .::stdlib_1_7 import mx_floor_color3; +export using .::stdlib_1_7 import mx_floor_color4; +export using .::stdlib_1_7 import mx_ceil_color3; +export using .::stdlib_1_7 import mx_ceil_color4; +export using .::stdlib_1_7 import mx_round_color3; +export using .::stdlib_1_7 import mx_round_color4; +export using .::stdlib_1_7 import mx_power_color4; +export using .::stdlib_1_7 import mx_power_color4FA; +export using .::stdlib_1_7 import mx_sin_float; +export using .::stdlib_1_7 import mx_cos_float; +export using .::stdlib_1_7 import mx_tan_float; +export using .::stdlib_1_7 import mx_asin_float; +export using .::stdlib_1_7 import mx_acos_float; +export using .::stdlib_1_7 import mx_atan2_float; +export using .::stdlib_1_7 import mx_sin_vector2; +export using .::stdlib_1_7 import mx_cos_vector2; +export using .::stdlib_1_7 import mx_tan_vector2; +export using .::stdlib_1_7 import mx_asin_vector2; +export using .::stdlib_1_7 import mx_acos_vector2; +export using .::stdlib_1_7 import mx_atan2_vector2; +export using .::stdlib_1_7 import mx_sin_vector3; +export using .::stdlib_1_7 import mx_cos_vector3; +export using .::stdlib_1_7 import mx_tan_vector3; +export using .::stdlib_1_7 import mx_asin_vector3; +export using .::stdlib_1_7 import mx_acos_vector3; +export using .::stdlib_1_7 import mx_atan2_vector3; +export using .::stdlib_1_7 import mx_sin_vector4; +export using .::stdlib_1_7 import mx_cos_vector4; +export using .::stdlib_1_7 import mx_tan_vector4; +export using .::stdlib_1_7 import mx_asin_vector4; +export using .::stdlib_1_7 import mx_acos_vector4; +export using .::stdlib_1_7 import mx_atan2_vector4; +export using .::stdlib_1_7 import mx_sqrt_float; +export using .::stdlib_1_7 import mx_ln_float; +export using .::stdlib_1_7 import mx_exp_float; +export using .::stdlib_1_7 import mx_sqrt_vector2; +export using .::stdlib_1_7 import mx_ln_vector2; +export using .::stdlib_1_7 import mx_exp_vector2; +export using .::stdlib_1_7 import mx_sqrt_vector3; +export using .::stdlib_1_7 import mx_ln_vector3; +export using .::stdlib_1_7 import mx_exp_vector3; +export using .::stdlib_1_7 import mx_sqrt_vector4; +export using .::stdlib_1_7 import mx_ln_vector4; +export using .::stdlib_1_7 import mx_exp_vector4; +export using .::stdlib_1_7 import mx_sign_color3; +export using .::stdlib_1_7 import mx_sign_color4; +export using .::stdlib_1_7 import mx_clamp_color4; +export using .::stdlib_1_7 import mx_clamp_color4FA; +export using .::stdlib_1_7 import mx_min_color4; +export using .::stdlib_1_7 import mx_min_color4; +export using .::stdlib_1_7 import mx_max_color4; +export using .::stdlib_1_7 import mx_max_color4; +export using .::stdlib_1_7 import mx_transformpoint_vector3; +export using .::stdlib_1_7 import mx_transformvector_vector3; +export using .::stdlib_1_7 import mx_transformnormal_vector3; +export using .::stdlib_1_7 import mx_transformmatrix_vector2M3; +export using .::stdlib_1_7 import mx_transformmatrix_vector3; +export using .::stdlib_1_7 import mx_transformmatrix_vector3M4; +export using .::stdlib_1_7 import mx_transformmatrix_vector4; +export using .::stdlib_1_7 import mx_normalmap_float; +export using .::stdlib_1_7 import mx_normalmap_vector2; +export using .::stdlib_1_7 import mx_transpose_matrix33; +export using .::stdlib_1_7 import mx_transpose_matrix44; +export using .::stdlib_1_7 import mx_determinant_matrix33; +export using .::stdlib_1_7 import mx_determinant_matrix44; +export using .::stdlib_1_7 import mx_invertmatrix_matrix33; +export using .::stdlib_1_7 import mx_invertmatrix_matrix44; +export using .::stdlib_1_7 import mx_rotate2d_vector2; +export using .::stdlib_1_7 import mx_rotate3d_vector3; +export using .::stdlib_1_7 import mx_remap_float; +export using .::stdlib_1_7 import mx_remap_color3; +export using .::stdlib_1_7 import mx_remap_color4; +export using .::stdlib_1_7 import mx_remap_vector2; +export using .::stdlib_1_7 import mx_remap_vector3; +export using .::stdlib_1_7 import mx_remap_vector4; +export using .::stdlib_1_7 import mx_remap_color3FA; +export using .::stdlib_1_7 import mx_remap_color4FA; +export using .::stdlib_1_7 import mx_remap_vector2FA; +export using .::stdlib_1_7 import mx_remap_vector3FA; +export using .::stdlib_1_7 import mx_remap_vector4FA; +export using .::stdlib_1_7 import mx_smoothstep_float; +export using .::stdlib_1_7 import mx_smoothstep_color3; +export using .::stdlib_1_7 import mx_smoothstep_color4; +export using .::stdlib_1_7 import mx_smoothstep_vector2; +export using .::stdlib_1_7 import mx_smoothstep_vector3; +export using .::stdlib_1_7 import mx_smoothstep_vector4; +export using .::stdlib_1_7 import mx_smoothstep_color3FA; +export using .::stdlib_1_7 import mx_smoothstep_color4FA; +export using .::stdlib_1_7 import mx_smoothstep_vector2FA; +export using .::stdlib_1_7 import mx_smoothstep_vector3FA; +export using .::stdlib_1_7 import mx_smoothstep_vector4FA; +export using .::stdlib_1_7 import mx_curveadjust_float; +export using .::stdlib_1_7 import mx_curveadjust_color3; +export using .::stdlib_1_7 import mx_curveadjust_color4; +export using .::stdlib_1_7 import mx_curveadjust_vector2; +export using .::stdlib_1_7 import mx_curveadjust_vector3; +export using .::stdlib_1_7 import mx_curveadjust_vector4; +export using .::stdlib_1_7 import mx_luminance_color3; +export using .::stdlib_1_7 import mx_luminance_color4; +export using .::stdlib_1_7 import mx_rgbtohsv_color3; +export using .::stdlib_1_7 import mx_rgbtohsv_color4; +export using .::stdlib_1_7 import mx_hsvtorgb_color3; +export using .::stdlib_1_7 import mx_hsvtorgb_color4; +export using .::stdlib_1_7 import mx_premult_color4; +export using .::stdlib_1_7 import mx_unpremult_color4; +export using .::stdlib_1_7 import mx_plus_color4; +export using .::stdlib_1_7 import mx_minus_color4; +export using .::stdlib_1_7 import mx_difference_color4; +export using .::stdlib_1_7 import mx_burn_float; +export using .::stdlib_1_7 import mx_burn_color3; +export using .::stdlib_1_7 import mx_burn_color4; +export using .::stdlib_1_7 import mx_dodge_float; +export using .::stdlib_1_7 import mx_dodge_color3; +export using .::stdlib_1_7 import mx_dodge_color4; +export using .::stdlib_1_7 import mx_screen_color4; +export using .::stdlib_1_7 import mx_disjointover_color4; +export using .::stdlib_1_7 import mx_in_color4; +export using .::stdlib_1_7 import mx_mask_color4; +export using .::stdlib_1_7 import mx_matte_color4; +export using .::stdlib_1_7 import mx_out_color4; +export using .::stdlib_1_7 import mx_over_color4; +export using .::stdlib_1_7 import mx_mix_color4; +export using .::stdlib_1_7 import mx_mix_color4_color4; +export using .::stdlib_1_7 import mx_mix_volumeshader; +export using .::stdlib_1_7 import mx_mix_displacementshader; +export using .::stdlib_1_7 import mx_ifgreater_float; +export using .::stdlib_1_7 import mx_ifgreater_integer; +export using .::stdlib_1_7 import mx_ifgreater_color3; +export using .::stdlib_1_7 import mx_ifgreater_color4; +export using .::stdlib_1_7 import mx_ifgreater_vector2; +export using .::stdlib_1_7 import mx_ifgreater_vector3; +export using .::stdlib_1_7 import mx_ifgreater_vector4; +export using .::stdlib_1_7 import mx_ifgreater_matrix33; +export using .::stdlib_1_7 import mx_ifgreater_matrix44; +export using .::stdlib_1_7 import mx_ifgreater_boolean; +export using .::stdlib_1_7 import mx_ifgreater_floatI; +export using .::stdlib_1_7 import mx_ifgreater_integerI; +export using .::stdlib_1_7 import mx_ifgreater_color3I; +export using .::stdlib_1_7 import mx_ifgreater_color4I; +export using .::stdlib_1_7 import mx_ifgreater_vector2I; +export using .::stdlib_1_7 import mx_ifgreater_vector3I; +export using .::stdlib_1_7 import mx_ifgreater_vector4I; +export using .::stdlib_1_7 import mx_ifgreater_matrix33I; +export using .::stdlib_1_7 import mx_ifgreater_matrix44I; +export using .::stdlib_1_7 import mx_ifgreater_booleanI; +export using .::stdlib_1_7 import mx_ifgreatereq_float; +export using .::stdlib_1_7 import mx_ifgreatereq_integer; +export using .::stdlib_1_7 import mx_ifgreatereq_color3; +export using .::stdlib_1_7 import mx_ifgreatereq_color4; +export using .::stdlib_1_7 import mx_ifgreatereq_vector2; +export using .::stdlib_1_7 import mx_ifgreatereq_vector3; +export using .::stdlib_1_7 import mx_ifgreatereq_vector4; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix33; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix44; +export using .::stdlib_1_7 import mx_ifgreatereq_boolean; +export using .::stdlib_1_7 import mx_ifgreatereq_floatI; +export using .::stdlib_1_7 import mx_ifgreatereq_integerI; +export using .::stdlib_1_7 import mx_ifgreatereq_color3I; +export using .::stdlib_1_7 import mx_ifgreatereq_color4I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector2I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector3I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector4I; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix33I; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix44I; +export using .::stdlib_1_7 import mx_ifgreatereq_booleanI; +export using .::stdlib_1_7 import mx_ifequal_float; +export using .::stdlib_1_7 import mx_ifequal_integer; +export using .::stdlib_1_7 import mx_ifequal_color3; +export using .::stdlib_1_7 import mx_ifequal_color4; +export using .::stdlib_1_7 import mx_ifequal_vector2; +export using .::stdlib_1_7 import mx_ifequal_vector3; +export using .::stdlib_1_7 import mx_ifequal_vector4; +export using .::stdlib_1_7 import mx_ifequal_matrix33; +export using .::stdlib_1_7 import mx_ifequal_matrix44; +export using .::stdlib_1_7 import mx_ifequal_boolean; +export using .::stdlib_1_7 import mx_ifequal_floatI; +export using .::stdlib_1_7 import mx_ifequal_integerI; +export using .::stdlib_1_7 import mx_ifequal_color3I; +export using .::stdlib_1_7 import mx_ifequal_color4I; +export using .::stdlib_1_7 import mx_ifequal_vector2I; +export using .::stdlib_1_7 import mx_ifequal_vector3I; +export using .::stdlib_1_7 import mx_ifequal_vector4I; +export using .::stdlib_1_7 import mx_ifequal_matrix33I; +export using .::stdlib_1_7 import mx_ifequal_matrix44I; +export using .::stdlib_1_7 import mx_ifequal_booleanI; +export using .::stdlib_1_7 import mx_ifequal_floatB; +export using .::stdlib_1_7 import mx_ifequal_integerB; +export using .::stdlib_1_7 import mx_ifequal_color3B; +export using .::stdlib_1_7 import mx_ifequal_color4B; +export using .::stdlib_1_7 import mx_ifequal_vector2B; +export using .::stdlib_1_7 import mx_ifequal_vector3B; +export using .::stdlib_1_7 import mx_ifequal_vector4B; +export using .::stdlib_1_7 import mx_ifequal_matrix33B; +export using .::stdlib_1_7 import mx_ifequal_matrix44B; +export using .::stdlib_1_7 import mx_ifequal_booleanB; +export using .::stdlib_1_7 import mx_creatematrix_vector3_matrix33; +export using .::stdlib_1_7 import mx_creatematrix_vector3_matrix44; +export using .::stdlib_1_7 import mx_creatematrix_vector4_matrix44; +export using .::stdlib_1_7 import mx_extract_color3; +export using .::stdlib_1_7 import mx_extract_color4; +export using .::stdlib_1_7 import mx_extract_vector2; +export using .::stdlib_1_7 import mx_extract_vector3; +export using .::stdlib_1_7 import mx_extract_vector4; +export using .::stdlib_1_7 import mx_blur_float; +export using .::stdlib_1_7 import mx_blur_color3; +export using .::stdlib_1_7 import mx_blur_color4; +export using .::stdlib_1_7 import mx_blur_vector2; +export using .::stdlib_1_7 import mx_blur_vector3; +export using .::stdlib_1_7 import mx_blur_vector4; +export using .::stdlib_1_7 import mx_heighttonormal_vector3; +export using .::stdlib_1_7 import mx_noise2d_float; +export using .::stdlib_1_7 import mx_noise2d_float2; +export using .::stdlib_1_7 import mx_noise2d_float3; +export using .::stdlib_1_7 import mx_noise2d_float4; +export using .::stdlib_1_7 import mx_noise3d_float; +export using .::stdlib_1_7 import mx_noise3d_float2; +export using .::stdlib_1_7 import mx_noise3d_float3; +export using .::stdlib_1_7 import mx_noise3d_float4; +export using .::stdlib_1_7 import mx_fractal3d_float; +export using .::stdlib_1_7 import mx_fractal3d_float2; +export using .::stdlib_1_7 import mx_fractal3d_float3; +export using .::stdlib_1_7 import mx_fractal3d_float4; +export using .::stdlib_1_7 import mx_cellnoise2d_float; +export using .::stdlib_1_7 import mx_cellnoise3d_float; +export using .::stdlib_1_7 import mx_worleynoise2d_float; +export using .::stdlib_1_7 import mx_worleynoise2d_float2; +export using .::stdlib_1_7 import mx_worleynoise2d_float3; +export using .::stdlib_1_7 import mx_worleynoise3d_float; +export using .::stdlib_1_7 import mx_worleynoise3d_float2; +export using .::stdlib_1_7 import mx_worleynoise3d_float3; +export using .::stdlib_1_7 import mx_combine2_color4CF; + +export using .::stdlib_1_7 import mx_geompropvalue_string; +export using .::stdlib_1_8 import mx_geompropvalue_boolean; +export using .::stdlib_1_8 import mx_geompropvalue_integer; +export using .::stdlib_1_8 import mx_geompropvalue_float; +export using .::stdlib_1_8 import mx_geompropvalue_color3; +export using .::stdlib_1_8 import mx_geompropvalue_color4; +export using .::stdlib_1_8 import mx_geompropvalue_vector2; +export using .::stdlib_1_8 import mx_geompropvalue_vector3; +export using .::stdlib_1_8 import mx_geompropvalue_vector4; +export using .::stdlib_1_8 import mx_viewdirection_vector3; + + + +// mix all parts of the material, bsdf, edf, and vdf, geometry +export material mx_mix_surfaceshader( + material mxp_fg = material() [[ anno::usage( "materialx:surfaceshader") ]], + material mxp_bg = material() [[ anno::usage( "materialx:surfaceshader") ]], + float mxp_mix = 0.0 +) [[ + anno::description("Node Group: compositing"), + anno::usage( "materialx:surfaceshader") +]] += material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mxp_mix, + layer: mxp_fg.surface.scattering, + base: mxp_bg.surface.scattering + ), + emission: material_emission( + emission: df::clamped_mix( + df::edf_component[]( + df::edf_component( mxp_mix, mxp_fg.surface.emission.emission), + df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission)) + ), + intensity: mxp_mix * mxp_fg.surface.emission.intensity + + (1.0 - mxp_mix) * mxp_bg.surface.emission.intensity + ) + ), + + // we need to carry volume properties along for SSS + ior: mxp_mix * mxp_fg.ior + (1.0 - mxp_mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component( mxp_mix, mxp_fg.volume.scattering), + df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mxp_mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mxp_mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: mxp_mix * mxp_fg.volume.scattering_coefficient + + (1.0 - mxp_mix) * mxp_bg.volume.scattering_coefficient + ), + geometry: material_geometry( + displacement: mxp_mix * mxp_fg.geometry.displacement + + (1.0 - mxp_mix) * mxp_bg.geometry.displacement, + cutout_opacity: mxp_mix * mxp_fg.geometry.cutout_opacity + + (1.0 - mxp_mix) * mxp_bg.geometry.cutout_opacity, + normal: mxp_mix * mxp_fg.geometry.normal + + (1.0 - mxp_mix) * mxp_bg.geometry.normal + ) +); diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index e1a23cf7d4..638a4fd10c 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -225,15 +225,9 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so moduleToTest = moduleToTest.substr(0, moduleToTest.size() - sourceCodePaths[0].getExtension().length() - 1); std::string renderExec(MATERIALX_MDL_RENDER_EXECUTABLE); - bool testMDLC = renderExec.empty(); - if (testMDLC) + std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); + if (!mdlcExec.empty()) // always run compiler { - std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); - if (mdlcExec.empty()) - { - return; - } - std::string mdlcCommand = mdlcExec; // use the same paths as the resolver @@ -264,12 +258,19 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so _logFile << "\tReturn code: " << std::to_string(returnValue) << std::endl; writeErrorCode = true; } - _logFile << "\tError: " << line << std::endl; + if (line.find(": Warning ") != std::string::npos) + { + _logFile << "\tWarning: " << line << std::endl; + } + else + { + _logFile << "\tError: " << line << std::endl; + } } CHECK(returnValue == 0); } - else + if (!renderExec.empty()) // render if renderer is availabe { std::string renderCommand = renderExec; @@ -358,6 +359,7 @@ TEST_CASE("GenShader: MDL Shader Generation", "[genmdl]") mx::FilePathVec testRootPaths; testRootPaths.push_back(searchPath.find("resources/Materials/TestSuite")); testRootPaths.push_back(searchPath.find("resources/Materials/Examples/StandardSurface")); + testRootPaths.push_back(searchPath.find("resources/Materials/Examples/UsdPreviewSurface")); const mx::FilePath logPath("genmdl_mdl_generate_test.txt"); From 6fd2dc2f3ebea66afa705c24cc795aa9e8f64420 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 25 Nov 2024 14:03:35 -0800 Subject: [PATCH 13/20] Remove unimplemented nodes from libraries (#2120) This changelist removes the unimplemented 'ambientocclusion', 'arrayappend', and 'curveadjust' nodes from the MaterialX data libraries, aligning the data libraries with the current 1.39 specification. Additionally, this change removes hardcoded skip count checks from MaterialXTest, as these tests have not proven themselves to be a beneficial safeguard against regressions, and frequently trip up contributors to the MaterialX project. --- libraries/README.md | 3 -- .../stdlib/genglsl/stdlib_genglsl_impl.mtlx | 6 --- .../stdlib/genmdl/stdlib_genmdl_impl.mtlx | 7 --- .../stdlib/genmsl/stdlib_genmsl_impl.mtlx | 4 -- .../genosl/mx_ambientocclusion_float.osl | 5 -- .../stdlib/genosl/stdlib_genosl_impl.mtlx | 7 --- libraries/stdlib/stdlib_defs.mtlx | 53 ------------------- python/Scripts/genmdl.py | 8 +-- .../mdl/materialx/stdlib_1_6.mdl | 17 ------ .../mdl/materialx/stdlib_1_8.mdl | 1 - .../mdl/materialx/stdlib_1_9.mdl | 1 - .../MaterialXGenGlsl/GenGlsl.cpp | 2 +- .../MaterialXTest/MaterialXGenGlsl/GenGlsl.h | 2 +- .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 2 +- source/MaterialXTest/MaterialXGenMdl/GenMdl.h | 2 +- .../MaterialXTest/MaterialXGenMsl/GenMsl.cpp | 2 +- source/MaterialXTest/MaterialXGenMsl/GenMsl.h | 2 +- .../MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 2 +- source/MaterialXTest/MaterialXGenOsl/GenOsl.h | 2 +- .../MaterialXGenShader/GenShaderUtil.cpp | 6 +-- .../MaterialXGenShader/GenShaderUtil.h | 3 +- .../MaterialXRenderOsl/GenReference.cpp | 3 +- 22 files changed, 12 insertions(+), 128 deletions(-) delete mode 100644 libraries/stdlib/genosl/mx_ambientocclusion_float.osl diff --git a/libraries/README.md b/libraries/README.md index 15916f76e2..0ace221bcc 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -74,7 +74,4 @@ This folder contains the standard data libraries for MaterialX, providing declar - Basic GLSL and MSL `lightshader` node definitions and implementations are provided for the following light types: - point, directional, spot - Shader generation does not currently support: - - `ambientocclusion` node. - - `arrayappend` node. - - `curveadjust` node. - `displacementshader` and `volumeshader` nodes for hardware shading targets (GLSL, MSL). diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index 69f8f9a7f8..ad3a21e9cf 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -129,12 +129,6 @@ - - - - - - diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index b190937c41..6ac2b862dd 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -131,13 +131,6 @@ - - - - - - - diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index afdfb2cfbb..3cb99052cf 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -45,10 +45,6 @@ - - - - diff --git a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl b/libraries/stdlib/genosl/mx_ambientocclusion_float.osl deleted file mode 100644 index 10baf0b736..0000000000 --- a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_ambientocclusion_float(float coneangle, float maxdistance, output float result) -{ - // This node is a stub and does not currently operate to specification - result = 0; -} diff --git a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx index 716e1072d7..db318976c5 100644 --- a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -131,13 +131,6 @@ - - - - - - - diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 943e36ec88..e6f8d431e7 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -1354,21 +1354,6 @@ - - - - - - - - - - - @@ -2899,44 +2884,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp index b77eebbd86..a72207c581 100644 --- a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp +++ b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp @@ -37,51 +37,6 @@ void ClosureLayerNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& ShaderNode* top = topInput->getConnection()->getNode(); ShaderNode* base = baseInput->getConnection()->getNode(); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - ClosureContext* cct = context.getClosureContext(); - - // Evaluate top and base nodes and combine their result - // according to throughput. - // - // TODO: In the BSDF over BSDF case should we emit code - // to check the top throughput amount before calling - // the base BSDF? - - // Make sure the connections are sibling nodes and not the graph interface. - if (top->getParent() == node.getParent()) - { - // If this layer node has closure parameters set, - // we pass this on to the top component only. - ScopedSetClosureParams setParams(&node, top, cct); - shadergen.emitFunctionCall(*top, context, stage); - } - if (base->getParent() == node.getParent()) - { - shadergen.emitFunctionCall(*base, context, stage); - } - - // Get the result variables. - const string& topResult = topInput->getConnection()->getVariable(); - const string& baseResult = baseInput->getConnection()->getVariable(); - - // Calculate the layering result. - emitOutputVariables(node, context, stage); - if (base->getOutput()->getType() == Type::VDF) - { - // Combining a surface closure with a volumetric closure is simply done with the add operator in OSL. - shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult, stage); - // Just pass the throughput along. - shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput", stage); - } - else - { - shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult + ".response * " + topResult + ".throughput", stage); - shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput * " + baseResult + ".throughput", stage); - } - -#else - // Emit the function call for top and base layer. // Make sure the connections are sibling nodes and not the graph interface. if (top->getParent() == node.getParent()) @@ -102,8 +57,6 @@ void ClosureLayerNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& shadergen.emitOutput(output, true, false, context, stage); shadergen.emitString(" = layer(" + topResult + ", " + baseResult + ")", stage); shadergen.emitLineEnd(stage); - -#endif // MATERIALX_OSL_LEGACY_CLOSURES } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index d0d9d96cba..ff8cad36f5 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -45,22 +45,6 @@ OslShaderGenerator::OslShaderGenerator() : registerImplementation("IM_layer_bsdf_" + OslShaderGenerator::TARGET, ClosureLayerNodeOsl::create); registerImplementation("IM_layer_vdf_" + OslShaderGenerator::TARGET, ClosureLayerNodeOsl::create); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - // - registerImplementation("IM_mix_bsdf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - registerImplementation("IM_mix_edf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - // - registerImplementation("IM_add_bsdf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - registerImplementation("IM_add_edf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - // - registerImplementation("IM_multiply_bsdfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_bsdfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - -#endif // MATERIALX_OSL_LEGACY_CLOSURES - // registerImplementation("IM_surface_" + OslShaderGenerator::TARGET, SurfaceNodeOsl::create); @@ -158,10 +142,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G const bool isSurfaceShaderOutput = singleOutput && singleOutput->getType() == Type::SURFACESHADER; -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - const bool isBsdfOutput = singleOutput && singleOutput->getType() == Type::BSDF; -#endif - if (isSurfaceShaderOutput) { // Special case for having 'surfaceshader' as final output type. @@ -170,16 +150,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G // to understand this output. emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); - } -#endif else { // Just emit all outputs the way they are declared. @@ -253,18 +223,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G emitLine(singleOutput->getVariable() + " = (" + result + ".bsdf + " + result + ".edf) * opacity_weight + transparent() * (1.0 - opacity_weight)", stage); emitScopeEnd(stage); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - const ShaderGraphOutputSocket* socket = graph.getOutputSocket(0); - const string result = getUpstreamResult(socket, context); - emitLine(singleOutput->getVariable() + " = " + result + ".response", stage); - } -#endif else { // Assign results to final outputs. diff --git a/source/MaterialXGenOsl/OslSyntax.cpp b/source/MaterialXGenOsl/OslSyntax.cpp index 797a891ce6..a85821c4fd 100644 --- a/source/MaterialXGenOsl/OslSyntax.cpp +++ b/source/MaterialXGenOsl/OslSyntax.cpp @@ -371,19 +371,6 @@ OslSyntax::OslSyntax() EMPTY_STRING, "struct textureresource { string filename; string colorspace; };")); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - registerTypeSyntax( - Type::BSDF, - std::make_shared( - "BSDF", - "BSDF(null_closure, color(1.0))", - "{ 0, color(1.0) }", - "closure color", - "struct BSDF { closure color response; color throughput; };")); - -#else - registerTypeSyntax( Type::BSDF, std::make_shared( @@ -393,8 +380,6 @@ OslSyntax::OslSyntax() "closure color", "#define BSDF closure color")); -#endif // MATERIALX_OSL_LEGACY_CLOSURES - registerTypeSyntax( Type::EDF, std::make_shared( diff --git a/source/MaterialXTest/CMakeLists.txt b/source/MaterialXTest/CMakeLists.txt index 4835787ed8..c3fae603dc 100644 --- a/source/MaterialXTest/CMakeLists.txt +++ b/source/MaterialXTest/CMakeLists.txt @@ -96,11 +96,6 @@ endif() add_custom_command(TARGET MaterialXTest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/../../libraries ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries) -if(MATERIALX_OSL_LEGACY_CLOSURES) - add_custom_command(TARGET MaterialXTest POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx) -endif() if(MATERIALX_BUILD_GEN_MDL) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../source/MaterialXGenMdl/mdl/" From 344705f0214332a8b7199832ff90aefb9b054200 Mon Sep 17 00:00:00 2001 From: Bernard Kwok Date: Tue, 26 Nov 2024 12:49:28 -0500 Subject: [PATCH 15/20] Fix mxvalidate to check for stdlib usage (#2122) Patch `mxvalidate.py` script to avoid trying to access an undefined object `stdlib` if not specified from the command line (default). --- python/Scripts/mxvalidate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/Scripts/mxvalidate.py b/python/Scripts/mxvalidate.py index 8cc1ee78fd..e0ccf34a4e 100755 --- a/python/Scripts/mxvalidate.py +++ b/python/Scripts/mxvalidate.py @@ -17,6 +17,7 @@ def main(): opts = parser.parse_args() # Load standard libraries if requested. + stdlib = None if opts.stdlib: stdlib = mx.createDocument() try: @@ -29,7 +30,8 @@ def main(): doc = mx.createDocument() try: mx.readFromXmlFile(doc, opts.inputFilename) - doc.setDataLibrary(stdlib) + if stdlib: + doc.setDataLibrary(stdlib) except mx.ExceptionFileMissing as err: print(err) sys.exit(0) From cbb63ec82de7be3cea6bc0c85f12223be1e87d5e Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 26 Nov 2024 16:26:27 -0800 Subject: [PATCH 16/20] Update MacOS version in GitHub CI (#2123) This changelist updates Python wheel generation to the `macos-14-large` environment in GitHub CI, as Python versions before 3.11 have been removed from the `macos-13` environment. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b2d5f182bf..3f67667550 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -389,7 +389,7 @@ jobs: fail-fast: false matrix: python-minor: ['7', '8', '9', '10', '11', '12'] - os: ['ubuntu-22.04', 'windows-2022', 'macos-13'] + os: ['ubuntu-22.04', 'windows-2022', 'macos-14-large'] steps: - name: Sync Repository From b6d473d01edcf2b61291e22f09ac182c32555a68 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 3 Dec 2024 17:28:54 -0800 Subject: [PATCH 17/20] Update changelog for recent work (#2129) --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fedc1ceaa..6fb0c98143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ ## [1.39.2] - Development +### Added +- Added support for the [Chiang Hair BSDF](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1968), with initial implementations in hardware shading languages and MDL. +- Added support for the [Disney Principled](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2004) shading model, implemented as a language-independent graph. +- Added support for [data library referencing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2054), enabling improved performance in shader generation. +- Added support for [custom structure types](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1831) in MaterialX. +- Added support for [functional equivalence](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2003) tests between MaterialX elements. +- Added support for [transmission effects](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2027) in the translation graph from Standard Surface to glTF PBR. +- Added support for [coated emission](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2087) in the translation graph from Standard Surface to UsdPreviewSurface. +- Added support for [Apple framework builds](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2020). +- Added support for [MDL 1.9](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2102) in shader generation. +- Added support for [viewdirection space](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2036) in hardware shading languages. +- Added a [combined version define](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2031) to MaterialX C++. +- Added a [release signing workflow](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2009) to GitHub Actions. +- Added documentation for [keyboard shortcuts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2026) in the MaterialX Viewer. + +### Changed +- Reduced duplication between the [MSL and GLSL implementations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2068) of nodes. + +### Fixed +- Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. +- Fixed [banding artifacts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1977) in the MaterialX Viewer on MacOS. +- Fixed a call to the [anisotropic_vdf closure](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2016) in OSL shader generation. + +### Removed +- Removed support for the [legacy OSL closures](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2121), focusing exclusively on the MaterialX-synchronized closures in OSL 1.12 and beyond. + ## [1.39.1] - 2024-09-03 ### Added From bfbf6729385a7820dc2ab00332b30b93eff6a3e8 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 4 Dec 2024 10:36:45 -0800 Subject: [PATCH 18/20] Static analysis fixes (#2130) This changelist addresses a handful of static analysis warnings flagged by PVS-Studio: - Add a missing reference to `rhs` in `ValueElement::isAttributeEquivalent`. - Remove unused variables and unneeded string copies in `StructTypeSyntax::getValue` and `GlslStructTypeSyntax::getValue`. - Simplify boolean logic in `ClosureLayerNodeMdl::emitFunctionCall`. - Declare an immutable array as a `std::array` in `Viewer::createDocumentationInterface`. --- source/MaterialXCore/Element.cpp | 2 +- source/MaterialXGenGlsl/GlslSyntax.cpp | 4 ++-- source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp | 2 +- source/MaterialXGenShader/Syntax.cpp | 7 ++----- source/MaterialXView/Viewer.cpp | 2 +- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 3bede2fe74..78c59e9efc 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -749,7 +749,7 @@ bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attr else if (uiAttributes.find(attributeName) != uiAttributes.end()) { const string& uiAttribute = getAttribute(attributeName); - const string& rhsUiAttribute = getAttribute(attributeName); + const string& rhsUiAttribute = rhs->getAttribute(attributeName); ValuePtr uiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(uiAttribute, getType()) : nullptr; ValuePtr rhsUiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(rhsUiAttribute, getType()) : nullptr; if (uiValue && rhsUiValue) diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp index 651a4ab5ff..7054725b76 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.cpp +++ b/source/MaterialXGenGlsl/GlslSyntax.cpp @@ -400,8 +400,8 @@ string GlslStructTypeSyntax::getValue(const Value& value, bool /* uniform */) co result += separator; separator = ","; - auto memberTypeName = memberValue->getTypeString(); - auto memberTypeDesc = TypeDesc::get(memberTypeName); + const string& memberTypeName = memberValue->getTypeString(); + TypeDesc memberTypeDesc = TypeDesc::get(memberTypeName); // Recursively use the syntax to generate the output, so we can supported nested structs. result += _parentSyntax->getValue(memberTypeDesc, *memberValue, true); diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index 8949ae6cc0..5b187f80aa 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -128,7 +128,7 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& ShaderNode* fg = fgOutput ? fgOutput->getNode() : nullptr; ShaderNode* bg = bgOutput ? bgOutput->getNode() : nullptr; ShaderNode* mix = mixOutput ? mixOutput->getNode() : nullptr; - if ((fg && !bg) || (!fg && bg)) + if ((bool) fg != (bool) bg) { baseReceiverNode = fg ? fg : bg; // take the node that is valid top = baseReceiverNode; diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index b8eed3e9b8..81daa9e0a7 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -286,9 +286,6 @@ string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const { const AggregateValue& aggValue = static_cast(value); - auto typeDesc = TypeDesc::get(aggValue.getTypeString()); - auto structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); - string result = "{"; string separator = ""; @@ -297,8 +294,8 @@ string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const result += separator; separator = ";"; - auto memberTypeName = memberValue->getTypeString(); - auto memberTypeDesc = TypeDesc::get(memberTypeName); + const string& memberTypeName = memberValue->getTypeString(); + TypeDesc memberTypeDesc = TypeDesc::get(memberTypeName); // Recursively use the syntax to generate the output, so we can support nested structs. const string valueStr = _parentSyntax->getValue(memberTypeDesc, *memberValue, true); diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 46d03a1665..aefdf2d401 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -702,7 +702,7 @@ void Viewer::createDocumentationInterface(ng::ref parent) ng::Alignment::Minimum, 2, 2); gridLayout2->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); - const std::vector> KEYBOARD_SHORTCUTS = + const std::array, 16> KEYBOARD_SHORTCUTS = { std::make_pair("R", "Reload the current material from file. " "Hold SHIFT to reload all standard libraries as well."), From f9a4222c8251c1d8bf808e5a705f74b72531bb88 Mon Sep 17 00:00:00 2001 From: JGamache-autodesk <56274617+JGamache-autodesk@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:28:45 -0500 Subject: [PATCH 19/20] Consider subsurface color in dielectric albedo (#2105) I am experimenting with OpenPBR to UsdPreviewSurface export code in Maya and tried chaining the two translator graphs already provided in MaterialX. Results are quite good, except when the subsurface color is extremely different from the base color. This can be fixed by computing a dielectric base albedo that mixes the scaled base color and the subsurface color. --- libraries/bxdf/translation/standard_surface_to_usd.mtlx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/bxdf/translation/standard_surface_to_usd.mtlx b/libraries/bxdf/translation/standard_surface_to_usd.mtlx index 51c7d5fc6e..f1009e3a4c 100644 --- a/libraries/bxdf/translation/standard_surface_to_usd.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_usd.mtlx @@ -12,6 +12,8 @@ + + @@ -47,13 +49,18 @@ + + + + + - + From bf2804d21aae379937ebbefcef62f62c9604dc0b Mon Sep 17 00:00:00 2001 From: samip Date: Wed, 4 Dec 2024 17:13:56 -0800 Subject: [PATCH 20/20] Fix handling of missing scenes in the Web Viewer (#2124) JsViewerX attempted to use a cube when the selected GLTF file contained no model, but the code never added it to the scene. --- javascript/MaterialXView/source/viewer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index febe34c809..e558ad0bc9 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -90,14 +90,14 @@ export class Scene } this.#_rootNode = null; - const model = gltfData.scene; + let model = gltfData.scene; if (!model) { const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0xdddddd }); const cube = new THREE.Mesh(geometry, material); - obj = new Group(); - obj.add(geometry); + model = new Group(); + model.add(cube); } else {