From 138d7a72f807ee141ed76c3747500702e0835c8d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 27 Feb 2024 16:22:36 -0800 Subject: [PATCH 01/14] Extend web deployment to branches This changelist extends web deployment to GitHub branches, allowing upcoming development in the dev_1.39 branch to be validated in the MaterialX Web Viewer. --- .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 0c42bf93ad..95ed463b34 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -331,7 +331,7 @@ jobs: working-directory: javascript/MaterialXView - name: Deploy Web Viewer - if: matrix.build_javascript == 'ON' && github.ref == 'refs/heads/main' + if: matrix.build_javascript == 'ON' && github.event_name != 'pull_request' uses: JamesIves/github-pages-deploy-action@v4 with: branch: gh-pages From ce287e595279fed3d75723ba77a63ba2f2b19fb1 Mon Sep 17 00:00:00 2001 From: Niklas Harrysson Date: Fri, 1 Mar 2024 23:23:18 +0100 Subject: [PATCH 02/14] Redesign of TypeDesc class (#1711) This change list implements a redesign of the TypeDesc class used for data type descriptions in MaterialX. The main purpose of this change is to solve issue #1608. But the new design also gives performance improvements to the use of this class. Since the TypeDesc class is used frequently many files are touched by this change and there are some API breakage. Function wrappers with [[deprecated]] are added to minimize API breakage, but it's not possible for everything that changed. For example, the TypeDesc instances are now stored and accessed by value rather then by pointer, requiring a change to the access syntax. --- .../GlslResourceBindingContext.cpp | 22 +-- .../MaterialXGenGlsl/GlslShaderGenerator.cpp | 28 +-- source/MaterialXGenGlsl/GlslShaderGenerator.h | 3 +- source/MaterialXGenGlsl/GlslSyntax.cpp | 8 +- source/MaterialXGenGlsl/GlslSyntax.h | 2 +- .../Nodes/GeomColorNodeGlsl.cpp | 4 +- .../Nodes/HeightToNormalNodeGlsl.cpp | 4 +- .../Nodes/HeightToNormalNodeGlsl.h | 2 +- .../Nodes/LightCompoundNodeGlsl.cpp | 2 +- .../VkResourceBindingContext.cpp | 22 +-- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 12 +- source/MaterialXGenMdl/MdlSyntax.cpp | 61 +++--- source/MaterialXGenMdl/MdlSyntax.h | 21 +- source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp | 4 +- source/MaterialXGenMdl/Nodes/BlurNodeMdl.h | 2 +- .../Nodes/ClosureLayerNodeMdl.cpp | 2 +- .../MaterialXGenMdl/Nodes/CombineNodeMdl.cpp | 4 +- .../MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp | 4 +- .../Nodes/HeightToNormalNodeMdl.cpp | 4 +- .../Nodes/HeightToNormalNodeMdl.h | 2 +- .../MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp | 2 +- .../MslResourceBindingContext.cpp | 20 +- source/MaterialXGenMsl/MslShaderGenerator.cpp | 30 +-- source/MaterialXGenMsl/MslShaderGenerator.h | 3 +- source/MaterialXGenMsl/MslSyntax.cpp | 10 +- source/MaterialXGenMsl/MslSyntax.h | 4 +- .../Nodes/GeomColorNodeMsl.cpp | 4 +- .../Nodes/HeightToNormalNodeMsl.cpp | 4 +- .../Nodes/HeightToNormalNodeMsl.h | 2 +- .../Nodes/LightCompoundNodeMsl.cpp | 2 +- source/MaterialXGenOsl/OslShaderGenerator.cpp | 26 +-- .../ColorManagementSystem.cpp | 2 +- .../ColorManagementSystem.h | 4 +- .../DefaultColorManagementSystem.cpp | 2 +- source/MaterialXGenShader/GenContext.h | 18 +- .../MaterialXGenShader/HwShaderGenerator.cpp | 2 +- source/MaterialXGenShader/Nodes/BlurNode.cpp | 9 +- source/MaterialXGenShader/Nodes/BlurNode.h | 9 +- .../Nodes/ClosureAddNode.cpp | 4 +- .../Nodes/ClosureCompoundNode.cpp | 6 +- .../Nodes/ClosureMixNode.cpp | 4 +- .../Nodes/ClosureMultiplyNode.cpp | 4 +- .../Nodes/ClosureSourceCodeNode.cpp | 4 +- .../MaterialXGenShader/Nodes/CombineNode.cpp | 6 +- .../MaterialXGenShader/Nodes/ConvertNode.cpp | 8 +- .../Nodes/ConvolutionNode.cpp | 6 +- .../Nodes/ConvolutionNode.h | 3 +- .../Nodes/HwTexCoordNode.cpp | 4 +- .../MaterialXGenShader/Nodes/SwizzleNode.cpp | 2 +- source/MaterialXGenShader/ShaderGenerator.cpp | 22 +-- source/MaterialXGenShader/ShaderGraph.cpp | 32 +-- source/MaterialXGenShader/ShaderGraph.h | 10 +- source/MaterialXGenShader/ShaderNode.cpp | 38 ++-- source/MaterialXGenShader/ShaderNode.h | 22 +-- source/MaterialXGenShader/ShaderNodeImpl.h | 1 + source/MaterialXGenShader/ShaderStage.cpp | 8 +- source/MaterialXGenShader/ShaderStage.h | 42 +++- source/MaterialXGenShader/Syntax.cpp | 90 ++++----- source/MaterialXGenShader/Syntax.h | 58 ++++-- source/MaterialXGenShader/TypeDesc.cpp | 132 +++++-------- source/MaterialXGenShader/TypeDesc.h | 184 +++++++++++------- source/MaterialXGenShader/UnitSystem.cpp | 4 +- source/MaterialXGenShader/UnitSystem.h | 4 +- source/MaterialXGenShader/Util.cpp | 4 +- source/MaterialXRender/LightHandler.cpp | 4 +- source/MaterialXRender/Util.cpp | 4 +- source/MaterialXRenderGlsl/GlslMaterial.cpp | 2 +- source/MaterialXRenderGlsl/GlslProgram.cpp | 36 ++-- source/MaterialXRenderGlsl/GlslProgram.h | 2 +- source/MaterialXRenderMsl/MslMaterial.mm | 2 +- .../MslPipelineStateObject.h | 2 +- .../MslPipelineStateObject.mm | 24 +-- .../MaterialXTest/MaterialXGenMdl/GenMdl.cpp | 4 +- .../MaterialXTest/MaterialXGenOsl/GenOsl.cpp | 4 +- .../MaterialXGenShader/GenShader.cpp | 49 +++-- .../MaterialXGenShader/GenShaderUtil.cpp | 2 +- .../PyColorManagement.cpp | 2 +- .../PyMaterialXGenShader/PyTypeDesc.cpp | 5 +- .../PyMaterialXGenShader/PyUnitSystem.cpp | 2 +- 79 files changed, 640 insertions(+), 572 deletions(-) diff --git a/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp b/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp index d4496bf154..e8863da008 100644 --- a/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp +++ b/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp @@ -93,7 +93,7 @@ void GlslResourceBindingContext::emitResourceBindings(GenContext& context, const // Second, emit all sampler uniforms as separate uniforms with separate layout bindings for (auto uniform : uniforms.getVariableOrder()) { - if (*uniform->getType() == *Type::FILENAME) + if (uniform->getType() == Type::FILENAME) { generator.emitString("layout (binding=" + std::to_string(_separateBindingLocation ? _hwUniformBindLocation++ : _hwSamplerBindLocation++) + ") " + syntax.getUniformQualifier() + " ", stage); generator.emitVariableDeclaration(uniform, EMPTY_STRING, context, stage, false); @@ -116,16 +116,16 @@ void GlslResourceBindingContext::emitStructuredResourceBindings(GenContext& cont // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_uniform_buffer_object.txt const size_t baseAlignment = 16; - std::unordered_map alignmentMap({ { Type::FLOAT, baseAlignment / 4 }, - { Type::INTEGER, baseAlignment / 4 }, - { Type::BOOLEAN, baseAlignment / 4 }, - { Type::COLOR3, baseAlignment }, - { Type::COLOR4, baseAlignment }, - { Type::VECTOR2, baseAlignment }, - { Type::VECTOR3, baseAlignment }, - { Type::VECTOR4, baseAlignment }, - { Type::MATRIX33, baseAlignment * 4 }, - { Type::MATRIX44, baseAlignment * 4 } }); + const std::unordered_map alignmentMap({ { Type::FLOAT, baseAlignment / 4 }, + { Type::INTEGER, baseAlignment / 4 }, + { Type::BOOLEAN, baseAlignment / 4 }, + { Type::COLOR3, baseAlignment }, + { Type::COLOR4, baseAlignment }, + { Type::VECTOR2, baseAlignment }, + { Type::VECTOR3, baseAlignment }, + { Type::VECTOR4, baseAlignment }, + { Type::MATRIX33, baseAlignment * 4 }, + { Type::MATRIX44, baseAlignment * 4 } }); // Get struct alignment and size // alignment, uniform member index diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp index f8ed1a4892..c33f262c79 100644 --- a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp +++ b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp @@ -713,7 +713,7 @@ void GlslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& c } else { - if (!outputSocket->getType()->isFloat4()) + if (!outputSocket->getType().isFloat4()) { toVec4(outputSocket->getType(), finalOutput); } @@ -725,7 +725,7 @@ void GlslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& c string outputValue = outputSocket->getValue() ? _syntax->getValue(outputSocket->getType(), *outputSocket->getValue()) : _syntax->getDefaultValue(outputSocket->getType()); - if (!outputSocket->getType()->isFloat4()) + if (!outputSocket->getType().isFloat4()) { string finalOutput = outputSocket->getVariable() + "_tmp"; emitLine(_syntax->getTypeName(outputSocket->getType()) + " " + finalOutput + " = " + outputValue, stage); @@ -772,21 +772,21 @@ void GlslShaderGenerator::emitLightFunctionDefinitions(const ShaderGraph& graph, } } -void GlslShaderGenerator::toVec4(const TypeDesc* type, string& variable) +void GlslShaderGenerator::toVec4(TypeDesc type, string& variable) { - if (type->isFloat3()) + if (type.isFloat3()) { variable = "vec4(" + variable + ", 1.0)"; } - else if (type->isFloat2()) + else if (type.isFloat2()) { variable = "vec4(" + variable + ", 0.0, 1.0)"; } - else if (*type == *Type::FLOAT || *type == *Type::INTEGER) + else if (type == Type::FLOAT || type == Type::INTEGER) { variable = "vec4(" + variable + ", " + variable + ", " + variable + ", 1.0)"; } - else if (*type == *Type::BSDF || *type == *Type::EDF) + else if (type == Type::BSDF || type == Type::EDF) { variable = "vec4(" + variable + ", 1.0)"; } @@ -802,7 +802,7 @@ void GlslShaderGenerator::emitVariableDeclaration(const ShaderPort* variable, co bool assignValue) const { // A file texture input needs special handling on GLSL - if (*variable->getType() == *Type::FILENAME) + if (variable->getType() == Type::FILENAME) { // Samplers must always be uniforms string str = qualifier.empty() ? EMPTY_STRING : qualifier + " "; @@ -813,14 +813,14 @@ void GlslShaderGenerator::emitVariableDeclaration(const ShaderPort* variable, co string str = qualifier.empty() ? EMPTY_STRING : qualifier + " "; // Varying parameters of type int must be flat qualified on output from vertex stage and // input to pixel stage. The only way to get these is with geompropvalue_integer nodes. - if (qualifier.empty() && *variable->getType() == *Type::INTEGER && !assignValue && variable->getName().rfind(HW::T_IN_GEOMPROP, 0) == 0) + if (qualifier.empty() && variable->getType() == Type::INTEGER && !assignValue && variable->getName().rfind(HW::T_IN_GEOMPROP, 0) == 0) { str += GlslSyntax::FLAT_QUALIFIER + " "; } str += _syntax->getTypeName(variable->getType()) + " " + variable->getVariable(); // If an array we need an array qualifier (suffix) for the variable name - if (variable->getType()->isArray() && variable->getValue()) + if (variable->getType().isArray() && variable->getValue()) { str += _syntax->getArrayVariableSuffix(variable->getType(), *variable->getValue()); } @@ -865,16 +865,16 @@ ShaderNodeImplPtr GlslShaderGenerator::getImplementation(const NodeDef& nodedef, throw ExceptionShaderGenError("NodeDef '" + nodedef.getName() + "' has no outputs defined"); } - const TypeDesc* outputType = TypeDesc::get(outputs[0]->getType()); + const TypeDesc outputType = TypeDesc::get(outputs[0]->getType()); if (implElement->isA()) { // Use a compound implementation. - if (*outputType == *Type::LIGHTSHADER) + if (outputType == Type::LIGHTSHADER) { impl = LightCompoundNodeGlsl::create(); } - else if (outputType->isClosure()) + else if (outputType.isClosure()) { impl = ClosureCompoundNode::create(); } @@ -890,7 +890,7 @@ ShaderNodeImplPtr GlslShaderGenerator::getImplementation(const NodeDef& nodedef, if (!impl) { // Fall back to source code implementation. - if (outputType->isClosure()) + if (outputType.isClosure()) { impl = ClosureSourceCodeNode::create(); } diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.h b/source/MaterialXGenGlsl/GlslShaderGenerator.h index aafd665140..c3dc78b5aa 100644 --- a/source/MaterialXGenGlsl/GlslShaderGenerator.h +++ b/source/MaterialXGenGlsl/GlslShaderGenerator.h @@ -81,7 +81,8 @@ class MX_GENGLSL_API GlslShaderGenerator : public HwShaderGenerator /// Emit function definitions for lighting code virtual void emitLightFunctionDefinitions(const ShaderGraph& graph, GenContext& context, ShaderStage& stage) const; - static void toVec4(const TypeDesc* type, string& variable); + static void toVec4(TypeDesc type, string& variable); + [[deprecated]] static void toVec4(const TypeDesc* type, string& variable) { toVec4(*type, variable); } /// Nodes used internally for light sampling. vector _lightSamplingNodes; diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp index 46f2307d5c..db7b2e742e 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.cpp +++ b/source/MaterialXGenGlsl/GlslSyntax.cpp @@ -350,10 +350,10 @@ GlslSyntax::GlslSyntax() bool GlslSyntax::typeSupported(const TypeDesc* type) const { - return type != Type::STRING; + return *type != Type::STRING; } -bool GlslSyntax::remapEnumeration(const string& value, const TypeDesc* type, const string& enumNames, std::pair& result) const +bool GlslSyntax::remapEnumeration(const string& value, TypeDesc type, const string& enumNames, std::pair& result) const { // Early out if not an enum input. if (enumNames.empty()) @@ -362,9 +362,7 @@ bool GlslSyntax::remapEnumeration(const string& value, const TypeDesc* type, con } // Don't convert already supported types - // or filenames and arrays. - if (typeSupported(type) || - *type == *Type::FILENAME || (type && type->isArray())) + if (type != Type::STRING) { return false; } diff --git a/source/MaterialXGenGlsl/GlslSyntax.h b/source/MaterialXGenGlsl/GlslSyntax.h index b988bd2a6d..8408534e7e 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.h +++ b/source/MaterialXGenGlsl/GlslSyntax.h @@ -33,7 +33,7 @@ class MX_GENGLSL_API GlslSyntax : public Syntax /// Given an input specification attempt to remap this to an enumeration which is accepted by /// the shader generator. The enumeration may be converted to a different type than the input. - bool remapEnumeration(const string& value, const TypeDesc* type, const string& enumNames, std::pair& result) const override; + bool remapEnumeration(const string& value, TypeDesc type, const string& enumNames, std::pair& result) const override; static const string INPUT_QUALIFIER; static const string OUTPUT_QUALIFIER; diff --git a/source/MaterialXGenGlsl/Nodes/GeomColorNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/GeomColorNodeGlsl.cpp index bdcb4c0fac..7e24331f93 100644 --- a/source/MaterialXGenGlsl/Nodes/GeomColorNodeGlsl.cpp +++ b/source/MaterialXGenGlsl/Nodes/GeomColorNodeGlsl.cpp @@ -49,11 +49,11 @@ void GeomColorNodeGlsl::emitFunctionCall(const ShaderNode& node, GenContext& con DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { string suffix = ""; - if (*output->getType() == *Type::FLOAT) + if (output->getType() == Type::FLOAT) { suffix = ".r"; } - else if (*output->getType() == *Type::COLOR3) + else if (output->getType() == Type::COLOR3) { suffix = ".rgb"; } diff --git a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.cpp index 14716eee1e..f65580b9e2 100644 --- a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.cpp +++ b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.cpp @@ -51,10 +51,10 @@ void HeightToNormalNodeGlsl::computeSampleOffsetStrings(const string& sampleSize } } -bool HeightToNormalNodeGlsl::acceptsInputType(const TypeDesc* type) const +bool HeightToNormalNodeGlsl::acceptsInputType(TypeDesc type) const { // Only support inputs which are float scalar - return (*type == *Type::FLOAT && type->isScalar()); + return (type == Type::FLOAT && type.isScalar()); } void HeightToNormalNodeGlsl::emitFunctionDefinition(const ShaderNode&, GenContext& context, ShaderStage& stage) const diff --git a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h index fc6e6b421f..8a08081987 100644 --- a/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h +++ b/source/MaterialXGenGlsl/Nodes/HeightToNormalNodeGlsl.h @@ -27,7 +27,7 @@ class MX_GENGLSL_API HeightToNormalNodeGlsl : public ConvolutionNode protected: /// Return if given type is an acceptible input - bool acceptsInputType(const TypeDesc* type) const override; + bool acceptsInputType(TypeDesc type) const override; /// Compute offset strings for sampling void computeSampleOffsetStrings(const string& sampleSizeName, const string& offsetTypeString, diff --git a/source/MaterialXGenGlsl/Nodes/LightCompoundNodeGlsl.cpp b/source/MaterialXGenGlsl/Nodes/LightCompoundNodeGlsl.cpp index a2052134d9..6f005766fd 100644 --- a/source/MaterialXGenGlsl/Nodes/LightCompoundNodeGlsl.cpp +++ b/source/MaterialXGenGlsl/Nodes/LightCompoundNodeGlsl.cpp @@ -96,7 +96,7 @@ void LightCompoundNodeGlsl::emitFunctionDefinition(ClosureContext* cct, GenConte { // Use the first output for classifying node type for the closure context. // This is only relevent for closures, and they only have a single output. - const TypeDesc* nodeType = _rootGraph->getOutputSocket()->getType(); + const TypeDesc nodeType = _rootGraph->getOutputSocket()->getType(); shadergen.emitLine("void " + _functionName + cct->getSuffix(nodeType) + "(LightData light, vec3 position, out lightshader result)", stage, false); } else diff --git a/source/MaterialXGenGlsl/VkResourceBindingContext.cpp b/source/MaterialXGenGlsl/VkResourceBindingContext.cpp index 89e65f9d07..543b2c2e02 100644 --- a/source/MaterialXGenGlsl/VkResourceBindingContext.cpp +++ b/source/MaterialXGenGlsl/VkResourceBindingContext.cpp @@ -80,7 +80,7 @@ void VkResourceBindingContext::emitResourceBindings(GenContext& context, const V // Second, emit all sampler uniforms as separate uniforms with separate layout bindings for (auto uniform : uniforms.getVariableOrder()) { - if (*uniform->getType() == *Type::FILENAME) + if (uniform->getType() == Type::FILENAME) { generator.emitString("layout (binding=" + std::to_string(_hwUniformBindLocation++) + ") " + syntax.getUniformQualifier() + " ", stage); generator.emitVariableDeclaration(uniform, EMPTY_STRING, context, stage, false); @@ -103,16 +103,16 @@ void VkResourceBindingContext::emitStructuredResourceBindings(GenContext& contex // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_uniform_buffer_object.txt const size_t baseAlignment = 16; - std::unordered_map alignmentMap({ { Type::FLOAT, baseAlignment / 4 }, - { Type::INTEGER, baseAlignment / 4 }, - { Type::BOOLEAN, baseAlignment / 4 }, - { Type::COLOR3, baseAlignment }, - { Type::COLOR4, baseAlignment }, - { Type::VECTOR2, baseAlignment }, - { Type::VECTOR3, baseAlignment }, - { Type::VECTOR4, baseAlignment }, - { Type::MATRIX33, baseAlignment * 4 }, - { Type::MATRIX44, baseAlignment * 4 } }); + const std::unordered_map alignmentMap({ { Type::FLOAT, baseAlignment / 4 }, + { Type::INTEGER, baseAlignment / 4 }, + { Type::BOOLEAN, baseAlignment / 4 }, + { Type::COLOR3, baseAlignment }, + { Type::COLOR4, baseAlignment }, + { Type::VECTOR2, baseAlignment }, + { Type::VECTOR3, baseAlignment }, + { Type::VECTOR4, baseAlignment }, + { Type::MATRIX33, baseAlignment * 4 }, + { Type::MATRIX44, baseAlignment * 4 } }); // Get struct alignment and size // alignment, uniform member index diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index 50acc66d47..bd9e2f725f 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -291,10 +291,10 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G // Get final result const string result = getUpstreamResult(outputSocket, context); - const TypeDesc* outputType = outputSocket->getType(); + const TypeDesc outputType = outputSocket->getType(); if (graph.hasClassification(ShaderNode::Classification::TEXTURE)) { - if (*outputType == *Type::DISPLACEMENTSHADER) + if (outputType == Type::DISPLACEMENTSHADER) { emitLine("float3 displacement__ = " + result + ".geometry.displacement", stage); emitLine("color finalOutput__ = mk_color3(" @@ -367,12 +367,12 @@ ShaderNodeImplPtr MdlShaderGenerator::getImplementation(const NodeDef& nodedef, throw ExceptionShaderGenError("NodeDef '" + nodedef.getName() + "' has no outputs defined"); } - const TypeDesc* outputType = TypeDesc::get(outputs[0]->getType()); + const TypeDesc outputType = TypeDesc::get(outputs[0]->getType()); if (implElement->isA()) { // Use a compound implementation. - if (outputType->isClosure()) + if (outputType.isClosure()) { impl = ClosureCompoundNodeMdl::create(); } @@ -388,7 +388,7 @@ ShaderNodeImplPtr MdlShaderGenerator::getImplementation(const NodeDef& nodedef, if (!impl) { // Fall back to source code implementation. - if (outputType->isClosure()) + if (outputType.isClosure()) { impl = ClosureSourceCodeNodeMdl::create(); } @@ -692,7 +692,7 @@ void MdlShaderGenerator::emitShaderInputs(const DocumentPtr doc, const VariableB { const ShaderPort* input = inputs[i]; - const string& qualifier = input->isUniform() || *input->getType() == *Type::FILENAME ? uniformPrefix : EMPTY_STRING; + const string& qualifier = input->isUniform() || input->getType() == Type::FILENAME ? uniformPrefix : EMPTY_STRING; const string& type = _syntax->getTypeName(input->getType()); string value = input->getValue() ? _syntax->getValue(input->getType(), *input->getValue(), true) : EMPTY_STRING; diff --git a/source/MaterialXGenMdl/MdlSyntax.cpp b/source/MaterialXGenMdl/MdlSyntax.cpp index f32fe6c60f..5565f3e31f 100644 --- a/source/MaterialXGenMdl/MdlSyntax.cpp +++ b/source/MaterialXGenMdl/MdlSyntax.cpp @@ -17,12 +17,12 @@ MATERIALX_NAMESPACE_BEGIN namespace Type { -const TypeDesc* MDL_COORDINATESPACE = TypeDesc::registerType("coordinatespace", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0); -const TypeDesc* MDL_ADDRESSMODE = TypeDesc::registerType("addressmode", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0); -const TypeDesc* MDL_FILTERLOOKUPMODE = TypeDesc::registerType("filterlookup", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0); -const TypeDesc* MDL_FILTERTYPE = TypeDesc::registerType("filtertype", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0); -const TypeDesc* MDL_DISTRIBUTION = TypeDesc::registerType("distributiontype", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0); -const TypeDesc* MDL_SCATTER_MODE = TypeDesc::registerType("scatter_mode", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0); +TYPEDESC_REGISTER_TYPE(MDL_COORDINATESPACE, "coordinatespace") +TYPEDESC_REGISTER_TYPE(MDL_ADDRESSMODE, "addressmode") +TYPEDESC_REGISTER_TYPE(MDL_FILTERLOOKUPMODE, "filterlookup") +TYPEDESC_REGISTER_TYPE(MDL_FILTERTYPE, "filtertype") +TYPEDESC_REGISTER_TYPE(MDL_DISTRIBUTIONTYPE, "distributiontype") +TYPEDESC_REGISTER_TYPE(MDL_SCATTER_MODE, "scatter_mode") } // namespace Type @@ -448,7 +448,7 @@ MdlSyntax::MdlSyntax() FILTERTYPE_MEMBERS)); registerTypeSyntax( - Type::MDL_DISTRIBUTION, + Type::MDL_DISTRIBUTIONTYPE, std::make_shared( "mx_distribution_type", "mx_distribution_type_ggx", @@ -464,7 +464,7 @@ MdlSyntax::MdlSyntax() SCATTER_MODE_MEMBERS)); } -const TypeDesc* MdlSyntax::getEnumeratedType(const string& value) const +TypeDesc MdlSyntax::getEnumeratedType(const string& value) const { for (const TypeSyntaxPtr& syntax : getTypeSyntaxes()) { @@ -475,24 +475,27 @@ const TypeDesc* MdlSyntax::getEnumeratedType(const string& value) const // We should find a more safe way to handled this. if (std::find(members.begin(), members.end(), value) != members.end()) { - return getTypeDescription(syntax); + auto pos = std::find(_typeSyntaxes.begin(), _typeSyntaxes.end(), syntax); + if (pos != _typeSyntaxes.end()) + { + const size_t index = static_cast(std::distance(_typeSyntaxes.begin(), pos)); + for (auto item : _typeSyntaxIndexByType) + { + if (item.second == index) + { + return item.first; + } + } + } } } } - return nullptr; + return Type::NONE; } -const std::unordered_map CHANNELS_TO_XYZW = +string MdlSyntax::getSwizzledVariable(const string& srcName, TypeDesc srcType, const string& channels, TypeDesc dstType) const { - { 'r', 'x' }, { 'x', 'x' }, - { 'g', 'y' }, { 'y', 'y' }, - { 'b', 'z' }, { 'z', 'z' }, - { 'a', 'w' }, { 'w', 'w' } -}; - -string MdlSyntax::getSwizzledVariable(const string& srcName, const TypeDesc* srcType, const string& channels, const TypeDesc* dstType) const -{ - if (*srcType == *Type::COLOR3 || *srcType == *Type::COLOR4) + if (srcType == Type::COLOR3 || srcType == Type::COLOR4) { const TypeSyntax& srcSyntax = getTypeSyntax(srcType); const TypeSyntax& dstSyntax = getTypeSyntax(dstType); @@ -516,14 +519,14 @@ string MdlSyntax::getSwizzledVariable(const string& srcName, const TypeDesc* src throw ExceptionShaderGenError("Invalid channel pattern '" + channels + "'."); } - int channelIndex = srcType->getChannelIndex(ch); - if (channelIndex < 0 || channelIndex >= static_cast(srcMembers.size())) + const size_t channelIndex = it->second; + if (channelIndex < 0 || channelIndex >= srcMembers.size()) { - throw ExceptionShaderGenError("Given channel index: '" + string(1, ch) + "' in channels pattern is incorrect for type '" + srcType->getName() + "'."); + throw ExceptionShaderGenError("Given channel index: '" + string(1, ch) + "' in channels pattern is incorrect for type '" + srcType.getName() + "'."); } string variable = srcName; - if (*srcType == *Type::COLOR3) + if (srcType == Type::COLOR3) { variable = "float3(" + srcName + ")"; } @@ -540,9 +543,9 @@ string MdlSyntax::getSwizzledVariable(const string& srcName, const TypeDesc* src return Syntax::getSwizzledVariable(srcName, srcType, channels, dstType); } -string MdlSyntax::getArrayTypeSuffix(const TypeDesc* type, const Value& value) const +string MdlSyntax::getArrayTypeSuffix(TypeDesc type, const Value& value) const { - if (type->isArray()) + if (type.isArray()) { if (value.isA>()) { @@ -558,7 +561,7 @@ string MdlSyntax::getArrayTypeSuffix(const TypeDesc* type, const Value& value) c return string(); } -bool MdlSyntax::remapEnumeration(const string& value, const TypeDesc* type, const string& enumNames, std::pair& result) const +bool MdlSyntax::remapEnumeration(const string& value, TypeDesc type, const string& enumNames, std::pair& result) const { // Early out if not an enum input. if (enumNames.empty()) @@ -567,7 +570,7 @@ bool MdlSyntax::remapEnumeration(const string& value, const TypeDesc* type, cons } // Don't convert filenames or arrays. - if (*type == *Type::FILENAME || (type && type->isArray())) + if (type == Type::FILENAME || type.isArray()) { return false; } @@ -576,7 +579,7 @@ bool MdlSyntax::remapEnumeration(const string& value, const TypeDesc* type, cons if (!value.empty()) { result.first = getEnumeratedType(value); - if (!result.first || (result.first->getSemantic() != TypeDesc::Semantic::SEMANTIC_ENUM)) + if (result.first == Type::NONE || (result.first.getSemantic() != TypeDesc::Semantic::SEMANTIC_ENUM)) { return false; } diff --git a/source/MaterialXGenMdl/MdlSyntax.h b/source/MaterialXGenMdl/MdlSyntax.h index c5b8408fc1..1e318ac19d 100644 --- a/source/MaterialXGenMdl/MdlSyntax.h +++ b/source/MaterialXGenMdl/MdlSyntax.h @@ -33,13 +33,13 @@ class MX_GENMDL_API MdlSyntax : public Syntax const string& getUniformQualifier() const override { return UNIFORM_QUALIFIER; }; const string& getSourceFileExtension() const override { return SOURCE_FILE_EXTENSION; }; - string getSwizzledVariable(const string& srcName, const TypeDesc* srcType, const string& channels, const TypeDesc* dstType) const override; + string getSwizzledVariable(const string& srcName, TypeDesc srcType, const string& channels, TypeDesc dstType) const override; /// Override to return array type suffix. - string getArrayTypeSuffix(const TypeDesc* type, const Value& value) const override; + string getArrayTypeSuffix(TypeDesc type, const Value& value) const override; /// Override to indicate array variables have no array suffix. - string getArrayVariableSuffix(const TypeDesc*, const Value&) const override { return EMPTY_STRING; }; + string getArrayVariableSuffix(TypeDesc, const Value&) const override { return EMPTY_STRING; }; static const string CONST_QUALIFIER; static const string UNIFORM_QUALIFIER; @@ -57,11 +57,11 @@ class MX_GENMDL_API MdlSyntax : public Syntax static const StringVec SCATTER_MODE_MEMBERS; /// Get an type description for an enumeration based on member value - const TypeDesc* getEnumeratedType(const string& value) const; + TypeDesc getEnumeratedType(const string& value) const; /// Given an input specification attempt to remap this to an enumeration which is accepted by /// the shader generator. The enumeration may be converted to a different type than the input. - bool remapEnumeration(const string& value, const TypeDesc* type, const string& enumNames, std::pair& result) const override; + bool remapEnumeration(const string& value, TypeDesc type, const string& enumNames, std::pair& result) const override; /// Modify the given name string to remove any invalid characters or tokens. void makeValidName(string& name) const override; @@ -70,11 +70,12 @@ class MX_GENMDL_API MdlSyntax : public Syntax namespace Type { -extern MX_GENMDL_API const TypeDesc* MDL_ADDRESSMODE; -extern MX_GENMDL_API const TypeDesc* MDL_COORDINATESPACE; -extern MX_GENMDL_API const TypeDesc* MDL_FILTERLOOKUPMODE; -extern MX_GENMDL_API const TypeDesc* MDL_FILTERTYPE; -extern MX_GENMDL_API const TypeDesc* MDL_DISTRIBUTIONTYPE; +TYPEDESC_DEFINE_TYPE(MDL_COORDINATESPACE, "coordinatespace", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0) +TYPEDESC_DEFINE_TYPE(MDL_ADDRESSMODE, "addressmode", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0) +TYPEDESC_DEFINE_TYPE(MDL_FILTERLOOKUPMODE, "filterlookup", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0) +TYPEDESC_DEFINE_TYPE(MDL_FILTERTYPE, "filtertype", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0) +TYPEDESC_DEFINE_TYPE(MDL_DISTRIBUTIONTYPE, "distributiontype", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0) +TYPEDESC_DEFINE_TYPE(MDL_SCATTER_MODE, "scatter_mode", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_ENUM, 0) } // namespace Type diff --git a/source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp index 77ad53a39e..ae10ca3fa8 100644 --- a/source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/BlurNodeMdl.cpp @@ -17,7 +17,7 @@ ShaderNodeImplPtr BlurNodeMdl::create() return std::make_shared(); } -void BlurNodeMdl::outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, const TypeDesc* inputType, +void BlurNodeMdl::outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, TypeDesc inputType, const string& sampleName, const StringVec& sampleStrings) const { const Syntax& syntax = shadergen.getSyntax(); @@ -149,7 +149,7 @@ void BlurNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& context, shadergen.emitString(" = ", stage); shadergen.emitInput(filterTypeInput, context, stage); // Remap enumeration for comparison as needed - std::pair result; + std::pair result; string emitValue = "\"" + GAUSSIAN_FILTER + "\""; if (syntax.remapEnumeration(GAUSSIAN_FILTER, Type::STRING, FILTER_LIST, result)) { diff --git a/source/MaterialXGenMdl/Nodes/BlurNodeMdl.h b/source/MaterialXGenMdl/Nodes/BlurNodeMdl.h index f2fef8dae1..aa271ea237 100644 --- a/source/MaterialXGenMdl/Nodes/BlurNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/BlurNodeMdl.h @@ -24,7 +24,7 @@ class MX_GENMDL_API BlurNodeMdl : public BlurNode void emitSamplingFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; /// Output sample array - void outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, const TypeDesc* inputType, + void outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, TypeDesc inputType, const string& sampleName, const StringVec& sampleStrings) const override; }; diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index e097b804cd..1dfa45317f 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -35,7 +35,7 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // // 1. Handle the BSDF-over-VDF case // - if (*baseInput->getType() == *Type::VDF) + if (baseInput->getType() == Type::VDF) { // Make sure we have a top BSDF connected. if (!topInput->getConnection()) diff --git a/source/MaterialXGenMdl/Nodes/CombineNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CombineNodeMdl.cpp index 83dc755b7a..9d6789c94c 100644 --- a/source/MaterialXGenMdl/Nodes/CombineNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/CombineNodeMdl.cpp @@ -33,10 +33,10 @@ void CombineNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex throw ExceptionShaderGenError("Node '" + node.getName() + "' is not a valid convert node"); } - if (*in1->getType() == *Type::COLOR3) + if (in1->getType() == Type::COLOR3) { const ShaderInput* in2 = node.getInput(1); - if (!in2 || *in2->getType() != *Type::FLOAT) + if (!in2 || in2->getType() != Type::FLOAT) { throw ExceptionShaderGenError("Node '" + node.getName() + "' is not a valid convert node"); } diff --git a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp index b7b81e5d30..80c449e507 100644 --- a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp @@ -34,7 +34,7 @@ void CompoundNodeMdl::initialize(const InterfaceElement& element, GenContext& co // Materials can not be members of structs. Identify this case in order to handle it. for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { - if (output->getType()->getSemantic() == TypeDesc::SEMANTIC_SHADER) + if (output->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER) { _unrollReturnStructMembers = true; } @@ -233,7 +233,7 @@ void CompoundNodeMdl::emitFunctionSignature(const ShaderNode&, GenContext& conte int count = int(_rootGraph->numInputSockets()); for (ShaderGraphInputSocket* input : _rootGraph->getInputSockets()) { - const string& qualifier = input->isUniform() || *input->getType() == *Type::FILENAME ? uniformPrefix : EMPTY_STRING; + const string& qualifier = input->isUniform() || input->getType() == Type::FILENAME ? uniformPrefix : EMPTY_STRING; const string& type = syntax.getTypeName(input->getType()); string value = input->getValue() ? syntax.getValue(input->getType(), *input->getValue(), true) : EMPTY_STRING; diff --git a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.cpp index b52ebc8ab2..0c214eee93 100644 --- a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.cpp @@ -47,10 +47,10 @@ void HeightToNormalNodeMdl::computeSampleOffsetStrings(const string& sampleSizeN } } -bool HeightToNormalNodeMdl::acceptsInputType(const TypeDesc* type) const +bool HeightToNormalNodeMdl::acceptsInputType(TypeDesc type) const { // Only support inputs which are float scalar - return (*type == *Type::FLOAT && type->isScalar()); + return (type == Type::FLOAT && type.isScalar()); } void HeightToNormalNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const diff --git a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h index 4a7f372ab7..1e295e5872 100644 --- a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h @@ -24,7 +24,7 @@ class MX_GENMDL_API HeightToNormalNodeMdl : public ConvolutionNode protected: /// Return if given type is an acceptible input - bool acceptsInputType(const TypeDesc* type) const override; + bool acceptsInputType(TypeDesc type) const override; /// Compute offset strings for sampling void computeSampleOffsetStrings(const string& sampleSizeName, const string& offsetTypeString, diff --git a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp index 305f2ad814..6477cd9ae8 100644 --- a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp @@ -38,7 +38,7 @@ const ShaderInput* findTransmissionIOR(const ShaderNode& node) } for (const ShaderInput* input : node.getInputs()) { - if (*input->getType() == *Type::BSDF && input->getConnection()) + if (input->getType() == Type::BSDF && input->getConnection()) { const ShaderInput* ior = findTransmissionIOR(*input->getConnection()->getNode()); if (ior) diff --git a/source/MaterialXGenMsl/MslResourceBindingContext.cpp b/source/MaterialXGenMsl/MslResourceBindingContext.cpp index 5d6cbab6f9..297d907418 100644 --- a/source/MaterialXGenMsl/MslResourceBindingContext.cpp +++ b/source/MaterialXGenMsl/MslResourceBindingContext.cpp @@ -74,16 +74,16 @@ void MslResourceBindingContext::emitStructuredResourceBindings(GenContext& conte const size_t baseAlignment = 16; // Values are adjusted based on // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf - std::unordered_map alignmentMap({ { Type::FLOAT, baseAlignment / 4 }, - { Type::INTEGER, baseAlignment / 4 }, - { Type::BOOLEAN, baseAlignment / 4 }, - { Type::COLOR3, baseAlignment }, - { Type::COLOR4, baseAlignment }, - { Type::VECTOR2, baseAlignment / 2 }, - { Type::VECTOR3, baseAlignment }, - { Type::VECTOR4, baseAlignment }, - { Type::MATRIX33, baseAlignment * 4 }, - { Type::MATRIX44, baseAlignment * 4 } }); + const std::unordered_map alignmentMap({ { Type::FLOAT, baseAlignment / 4 }, + { Type::INTEGER, baseAlignment / 4 }, + { Type::BOOLEAN, baseAlignment / 4 }, + { Type::COLOR3, baseAlignment }, + { Type::COLOR4, baseAlignment }, + { Type::VECTOR2, baseAlignment / 2 }, + { Type::VECTOR3, baseAlignment }, + { Type::VECTOR4, baseAlignment }, + { Type::MATRIX33, baseAlignment * 4 }, + { Type::MATRIX44, baseAlignment * 4 } }); // Get struct alignment and size // alignment, uniform member index diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index c6f8ed979f..db23510ad8 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -604,7 +604,7 @@ void MslShaderGenerator::emitGlobalVariables(GenContext& context, bool hasUniforms = false; for (const ShaderPort* uniform : uniforms.getVariableOrder()) { - if (*uniform->getType() == *Type::FILENAME) + if (uniform->getType() == Type::FILENAME) { emitString(separator, stage); emitString("texture2d " + TEXTURE_NAME(uniform->getVariable()), stage); @@ -1181,7 +1181,7 @@ void MslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& co } else { - if (!outputSocket->getType()->isFloat4()) + if (!outputSocket->getType().isFloat4()) { toVec4(outputSocket->getType(), finalOutput); } @@ -1193,7 +1193,7 @@ void MslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& co string outputValue = outputSocket->getValue() ? _syntax->getValue(outputSocket->getType(), *outputSocket->getValue()) : _syntax->getDefaultValue(outputSocket->getType()); - if (!outputSocket->getType()->isFloat4()) + if (!outputSocket->getType().isFloat4()) { string finalOutput = outputSocket->getVariable() + "_tmp"; emitLine(_syntax->getTypeName(outputSocket->getType()) + " " + finalOutput + " = " + outputValue, stage); @@ -1272,21 +1272,21 @@ void MslShaderGenerator::emitLightFunctionDefinitions(const ShaderGraph& graph, } } -void MslShaderGenerator::toVec4(const TypeDesc* type, string& variable) +void MslShaderGenerator::toVec4(TypeDesc type, string& variable) { - if (type->isFloat3()) + if (type.isFloat3()) { variable = "float4(" + variable + ", 1.0)"; } - else if (type->isFloat2()) + else if (type.isFloat2()) { variable = "float4(" + variable + ", 0.0, 1.0)"; } - else if (*type == *Type::FLOAT || *type == *Type::INTEGER) + else if (type == Type::FLOAT || type == Type::INTEGER) { variable = "float4(" + variable + ", " + variable + ", " + variable + ", 1.0)"; } - else if (*type == *Type::BSDF || *type == *Type::EDF) + else if (type == Type::BSDF || type == Type::EDF) { variable = "float4(" + variable + ", 1.0)"; } @@ -1302,7 +1302,7 @@ void MslShaderGenerator::emitVariableDeclaration(const ShaderPort* variable, con bool assignValue) const { // A file texture input needs special handling on MSL - if (*variable->getType() == *Type::FILENAME) + if (variable->getType() == Type::FILENAME) { // Samplers must always be uniforms string str = qualifier.empty() ? EMPTY_STRING : qualifier + " "; @@ -1315,7 +1315,7 @@ void MslShaderGenerator::emitVariableDeclaration(const ShaderPort* variable, con str += _syntax->getTypeName(variable->getType()) + " " + variable->getVariable(); // If an array we need an array qualifier (suffix) for the variable name - if (variable->getType()->isArray() && variable->getValue()) + if (variable->getType().isArray() && variable->getValue()) { str += _syntax->getArrayVariableSuffix(variable->getType(), *variable->getValue()); } @@ -1327,7 +1327,7 @@ void MslShaderGenerator::emitVariableDeclaration(const ShaderPort* variable, con // Varying parameters of type int must be flat qualified on output from vertex stage and // input to pixel stage. The only way to get these is with geompropvalue_integer nodes. - if (qualifier.empty() && *variable->getType() == *Type::INTEGER && !assignValue && variable->getName().rfind(HW::T_IN_GEOMPROP, 0) == 0) + if (qualifier.empty() && variable->getType() == Type::INTEGER && !assignValue && variable->getName().rfind(HW::T_IN_GEOMPROP, 0) == 0) { str += "[[ " + MslSyntax::FLAT_QUALIFIER + " ]]"; } @@ -1367,16 +1367,16 @@ ShaderNodeImplPtr MslShaderGenerator::getImplementation(const NodeDef& nodedef, throw ExceptionShaderGenError("NodeDef '" + nodedef.getName() + "' has no outputs defined"); } - const TypeDesc* outputType = TypeDesc::get(outputs[0]->getType()); + const TypeDesc outputType = TypeDesc::get(outputs[0]->getType()); if (implElement->isA()) { // Use a compound implementation. - if (*outputType == *Type::LIGHTSHADER) + if (outputType == Type::LIGHTSHADER) { impl = LightCompoundNodeMsl::create(); } - else if (outputType->isClosure()) + else if (outputType.isClosure()) { impl = ClosureCompoundNode::create(); } @@ -1392,7 +1392,7 @@ ShaderNodeImplPtr MslShaderGenerator::getImplementation(const NodeDef& nodedef, if (!impl) { // Fall back to source code implementation. - if (outputType->isClosure()) + if (outputType.isClosure()) { impl = ClosureSourceCodeNode::create(); } diff --git a/source/MaterialXGenMsl/MslShaderGenerator.h b/source/MaterialXGenMsl/MslShaderGenerator.h index e9f2981045..6796f545d3 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.h +++ b/source/MaterialXGenMsl/MslShaderGenerator.h @@ -108,7 +108,8 @@ class MX_GENMSL_API MslShaderGenerator : public HwShaderGenerator /// Emit function definitions for lighting code virtual void emitLightFunctionDefinitions(const ShaderGraph& graph, GenContext& context, ShaderStage& stage) const; - static void toVec4(const TypeDesc* type, string& variable); + static void toVec4(TypeDesc type, string& variable); + [[deprecated]] static void toVec4(const TypeDesc* type, string& variable) { toVec4(*type, variable); } /// Nodes used internally for light sampling. vector _lightSamplingNodes; diff --git a/source/MaterialXGenMsl/MslSyntax.cpp b/source/MaterialXGenMsl/MslSyntax.cpp index a4ec46e0c0..dc062ef67b 100644 --- a/source/MaterialXGenMsl/MslSyntax.cpp +++ b/source/MaterialXGenMsl/MslSyntax.cpp @@ -330,7 +330,7 @@ MslSyntax::MslSyntax() "#define material surfaceshader")); } -string MslSyntax::getOutputTypeName(const TypeDesc* type) const +string MslSyntax::getOutputTypeName(TypeDesc type) const { const TypeSyntax& syntax = getTypeSyntax(type); return "thread " + syntax.getName() + "&"; @@ -338,10 +338,10 @@ string MslSyntax::getOutputTypeName(const TypeDesc* type) const bool MslSyntax::typeSupported(const TypeDesc* type) const { - return type != Type::STRING; + return *type != Type::STRING; } -bool MslSyntax::remapEnumeration(const string& value, const TypeDesc* type, const string& enumNames, std::pair& result) const +bool MslSyntax::remapEnumeration(const string& value, TypeDesc type, const string& enumNames, std::pair& result) const { // Early out if not an enum input. if (enumNames.empty()) @@ -350,9 +350,7 @@ bool MslSyntax::remapEnumeration(const string& value, const TypeDesc* type, cons } // Don't convert already supported types - // or filenames and arrays. - if (typeSupported(type) || - *type == *Type::FILENAME || (type && type->isArray())) + if (type != Type::STRING) { return false; } diff --git a/source/MaterialXGenMsl/MslSyntax.h b/source/MaterialXGenMsl/MslSyntax.h index 6bab3ee6f9..22469e2193 100644 --- a/source/MaterialXGenMsl/MslSyntax.h +++ b/source/MaterialXGenMsl/MslSyntax.h @@ -30,13 +30,13 @@ class MX_GENMSL_API MslSyntax : public Syntax const string& getSourceFileExtension() const override { return SOURCE_FILE_EXTENSION; }; const string& getStructKeyword() const { return STRUCT_KEYWORD; } - string getOutputTypeName(const TypeDesc* type) const override; + string getOutputTypeName(TypeDesc type) const override; bool typeSupported(const TypeDesc* type) const override; /// Given an input specification attempt to remap this to an enumeration which is accepted by /// the shader generator. The enumeration may be converted to a different type than the input. - bool remapEnumeration(const string& value, const TypeDesc* type, const string& enumNames, std::pair& result) const override; + bool remapEnumeration(const string& value, TypeDesc type, const string& enumNames, std::pair& result) const override; static const string INPUT_QUALIFIER; static const string OUTPUT_QUALIFIER; diff --git a/source/MaterialXGenMsl/Nodes/GeomColorNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/GeomColorNodeMsl.cpp index c540960906..3845e2ae76 100644 --- a/source/MaterialXGenMsl/Nodes/GeomColorNodeMsl.cpp +++ b/source/MaterialXGenMsl/Nodes/GeomColorNodeMsl.cpp @@ -49,11 +49,11 @@ void GeomColorNodeMsl::emitFunctionCall(const ShaderNode& node, GenContext& cont DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { string suffix = ""; - if (*output->getType() == *Type::FLOAT) + if (output->getType() == Type::FLOAT) { suffix = ".r"; } - else if (*output->getType() == *Type::COLOR3) + else if (output->getType() == Type::COLOR3) { suffix = ".rgb"; } diff --git a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.cpp index 2f07e55dfd..ab467c89ea 100644 --- a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.cpp +++ b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.cpp @@ -51,10 +51,10 @@ void HeightToNormalNodeMsl::computeSampleOffsetStrings(const string& sampleSizeN } } -bool HeightToNormalNodeMsl::acceptsInputType(const TypeDesc* type) const +bool HeightToNormalNodeMsl::acceptsInputType(TypeDesc type) const { // Only support inputs which are float scalar - return (*type == *Type::FLOAT && type->isScalar()); + return (type == Type::FLOAT && type.isScalar()); } void HeightToNormalNodeMsl::emitFunctionDefinition(const ShaderNode&, GenContext& context, ShaderStage& stage) const diff --git a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h index 035ad300b4..e8dd879949 100644 --- a/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h +++ b/source/MaterialXGenMsl/Nodes/HeightToNormalNodeMsl.h @@ -27,7 +27,7 @@ class MX_GENMSL_API HeightToNormalNodeMsl : public ConvolutionNode protected: /// Return if given type is an acceptible input - bool acceptsInputType(const TypeDesc* type) const override; + bool acceptsInputType(TypeDesc type) const override; /// Compute offset strings for sampling void computeSampleOffsetStrings(const string& sampleSizeName, const string& offsetTypeString, diff --git a/source/MaterialXGenMsl/Nodes/LightCompoundNodeMsl.cpp b/source/MaterialXGenMsl/Nodes/LightCompoundNodeMsl.cpp index 084518fa46..1e5bd787a8 100644 --- a/source/MaterialXGenMsl/Nodes/LightCompoundNodeMsl.cpp +++ b/source/MaterialXGenMsl/Nodes/LightCompoundNodeMsl.cpp @@ -96,7 +96,7 @@ void LightCompoundNodeMsl::emitFunctionDefinition(ClosureContext* cct, GenContex { // Use the first output for classifying node type for the closure context. // This is only relevent for closures, and they only have a single output. - const TypeDesc* nodeType = _rootGraph->getOutputSocket()->getType(); + const TypeDesc nodeType = _rootGraph->getOutputSocket()->getType(); shadergen.emitLine("void " + _functionName + cct->getSuffix(nodeType) + "(LightData light, float3 position, out lightshader result)", stage, false); } else diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index ff9f5b8a8e..5f6a37e332 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -196,11 +196,11 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G // Emit shader type, determined from the first // output if there are multiple outputs. const ShaderGraphOutputSocket* outputSocket0 = graph.getOutputSocket(0); - if (*outputSocket0->getType() == *Type::SURFACESHADER) + if (outputSocket0->getType() == Type::SURFACESHADER) { emitString("surface ", stage); } - else if (*outputSocket0->getType() == *Type::VOLUMESHADER) + else if (outputSocket0->getType() == Type::VOLUMESHADER) { emitString("volume ", stage); } @@ -250,10 +250,10 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G const VariableBlock& outputs = stage.getOutputBlock(OSL::OUTPUTS); const ShaderPort* singleOutput = outputs.size() == 1 ? outputs[0] : NULL; - const bool isSurfaceShaderOutput = singleOutput && *singleOutput->getType() == *Type::SURFACESHADER; + const bool isSurfaceShaderOutput = singleOutput && singleOutput->getType() == Type::SURFACESHADER; #ifdef MATERIALX_OSL_LEGACY_CLOSURES - const bool isBsdfOutput = singleOutput && *singleOutput->getType() == *Type::BSDF; + const bool isBsdfOutput = singleOutput && singleOutput->getType() == Type::BSDF; #endif if (isSurfaceShaderOutput) @@ -301,7 +301,7 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G for (size_t i = 0; i < inputs.size(); ++i) { ShaderPort* input = inputs[i]; - if (*input->getType() == *Type::FILENAME) + if (input->getType() == Type::FILENAME) { // Construct the textureresource variable. const string newVariableName = input->getVariable() + "_"; @@ -529,7 +529,7 @@ void OslShaderGenerator::emitShaderInputs(const VariableBlock& inputs, ShaderSta const ShaderPort* input = inputs[i]; const string& type = _syntax->getTypeName(input->getType()); - if (*input->getType() == *Type::FILENAME) + if (input->getType() == Type::FILENAME) { // Shader inputs of type 'filename' (textures) need special handling. // In OSL codegen a 'filename' is translated to the custom type 'textureresource', @@ -593,7 +593,7 @@ void OslShaderGenerator::emitShaderOutputs(const VariableBlock& outputs, ShaderS for (size_t i = 0; i < outputs.size(); ++i) { const ShaderPort* output = outputs[i]; - const TypeDesc* outputType = output->getType(); + const TypeDesc outputType = output->getType(); const string type = _syntax->getOutputTypeName(outputType); const string value = _syntax->getDefaultValue(outputType, true); const string& delim = (i == outputs.size() - 1) ? EMPTY_STRING : Syntax::COMMA; @@ -603,15 +603,15 @@ void OslShaderGenerator::emitShaderOutputs(const VariableBlock& outputs, ShaderS void OslShaderGenerator::emitMetadata(const ShaderPort* port, ShaderStage& stage) const { - static const std::unordered_map UI_WIDGET_METADATA = + 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, Value::createValueFromStrings("number", Type::STRING.getName())) }, + { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, + { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("filename", Type::STRING.getName())) }, + { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("checkBox", Type::STRING.getName())) } }; - static const std::set METADATA_TYPE_BLACKLIST = + static const std::set METADATA_TYPE_BLACKLIST = { Type::VECTOR2, // Custom struct types doesn't support metadata declarations. Type::VECTOR4, // diff --git a/source/MaterialXGenShader/ColorManagementSystem.cpp b/source/MaterialXGenShader/ColorManagementSystem.cpp index 1b6e5655a5..90cfbbc626 100644 --- a/source/MaterialXGenShader/ColorManagementSystem.cpp +++ b/source/MaterialXGenShader/ColorManagementSystem.cpp @@ -15,7 +15,7 @@ MATERIALX_NAMESPACE_BEGIN // ColorSpaceTransform methods // -ColorSpaceTransform::ColorSpaceTransform(const string& ss, const string& ts, const TypeDesc* t) : +ColorSpaceTransform::ColorSpaceTransform(const string& ss, const string& ts, TypeDesc t) : sourceSpace(ss), targetSpace(ts), type(t) diff --git a/source/MaterialXGenShader/ColorManagementSystem.h b/source/MaterialXGenShader/ColorManagementSystem.h index caf3826f94..5eb37b0a97 100644 --- a/source/MaterialXGenShader/ColorManagementSystem.h +++ b/source/MaterialXGenShader/ColorManagementSystem.h @@ -28,11 +28,11 @@ using ColorManagementSystemPtr = shared_ptr; /// Structure that represents color space transform information struct MX_GENSHADER_API ColorSpaceTransform { - ColorSpaceTransform(const string& ss, const string& ts, const TypeDesc* t); + ColorSpaceTransform(const string& ss, const string& ts, TypeDesc t); string sourceSpace; string targetSpace; - const TypeDesc* type; + TypeDesc type; /// Comparison operator bool operator==(const ColorSpaceTransform& other) const diff --git a/source/MaterialXGenShader/DefaultColorManagementSystem.cpp b/source/MaterialXGenShader/DefaultColorManagementSystem.cpp index 61209e153c..06e6e13c17 100644 --- a/source/MaterialXGenShader/DefaultColorManagementSystem.cpp +++ b/source/MaterialXGenShader/DefaultColorManagementSystem.cpp @@ -59,7 +59,7 @@ NodeDefPtr DefaultColorManagementSystem::getNodeDef(const ColorSpaceTransform& t { for (OutputPtr output : nodeDef->getOutputs()) { - if (output->getType() == transform.type->getName()) + if (output->getType() == transform.type.getName()) { return nodeDef; } diff --git a/source/MaterialXGenShader/GenContext.h b/source/MaterialXGenShader/GenContext.h index 1a936ac0dd..8ddf92771f 100644 --- a/source/MaterialXGenShader/GenContext.h +++ b/source/MaterialXGenShader/GenContext.h @@ -250,7 +250,7 @@ class MX_GENSHADER_API ClosureContext /// An extra argument for closure functions. /// An argument is a pair of strings holding the /// 'type' and 'name' of the argument. - using Argument = std::pair; + using Argument = std::pair; /// An array of arguments using Arguments = vector; @@ -265,30 +265,34 @@ class MX_GENSHADER_API ClosureContext int getType() const { return _type; } /// For the given node type add an extra argument to be used for the function in this context. - void addArgument(const TypeDesc* nodeType, const Argument& arg) + void addArgument(TypeDesc nodeType, const Argument& arg) { _arguments[nodeType].push_back(arg); } + [[deprecated]] void addArgument(const TypeDesc* nodeType, const Argument& arg) { addArgument(*nodeType, arg); } /// Return a list of extra argument to be used for the given node in this context. - const Arguments& getArguments(const TypeDesc* nodeType) const + const Arguments& getArguments(TypeDesc nodeType) const { auto it = _arguments.find(nodeType); return it != _arguments.end() ? it->second : EMPTY_ARGUMENTS; } + [[deprecated]] const Arguments& getArguments(const TypeDesc* nodeType) const { return getArguments(*nodeType); } /// For the given node type set a function name suffix to be used for the function in this context. - void setSuffix(const TypeDesc* nodeType, const string& suffix) + void setSuffix(TypeDesc nodeType, const string& suffix) { _suffix[nodeType] = suffix; } + [[deprecated]] void setSuffix(const TypeDesc* nodeType, const string& suffix) { setSuffix(*nodeType, suffix); } /// Return the function name suffix to be used for the given node in this context. - const string& getSuffix(const TypeDesc* nodeType) const + const string& getSuffix(TypeDesc nodeType) const { auto it = _suffix.find(nodeType); return it != _suffix.end() ? it->second : EMPTY_STRING; } + [[deprecated]] const string& getSuffix(const TypeDesc* nodeType) const { return getSuffix(*nodeType); } /// Set extra parameters to use for evaluating a closure. void setClosureParams(const ShaderNode* closure, const ClosureParams* params) @@ -313,8 +317,8 @@ class MX_GENSHADER_API ClosureContext protected: const int _type; - std::unordered_map _arguments; - std::unordered_map _suffix; + std::unordered_map _arguments; + std::unordered_map _suffix; std::unordered_map _params; static const Arguments EMPTY_ARGUMENTS; diff --git a/source/MaterialXGenShader/HwShaderGenerator.cpp b/source/MaterialXGenShader/HwShaderGenerator.cpp index 693e95da7c..d0ca836416 100644 --- a/source/MaterialXGenShader/HwShaderGenerator.cpp +++ b/source/MaterialXGenShader/HwShaderGenerator.cpp @@ -457,7 +457,7 @@ ShaderPtr HwShaderGenerator::createShader(const string& name, ElementPtr element { for (ShaderInput* input : node->getInputs()) { - if (!input->getConnection() && *input->getType() == *Type::FILENAME) + if (!input->getConnection() && input->getType() == Type::FILENAME) { // Create the uniform using the filename type to make this uniform into a texture sampler. ShaderPort* filename = psPublicUniforms->add(Type::FILENAME, input->getVariable(), input->getValue()); diff --git a/source/MaterialXGenShader/Nodes/BlurNode.cpp b/source/MaterialXGenShader/Nodes/BlurNode.cpp index 56f4de85a9..5826370fd0 100644 --- a/source/MaterialXGenShader/Nodes/BlurNode.cpp +++ b/source/MaterialXGenShader/Nodes/BlurNode.cpp @@ -46,14 +46,13 @@ void BlurNode::computeSampleOffsetStrings(const string& sampleSizeName, const st } } -bool BlurNode::acceptsInputType(const TypeDesc* type) const +bool BlurNode::acceptsInputType(TypeDesc type) const { // Float 1-4 is acceptable as input - return ((*type == *Type::FLOAT && type->isScalar()) || - type->isFloat2() || type->isFloat3() || type->isFloat4()); + return (type == Type::FLOAT || type.isFloat2() || type.isFloat3() || type.isFloat4()); } -void BlurNode::outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, const TypeDesc* inputType, +void BlurNode::outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, TypeDesc inputType, const string& sampleName, const StringVec& sampleStrings) const { const string MX_MAX_SAMPLE_COUNT_STRING("MX_MAX_SAMPLE_COUNT"); @@ -164,7 +163,7 @@ void BlurNode::emitFunctionCall(const ShaderNode& node, GenContext& context, Sha shadergen.emitString("if (", stage); shadergen.emitInput(filterTypeInput, context, stage); // Remap enumeration for comparison as needed - std::pair result; + std::pair result; string emitValue = "\"" + GAUSSIAN_FILTER + "\""; if (syntax.remapEnumeration(GAUSSIAN_FILTER, Type::STRING, FILTER_LIST, result)) { diff --git a/source/MaterialXGenShader/Nodes/BlurNode.h b/source/MaterialXGenShader/Nodes/BlurNode.h index f5139c7f1f..2d6d479a10 100644 --- a/source/MaterialXGenShader/Nodes/BlurNode.h +++ b/source/MaterialXGenShader/Nodes/BlurNode.h @@ -25,15 +25,20 @@ class MX_GENSHADER_API BlurNode : public ConvolutionNode virtual void emitSamplingFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const = 0; /// Return if given type is an acceptible input - bool acceptsInputType(const TypeDesc* type) const override; + bool acceptsInputType(TypeDesc type) const override; /// Compute offset strings for sampling void computeSampleOffsetStrings(const string& sampleSizeName, const string& offsetTypeString, unsigned int filterWidth, StringVec& offsetStrings) const override; /// Output sample array - virtual void outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, const TypeDesc* inputType, + virtual void outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, TypeDesc inputType, const string& sampleName, const StringVec& sampleStrings) const; + [[deprecated]] void outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, const TypeDesc* inputType, + const string& sampleName, const StringVec& sampleStrings) const + { + return outputSampleArray(shadergen, stage, *inputType, sampleName, sampleStrings); + } static const string _sampleSizeFunctionUV; static const float _filterSize; diff --git a/source/MaterialXGenShader/Nodes/ClosureAddNode.cpp b/source/MaterialXGenShader/Nodes/ClosureAddNode.cpp index f401b577d8..34883c6c36 100644 --- a/source/MaterialXGenShader/Nodes/ClosureAddNode.cpp +++ b/source/MaterialXGenShader/Nodes/ClosureAddNode.cpp @@ -59,13 +59,13 @@ void ClosureAddNode::emitFunctionCall(const ShaderNode& _node, GenContext& conte const string in2Result = shadergen.getUpstreamResult(in2, context); ShaderOutput* output = node.getOutput(); - if (*output->getType() == *Type::BSDF) + if (output->getType() == Type::BSDF) { emitOutputVariables(node, context, stage); shadergen.emitLine(output->getVariable() + ".response = " + in1Result + ".response + " + in2Result + ".response", stage); shadergen.emitLine(output->getVariable() + ".throughput = " + in1Result + ".throughput * " + in2Result + ".throughput", stage); } - else if (*output->getType() == *Type::EDF) + else if (output->getType() == Type::EDF) { shadergen.emitLine(shadergen.getSyntax().getTypeName(Type::EDF) + " " + output->getVariable() + " = " + in1Result + " + " + in2Result, stage); } diff --git a/source/MaterialXGenShader/Nodes/ClosureCompoundNode.cpp b/source/MaterialXGenShader/Nodes/ClosureCompoundNode.cpp index 1cde95a1a6..2f9f5a7dec 100644 --- a/source/MaterialXGenShader/Nodes/ClosureCompoundNode.cpp +++ b/source/MaterialXGenShader/Nodes/ClosureCompoundNode.cpp @@ -61,7 +61,7 @@ void ClosureCompoundNode::emitFunctionDefinition(ClosureContext* cct, GenContext { // Use the first output for classifying node type for the closure context. // This is only relevent for closures, and they only have a single output. - const TypeDesc* closureType = _rootGraph->getOutputSocket()->getType(); + const TypeDesc closureType = _rootGraph->getOutputSocket()->getType(); shadergen.emitString("void " + _functionName + cct->getSuffix(closureType) + "(", stage); @@ -167,11 +167,11 @@ void ClosureCompoundNode::emitFunctionCall(const ShaderNode& node, GenContext& c // Use the first output for classifying node type for the closure context. // This is only relevent for closures, and they only have a single output. const ShaderGraphOutputSocket* outputSocket = _rootGraph->getOutputSocket(); - const TypeDesc* closureType = outputSocket->getType(); + const TypeDesc closureType = outputSocket->getType(); // Check if extra parameters has been added for this node. const ClosureContext::ClosureParams* params = cct->getClosureParams(&node); - if (*closureType == *Type::BSDF && params) + if (closureType == Type::BSDF && params) { // Assign the parameters to the BSDF. for (auto it : *params) diff --git a/source/MaterialXGenShader/Nodes/ClosureMixNode.cpp b/source/MaterialXGenShader/Nodes/ClosureMixNode.cpp index 8e5b737698..bd314ac7ed 100644 --- a/source/MaterialXGenShader/Nodes/ClosureMixNode.cpp +++ b/source/MaterialXGenShader/Nodes/ClosureMixNode.cpp @@ -61,13 +61,13 @@ void ClosureMixNode::emitFunctionCall(const ShaderNode& _node, GenContext& conte const string mixResult = shadergen.getUpstreamResult(mix, context); ShaderOutput* output = node.getOutput(); - if (*output->getType() == *Type::BSDF) + if (output->getType() == Type::BSDF) { emitOutputVariables(node, context, stage); shadergen.emitLine(output->getVariable() + ".response = mix(" + bgResult + ".response, " + fgResult + ".response, " + mixResult + ")", stage); shadergen.emitLine(output->getVariable() + ".throughput = mix(" + bgResult + ".throughput, " + fgResult + ".throughput, " + mixResult + ")", stage); } - else if (*output->getType() == *Type::EDF) + else if (output->getType() == Type::EDF) { shadergen.emitLine(shadergen.getSyntax().getTypeName(Type::EDF) + " " + output->getVariable() + " = mix(" + bgResult + ", " + fgResult + ", " + mixResult + ")", stage); } diff --git a/source/MaterialXGenShader/Nodes/ClosureMultiplyNode.cpp b/source/MaterialXGenShader/Nodes/ClosureMultiplyNode.cpp index d582e19ebf..ac7906e6bb 100644 --- a/source/MaterialXGenShader/Nodes/ClosureMultiplyNode.cpp +++ b/source/MaterialXGenShader/Nodes/ClosureMultiplyNode.cpp @@ -50,7 +50,7 @@ void ClosureMultiplyNode::emitFunctionCall(const ShaderNode& _node, GenContext& const string in2Result = shadergen.getUpstreamResult(in2, context); ShaderOutput* output = node.getOutput(); - if (*output->getType() == *Type::BSDF) + if (output->getType() == Type::BSDF) { const string in2clamped = output->getVariable() + "_in2_clamped"; shadergen.emitLine(syntax.getTypeName(in2->getType()) + " " + in2clamped + " = clamp(" + in2Result + ", 0.0, 1.0)", stage); @@ -59,7 +59,7 @@ void ClosureMultiplyNode::emitFunctionCall(const ShaderNode& _node, GenContext& shadergen.emitLine(output->getVariable() + ".response = " + in1Result + ".response * " + in2clamped, stage); shadergen.emitLine(output->getVariable() + ".throughput = " + in1Result + ".throughput * " + in2clamped, stage); } - else if (*output->getType() == *Type::EDF) + else if (output->getType() == Type::EDF) { shadergen.emitLine(shadergen.getSyntax().getTypeName(Type::EDF) + " " + output->getVariable() + " = " + in1Result + " * " + in2Result, stage); } diff --git a/source/MaterialXGenShader/Nodes/ClosureSourceCodeNode.cpp b/source/MaterialXGenShader/Nodes/ClosureSourceCodeNode.cpp index a1a53b3bcd..476af09dec 100644 --- a/source/MaterialXGenShader/Nodes/ClosureSourceCodeNode.cpp +++ b/source/MaterialXGenShader/Nodes/ClosureSourceCodeNode.cpp @@ -40,9 +40,9 @@ void ClosureSourceCodeNode::emitFunctionCall(const ShaderNode& node, GenContext& if (cct) { // Check if extra parameters has been added for this node. - const TypeDesc* closureType = output->getType(); + const TypeDesc closureType = output->getType(); const ClosureContext::ClosureParams* params = cct->getClosureParams(&node); - if (*closureType == *Type::BSDF && params) + if (closureType == Type::BSDF && params) { // Assign the parameters to the BSDF. for (auto it : *params) diff --git a/source/MaterialXGenShader/Nodes/CombineNode.cpp b/source/MaterialXGenShader/Nodes/CombineNode.cpp index d7b2eb6e22..0237830c52 100644 --- a/source/MaterialXGenShader/Nodes/CombineNode.cpp +++ b/source/MaterialXGenShader/Nodes/CombineNode.cpp @@ -34,7 +34,7 @@ void CombineNode::emitFunctionCall(const ShaderNode& node, GenContext& context, // components to use for constructing the new value. // StringVec valueComponents; - if (*in1->getType() == *Type::FLOAT) + if (in1->getType() == Type::FLOAT) { // Get the components of the input values. const size_t numInputs = node.numInputs(); @@ -45,7 +45,7 @@ void CombineNode::emitFunctionCall(const ShaderNode& node, GenContext& context, valueComponents[i] = shadergen.getUpstreamResult(input, context); } } - else if (*in1->getType() == *Type::COLOR3 || *in1->getType() == *Type::VECTOR3) + else if (in1->getType() == Type::COLOR3 || in1->getType() == Type::VECTOR3) { const ShaderInput* in2 = node.getInput(1); if (!in2 || in2->getType() != Type::FLOAT) @@ -84,7 +84,7 @@ void CombineNode::emitFunctionCall(const ShaderNode& node, GenContext& context, // Get component from in2 valueComponents[memberSize] = shadergen.getUpstreamResult(in2, context); } - else if (*in1->getType() == *Type::VECTOR2) + else if (in1->getType() == Type::VECTOR2) { const ShaderInput* in2 = node.getInput(1); if (!in2 || (in2->getType() != Type::VECTOR2)) diff --git a/source/MaterialXGenShader/Nodes/ConvertNode.cpp b/source/MaterialXGenShader/Nodes/ConvertNode.cpp index b3407006da..fbd56b7768 100644 --- a/source/MaterialXGenShader/Nodes/ConvertNode.cpp +++ b/source/MaterialXGenShader/Nodes/ConvertNode.cpp @@ -19,7 +19,7 @@ ShaderNodeImplPtr ConvertNode::create() void ConvertNode::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const { - using ConvertTable = std::unordered_map>; + using ConvertTable = std::unordered_map, TypeDesc::Hasher>; static const ConvertTable CONVERT_TABLE({ { Type::COLOR3, { { Type::VECTOR3, string("rgb") }, @@ -63,7 +63,7 @@ void ConvertNode::emitFunctionCall(const ShaderNode& node, GenContext& context, string result; // Handle supported scalar type conversions. - if (in->getType()->isScalar() && out->getType()->isScalar()) + if (in->getType().isScalar() && out->getType().isScalar()) { result = shadergen.getUpstreamResult(in, context); result = shadergen.getSyntax().getTypeName(out->getType()) + "(" + result + ")"; @@ -84,7 +84,7 @@ void ConvertNode::emitFunctionCall(const ShaderNode& node, GenContext& context, } if (!swizzle || swizzle->empty()) { - throw ExceptionShaderGenError("Conversion from '" + in->getType()->getName() + "' to '" + out->getType()->getName() + "' is not supported by convert node"); + throw ExceptionShaderGenError("Conversion from '" + in->getType().getName() + "' to '" + out->getType().getName() + "' is not supported by convert node"); } // If the input is unconnected we must declare a local variable @@ -101,7 +101,7 @@ void ConvertNode::emitFunctionCall(const ShaderNode& node, GenContext& context, variableName = shadergen.getUpstreamResult(in, context); } - const TypeDesc* type = in->getConnection() ? in->getConnection()->getType() : in->getType(); + const TypeDesc type = in->getConnection() ? in->getConnection()->getType() : in->getType(); result = shadergen.getSyntax().getSwizzledVariable(variableName, type, *swizzle, node.getOutput()->getType()); } diff --git a/source/MaterialXGenShader/Nodes/ConvolutionNode.cpp b/source/MaterialXGenShader/Nodes/ConvolutionNode.cpp index 892920569e..0e3999788a 100644 --- a/source/MaterialXGenShader/Nodes/ConvolutionNode.cpp +++ b/source/MaterialXGenShader/Nodes/ConvolutionNode.cpp @@ -94,12 +94,12 @@ const ShaderInput* ConvolutionNode::getSamplingInput(const ShaderNode& node) con if (node.hasClassification(ShaderNode::Classification::SAMPLE2D)) { const ShaderInput* input = node.getInput(SAMPLE2D_INPUT); - return *input->getType() == *Type::VECTOR2 ? input : nullptr; + return input->getType() == Type::VECTOR2 ? input : nullptr; } else if (node.hasClassification(ShaderNode::Classification::SAMPLE3D)) { const ShaderInput* input = node.getInput(SAMPLE3D_INPUT); - return *input->getType() == *Type::VECTOR3 ? input : nullptr; + return input->getType() == Type::VECTOR3 ? input : nullptr; } return nullptr; } @@ -119,7 +119,7 @@ void ConvolutionNode::emitInputSamplesUV(const ShaderNode& node, const ShaderInput* inInput = node.getInput("in"); const ShaderOutput* inConnection = inInput ? inInput->getConnection() : nullptr; - if (inConnection && inConnection->getType() && acceptsInputType(inConnection->getType())) + if (inConnection && acceptsInputType(inConnection->getType())) { const ShaderNode* upstreamNode = inConnection->getNode(); if (upstreamNode && upstreamNode->hasClassification(ShaderNode::Classification::SAMPLE2D)) diff --git a/source/MaterialXGenShader/Nodes/ConvolutionNode.h b/source/MaterialXGenShader/Nodes/ConvolutionNode.h index 0d90588693..4b25c3d84e 100644 --- a/source/MaterialXGenShader/Nodes/ConvolutionNode.h +++ b/source/MaterialXGenShader/Nodes/ConvolutionNode.h @@ -28,7 +28,8 @@ class MX_GENSHADER_API ConvolutionNode : public ShaderNodeImpl ConvolutionNode(); /// Derived classes are responsible for returning if a given type is an acceptable input. - virtual bool acceptsInputType(const TypeDesc* type) const = 0; + virtual bool acceptsInputType(TypeDesc type) const = 0; + [[deprecated]] bool acceptsInputType(const TypeDesc* type) const { return acceptsInputType(*type); } // Derived classes are responsible for computing offset strings relative to the center sample // The sample size and offset type are passed in as arguments. diff --git a/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp b/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp index 3e5c5c0a65..3aa84400df 100644 --- a/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp +++ b/source/MaterialXGenShader/Nodes/HwTexCoordNode.cpp @@ -60,11 +60,11 @@ void HwTexCoordNode::emitFunctionCall(const ShaderNode& node, GenContext& contex // larger datatype than the requested number of texture coordinates, if several texture // coordinate nodes with different width coexist). string suffix = EMPTY_STRING; - if (*output->getType() == *Type::VECTOR2) + if (output->getType() == Type::VECTOR2) { suffix = ".xy"; } - else if (*output->getType() == *Type::VECTOR3) + else if (output->getType() == Type::VECTOR3) { suffix = ".xyz"; } diff --git a/source/MaterialXGenShader/Nodes/SwizzleNode.cpp b/source/MaterialXGenShader/Nodes/SwizzleNode.cpp index d12d81497a..185a6e47a1 100644 --- a/source/MaterialXGenShader/Nodes/SwizzleNode.cpp +++ b/source/MaterialXGenShader/Nodes/SwizzleNode.cpp @@ -49,7 +49,7 @@ void SwizzleNode::emitFunctionCall(const ShaderNode& node, GenContext& context, if (!swizzle.empty()) { - const TypeDesc* type = in->getConnection() ? in->getConnection()->getType() : in->getType(); + const TypeDesc type = in->getConnection() ? in->getConnection()->getType() : in->getType(); variableName = shadergen.getSyntax().getSwizzledVariable(variableName, type, swizzle, node.getOutput()->getType()); } diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index d5f51aed1c..b52170180a 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -170,7 +170,7 @@ void ShaderGenerator::emitVariableDeclaration(const ShaderPort* variable, const string str = qualifier.empty() ? EMPTY_STRING : qualifier + " "; str += _syntax->getTypeName(variable->getType()); - bool haveArray = variable->getType()->isArray() && variable->getValue(); + bool haveArray = variable->getType().isArray() && variable->getValue(); if (haveArray) { str += _syntax->getArrayTypeSuffix(variable->getType(), *variable->getValue()); @@ -304,12 +304,12 @@ ShaderNodeImplPtr ShaderGenerator::getImplementation(const NodeDef& nodedef, Gen throw ExceptionShaderGenError("NodeDef '" + nodedef.getName() + "' has no outputs defined"); } - const TypeDesc* outputType = TypeDesc::get(outputs[0]->getType()); + const TypeDesc outputType = TypeDesc::get(outputs[0]->getType()); if (implElement->isA()) { // Use a compound implementation. - if (outputType->isClosure()) + if (outputType.isClosure()) { impl = ClosureCompoundNode::create(); } @@ -325,7 +325,7 @@ ShaderNodeImplPtr ShaderGenerator::getImplementation(const NodeDef& nodedef, Gen if (!impl) { // Fall back to source code implementation. - if (outputType->isClosure()) + if (outputType.isClosure()) { impl = ClosureSourceCodeNode::create(); } @@ -377,11 +377,11 @@ void ShaderGenerator::registerShaderMetadata(const DocumentPtr& doc, GenContext& { ShaderMetadata(ValueElement::UI_NAME_ATTRIBUTE, Type::STRING), ShaderMetadata(ValueElement::UI_FOLDER_ATTRIBUTE, Type::STRING), - ShaderMetadata(ValueElement::UI_MIN_ATTRIBUTE, nullptr), - ShaderMetadata(ValueElement::UI_MAX_ATTRIBUTE, nullptr), - ShaderMetadata(ValueElement::UI_SOFT_MIN_ATTRIBUTE, nullptr), - ShaderMetadata(ValueElement::UI_SOFT_MAX_ATTRIBUTE, nullptr), - ShaderMetadata(ValueElement::UI_STEP_ATTRIBUTE, nullptr), + ShaderMetadata(ValueElement::UI_MIN_ATTRIBUTE, Type::NONE), + ShaderMetadata(ValueElement::UI_MAX_ATTRIBUTE, Type::NONE), + ShaderMetadata(ValueElement::UI_SOFT_MIN_ATTRIBUTE, Type::NONE), + ShaderMetadata(ValueElement::UI_SOFT_MAX_ATTRIBUTE, Type::NONE), + ShaderMetadata(ValueElement::UI_STEP_ATTRIBUTE, Type::NONE), ShaderMetadata(ValueElement::UI_ADVANCED_ATTRIBUTE, Type::BOOLEAN), ShaderMetadata(ValueElement::DOC_ATTRIBUTE, Type::STRING), ShaderMetadata(ValueElement::UNIT_ATTRIBUTE, Type::STRING), @@ -399,8 +399,8 @@ void ShaderGenerator::registerShaderMetadata(const DocumentPtr& doc, GenContext& if (def->getExportable()) { const string& attrName = def->getAttrName(); - const TypeDesc* type = TypeDesc::get(def->getType()); - if (!attrName.empty() && type) + const TypeDesc type = TypeDesc::get(def->getType()); + if (!attrName.empty() && type != Type::NONE) { registry->addMetadata(attrName, type, def->getValue()); } diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index bcfe1ae441..8e75b18525 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -36,9 +36,9 @@ void ShaderGraph::addInputSockets(const InterfaceElement& elem, GenContext& cont ShaderGraphInputSocket* inputSocket = nullptr; ValuePtr portValue = input->getResolvedValue(); const string& portValueString = portValue ? portValue->getValueString() : EMPTY_STRING; - std::pair enumResult; + std::pair enumResult; const string& enumNames = input->getAttribute(ValueElement::ENUM_ATTRIBUTE); - const TypeDesc* portType = TypeDesc::get(input->getType()); + const TypeDesc portType = TypeDesc::get(input->getType()); if (context.getShaderGenerator().getSyntax().remapEnumeration(portValueString, portType, enumNames, enumResult)) { inputSocket = addInputSocket(input->getName(), enumResult.first); @@ -201,7 +201,7 @@ void ShaderGraph::addDefaultGeomNode(ShaderInput* input, const GeomPropDef& geom { // Find the nodedef for the geometric node referenced by the geomprop. Use the type of the // input here and ignore the type of the geomprop. They are required to have the same type. - string geomNodeDefName = "ND_" + geomprop.getGeomProp() + "_" + input->getType()->getName(); + string geomNodeDefName = "ND_" + geomprop.getGeomProp() + "_" + input->getType().getName(); NodeDefPtr geomNodeDef = _document->getNodeDef(geomNodeDefName); if (!geomNodeDef) { @@ -221,9 +221,9 @@ void ShaderGraph::addDefaultGeomNode(ShaderInput* input, const GeomPropDef& geom ValueElementPtr nodeDefSpaceInput = geomNodeDef->getActiveValueElement(GeomPropDef::SPACE_ATTRIBUTE); if (spaceInput && nodeDefSpaceInput) { - std::pair enumResult; + std::pair enumResult; const string& enumNames = nodeDefSpaceInput->getAttribute(ValueElement::ENUM_ATTRIBUTE); - const TypeDesc* portType = TypeDesc::get(nodeDefSpaceInput->getType()); + const TypeDesc portType = TypeDesc::get(nodeDefSpaceInput->getType()); if (context.getShaderGenerator().getSyntax().remapEnumeration(space, portType, enumNames, enumResult)) { spaceInput->setValue(enumResult.second); @@ -556,8 +556,8 @@ ShaderGraphPtr ShaderGraph::create(const ShaderGraph* parent, const string& name if (value) { const string& valueString = value->getValueString(); - std::pair enumResult; - const TypeDesc* type = TypeDesc::get(nodedefInput->getType()); + std::pair enumResult; + const TypeDesc type = TypeDesc::get(nodedefInput->getType()); const string& enumNames = nodedefInput->getAttribute(ValueElement::ENUM_ATTRIBUTE); if (context.getShaderGenerator().getSyntax().remapEnumeration(valueString, type, enumNames, enumResult)) { @@ -717,12 +717,12 @@ ShaderNode* ShaderGraph::createNode(ConstNodePtr node, GenContext& context) return newNode.get(); } -ShaderGraphInputSocket* ShaderGraph::addInputSocket(const string& name, const TypeDesc* type) +ShaderGraphInputSocket* ShaderGraph::addInputSocket(const string& name, TypeDesc type) { return ShaderNode::addOutput(name, type); } -ShaderGraphOutputSocket* ShaderGraph::addOutputSocket(const string& name, const TypeDesc* type) +ShaderGraphOutputSocket* ShaderGraph::addOutputSocket(const string& name, TypeDesc type) { return ShaderNode::addInput(name, type); } @@ -809,7 +809,7 @@ void ShaderGraph::finalize(GenContext& context) { // Check if the type is editable otherwise we can't // publish the input as an editable uniform. - if (input->getType()->isEditable() && node->isEditable(*input)) + if (!input->getType().isClosure() && node->isEditable(*input)) { // Use a consistent naming convention: _ // so application side can figure out what uniforms to set @@ -868,7 +868,7 @@ void ShaderGraph::optimize(GenContext& context) { // Filename dot nodes must be elided so they do not create extra samplers. ShaderInput* in = node->getInput("in"); - if (in->getChannels().empty() && *in->getType() == *Type::FILENAME) + if (in->getChannels().empty() && in->getType() == Type::FILENAME) { bypass(context, node, 0); ++numEdits; @@ -1079,7 +1079,7 @@ void ShaderGraph::populateColorTransformMap(ColorManagementSystemPtr colorManage return; } - if (*(shaderPort->getType()) == *Type::COLOR3 || *(shaderPort->getType()) == *Type::COLOR4) + if (shaderPort->getType() == Type::COLOR3 || shaderPort->getType() == Type::COLOR4) { // Store the source color space on the shader port. shaderPort->setColorSpace(sourceColorSpace); @@ -1144,10 +1144,10 @@ void ShaderGraph::populateUnitTransformMap(UnitSystemPtr unitSystem, ShaderPort* // Only support convertion for float and vectors. arrays, matrices are not supported. // TODO: This should be provided by the UnitSystem. - bool supportedType = (*shaderPort->getType() == *Type::FLOAT || - *shaderPort->getType() == *Type::VECTOR2 || - *shaderPort->getType() == *Type::VECTOR3 || - *shaderPort->getType() == *Type::VECTOR4); + bool supportedType = (shaderPort->getType() == Type::FLOAT || + shaderPort->getType() == Type::VECTOR2 || + shaderPort->getType() == Type::VECTOR3 || + shaderPort->getType() == Type::VECTOR4); if (supportedType) { UnitTransform transform(sourceUnitSpace, targetUnitSpace, shaderPort->getType(), unitType); diff --git a/source/MaterialXGenShader/ShaderGraph.h b/source/MaterialXGenShader/ShaderGraph.h index b8ac15fc46..d04ede7b4b 100644 --- a/source/MaterialXGenShader/ShaderGraph.h +++ b/source/MaterialXGenShader/ShaderGraph.h @@ -95,9 +95,13 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode /// Create a new node in the graph ShaderNode* createNode(ConstNodePtr node, GenContext& context); - /// Add input/output sockets - ShaderGraphInputSocket* addInputSocket(const string& name, const TypeDesc* type); - ShaderGraphOutputSocket* addOutputSocket(const string& name, const TypeDesc* type); + /// Add input sockets + ShaderGraphInputSocket* addInputSocket(const string& name, TypeDesc type); + [[deprecated]] ShaderGraphInputSocket* addInputSocket(const string& name, const TypeDesc* type) { return addInputSocket(name, *type); } + + /// Add output sockets + ShaderGraphOutputSocket* addOutputSocket(const string& name, TypeDesc type); + [[deprecated]] ShaderGraphOutputSocket* addOutputSocket(const string& name, const TypeDesc* type) { return addOutputSocket(name, *type); } /// Add a default geometric node and connect to the given input. void addDefaultGeomNode(ShaderInput* input, const GeomPropDef& geomprop, GenContext& context); diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index 6e951b06e6..e04bd7c8f1 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -17,7 +17,7 @@ const string ShaderMetadataRegistry::USER_DATA_NAME = "ShaderMetadataRegistry"; // ShaderPort methods // -ShaderPort::ShaderPort(ShaderNode* node, const TypeDesc* type, const string& name, ValuePtr value) : +ShaderPort::ShaderPort(ShaderNode* node, TypeDesc type, const string& name, ValuePtr value) : _node(node), _type(type), _name(name), @@ -41,7 +41,7 @@ string ShaderPort::getValueString() const // ShaderInput methods // -ShaderInput::ShaderInput(ShaderNode* node, const TypeDesc* type, const string& name) : +ShaderInput::ShaderInput(ShaderNode* node, TypeDesc type, const string& name) : ShaderPort(node, type, name), _connection(nullptr) { @@ -92,7 +92,7 @@ ShaderNode* ShaderInput::getConnectedSibling() const // ShaderOutput methods // -ShaderOutput::ShaderOutput(ShaderNode* node, const TypeDesc* type, const string& name) : +ShaderOutput::ShaderOutput(ShaderNode* node, TypeDesc type, const string& name) : ShaderPort(node, type, name) { } @@ -179,7 +179,7 @@ ShaderNodePtr ShaderNode::create(const ShaderGraph* parent, const string& name, // Create interface from nodedef for (const ValueElementPtr& port : nodeDef.getActiveValueElements()) { - const TypeDesc* portType = TypeDesc::get(port->getType()); + const TypeDesc portType = TypeDesc::get(port->getType()); if (port->isA()) { newNode->addOutput(port->getName(), portType); @@ -188,7 +188,7 @@ ShaderNodePtr ShaderNode::create(const ShaderGraph* parent, const string& name, { ShaderInput* input; const string& portValue = port->getResolvedValueString(); - std::pair enumResult; + std::pair enumResult; const string& enumNames = port->getAttribute(ValueElement::ENUM_ATTRIBUTE); if (context.getShaderGenerator().getSyntax().remapEnumeration(portValue, portType, enumNames, enumResult)) { @@ -229,11 +229,11 @@ ShaderNodePtr ShaderNode::create(const ShaderGraph* parent, const string& name, // First, check for specific output types const ShaderOutput* primaryOutput = newNode->getOutput(); - if (*primaryOutput->getType() == *Type::MATERIAL) + if (primaryOutput->getType() == Type::MATERIAL) { newNode->_classification = Classification::MATERIAL; } - else if (*primaryOutput->getType() == *Type::SURFACESHADER) + else if (primaryOutput->getType() == Type::SURFACESHADER) { if (nodeDefName == "ND_surface_unlit") { @@ -244,15 +244,15 @@ ShaderNodePtr ShaderNode::create(const ShaderGraph* parent, const string& name, newNode->_classification = Classification::SHADER | Classification::SURFACE | Classification::CLOSURE; } } - else if (*primaryOutput->getType() == *Type::VOLUMESHADER) + else if (primaryOutput->getType() == Type::VOLUMESHADER) { newNode->_classification = Classification::SHADER | Classification::VOLUME | Classification::CLOSURE; } - else if (*primaryOutput->getType() == *Type::LIGHTSHADER) + else if (primaryOutput->getType() == Type::LIGHTSHADER) { newNode->_classification = Classification::LIGHT | Classification::SHADER | Classification::CLOSURE; } - else if (*primaryOutput->getType() == *Type::BSDF) + else if (primaryOutput->getType() == Type::BSDF) { newNode->_classification = Classification::BSDF | Classification::CLOSURE; @@ -282,11 +282,11 @@ ShaderNodePtr ShaderNode::create(const ShaderGraph* parent, const string& name, newNode->_classification |= Classification::THINFILM; } } - else if (*primaryOutput->getType() == *Type::EDF) + else if (primaryOutput->getType() == Type::EDF) { newNode->_classification = Classification::EDF | Classification::CLOSURE; } - else if (*primaryOutput->getType() == *Type::VDF) + else if (primaryOutput->getType() == Type::VDF) { newNode->_classification = Classification::VDF | Classification::CLOSURE; } @@ -352,9 +352,9 @@ void ShaderNode::initialize(const Node& node, const NodeDef& nodeDef, GenContext } } const string& valueString = portValue ? portValue->getValueString() : EMPTY_STRING; - std::pair enumResult; + std::pair enumResult; const string& enumNames = nodeDefInput->getAttribute(ValueElement::ENUM_ATTRIBUTE); - const TypeDesc* type = TypeDesc::get(nodeDefInput->getType()); + const TypeDesc type = TypeDesc::get(nodeDefInput->getType()); if (context.getShaderGenerator().getSyntax().remapEnumeration(valueString, type, enumNames, enumResult)) { input->setValue(enumResult.second); @@ -444,7 +444,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 = Value::createValueFromStrings(attrValue, metadataEntry->type.getName()); if (!value) { value = metadataEntry->value; @@ -478,8 +478,8 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) const string& attrValue = nodedefPort->getAttribute(nodedefPortAttr); if (!attrValue.empty()) { - const TypeDesc* type = metadataEntry->type ? metadataEntry->type : input->getType(); - ValuePtr value = Value::createValueFromStrings(attrValue, type->getName()); + const TypeDesc type = metadataEntry->type != Type::NONE ? metadataEntry->type : input->getType(); + ValuePtr value = Value::createValueFromStrings(attrValue, type.getName()); if (!value) { value = metadataEntry->value; @@ -524,7 +524,7 @@ const ShaderOutput* ShaderNode::getOutput(const string& name) const return it != _outputMap.end() ? it->second.get() : nullptr; } -ShaderInput* ShaderNode::addInput(const string& name, const TypeDesc* type) +ShaderInput* ShaderNode::addInput(const string& name, TypeDesc type) { if (getInput(name)) { @@ -538,7 +538,7 @@ ShaderInput* ShaderNode::addInput(const string& name, const TypeDesc* type) return input.get(); } -ShaderOutput* ShaderNode::addOutput(const string& name, const TypeDesc* type) +ShaderOutput* ShaderNode::addOutput(const string& name, TypeDesc type) { if (getOutput(name)) { diff --git a/source/MaterialXGenShader/ShaderNode.h b/source/MaterialXGenShader/ShaderNode.h index dd74269764..ed55a47bac 100644 --- a/source/MaterialXGenShader/ShaderNode.h +++ b/source/MaterialXGenShader/ShaderNode.h @@ -40,9 +40,9 @@ using ShaderInputVec = vector; struct MX_GENSHADER_API ShaderMetadata { string name; - const TypeDesc* type; + TypeDesc type; ValuePtr value; - ShaderMetadata(const string& n, const TypeDesc* t, ValuePtr v = nullptr) : + ShaderMetadata(const string& n, TypeDesc t, ValuePtr v = nullptr) : name(n), type(t), value(v) @@ -63,7 +63,7 @@ class MX_GENSHADER_API ShaderMetadataRegistry : public GenUserData /// Add a new metadata entry to the registry. /// The entry contains the name and data type /// for the metadata. - void addMetadata(const string& name, const TypeDesc* type, ValuePtr value = nullptr) + void addMetadata(const string& name, TypeDesc type, ValuePtr value = nullptr) { if (_entryIndex.count(name) == 0) { @@ -123,7 +123,7 @@ class MX_GENSHADER_API ShaderPort : public std::enable_shared_from_this #include +#include #include MATERIALX_NAMESPACE_BEGIN diff --git a/source/MaterialXGenShader/ShaderStage.cpp b/source/MaterialXGenShader/ShaderStage.cpp index d304c22dd2..440a280e1e 100644 --- a/source/MaterialXGenShader/ShaderStage.cpp +++ b/source/MaterialXGenShader/ShaderStage.cpp @@ -65,7 +65,7 @@ ShaderPort* VariableBlock::find(const ShaderPortPredicate& predicate) return nullptr; } -ShaderPort* VariableBlock::add(const TypeDesc* type, const string& name, ValuePtr value, bool shouldWiden) +ShaderPort* VariableBlock::add(TypeDesc type, const string& name, ValuePtr value, bool shouldWiden) { auto it = _variableMap.find(name); if (it != _variableMap.end()) @@ -74,7 +74,7 @@ ShaderPort* VariableBlock::add(const TypeDesc* type, const string& name, ValuePt { // Automatically try to widen the type of the shader port if the requested type differs from // the existing port's type. - if (it->second->getType()->getSize() < type->getSize()) + if (it->second->getType().getSize() < type.getSize()) { it->second->setType(type); } @@ -82,8 +82,8 @@ ShaderPort* VariableBlock::add(const TypeDesc* type, const string& name, ValuePt else if (type != it->second->getType()) { throw ExceptionShaderGenError("Trying to add shader port '" + name + "' with type '" + - type->getName() + "', but existing shader port with type '" + - it->second->getType()->getName() + "' was found"); + type.getName() + "', but existing shader port with type '" + + it->second->getType().getName() + "' was found"); } return it->second.get(); } diff --git a/source/MaterialXGenShader/ShaderStage.h b/source/MaterialXGenShader/ShaderStage.h index a6a5cec0b8..47041cabe9 100644 --- a/source/MaterialXGenShader/ShaderStage.h +++ b/source/MaterialXGenShader/ShaderStage.h @@ -120,7 +120,7 @@ class MX_GENSHADER_API VariableBlock /// the same name does not match the requested type. When true, the types can mismatch, and the /// type of any existing port is widened to match the requested type when necessary. /// @return A new shader port, or a pre-existing shader port with the same name. - ShaderPort* add(const TypeDesc* type, const string& name, ValuePtr value = nullptr, bool shouldWiden = false); + ShaderPort* add(TypeDesc type, const string& name, ValuePtr value = nullptr, bool shouldWiden = false); /// Add an existing shader port to this block. void add(ShaderPortPtr port); @@ -334,17 +334,24 @@ using ShaderStagePtr = std::shared_ptr; /// Utility function for adding a new shader port to a uniform block. inline ShaderPort* addStageUniform(const string& block, - const TypeDesc* type, + TypeDesc type, const string& name, ShaderStage& stage) { VariableBlock& uniforms = stage.getUniformBlock(block); return uniforms.add(type, name); } +[[deprecated]] inline ShaderPort* addStageUniform(const string& block, + const TypeDesc* type, + const string& name, + ShaderStage& stage) +{ + return addStageUniform(block, *type, name, stage); +} /// Utility function for adding a new shader port to an input block. inline ShaderPort* addStageInput(const string& block, - const TypeDesc* type, + TypeDesc type, const string& name, ShaderStage& stage, bool shouldWiden = false) @@ -352,10 +359,18 @@ inline ShaderPort* addStageInput(const string& block, VariableBlock& inputs = stage.getInputBlock(block); return inputs.add(type, name, {}, shouldWiden); } +[[deprecated]] inline ShaderPort* addStageInput(const string& block, + const TypeDesc* type, + const string& name, + ShaderStage& stage, + bool shouldWiden = false) +{ + return addStageInput(block, *type, name, stage, shouldWiden); +} /// Utility function for adding a new shader port to an output block. inline ShaderPort* addStageOutput(const string& block, - const TypeDesc* type, + TypeDesc type, const string& name, ShaderStage& stage, bool shouldWiden = false) @@ -363,6 +378,14 @@ inline ShaderPort* addStageOutput(const string& block, VariableBlock& outputs = stage.getOutputBlock(block); return outputs.add(type, name, {}, shouldWiden); } +[[deprecated]] inline ShaderPort* addStageOutput(const string& block, + const TypeDesc* type, + const string& name, + ShaderStage& stage, + bool shouldWiden = false) +{ + return addStageOutput(block, *type, name, stage, shouldWiden); +} /// Utility function for adding a connector block between stages. inline void addStageConnectorBlock(const string& block, @@ -376,7 +399,7 @@ inline void addStageConnectorBlock(const string& block, /// Utility function for adding a variable to a stage connector block. inline void addStageConnector(const string& block, - const TypeDesc* type, + TypeDesc type, const string& name, ShaderStage& from, ShaderStage& to, @@ -385,6 +408,15 @@ inline void addStageConnector(const string& block, addStageOutput(block, type, name, from, shouldWiden); addStageInput(block, type, name, to, shouldWiden); } +[[deprecated]] inline void addStageConnector(const string& block, + const TypeDesc* type, + const string& name, + ShaderStage& from, + ShaderStage& to, + bool shouldWiden = false) +{ + addStageConnector(block, *type, name, from, to, shouldWiden); +} MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index 6e97a56609..2917164417 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -38,17 +38,17 @@ Syntax::Syntax() { } -void Syntax::registerTypeSyntax(const TypeDesc* type, TypeSyntaxPtr syntax) +void Syntax::registerTypeSyntax(TypeDesc type, TypeSyntaxPtr syntax) { - auto it = _typeSyntaxByType.find(type); - if (it != _typeSyntaxByType.end()) + auto it = _typeSyntaxIndexByType.find(type); + if (it != _typeSyntaxIndexByType.end()) { _typeSyntaxes[it->second] = syntax; } else { _typeSyntaxes.push_back(syntax); - _typeSyntaxByType[type] = _typeSyntaxes.size() - 1; + _typeSyntaxIndexByType[type] = _typeSyntaxes.size() - 1; } // Make this type a restricted name @@ -67,79 +67,60 @@ void Syntax::registerInvalidTokens(const StringMap& tokens) /// Returns the type syntax object for a named type. /// Throws an exception if a type syntax is not defined for the given type. -const TypeSyntax& Syntax::getTypeSyntax(const TypeDesc* type) const +const TypeSyntax& Syntax::getTypeSyntax(TypeDesc type) const { - auto it = _typeSyntaxByType.find(type); - if (it == _typeSyntaxByType.end()) + auto it = _typeSyntaxIndexByType.find(type); + if (it == _typeSyntaxIndexByType.end()) { - string typeName = type ? type->getName() : "nullptr"; - throw ExceptionShaderGenError("No syntax is defined for the given type '" + typeName + "'."); + throw ExceptionShaderGenError("No syntax is defined for the given type '" + type.getName() + "'."); } return *_typeSyntaxes[it->second]; } -const TypeDesc* Syntax::getTypeDescription(const TypeSyntaxPtr& typeSyntax) const -{ - auto pos = std::find(_typeSyntaxes.begin(), _typeSyntaxes.end(), typeSyntax); - if (pos == _typeSyntaxes.end()) - { - throw ExceptionShaderGenError("The syntax'" + typeSyntax->getName() + "' is not registered."); - } - const size_t index = static_cast(std::distance(_typeSyntaxes.begin(), pos)); - for (auto item : _typeSyntaxByType) - { - if (item.second == index) - { - return item.first; - } - } - return nullptr; -} - string Syntax::getValue(const ShaderPort* port, bool uniform) const { const TypeSyntax& syntax = getTypeSyntax(port->getType()); return syntax.getValue(port, uniform); } -string Syntax::getValue(const TypeDesc* type, const Value& value, bool uniform) const +string Syntax::getValue(TypeDesc type, const Value& value, bool uniform) const { const TypeSyntax& syntax = getTypeSyntax(type); return syntax.getValue(value, uniform); } -const string& Syntax::getDefaultValue(const TypeDesc* type, bool uniform) const +const string& Syntax::getDefaultValue(TypeDesc type, bool uniform) const { const TypeSyntax& syntax = getTypeSyntax(type); return syntax.getDefaultValue(uniform); } -const string& Syntax::getTypeName(const TypeDesc* type) const +const string& Syntax::getTypeName(TypeDesc type) const { const TypeSyntax& syntax = getTypeSyntax(type); return syntax.getName(); } -string Syntax::getOutputTypeName(const TypeDesc* type) const +string Syntax::getOutputTypeName(TypeDesc type) const { const TypeSyntax& syntax = getTypeSyntax(type); const string& outputModifier = getOutputQualifier(); return outputModifier.size() ? outputModifier + " " + syntax.getName() : syntax.getName(); } -const string& Syntax::getTypeAlias(const TypeDesc* type) const +const string& Syntax::getTypeAlias(TypeDesc type) const { const TypeSyntax& syntax = getTypeSyntax(type); return syntax.getTypeAlias(); } -const string& Syntax::getTypeDefinition(const TypeDesc* type) const +const string& Syntax::getTypeDefinition(TypeDesc type) const { const TypeSyntax& syntax = getTypeSyntax(type); return syntax.getTypeDefinition(); } -string Syntax::getSwizzledVariable(const string& srcName, const TypeDesc* srcType, const string& channels, const TypeDesc* dstType) const +string Syntax::getSwizzledVariable(const string& srcName, TypeDesc srcType, const string& channels, TypeDesc dstType) const { const TypeSyntax& srcSyntax = getTypeSyntax(srcType); const TypeSyntax& dstSyntax = getTypeSyntax(dstType); @@ -169,10 +150,10 @@ string Syntax::getSwizzledVariable(const string& srcName, const TypeDesc* srcTyp } else { - int channelIndex = srcType->getChannelIndex(ch); - if (channelIndex < 0 || channelIndex >= static_cast(srcMembers.size())) + const size_t channelIndex = it->second; + if (channelIndex < 0 || channelIndex >= srcMembers.size()) { - throw ExceptionShaderGenError("Given channel index: '" + string(1, ch) + "' in channels pattern is incorrect for type '" + srcType->getName() + "'."); + throw ExceptionShaderGenError("Given channel index: '" + string(1, ch) + "' in channels pattern is incorrect for type '" + srcType.getName() + "'."); } membersSwizzled.push_back(srcName + srcMembers[channelIndex]); } @@ -181,7 +162,7 @@ string Syntax::getSwizzledVariable(const string& srcName, const TypeDesc* srcTyp return dstSyntax.getValue(membersSwizzled, false); } -ValuePtr Syntax::getSwizzledValue(ValuePtr value, const TypeDesc* srcType, const string& channels, const TypeDesc* dstType) const +ValuePtr Syntax::getSwizzledValue(ValuePtr value, TypeDesc srcType, const string& channels, TypeDesc dstType) const { const TypeSyntax& srcSyntax = getTypeSyntax(srcType); const vector& srcMembers = srcSyntax.getMembers(); @@ -215,47 +196,47 @@ ValuePtr Syntax::getSwizzledValue(ValuePtr value, const TypeDesc* srcType, const } else { - int channelIndex = srcType->getChannelIndex(ch); - if (channelIndex < 0 || channelIndex >= static_cast(srcMembers.size())) + const size_t channelIndex = it->second; + if (channelIndex < 0 || channelIndex >= srcMembers.size()) { - throw ExceptionShaderGenError("Given channel index: '" + string(1, ch) + "' in channels pattern is incorrect for type '" + srcType->getName() + "'."); + throw ExceptionShaderGenError("Given channel index: '" + string(1, ch) + "' in channels pattern is incorrect for type '" + srcType.getName() + "'."); } - if (*srcType == *Type::FLOAT) + if (srcType == Type::FLOAT) { float v = value->asA(); ss << std::to_string(v); } - else if (*srcType == *Type::INTEGER) + else if (srcType == Type::INTEGER) { int v = value->asA(); ss << std::to_string(v); } - else if (*srcType == *Type::BOOLEAN) + else if (srcType == Type::BOOLEAN) { bool v = value->asA(); ss << std::to_string(v); } - else if (*srcType == *Type::COLOR3) + else if (srcType == Type::COLOR3) { Color3 v = value->asA(); ss << std::to_string(v[channelIndex]); } - else if (*srcType == *Type::COLOR4) + else if (srcType == Type::COLOR4) { Color4 v = value->asA(); ss << std::to_string(v[channelIndex]); } - else if (*srcType == *Type::VECTOR2) + else if (srcType == Type::VECTOR2) { Vector2 v = value->asA(); ss << std::to_string(v[channelIndex]); } - else if (*srcType == *Type::VECTOR3) + else if (srcType == Type::VECTOR3) { Vector3 v = value->asA(); ss << std::to_string(v[channelIndex]); } - else if (*srcType == *Type::VECTOR4) + else if (srcType == Type::VECTOR4) { Vector4 v = value->asA(); ss << std::to_string(v[channelIndex]); @@ -264,7 +245,7 @@ ValuePtr Syntax::getSwizzledValue(ValuePtr value, const TypeDesc* srcType, const ss << delimiter; } - return Value::createValueFromStrings(ss.str(), dstType->getName()); + return Value::createValueFromStrings(ss.str(), dstType.getName()); } bool Syntax::typeSupported(const TypeDesc*) const @@ -272,9 +253,9 @@ bool Syntax::typeSupported(const TypeDesc*) const return true; } -string Syntax::getArrayVariableSuffix(const TypeDesc* type, const Value& value) const +string Syntax::getArrayVariableSuffix(TypeDesc type, const Value& value) const { - if (type->isArray()) + if (type.isArray()) { if (value.isA>()) { @@ -323,7 +304,7 @@ void Syntax::makeIdentifier(string& name, IdentifierMap& identifiers) const identifiers[name] = 1; } -string Syntax::getVariableName(const string& name, const TypeDesc* /*type*/, IdentifierMap& identifiers) const +string Syntax::getVariableName(const string& name, TypeDesc /*type*/, IdentifierMap& identifiers) const { // Default implementation just makes an identifier, but derived // classes can override this for custom variable naming. @@ -332,11 +313,12 @@ string Syntax::getVariableName(const string& name, const TypeDesc* /*type*/, Ide return variable; } -bool Syntax::remapEnumeration(const string&, const TypeDesc*, const string&, std::pair&) const +bool Syntax::remapEnumeration(const string&, TypeDesc, const string&, std::pair&) const { return false; } + const StringVec TypeSyntax::EMPTY_MEMBERS; TypeSyntax::TypeSyntax(const string& name, const string& defaultValue, const string& uniformDefaultValue, diff --git a/source/MaterialXGenShader/Syntax.h b/source/MaterialXGenShader/Syntax.h index 1dec9419b5..f069f19189 100644 --- a/source/MaterialXGenShader/Syntax.h +++ b/source/MaterialXGenShader/Syntax.h @@ -10,6 +10,7 @@ /// Base class for syntax handling for shader generators #include +#include #include #include @@ -53,7 +54,8 @@ class MX_GENSHADER_API Syntax /// Register syntax handling for a data type. /// Required to be set for all supported data types. - void registerTypeSyntax(const TypeDesc* type, TypeSyntaxPtr syntax); + void registerTypeSyntax(TypeDesc type, TypeSyntaxPtr syntax); + [[deprecated]] void registerTypeSyntax(const TypeDesc* type, TypeSyntaxPtr syntax) { registerTypeSyntax(*type, syntax); } /// Register names that are reserved words not to be used by a code generator when naming /// variables and functions. Keywords, types, built-in functions etc. should be @@ -73,43 +75,54 @@ class MX_GENSHADER_API Syntax /// Returns the type syntax object for a named type. /// Throws an exception if a type syntax is not defined for the given type. - const TypeSyntax& getTypeSyntax(const TypeDesc* type) const; + const TypeSyntax& getTypeSyntax(TypeDesc type) const; + [[deprecated]] const TypeSyntax& getTypeSyntax(const TypeDesc* type) const { return getTypeSyntax(*type); } /// Returns an array of all registered type syntax objects const vector& getTypeSyntaxes() const { return _typeSyntaxes; } - /// Returns a type description given a type syntax. Throws an exception - /// if the type syntax has not been registered - const TypeDesc* getTypeDescription(const TypeSyntaxPtr& typeSyntax) const; - /// Returns the name syntax of the given type - const string& getTypeName(const TypeDesc* type) const; + const string& getTypeName(TypeDesc type) const; + [[deprecated]] const string& getTypeName(const TypeDesc* type) const { return getTypeName(*type); } /// Returns the type name in an output context - virtual string getOutputTypeName(const TypeDesc* type) const; + virtual string getOutputTypeName(TypeDesc type) const; + [[deprecated]] string getOutputTypeName(const TypeDesc* type) const { return getOutputTypeName(*type); } /// Returns a type alias for the given data type. /// If not used returns an empty string. - const string& getTypeAlias(const TypeDesc* type) const; + const string& getTypeAlias(TypeDesc type) const; + [[deprecated]] const string& getTypeAlias(const TypeDesc* type) const { return getTypeAlias(*type); } /// Returns a custom type definition if needed for the given data type. /// If not used returns an empty string. - const string& getTypeDefinition(const TypeDesc* type) const; + const string& getTypeDefinition(TypeDesc type) const; + [[deprecated]] const string& getTypeDefinition(const TypeDesc* type) const { return getTypeDefinition(*type); } /// Returns the default value string for the given type - const string& getDefaultValue(const TypeDesc* type, bool uniform = false) const; + const string& getDefaultValue(TypeDesc type, bool uniform = false) const; + [[deprecated]] const string& getDefaultValue(const TypeDesc* type, bool uniform = false) const { return getDefaultValue(*type, uniform); } /// Returns the value string for a given type and value object - virtual string getValue(const TypeDesc* type, const Value& value, bool uniform = false) const; + virtual string getValue(TypeDesc type, const Value& value, bool uniform = false) const; + [[deprecated]] string getValue(const TypeDesc* type, const Value& value, bool uniform = false) const { return getValue(*type, value, uniform); } /// Returns the value string for a given shader port object virtual string getValue(const ShaderPort* port, bool uniform = false) const; /// Get syntax for a swizzled variable - virtual string getSwizzledVariable(const string& srcName, const TypeDesc* srcType, const string& channels, const TypeDesc* dstType) const; + virtual string getSwizzledVariable(const string& srcName, TypeDesc srcType, const string& channels, TypeDesc dstType) const; + [[deprecated]] string getSwizzledVariable(const string& srcName, const TypeDesc* srcType, const string& channels, const TypeDesc* dstType) const + { + return getSwizzledVariable(srcName, *srcType, channels, *dstType); + } /// Get swizzled value - virtual ValuePtr getSwizzledValue(ValuePtr value, const TypeDesc* srcType, const string& channels, const TypeDesc* dstType) const; + virtual ValuePtr getSwizzledValue(ValuePtr value, TypeDesc srcType, const string& channels, TypeDesc dstType) const; + [[deprecated]] ValuePtr getSwizzledValue(ValuePtr value, const TypeDesc* srcType, const string& channels, const TypeDesc* dstType) const + { + return getSwizzledValue(value, *srcType, channels, *dstType); + } /// Returns a type qualifier to be used when declaring types for input variables. /// Default implementation returns empty string and derived syntax classes should @@ -155,14 +168,16 @@ class MX_GENSHADER_API Syntax virtual const string& getSourceFileExtension() const = 0; /// Return the array suffix to use for declaring an array type. - virtual string getArrayTypeSuffix(const TypeDesc*, const Value&) const { return EMPTY_STRING; }; + virtual string getArrayTypeSuffix(TypeDesc, const Value&) const { return EMPTY_STRING; }; + [[deprecated]] string getArrayTypeSuffix(const TypeDesc* type, const Value& value) const { return getArrayTypeSuffix(*type, value); } /// Return the array suffix to use for declaring an array variable. - virtual string getArrayVariableSuffix(const TypeDesc* type, const Value& value) const; + virtual string getArrayVariableSuffix(TypeDesc type, const Value& value) const; + [[deprecated]] string getArrayVariableSuffix(const TypeDesc* type, const Value& value) const { return getArrayVariableSuffix(*type, value); } /// Query if given type is suppored in the syntax. /// By default all types are assumed to be supported. - virtual bool typeSupported(const TypeDesc* type) const; + [[deprecated]] virtual bool typeSupported(const TypeDesc* type) const; /// Modify the given name string to remove any invalid characters or tokens. virtual void makeValidName(string& name) const; @@ -176,7 +191,8 @@ class MX_GENSHADER_API Syntax /// Derived classes can override this method to have a custom naming strategy. /// Default implementation adds a number suffix, or increases an existing number suffix, /// on the name string if there is a name collision. - virtual string getVariableName(const string& name, const TypeDesc* type, IdentifierMap& identifiers) const; + virtual string getVariableName(const string& name, TypeDesc type, IdentifierMap& identifiers) const; + [[deprecated]] string getVariableName(const string& name, const TypeDesc* type, IdentifierMap& identifiers) const { return getVariableName(name, *type, identifiers); } /// Given an input specification attempt to remap this to an enumeration which is accepted by /// the shader generator. The enumeration may be converted to a different type than the input. @@ -185,8 +201,8 @@ class MX_GENSHADER_API Syntax /// @param enumNames Type enumeration names /// @param result Enumeration type and value (returned). /// @return Return true if the remapping was successful. - virtual bool remapEnumeration(const string& value, const TypeDesc* type, const string& enumNames, - std::pair& result) const; + virtual bool remapEnumeration(const string& value, TypeDesc type, const string& enumNames, + std::pair& result) const; /// Constants with commonly used strings. static const string NEWLINE; @@ -198,7 +214,7 @@ class MX_GENSHADER_API Syntax Syntax(); vector _typeSyntaxes; - std::unordered_map _typeSyntaxByType; + std::unordered_map _typeSyntaxIndexByType; StringSet _reservedWords; StringMap _invalidTokens; diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp index dbe2504758..5f631f67e3 100644 --- a/source/MaterialXGenShader/TypeDesc.cpp +++ b/source/MaterialXGenShader/TypeDesc.cpp @@ -11,102 +11,78 @@ MATERIALX_NAMESPACE_BEGIN namespace { + using TypeDescMap = std::unordered_map; + using TypeDescNameMap = std::unordered_map; -using TypeDescPtr = std::unique_ptr; -using TypeDescMap = std::unordered_map; + // Internal storage of registered type descriptors + TypeDescMap& typeMap() + { + static TypeDescMap map; + return map; + } -// Internal storage of the type descriptor pointers -TypeDescMap& typeMap() -{ - static TypeDescMap map; - return map; -} + TypeDescNameMap& typeNameMap() + { + static TypeDescNameMap map; + return map; + } } // anonymous namespace -// -// TypeDesc methods -// +const string TypeDesc::NONE_TYPE_NAME = "none"; -TypeDesc::TypeDesc(const string& name, unsigned char basetype, unsigned char semantic, size_t size, - bool editable, const std::unordered_map& channelMapping) : - _name(name), - _basetype(basetype), - _semantic(semantic), - _size(size), - _editable(editable), - _channelMapping(channelMapping) +const string& TypeDesc::getName() const { + TypeDescNameMap& typenames = typeNameMap(); + auto it = typenames.find(_id); + return it != typenames.end() ? it->second : NONE_TYPE_NAME; } -bool TypeDesc::operator==(const TypeDesc& rhs) const +TypeDesc TypeDesc::get(const string& name) { - return (this->_name == rhs._name); + TypeDescMap& types = typeMap(); + auto it = types.find(name); + return it != types.end() ? it->second : Type::NONE; } -bool TypeDesc::operator!=(const TypeDesc& rhs) const +TypeDescRegistry::TypeDescRegistry(TypeDesc type, const std::string& name) { - return !(*this == rhs); -} - -const TypeDesc* TypeDesc::registerType(const string& name, unsigned char basetype, unsigned char semantic, size_t size, - bool editable, const std::unordered_map& channelMapping) -{ - TypeDescMap& map = typeMap(); - auto it = map.find(name); - if (it != map.end()) - { - throw Exception("A type with name '" + name + "' is already registered"); - } - - TypeDesc* typeDesc = new TypeDesc(name, basetype, semantic, size, editable, channelMapping); - map[name] = std::unique_ptr(typeDesc); - return typeDesc; -} - -int TypeDesc::getChannelIndex(char channel) const -{ - auto it = _channelMapping.find(channel); - return it != _channelMapping.end() ? it->second : -1; -} - -const TypeDesc* TypeDesc::get(const string& name) -{ - const TypeDescMap& map = typeMap(); - auto it = map.find(name); - return it != map.end() ? it->second.get() : nullptr; + TypeDescMap& types = typeMap(); + TypeDescNameMap& typenames = typeNameMap(); + types[name] = type; + typenames[type.typeId()] = name; } namespace Type { -// Register all standard types and save their pointers -// for quick access and type comparisons later. -const TypeDesc* NONE = TypeDesc::registerType("none", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_NONE, 1, false); -const TypeDesc* MULTIOUTPUT = TypeDesc::registerType("multioutput", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_NONE, 1, false); -const TypeDesc* BOOLEAN = TypeDesc::registerType("boolean", TypeDesc::BASETYPE_BOOLEAN); -const TypeDesc* INTEGER = TypeDesc::registerType("integer", TypeDesc::BASETYPE_INTEGER); -const TypeDesc* INTEGERARRAY = TypeDesc::registerType("integerarray", TypeDesc::BASETYPE_INTEGER, TypeDesc::SEMANTIC_NONE, 0); -const TypeDesc* FLOAT = TypeDesc::registerType("float", TypeDesc::BASETYPE_FLOAT); -const TypeDesc* FLOATARRAY = TypeDesc::registerType("floatarray", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_NONE, 0); -const TypeDesc* VECTOR2 = TypeDesc::registerType("vector2", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_VECTOR, 2, true, {{'x', 0}, {'y', 1}}); -const TypeDesc* VECTOR3 = TypeDesc::registerType("vector3", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_VECTOR, 3, true, {{'x', 0}, {'y', 1}, {'z', 2}}); -const TypeDesc* VECTOR4 = TypeDesc::registerType("vector4", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_VECTOR, 4, true, {{'x', 0}, {'y', 1}, {'z', 2}, {'w', 3}}); -const TypeDesc* COLOR3 = TypeDesc::registerType("color3", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_COLOR, 3, true, {{'r', 0}, {'g', 1}, {'b', 2}}); -const TypeDesc* COLOR4 = TypeDesc::registerType("color4", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_COLOR, 4, true, {{'r', 0}, {'g', 1}, {'b', 2}, {'a', 3}}); -const TypeDesc* MATRIX33 = TypeDesc::registerType("matrix33", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_MATRIX, 9); -const TypeDesc* MATRIX44 = TypeDesc::registerType("matrix44", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_MATRIX, 16); -const TypeDesc* STRING = TypeDesc::registerType("string", TypeDesc::BASETYPE_STRING); -const TypeDesc* FILENAME = TypeDesc::registerType("filename", TypeDesc::BASETYPE_STRING, TypeDesc::SEMANTIC_FILENAME); -const TypeDesc* BSDF = TypeDesc::registerType("BSDF", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_CLOSURE, 1, false); -const TypeDesc* EDF = TypeDesc::registerType("EDF", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_CLOSURE, 1, false); -const TypeDesc* VDF = TypeDesc::registerType("VDF", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_CLOSURE, 1, false); -const TypeDesc* SURFACESHADER = TypeDesc::registerType("surfaceshader", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_SHADER, 1, false); -const TypeDesc* VOLUMESHADER = TypeDesc::registerType("volumeshader", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_SHADER, 1, false); -const TypeDesc* DISPLACEMENTSHADER = TypeDesc::registerType("displacementshader", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_SHADER, 1, false); -const TypeDesc* LIGHTSHADER = TypeDesc::registerType("lightshader", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_SHADER, 1, false); -const TypeDesc* MATERIAL = TypeDesc::registerType("material", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_MATERIAL, 1, false); +/// +/// Register type descriptors for standard types. +/// +TYPEDESC_REGISTER_TYPE(NONE, "none") +TYPEDESC_REGISTER_TYPE(BOOLEAN, "boolean") +TYPEDESC_REGISTER_TYPE(INTEGER, "integer") +TYPEDESC_REGISTER_TYPE(INTEGERARRAY, "integerarray") +TYPEDESC_REGISTER_TYPE(FLOAT, "float") +TYPEDESC_REGISTER_TYPE(FLOATARRAY, "floatarray") +TYPEDESC_REGISTER_TYPE(VECTOR2, "vector2") +TYPEDESC_REGISTER_TYPE(VECTOR3, "vector3") +TYPEDESC_REGISTER_TYPE(VECTOR4, "vector4") +TYPEDESC_REGISTER_TYPE(COLOR3, "color3") +TYPEDESC_REGISTER_TYPE(COLOR4, "color4") +TYPEDESC_REGISTER_TYPE(MATRIX33, "matrix33") +TYPEDESC_REGISTER_TYPE(MATRIX44, "matrix44") +TYPEDESC_REGISTER_TYPE(STRING, "string") +TYPEDESC_REGISTER_TYPE(FILENAME, "filename") +TYPEDESC_REGISTER_TYPE(BSDF, "BSDF") +TYPEDESC_REGISTER_TYPE(EDF, "EDF") +TYPEDESC_REGISTER_TYPE(VDF, "VDF") +TYPEDESC_REGISTER_TYPE(SURFACESHADER, "surfaceshader") +TYPEDESC_REGISTER_TYPE(VOLUMESHADER, "volumeshader") +TYPEDESC_REGISTER_TYPE(DISPLACEMENTSHADER, "displacementshader") +TYPEDESC_REGISTER_TYPE(LIGHTSHADER, "lightshader") +TYPEDESC_REGISTER_TYPE(MATERIAL, "material") -} // namespace Type +} MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index daed87d7e2..a0cd9bd89e 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -11,22 +11,29 @@ #include -MATERIALX_NAMESPACE_BEGIN +#include -using ChannelMap = std::unordered_map; +MATERIALX_NAMESPACE_BEGIN /// @class TypeDesc /// A type descriptor for MaterialX data types. +/// /// All types need to have a type descriptor registered in order for shader generators -/// to know about the type. A unique type descriptor pointer is the identifier used for -/// types, and can be used for type comparisons as well as getting more information -/// about the type. All standard library data types are registered by default and their -/// type descriptors can be accessed from the Type namespace, e.g. MaterialX::Type::FLOAT. -/// If custom types are used they must be registered by calling TypeDesc::registerType(). -/// Descriptors for registered types can be retreived using TypeDesc::get(), see below. +/// to know about the type. It can be used for type comparisons as well as getting more +/// information about the type. Type descriptors for all standard library data types are +/// registered by default and can be accessed from the Type namespace, e.g. Type::FLOAT. +/// +/// To register custom types use the macro TYPEDESC_DEFINE_TYPE to define it in a header +/// and the macro TYPEDESC_REGISTER_TYPE to register it in the type registry. Registration +/// must be done in order to access the type's name later using getName() and to find the +/// type by name using TypeDesc::get(). +/// +/// The class is a POD type of 64-bits and can efficiently be stored and passed by value. +/// Type compare operations and hash operations are done using a precomputed hash value. +/// class MX_GENSHADER_API TypeDesc { - public: +public: enum BaseType { BASETYPE_NONE, @@ -52,31 +59,27 @@ class MX_GENSHADER_API TypeDesc SEMANTIC_LAST }; - /// Register a type descriptor for a MaterialX data type. - /// Throws an exception if a type with the same name is already registered. - static const TypeDesc* registerType(const string& name, unsigned char basetype, unsigned char semantic = SEMANTIC_NONE, - size_t size = 1, bool editable = true, const ChannelMap& channelMapping = ChannelMap()); + /// Empty constructor. + constexpr TypeDesc() noexcept : _id(0), _basetype(BASETYPE_NONE), _semantic(SEMANTIC_NONE), _size(0) {} - /// Equality operator overload - bool operator==(const TypeDesc& rhs) const; + /// Constructor. + constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1) noexcept : + _id(constexpr_hash(name)), // Note: We only store the hash to keep the class size minimal. + _basetype(basetype), + _semantic(semantic), + _size(size) + {} - /// Inequality operator overload - bool operator!=(const TypeDesc& rhs) const; - - /// Get a type descriptor for given name. - /// Returns an empty shared pointer if no type with the given name is found. - static const TypeDesc* get(const string& name); + /// Return the unique id assigned to this type. + /// The id is a hash of the given type name. + uint32_t typeId() const { return _id; } /// Return the name of the type. - const string& getName() const { return _name; } + const string& getName() const; /// Return the basetype for the type. unsigned char getBaseType() const { return _basetype; } - /// Returns the channel index for the supplied channel name. - /// Will return -1 on failure to find a matching index. - int getChannelIndex(char channel) const; - /// Return the semantic for the type. unsigned char getSemantic() const { return _semantic; } @@ -86,11 +89,6 @@ class MX_GENSHADER_API TypeDesc /// until an array is instantiated. size_t getSize() const { return _size; } - /// Returns true if the type is editable by users. - /// Editable types are allowed to be published as shader uniforms - /// and hence must be presentable in a user interface. - bool isEditable() const { return _editable; } - /// Return true if the type is a scalar type. bool isScalar() const { return _size == 1; } @@ -112,49 +110,99 @@ 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); } - private: - TypeDesc(const string& name, unsigned char basetype, unsigned char semantic, size_t size, - bool editable, const ChannelMap& channelMapping); + /// Equality operator + bool operator==(TypeDesc rhs) const + { + return _id == rhs._id; + } + + /// Inequality operator + bool operator!=(TypeDesc rhs) const + { + return _id != rhs._id; + } + + /// Less-than operator + bool operator<(TypeDesc rhs) const + { + return _id < rhs._id; + } + + /// Hash operator + struct Hasher + { + size_t operator()(TypeDesc t) const + { + return t._id; + } + }; + + /// Return a type description by name. + /// If no type is found Type::NONE is returned. + static TypeDesc get(const string& name); + + static const string NONE_TYPE_NAME; + +private: + /// Simple constexpr hash function, good enough for the small set of short strings that + /// are used for our data type names. + constexpr uint32_t constexpr_hash(std::string_view str, uint32_t n = 0, uint32_t h = 2166136261) + { + return n == uint32_t(str.size()) ? h : constexpr_hash(str, n + 1, (h * 16777619) ^ (str[n])); + } + + uint32_t _id; + uint8_t _basetype; + uint8_t _semantic; + uint16_t _size; +}; - const string _name; - const unsigned char _basetype; - const unsigned char _semantic; - const size_t _size; - const bool _editable; - const ChannelMap _channelMapping; +/// @class TypeDescRegistry +/// Helper class for type registration. +class MX_GENSHADER_API TypeDescRegistry +{ +public: + TypeDescRegistry(TypeDesc type, const string& name); }; +/// Macro to define global type descriptions for commonly used types. +#define TYPEDESC_DEFINE_TYPE(T, name, basetype, semantic, size) \ + static constexpr TypeDesc T(name, basetype, semantic, size); + +/// Macro to register a previously defined type in the type registry. +/// Registration must be done in order for the type to be searchable by name. +#define TYPEDESC_REGISTER_TYPE(T, name) \ + TypeDescRegistry register_##T(T, name); + namespace Type { -/// Type descriptors for all standard types. -/// These are always registered by default. -/// -/// TODO: Add support for the standard array types. -/// -extern MX_GENSHADER_API const TypeDesc* NONE; -extern MX_GENSHADER_API const TypeDesc* BOOLEAN; -extern MX_GENSHADER_API const TypeDesc* INTEGER; -extern MX_GENSHADER_API const TypeDesc* INTEGERARRAY; -extern MX_GENSHADER_API const TypeDesc* FLOAT; -extern MX_GENSHADER_API const TypeDesc* FLOATARRAY; -extern MX_GENSHADER_API const TypeDesc* VECTOR2; -extern MX_GENSHADER_API const TypeDesc* VECTOR3; -extern MX_GENSHADER_API const TypeDesc* VECTOR4; -extern MX_GENSHADER_API const TypeDesc* COLOR3; -extern MX_GENSHADER_API const TypeDesc* COLOR4; -extern MX_GENSHADER_API const TypeDesc* MATRIX33; -extern MX_GENSHADER_API const TypeDesc* MATRIX44; -extern MX_GENSHADER_API const TypeDesc* STRING; -extern MX_GENSHADER_API const TypeDesc* FILENAME; -extern MX_GENSHADER_API const TypeDesc* BSDF; -extern MX_GENSHADER_API const TypeDesc* EDF; -extern MX_GENSHADER_API const TypeDesc* VDF; -extern MX_GENSHADER_API const TypeDesc* SURFACESHADER; -extern MX_GENSHADER_API const TypeDesc* VOLUMESHADER; -extern MX_GENSHADER_API const TypeDesc* DISPLACEMENTSHADER; -extern MX_GENSHADER_API const TypeDesc* LIGHTSHADER; -extern MX_GENSHADER_API const TypeDesc* MATERIAL; +// +/// Define type descriptors for standard types. +// +TYPEDESC_DEFINE_TYPE(NONE, "none", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_NONE, 1) +TYPEDESC_DEFINE_TYPE(BOOLEAN, "boolean", TypeDesc::BASETYPE_BOOLEAN, TypeDesc::SEMANTIC_NONE, 1) +TYPEDESC_DEFINE_TYPE(INTEGER, "integer", TypeDesc::BASETYPE_INTEGER, TypeDesc::SEMANTIC_NONE, 1) +TYPEDESC_DEFINE_TYPE(FLOAT, "float", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_NONE, 1) +TYPEDESC_DEFINE_TYPE(INTEGERARRAY, "integerarray", TypeDesc::BASETYPE_INTEGER, TypeDesc::SEMANTIC_NONE, 0) +TYPEDESC_DEFINE_TYPE(FLOATARRAY, "floatarray", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_NONE, 0) +TYPEDESC_DEFINE_TYPE(VECTOR2, "vector2", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_VECTOR, 2) +TYPEDESC_DEFINE_TYPE(VECTOR3, "vector3", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_VECTOR, 3) +TYPEDESC_DEFINE_TYPE(VECTOR4, "vector4", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_VECTOR, 4) +TYPEDESC_DEFINE_TYPE(COLOR3, "color3", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_COLOR, 3) +TYPEDESC_DEFINE_TYPE(COLOR4, "color4", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_COLOR, 4) +TYPEDESC_DEFINE_TYPE(MATRIX33, "matrix33", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_MATRIX, 9) +TYPEDESC_DEFINE_TYPE(MATRIX44, "matrix44", TypeDesc::BASETYPE_FLOAT, TypeDesc::SEMANTIC_MATRIX, 16) +TYPEDESC_DEFINE_TYPE(STRING, "string", TypeDesc::BASETYPE_STRING, TypeDesc::SEMANTIC_NONE, 1) +TYPEDESC_DEFINE_TYPE(FILENAME, "filename", TypeDesc::BASETYPE_STRING, TypeDesc::SEMANTIC_FILENAME, 1) +TYPEDESC_DEFINE_TYPE(BSDF, "BSDF", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_CLOSURE, 1) +TYPEDESC_DEFINE_TYPE(EDF, "EDF", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_CLOSURE, 1) +TYPEDESC_DEFINE_TYPE(VDF, "VDF", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_CLOSURE, 1) +TYPEDESC_DEFINE_TYPE(SURFACESHADER, "surfaceshader", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_SHADER, 1) +TYPEDESC_DEFINE_TYPE(VOLUMESHADER, "volumeshader", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_SHADER, 1) +TYPEDESC_DEFINE_TYPE(DISPLACEMENTSHADER, "displacementshader", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_SHADER, 1) +TYPEDESC_DEFINE_TYPE(LIGHTSHADER, "lightshader", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_SHADER, 1) +TYPEDESC_DEFINE_TYPE(MATERIAL, "material", TypeDesc::BASETYPE_NONE, TypeDesc::SEMANTIC_MATERIAL, 1) } // namespace Type diff --git a/source/MaterialXGenShader/UnitSystem.cpp b/source/MaterialXGenShader/UnitSystem.cpp index 2b73303de7..232351b526 100644 --- a/source/MaterialXGenShader/UnitSystem.cpp +++ b/source/MaterialXGenShader/UnitSystem.cpp @@ -104,7 +104,7 @@ void ScalarUnitNode::emitFunctionCall(const ShaderNode& node, GenContext& contex // Unit transform methods // -UnitTransform::UnitTransform(const string& ss, const string& ts, const TypeDesc* t, const string& unittype) : +UnitTransform::UnitTransform(const string& ss, const string& ts, TypeDesc t, const string& unittype) : sourceUnit(ss), targetUnit(ts), type(t), @@ -157,7 +157,7 @@ NodeDefPtr UnitSystem::getNodeDef(const UnitTransform& transform) const { vector nodeInputs = nodeDef->getInputs(); if (nodeInputs.size() == 2 && - nodeInputs[0]->getType() == transform.type->getName() && + nodeInputs[0]->getType() == transform.type.getName() && nodeInputs[1]->getType() == "float") { return nodeDef; diff --git a/source/MaterialXGenShader/UnitSystem.h b/source/MaterialXGenShader/UnitSystem.h index d9431c4b98..4108917558 100644 --- a/source/MaterialXGenShader/UnitSystem.h +++ b/source/MaterialXGenShader/UnitSystem.h @@ -29,11 +29,11 @@ using UnitSystemPtr = shared_ptr; /// Structure that represents unit transform information struct MX_GENSHADER_API UnitTransform { - UnitTransform(const string& ss, const string& ts, const TypeDesc* t, const string& unittype); + UnitTransform(const string& ss, const string& ts, TypeDesc t, const string& unittype); string sourceUnit; string targetUnit; - const TypeDesc* type; + TypeDesc type; string unitType; /// Comparison operator diff --git a/source/MaterialXGenShader/Util.cpp b/source/MaterialXGenShader/Util.cpp index a9f48b31c4..f8a5f14d1f 100644 --- a/source/MaterialXGenShader/Util.cpp +++ b/source/MaterialXGenShader/Util.cpp @@ -209,8 +209,8 @@ bool isTransparentShaderGraph(OutputPtr output, const string& target, NodePtr in NodeDefPtr nodeDef = node->getNodeDef(); if (nodeDef) { - const TypeDesc* nodeDefType = TypeDesc::get(nodeDef->getType()); - if (*nodeDefType == *Type::BSDF) + const TypeDesc nodeDefType = TypeDesc::get(nodeDef->getType()); + if (nodeDefType == Type::BSDF) { InterfaceElementPtr impl = nodeDef->getImplementation(target); if (impl && impl->isA()) diff --git a/source/MaterialXRender/LightHandler.cpp b/source/MaterialXRender/LightHandler.cpp index 1daef328dd..0b841e5dc8 100644 --- a/source/MaterialXRender/LightHandler.cpp +++ b/source/MaterialXRender/LightHandler.cpp @@ -41,8 +41,8 @@ void LightHandler::findLights(DocumentPtr doc, vector& lights) lights.clear(); for (NodePtr node : doc->getNodes()) { - const TypeDesc* type = TypeDesc::get(node->getType()); - if (*type == *Type::LIGHTSHADER) + const TypeDesc type = TypeDesc::get(node->getType()); + if (type == Type::LIGHTSHADER) { lights.push_back(node); } diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index f33c67173e..5a9b116d59 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -157,12 +157,12 @@ unsigned int getUIProperties(InputPtr input, const string& target, UIProperties& if (!enumValuesAttr.empty()) { const string COMMA_SEPARATOR = ","; - const TypeDesc* typeDesc = TypeDesc::get(input->getType()); + const TypeDesc typeDesc = TypeDesc::get(input->getType()); string valueString; size_t index = 0; for (const string& val : splitString(enumValuesAttr, COMMA_SEPARATOR)) { - if (index < typeDesc->getSize() - 1) + if (index < typeDesc.getSize() - 1) { valueString += val + COMMA_SEPARATOR; index++; diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index 84668d2d0a..2586cc4ef8 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -361,7 +361,7 @@ void GlslMaterial::modifyUniform(const std::string& path, ConstValuePtr value, s { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType()->getName())); + uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index c9d0467b01..5da89c63b4 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -924,11 +924,11 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() } // TODO: Shoud we really create new ones here each update? - InputPtr inputPtr = std::make_shared(-1, -1, int(v->getType()->getSize()), EMPTY_STRING); + InputPtr inputPtr = std::make_shared(-1, -1, int(v->getType().getSize()), EMPTY_STRING); _uniformList[v->getVariable()] = inputPtr; inputPtr->isConstant = true; inputPtr->value = v->getValue(); - inputPtr->typeString = v->getType()->getName(); + inputPtr->typeString = v->getType().getName(); inputPtr->path = v->getPath(); } @@ -969,14 +969,14 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() input->value = v->getValue(); if (input->gltype == glType) { - input->typeString = v->getType()->getName(); + input->typeString = v->getType().getName(); } else { errors.push_back( "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType()->getName() + + "\". Type: \"" + v->getType().getName() + "\". Semantic: \"" + v->getSemantic() + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") + "\". Unit: \"" + (!v->getUnit().empty() ? v->getUnit() : "") @@ -1002,7 +1002,7 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() Input* input = inputIt->second.get(); if (input->gltype == mapTypeToOpenGLType(v->getType())) { - input->typeString = v->getType()->getName(); + input->typeString = v->getType().getName(); input->value = v->getValue(); input->path = v->getPath(); input->unit = v->getUnit(); @@ -1013,7 +1013,7 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() errors.push_back( "Vertex shader uniform block type mismatch [" + uniforms.getName() + "]. " + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType()->getName() + + "\". Type: \"" + v->getType().getName() + "\". Semantic: \"" + v->getSemantic() + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") + "\". Unit: \"" + (!v->getUnit().empty() ? v->getUnit() : "") @@ -1036,25 +1036,25 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() return _uniformList; } -int GlslProgram::mapTypeToOpenGLType(const TypeDesc* type) +int GlslProgram::mapTypeToOpenGLType(TypeDesc type) { - if (*type == *Type::INTEGER) + if (type == Type::INTEGER) return GL_INT; - else if (*type == *Type::BOOLEAN) + else if (type == Type::BOOLEAN) return GL_BOOL; - else if (*type == *Type::FLOAT) + else if (type == Type::FLOAT) return GL_FLOAT; - else if (type->isFloat2()) + else if (type.isFloat2()) return GL_FLOAT_VEC2; - else if (type->isFloat3()) + else if (type.isFloat3()) return GL_FLOAT_VEC3; - else if (type->isFloat4()) + else if (type.isFloat4()) return GL_FLOAT_VEC4; - else if (*type == *Type::MATRIX33) + else if (type == Type::MATRIX33) return GL_FLOAT_MAT3; - else if (*type == *Type::MATRIX44) + else if (type == Type::MATRIX44) return GL_FLOAT_MAT4; - else if (*type == *Type::FILENAME) + else if (type == Type::FILENAME) { // A "filename" is not indicative of type, so just return a 2d sampler. return GL_SAMPLER_2D; @@ -1131,13 +1131,13 @@ const GlslProgram::InputMap& GlslProgram::updateAttributesList() input->value = v->getValue(); if (input->gltype == mapTypeToOpenGLType(v->getType())) { - input->typeString = v->getType()->getName(); + input->typeString = v->getType().getName(); } else { errors.push_back( "Vertex shader attribute type mismatch in block. Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType()->getName() + + "\". Type: \"" + v->getType().getName() + "\". Semantic: \"" + v->getSemantic() + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") + "\". GLType: " + std::to_string(mapTypeToOpenGLType(v->getType())) diff --git a/source/MaterialXRenderGlsl/GlslProgram.h b/source/MaterialXRenderGlsl/GlslProgram.h index e90853eedb..7d58dbaca7 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.h +++ b/source/MaterialXRenderGlsl/GlslProgram.h @@ -230,7 +230,7 @@ class MX_RENDERGLSL_API GlslProgram ImageHandlerPtr imageHandler, const ImageSamplingProperties& imageProperties); // Utility to map a MaterialX type to an OpenGL type - static int mapTypeToOpenGLType(const TypeDesc* type); + static int mapTypeToOpenGLType(TypeDesc type); // Bind a value to the uniform at the given location. void bindUniformLocation(int location, ConstValuePtr value); diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm index 66fc0462f2..4177403a99 100644 --- a/source/MaterialXRenderMsl/MslMaterial.mm +++ b/source/MaterialXRenderMsl/MslMaterial.mm @@ -319,7 +319,7 @@ { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType()->getName())); + uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.h b/source/MaterialXRenderMsl/MslPipelineStateObject.h index acc603407d..6fe21a7e81 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.h +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.h @@ -278,7 +278,7 @@ class MX_RENDERMSL_API MslProgram void reset(); // Utility to map a MaterialX type to an METAL type - static MTLDataType mapTypeToMetalType(const TypeDesc* type); + static MTLDataType mapTypeToMetalType(TypeDesc type); private: // Stages used to create program diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm index f0cc8e47bb..2704f78d4b 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm @@ -983,11 +983,11 @@ int GetStrideOfMetalType(MTLDataType type) } // TODO: Shoud we really create new ones here each update? - InputPtr inputPtr = std::make_shared(-1, -1, int(v->getType()->getSize()), EMPTY_STRING); + InputPtr inputPtr = std::make_shared(-1, -1, int(v->getType().getSize()), EMPTY_STRING); _uniformList[v->getVariable()] = inputPtr; inputPtr->isConstant = true; inputPtr->value = v->getValue(); - inputPtr->typeString = v->getType()->getName(); + inputPtr->typeString = v->getType().getName(); inputPtr->path = v->getPath(); } @@ -1027,14 +1027,14 @@ int GetStrideOfMetalType(MTLDataType type) input->value = v->getValue(); if (input->resourceType == resourceType) { - input->typeString = v->getType()->getName(); + input->typeString = v->getType().getName(); } else { errors.push_back( "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType()->getName() + + "\". Type: \"" + v->getType().getName() + "\". Semantic: \"" + v->getSemantic() + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") + "\". resourceType: " + std::to_string(mapTypeToMetalType(v->getType())) @@ -1074,7 +1074,7 @@ int GetStrideOfMetalType(MTLDataType type) Input* input = inputIt->second.get(); if (input->resourceType == mapTypeToMetalType(v->getType())) { - input->typeString = v->getType()->getName(); + input->typeString = v->getType().getName(); input->value = v->getValue(); input->path = v->getPath(); input->unit = v->getUnit(); @@ -1084,7 +1084,7 @@ int GetStrideOfMetalType(MTLDataType type) errors.push_back( "Vertex shader uniform block type mismatch [" + uniforms.getName() + "]. " + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType()->getName() + + "\". Type: \"" + v->getType().getName() + "\". Semantic: \"" + v->getSemantic() + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") + "\". Unit: \"" + (!v->getUnit().empty() ? v->getUnit() : "") @@ -1398,7 +1398,7 @@ throw ExceptionRenderError( clearInputLists(); } -MTLDataType MslProgram::mapTypeToMetalType(const TypeDesc* type) +MTLDataType MslProgram::mapTypeToMetalType(TypeDesc type) { if (type == Type::INTEGER) return MTLDataTypeInt; @@ -1406,11 +1406,11 @@ throw ExceptionRenderError( return MTLDataTypeBool; else if (type == Type::FLOAT) return MTLDataTypeFloat; - else if (type->isFloat2()) + else if (type.isFloat2()) return MTLDataTypeFloat2; - else if (type->isFloat3()) + else if (type.isFloat3()) return MTLDataTypeFloat3; - else if (type->isFloat4()) + else if (type.isFloat4()) return MTLDataTypeFloat4; else if (type == Type::MATRIX33) return MTLDataTypeFloat3x3; @@ -1469,13 +1469,13 @@ throw ExceptionRenderError( input->value = v->getValue(); if (input->resourceType == mapTypeToMetalType(v->getType())) { - input->typeString = v->getType()->getName(); + input->typeString = v->getType().getName(); } else { errors.push_back( "Vertex shader attribute type mismatch in block. Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType()->getName() + + "\". Type: \"" + v->getType().getName() + "\". Semantic: \"" + v->getSemantic() + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") + "\". resourceType: " + std::to_string(mapTypeToMetalType(v->getType())) diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index eadb25eb9f..3d97c567cd 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -30,8 +30,8 @@ TEST_CASE("GenShader: MDL Syntax", "[genmdl]") REQUIRE(syntax->getTypeName(mx::Type::VECTOR3) == "float3"); REQUIRE(syntax->getTypeName(mx::Type::FLOATARRAY) == "float"); REQUIRE(syntax->getTypeName(mx::Type::INTEGERARRAY) == "int"); - REQUIRE(mx::Type::FLOATARRAY->isArray()); - REQUIRE(mx::Type::INTEGERARRAY->isArray()); + REQUIRE(mx::Type::FLOATARRAY.isArray()); + REQUIRE(mx::Type::INTEGERARRAY.isArray()); REQUIRE(syntax->getTypeName(mx::Type::BSDF) == "material"); REQUIRE(syntax->getOutputTypeName(mx::Type::BSDF) == "material"); diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp index f074a4fabd..9fa3329fcb 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp @@ -27,8 +27,8 @@ TEST_CASE("GenShader: OSL Syntax", "[genosl]") REQUIRE(syntax->getTypeName(mx::Type::VECTOR3) == "vector"); REQUIRE(syntax->getTypeName(mx::Type::FLOATARRAY) == "float"); REQUIRE(syntax->getTypeName(mx::Type::INTEGERARRAY) == "int"); - REQUIRE(mx::Type::FLOATARRAY->isArray()); - REQUIRE(mx::Type::INTEGERARRAY->isArray()); + REQUIRE(mx::Type::FLOATARRAY.isArray()); + REQUIRE(mx::Type::INTEGERARRAY.isArray()); REQUIRE(syntax->getTypeName(mx::Type::BSDF) == "BSDF"); REQUIRE(syntax->getOutputTypeName(mx::Type::BSDF) == "output BSDF"); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShader.cpp b/source/MaterialXTest/MaterialXGenShader/GenShader.cpp index 9b25a1d6b7..22afffbff4 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShader.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShader.cpp @@ -74,35 +74,34 @@ TEST_CASE("GenShader: Valid Libraries", "[genshader]") TEST_CASE("GenShader: TypeDesc Check", "[genshader]") { // Make sure the standard types are registered - const mx::TypeDesc* floatType = mx::TypeDesc::get("float"); - REQUIRE(floatType != nullptr); - REQUIRE(floatType->getBaseType() == mx::TypeDesc::BASETYPE_FLOAT); - const mx::TypeDesc* integerType = mx::TypeDesc::get("integer"); - REQUIRE(integerType != nullptr); - REQUIRE(integerType->getBaseType() == mx::TypeDesc::BASETYPE_INTEGER); - const mx::TypeDesc* booleanType = mx::TypeDesc::get("boolean"); - REQUIRE(booleanType != nullptr); - REQUIRE(booleanType->getBaseType() == mx::TypeDesc::BASETYPE_BOOLEAN); - const mx::TypeDesc* color3Type = mx::TypeDesc::get("color3"); - REQUIRE(color3Type != nullptr); - REQUIRE(color3Type->getBaseType() == mx::TypeDesc::BASETYPE_FLOAT); - REQUIRE(color3Type->getSemantic() == mx::TypeDesc::SEMANTIC_COLOR); - REQUIRE(color3Type->isFloat3()); - const mx::TypeDesc* color4Type = mx::TypeDesc::get("color4"); - REQUIRE(color4Type != nullptr); - REQUIRE(color4Type->getBaseType() == mx::TypeDesc::BASETYPE_FLOAT); - REQUIRE(color4Type->getSemantic() == mx::TypeDesc::SEMANTIC_COLOR); - REQUIRE(color4Type->isFloat4()); + const mx::TypeDesc floatType = mx::TypeDesc::get("float"); + REQUIRE(floatType != mx::Type::NONE); + REQUIRE(floatType.getBaseType() == mx::TypeDesc::BASETYPE_FLOAT); + const mx::TypeDesc integerType = mx::TypeDesc::get("integer"); + REQUIRE(integerType != mx::Type::NONE); + REQUIRE(integerType.getBaseType() == mx::TypeDesc::BASETYPE_INTEGER); + const mx::TypeDesc booleanType = mx::TypeDesc::get("boolean"); + REQUIRE(booleanType != mx::Type::NONE); + REQUIRE(booleanType.getBaseType() == mx::TypeDesc::BASETYPE_BOOLEAN); + const mx::TypeDesc color3Type = mx::TypeDesc::get("color3"); + REQUIRE(color3Type != mx::Type::NONE); + REQUIRE(color3Type.getBaseType() == mx::TypeDesc::BASETYPE_FLOAT); + REQUIRE(color3Type.getSemantic() == mx::TypeDesc::SEMANTIC_COLOR); + REQUIRE(color3Type.isFloat3()); + const mx::TypeDesc color4Type = mx::TypeDesc::get("color4"); + REQUIRE(color4Type != mx::Type::NONE); + REQUIRE(color4Type.getBaseType() == mx::TypeDesc::BASETYPE_FLOAT); + REQUIRE(color4Type.getSemantic() == mx::TypeDesc::SEMANTIC_COLOR); + REQUIRE(color4Type.isFloat4()); // Make sure we can register a new custom type - const mx::TypeDesc* fooType = mx::TypeDesc::registerType("foo", mx::TypeDesc::BASETYPE_FLOAT, mx::TypeDesc::SEMANTIC_COLOR, 5); - REQUIRE(fooType != nullptr); - - // Make sure we can't use a name that is already taken - REQUIRE_THROWS(mx::TypeDesc::registerType("color3", mx::TypeDesc::BASETYPE_FLOAT)); + const std::string fooTypeName = "foo"; + mx::TypeDescRegistry reg(mx::TypeDesc(fooTypeName, mx::TypeDesc::BASETYPE_FLOAT, mx::TypeDesc::SEMANTIC_COLOR, 5), fooTypeName); + const mx::TypeDesc fooType = mx::TypeDesc::get(fooTypeName); + REQUIRE(fooType != mx::Type::NONE); // Make sure we can't request an unknown type - REQUIRE(mx::TypeDesc::get("bar") == nullptr); + REQUIRE(mx::TypeDesc::get("bar") == mx::Type::NONE); } TEST_CASE("GenShader: Shader Translation", "[translate]") diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 51bb7af64b..f71f6dc6a6 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -581,7 +581,7 @@ void ShaderGeneratorTester::findLights(mx::DocumentPtr doc, std::vectorgetNodes()) { - const mx::TypeDesc* type = mx::TypeDesc::get(node->getType()); + const mx::TypeDesc type = mx::TypeDesc::get(node->getType()); if (type == mx::Type::LIGHTSHADER) { lights.push_back(node); diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyColorManagement.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyColorManagement.cpp index f35619e777..701b124c3c 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyColorManagement.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyColorManagement.cpp @@ -44,7 +44,7 @@ class PyColorManagementSystem : public mx::ColorManagementSystem void bindPyColorManagement(py::module& mod) { py::class_(mod, "ColorSpaceTransform") - .def(py::init()) + .def(py::init()) .def_readwrite("sourceSpace", &mx::ColorSpaceTransform::sourceSpace) .def_readwrite("targetSpace", &mx::ColorSpaceTransform::targetSpace) .def_readwrite("type", &mx::ColorSpaceTransform::type); diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyTypeDesc.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyTypeDesc.cpp index eb3aea9827..dc0a6c9fe8 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyTypeDesc.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyTypeDesc.cpp @@ -19,14 +19,13 @@ void bindPyTypeDesc(py::module& mod) .def_static("get", &mx::TypeDesc::get) .def("getName", &mx::TypeDesc::getName) .def("getBaseType", &mx::TypeDesc::getBaseType) - .def("getChannelIndex", &mx::TypeDesc::getChannelIndex) .def("getSemantic", &mx::TypeDesc::getSemantic) .def("getSize", &mx::TypeDesc::getSize) - .def("isEditable", &mx::TypeDesc::isEditable) .def("isScalar", &mx::TypeDesc::isScalar) .def("isAggregate", &mx::TypeDesc::isAggregate) .def("isArray", &mx::TypeDesc::isArray) .def("isFloat2", &mx::TypeDesc::isFloat2) .def("isFloat3", &mx::TypeDesc::isFloat3) - .def("isFloat4", &mx::TypeDesc::isFloat4); + .def("isFloat4", &mx::TypeDesc::isFloat4) + .def("isClosure", &mx::TypeDesc::isClosure); } diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyUnitSystem.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyUnitSystem.cpp index 746d0f929b..e5befc21e6 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyUnitSystem.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyUnitSystem.cpp @@ -15,7 +15,7 @@ namespace mx = MaterialX; void bindPyUnitSystem(py::module& mod) { py::class_(mod, "UnitTransform") - .def(py::init()) + .def(py::init()) .def_readwrite("sourceUnit", &mx::UnitTransform::sourceUnit) .def_readwrite("targetUnit", &mx::UnitTransform::targetUnit) .def_readwrite("type", &mx::UnitTransform::type) From fe996730950f399af8b2baae95693680aa788a56 Mon Sep 17 00:00:00 2001 From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com> Date: Tue, 5 Mar 2024 20:44:50 -0800 Subject: [PATCH 03/14] Fix Python binding of setUnitType (#1728) Fix Python API setUnitType() was bound to C++ hasUnitType(). --- source/PyMaterialX/PyMaterialXCore/PyDefinition.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/PyMaterialX/PyMaterialXCore/PyDefinition.cpp b/source/PyMaterialX/PyMaterialXCore/PyDefinition.cpp index d4ccdfb13c..4601e57f7f 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyDefinition.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyDefinition.cpp @@ -73,7 +73,7 @@ void bindPyDefinition(py::module& mod) .def_readonly_static("CATEGORY", &mx::Unit::CATEGORY); py::class_(mod, "UnitDef") - .def("setUnitType", &mx::UnitDef::hasUnitType) + .def("setUnitType", &mx::UnitDef::setUnitType) .def("hasUnitType", &mx::UnitDef::hasUnitType) .def("getUnitType", &mx::UnitDef::getUnitType) .def("addUnit", &mx::UnitDef::addUnit) From cb9a99dfeec276d9d44a8409139f4973c837ae3e Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 7 Mar 2024 08:32:05 -0800 Subject: [PATCH 04/14] Add color82 to generalized_schlick_bsdf (#1727) This changelist adds a color82 input to the generalized_schlick_bsdf node in MaterialX, with a full implementation in hardware shading languages (GLSL/MSL/ESSL) and simple fallback behavior in closure-based shading languages (OSL/MDL). The real-time implementation is based on Naty Hoffman's generalization of Adobe Fresnel (https://renderwonk.com/publications/wp-generalization-adobe/gen-adobe.pdf), which is visually consistent with previous versions of generalized_schlick_bsdf when color82 is left at its default setting. --- .../pbrlib/genglsl/lib/mx_microfacet.glsl | 6 ++++ .../genglsl/lib/mx_microfacet_specular.glsl | 31 ++++++++++++++----- .../genglsl/mx_generalized_schlick_bsdf.glsl | 21 +++++++------ .../legacy/mx_generalized_schlick_bsdf.osl | 2 +- .../genosl/mx_generalized_schlick_bsdf.osl | 2 +- libraries/pbrlib/pbrlib_defs.mtlx | 1 + .../pbrlib/bsdf/generalized_schlick.mtlx | 19 ++++++++++++ 7 files changed, 63 insertions(+), 19 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl index d935798f76..e59c3e6b51 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl @@ -6,6 +6,12 @@ float mx_pow5(float x) return mx_square(mx_square(x)) * x; } +float mx_pow6(float x) +{ + float x2 = mx_square(x); + return mx_square(x2) * x2; +} + // Standard Schlick Fresnel float mx_fresnel_schlick(float cosTheta, float F0) { diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index a27f717a24..d34f7e7e1a 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -21,6 +21,7 @@ struct FresnelData // Generalized Schlick Fresnel vec3 F0; + vec3 F82; vec3 F90; float exponent; @@ -36,6 +37,7 @@ FresnelData(int _model = 0, vec3 _ior = vec3(0.0f), vec3 _extinction = vec3(0.0f), vec3 _F0 = vec3(0.0f), + vec3 _F82 = vec3(0.0f), vec3 _F90 = vec3(0.0f), float _exponent = 0.0f, float _tf_thickness = 0.0f, @@ -247,6 +249,17 @@ float mx_fresnel_dielectric(float cosTheta, float ior) return 0.5 * x * x * (1.0 + y * y); } +// https://renderwonk.com/publications/wp-generalization-adobe/gen-adobe.pdf +vec3 mx_fresnel_hoffman_schlick(float cosTheta, vec3 F0, vec3 F82, vec3 F90, float exponent) +{ + const float COS_THETA_MAX = 1.0 / 7.0; + const float COS_THETA_FACTOR = 1.0 / (COS_THETA_MAX * pow(1.0 - COS_THETA_MAX, 6.0)); + + float x = clamp(cosTheta, 0.0, 1.0); + vec3 a = mix(F0, F90, pow(1.0 - COS_THETA_MAX, exponent)) * (vec3(1.0) - F82) * COS_THETA_FACTOR; + return mix(F0, F90, pow(1.0 - x, exponent)) - a * x * mx_pow6(1.0 - x); +} + void mx_fresnel_dielectric_polarized(float cosTheta, float n, out float Rp, out float Rs) { if (cosTheta < 0.0) { @@ -363,7 +376,7 @@ vec3 mx_eval_sensitivity(float opd, vec3 shift) // A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence // https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickness, float tf_ior, - vec3 f0, vec3 f90, float exponent, bool use_schlick) + vec3 F0, vec3 F82, vec3 F90, float exponent, bool use_schlick) { // Convert nm -> m float d = tf_thickness * 1.0e-9; @@ -371,7 +384,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne // Assume vacuum on the outside float eta1 = 1.0; float eta2 = max(tf_ior, eta1); - vec3 eta3 = use_schlick ? mx_f0_to_ior_colored(f0) : ior; + vec3 eta3 = use_schlick ? mx_f0_to_ior_colored(F0) : ior; vec3 kappa3 = use_schlick ? vec3(0.0) : extinction; // Compute the Spectral versions of the Fresnel reflectance and @@ -388,7 +401,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne float cosTheta2 = sqrt(cosThetaTSqr); if (use_schlick) { - vec3 f = mx_fresnel_schlick(cosTheta2, f0, f90, exponent); + vec3 f = mx_fresnel_hoffman_schlick(cosTheta2, F0, F82, F90, exponent); R23p = 0.5 * f; R23s = 0.5 * f; } @@ -484,7 +497,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne FresnelData mx_init_fresnel_data(int model) { - return FresnelData(model, vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), 0.0, 0.0, 0.0, false); + return FresnelData(model, vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), 0.0, 0.0, 0.0, false); } FresnelData mx_init_fresnel_dielectric(float ior) @@ -511,19 +524,21 @@ FresnelData mx_init_fresnel_schlick(vec3 F0) return fd; } -FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F90, float exponent) +FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F82, vec3 F90, float exponent) { FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK); fd.F0 = F0; + fd.F82 = F82; fd.F90 = F90; fd.exponent = exponent; return fd; } -FresnelData mx_init_fresnel_schlick_airy(vec3 F0, vec3 F90, float exponent, float tf_thickness, float tf_ior) +FresnelData mx_init_fresnel_schlick_airy(vec3 F0, vec3 F82, vec3 F90, float exponent, float tf_thickness, float tf_ior) { FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK_AIRY); fd.F0 = F0; + fd.F82 = F82; fd.F90 = F90; fd.exponent = exponent; fd.tf_thickness = tf_thickness; @@ -562,12 +577,12 @@ vec3 mx_compute_fresnel(float cosTheta, FresnelData fd) } else if (fd.model == FRESNEL_MODEL_SCHLICK) { - return mx_fresnel_schlick(cosTheta, fd.F0, fd.F90, fd.exponent); + return mx_fresnel_hoffman_schlick(cosTheta, fd.F0, fd.F82, fd.F90, fd.exponent); } else { return mx_fresnel_airy(cosTheta, fd.ior, fd.extinction, fd.tf_thickness, fd.tf_ior, - fd.F0, fd.F90, fd.exponent, + fd.F0, fd.F82, fd.F90, fd.exponent, fd.model == FRESNEL_MODEL_SCHLICK_AIRY); } } diff --git a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl index e091f4b5ad..f526ee1e0f 100644 --- a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl @@ -1,6 +1,6 @@ #include "lib/mx_microfacet_specular.glsl" -void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color0, vec3 color82, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) { if (weight < M_FLOAT_EPS) { @@ -23,14 +23,15 @@ void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlus FresnelData fd; vec3 safeColor0 = max(color0, 0.0); + vec3 safeColor82 = max(color82, 0.0); vec3 safeColor90 = max(color90, 0.0); if (thinfilm_thickness > 0.0) { - fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); + fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); } else { - fd = mx_init_fresnel_schlick(safeColor0, safeColor90, exponent); + fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent); } vec3 F = mx_compute_fresnel(VdotH, fd); float D = mx_ggx_NDF(Ht, safeAlpha); @@ -45,7 +46,7 @@ void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlus bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV); } -void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, vec3 color82, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) { if (weight < M_FLOAT_EPS) { @@ -57,14 +58,15 @@ void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, FresnelData fd; vec3 safeColor0 = max(color0, 0.0); + vec3 safeColor82 = max(color82, 0.0); vec3 safeColor90 = max(color90, 0.0); if (thinfilm_thickness > 0.0) { - fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor90, exponent, thinfilm_thickness, thinfilm_thickness); + fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_thickness); } else { - fd = mx_init_fresnel_schlick(safeColor0, safeColor90, exponent); + fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent); } vec3 F = mx_compute_fresnel(NdotV, fd); @@ -84,7 +86,7 @@ void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, } } -void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec3 color82, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) { if (weight < M_FLOAT_EPS) { @@ -96,14 +98,15 @@ void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec FresnelData fd; vec3 safeColor0 = max(color0, 0.0); + vec3 safeColor82 = max(color82, 0.0); vec3 safeColor90 = max(color90, 0.0); if (thinfilm_thickness > 0.0) { - fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); + fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); } else { - fd = mx_init_fresnel_schlick(safeColor0, safeColor90, exponent); + fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent); } vec3 F = mx_compute_fresnel(NdotV, fd); diff --git a/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl index 59fc64bfd4..cd022f8295 100644 --- a/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl +++ b/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl @@ -1,6 +1,6 @@ #include "../lib/mx_microfacet_specular.osl" -void mx_generalized_schlick_bsdf(float weight, color color0, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) +void mx_generalized_schlick_bsdf(float weight, color color0, color color82, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) { float avgF0 = dot(color0, color(1.0 / 3.0)); float ior = mx_f0_to_ior(avgF0); diff --git a/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl b/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl index 80431b5af2..53919e8518 100644 --- a/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl +++ b/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl @@ -1,4 +1,4 @@ -void mx_generalized_schlick_bsdf(float weight, color color0, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) +void mx_generalized_schlick_bsdf(float weight, color color0, color color82, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) { if (scatter_mode == "R") { diff --git a/libraries/pbrlib/pbrlib_defs.mtlx b/libraries/pbrlib/pbrlib_defs.mtlx index 47fa249b08..b90cf3772d 100644 --- a/libraries/pbrlib/pbrlib_defs.mtlx +++ b/libraries/pbrlib/pbrlib_defs.mtlx @@ -96,6 +96,7 @@ + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx index a320dcda9a..5f950337f2 100644 --- a/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx +++ b/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx @@ -4,6 +4,7 @@ + @@ -16,6 +17,7 @@ + @@ -28,6 +30,7 @@ + @@ -49,6 +52,7 @@ + @@ -61,6 +65,7 @@ + @@ -73,6 +78,7 @@ + @@ -91,5 +97,18 @@ + + + + + + + + + + + + + From e4dc8a1993a17607b9a7c87029a84c77315ad9c3 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 7 Mar 2024 08:47:07 -0800 Subject: [PATCH 05/14] Improvements to GLSL Fresnel - Simplify argument passing for FresnelData, and fix a missing initializer in MSL. - Minor optimizations to mx_fresnel_dielectric_polarized and mx_fresnel_airy. - Minor formatting improvements in GLSL Fresnel logic. --- .../genglsl/lib/mx_microfacet_specular.glsl | 180 ++++++++---------- 1 file changed, 83 insertions(+), 97 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index d34f7e7e1a..c2811d31cc 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -7,9 +7,6 @@ const int FRESNEL_MODEL_SCHLICK = 2; const int FRESNEL_MODEL_AIRY = 3; const int FRESNEL_MODEL_SCHLICK_AIRY = 4; -// XYZ to CIE 1931 RGB color space (using neutral E illuminant) -const mat3 XYZ_TO_RGB = mat3(2.3706743, -0.5138850, 0.0052982, -0.9000405, 1.4253036, -0.0146949, -0.4706338, 0.0885814, 1.0093968); - // Parameters for Fresnel calculations. struct FresnelData { @@ -32,24 +29,29 @@ struct FresnelData // Refraction bool refraction; -#ifdef __METAL__ -FresnelData(int _model = 0, - vec3 _ior = vec3(0.0f), - vec3 _extinction = vec3(0.0f), - vec3 _F0 = vec3(0.0f), - vec3 _F82 = vec3(0.0f), - vec3 _F90 = vec3(0.0f), - float _exponent = 0.0f, +#ifdef __METAL__ +FresnelData(int _model = 0, + vec3 _ior = vec3(0.0f), + vec3 _extinction = vec3(0.0f), + vec3 _F0 = vec3(0.0f), + vec3 _F82 = vec3(0.0f), + vec3 _F90 = vec3(0.0f), + float _exponent = 0.0f, float _tf_thickness = 0.0f, - float _tf_ior = 0.0f, - bool _refraction = false) : - model(_model), - ior(_ior), - extinction(_extinction), - F0(_F0), F90(_F90), exponent(_exponent), - tf_thickness(_tf_thickness), - tf_ior(_tf_ior), - refraction(_refraction) {} + float _tf_ior = 0.0f, + bool _refraction = false) : + model(_model), + ior(_ior), + extinction(_extinction), + F0(_F0), + F82(_F82), + F90(_F90), + exponent(_exponent), + tf_thickness(_tf_thickness), + tf_ior(_tf_ior), + refraction(_refraction) +{ +} #endif }; @@ -224,22 +226,38 @@ float mx_f0_to_ior(float F0) return (1.0 + sqrtF0) / (1.0 - sqrtF0); } -vec3 mx_f0_to_ior_colored(vec3 F0) +vec3 mx_f0_to_ior(vec3 F0) { vec3 sqrtF0 = sqrt(clamp(F0, 0.01, 0.99)); return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0); } +// https://renderwonk.com/publications/wp-generalization-adobe/gen-adobe.pdf +vec3 mx_fresnel_hoffman_schlick(float cosTheta, FresnelData fd) +{ + const float COS_THETA_MAX = 1.0 / 7.0; + const float COS_THETA_FACTOR = 1.0 / (COS_THETA_MAX * pow(1.0 - COS_THETA_MAX, 6.0)); + + float x = clamp(cosTheta, 0.0, 1.0); + vec3 a = mix(fd.F0, fd.F90, pow(1.0 - COS_THETA_MAX, fd.exponent)) * (vec3(1.0) - fd.F82) * COS_THETA_FACTOR; + return mix(fd.F0, fd.F90, pow(1.0 - x, fd.exponent)) - a * x * mx_pow6(1.0 - x); +} + // https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ float mx_fresnel_dielectric(float cosTheta, float ior) { if (cosTheta < 0.0) + { return 1.0; + } + + float g = ior*ior + cosTheta*cosTheta - 1.0; - float g = ior*ior + cosTheta*cosTheta - 1.0; // Check for total internal reflection if (g < 0.0) + { return 1.0; + } g = sqrt(g); float gmc = g - cosTheta; @@ -249,20 +267,10 @@ float mx_fresnel_dielectric(float cosTheta, float ior) return 0.5 * x * x * (1.0 + y * y); } -// https://renderwonk.com/publications/wp-generalization-adobe/gen-adobe.pdf -vec3 mx_fresnel_hoffman_schlick(float cosTheta, vec3 F0, vec3 F82, vec3 F90, float exponent) -{ - const float COS_THETA_MAX = 1.0 / 7.0; - const float COS_THETA_FACTOR = 1.0 / (COS_THETA_MAX * pow(1.0 - COS_THETA_MAX, 6.0)); - - float x = clamp(cosTheta, 0.0, 1.0); - vec3 a = mix(F0, F90, pow(1.0 - COS_THETA_MAX, exponent)) * (vec3(1.0) - F82) * COS_THETA_FACTOR; - return mix(F0, F90, pow(1.0 - x, exponent)) - a * x * mx_pow6(1.0 - x); -} - -void mx_fresnel_dielectric_polarized(float cosTheta, float n, out float Rp, out float Rs) +void mx_fresnel_dielectric_polarized(float cosTheta, float ior, out float Rp, out float Rs) { - if (cosTheta < 0.0) { + if (cosTheta < 0.0) + { Rp = 1.0; Rs = 1.0; return; @@ -270,30 +278,20 @@ void mx_fresnel_dielectric_polarized(float cosTheta, float n, out float Rp, out float cosTheta2 = cosTheta * cosTheta; float sinTheta2 = 1.0 - cosTheta2; - float n2 = n * n; - float t0 = n2 - sinTheta2; - float a2plusb2 = sqrt(t0 * t0); - float t1 = a2plusb2 + cosTheta2; - float a = sqrt(max(0.5 * (a2plusb2 + t0), 0.0)); - float t2 = 2.0 * a * cosTheta; + float t0 = max(ior * ior - sinTheta2, 0.0); + float t1 = t0 + cosTheta2; + float t2 = 2.0 * sqrt(t0) * cosTheta; Rs = (t1 - t2) / (t1 + t2); - float t3 = cosTheta2 * a2plusb2 + sinTheta2 * sinTheta2; + float t3 = cosTheta2 * t0 + sinTheta2 * sinTheta2; float t4 = t2 * sinTheta2; Rp = Rs * (t3 - t4) / (t3 + t4); } -void mx_fresnel_dielectric_polarized(float cosTheta, float eta1, float eta2, out float Rp, out float Rs) -{ - float n = eta2 / eta1; - mx_fresnel_dielectric_polarized(cosTheta, n, Rp, Rs); -} - void mx_fresnel_conductor_polarized(float cosTheta, vec3 n, vec3 k, out vec3 Rp, out vec3 Rs) { - cosTheta = clamp(cosTheta, 0.0, 1.0); - float cosTheta2 = cosTheta * cosTheta; + float cosTheta2 = mx_square(clamp(cosTheta, 0.0, 1.0)); float sinTheta2 = 1.0 - cosTheta2; vec3 n2 = n * n; vec3 k2 = k * k; @@ -310,13 +308,6 @@ void mx_fresnel_conductor_polarized(float cosTheta, vec3 n, vec3 k, out vec3 Rp, Rp = Rs * (t3 - t4) / (t3 + t4); } -void mx_fresnel_conductor_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 Rp, out vec3 Rs) -{ - vec3 n = eta2 / eta1; - vec3 k = kappa2 / eta1; - mx_fresnel_conductor_polarized(cosTheta, n, k, Rp, Rs); -} - vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k) { vec3 Rp, Rs; @@ -327,11 +318,14 @@ vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k) // Phase shift due to a dielectric material void mx_fresnel_dielectric_phase_polarized(float cosTheta, float eta1, float eta2, out float phiP, out float phiS) { - float cosB = cos(atan(eta2 / eta1)); // Brewster's angle - if (eta2 > eta1) { + float cosB = cos(atan(eta2 / eta1)); // Brewster's angle + if (eta2 > eta1) + { phiP = cosTheta < cosB ? M_PI : 0.0f; phiS = 0.0f; - } else { + } + else + { phiP = cosTheta < cosB ? 0.0f : M_PI; phiS = M_PI; } @@ -340,7 +334,8 @@ void mx_fresnel_dielectric_phase_polarized(float cosTheta, float eta1, float eta // Phase shift due to a conducting material void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS) { - if (dot(kappa2, kappa2) == 0.0 && eta2.x == eta2.y && eta2.y == eta2.z) { + if (dot(kappa2, kappa2) == 0.0 && eta2.x == eta2.y && eta2.y == eta2.z) + { // Use dielectric formula to increase performance float phiPx, phiSx; mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2.x, phiPx, phiSx); @@ -375,17 +370,22 @@ vec3 mx_eval_sensitivity(float opd, vec3 shift) // A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence // https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html -vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickness, float tf_ior, - vec3 F0, vec3 F82, vec3 F90, float exponent, bool use_schlick) +vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) { + // XYZ to CIE 1931 RGB color space (using neutral E illuminant) + const mat3 XYZ_TO_RGB = mat3(2.3706743, -0.5138850, 0.0052982, -0.9000405, 1.4253036, -0.0146949, -0.4706338, 0.0885814, 1.0093968); + + // Select between Schlick and physical models. + bool useSchlickAiry = fd.model == FRESNEL_MODEL_SCHLICK_AIRY; + // Convert nm -> m - float d = tf_thickness * 1.0e-9; + float d = fd.tf_thickness * 1.0e-9; // Assume vacuum on the outside float eta1 = 1.0; - float eta2 = max(tf_ior, eta1); - vec3 eta3 = use_schlick ? mx_f0_to_ior_colored(F0) : ior; - vec3 kappa3 = use_schlick ? vec3(0.0) : extinction; + float eta2 = max(fd.tf_ior, eta1); + vec3 eta3 = useSchlickAiry ? mx_f0_to_ior(fd.F0) : fd.ior; + vec3 kappa3 = useSchlickAiry ? vec3(0.0) : fd.extinction; // Compute the Spectral versions of the Fresnel reflectance and // transmitance for each interface. @@ -393,28 +393,28 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne vec3 R23p, R23s; // Reflected and transmitted parts in the thin film - mx_fresnel_dielectric_polarized(cosTheta, eta1, eta2, R12p, R12s); + mx_fresnel_dielectric_polarized(cosTheta, eta2 / eta1, R12p, R12s); // Reflected part by the base float scale = eta1 / eta2; float cosThetaTSqr = 1.0 - (1.0-cosTheta*cosTheta) * scale*scale; float cosTheta2 = sqrt(cosThetaTSqr); - if (use_schlick) + if (useSchlickAiry) { - vec3 f = mx_fresnel_hoffman_schlick(cosTheta2, F0, F82, F90, exponent); + vec3 f = mx_fresnel_hoffman_schlick(cosTheta2, fd); R23p = 0.5 * f; R23s = 0.5 * f; } else { - mx_fresnel_conductor_polarized(cosTheta2, eta2, eta3, kappa3, R23p, R23s); + mx_fresnel_conductor_polarized(cosTheta2, eta3 / eta2, kappa3 / eta2, R23p, R23s); } // Check for total internal reflection if (cosThetaTSqr <= 0.0f) { - R12s = 1.0; R12p = 1.0; + R12s = 1.0; } // Compute the transmission coefficients @@ -429,12 +429,11 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne // Evaluate the phase shift mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2, phi21p, phi21s); - if (use_schlick) + if (useSchlickAiry) { - phi23p = vec3( - (eta3[0] < eta2) ? M_PI : 0.0, - (eta3[1] < eta2) ? M_PI : 0.0, - (eta3[2] < eta2) ? M_PI : 0.0); + phi23p = vec3((eta3[0] < eta2) ? M_PI : 0.0, + (eta3[1] < eta2) ? M_PI : 0.0, + (eta3[2] < eta2) ? M_PI : 0.0); phi23s = phi23p; } else @@ -454,16 +453,14 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne // Iridescence term using spectral antialiasing for Parallel polarization - vec3 S0 = vec3(1.0); - // Reflectance term for m=0 (DC term amplitude) vec3 Rs = (T121p*T121p*R23p) / (vec3(1.0) - R12p*R23p); C0 = R12p + Rs; - I += C0 * S0; + I += C0; // Reflectance term for m>0 (pairs of diracs) Cm = Rs - T121p; - for (int m=1; m<=2; ++m) + for (int m=1; m<=2; m++) { Cm *= r123p; Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23p+vec3(phi21p))); @@ -475,11 +472,11 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne // Reflectance term for m=0 (DC term amplitude) vec3 Rp = (T121s*T121s*R23s) / (vec3(1.0) - R12s*R23s); C0 = R12s + Rp; - I += C0 * S0; + I += C0; // Reflectance term for m>0 (pairs of diracs) - Cm = Rp - T121s ; - for (int m=1; m<=2; ++m) + Cm = Rp - T121s; + for (int m=1; m<=2; m++) { Cm *= r123s; Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23s+vec3(phi21s))); @@ -515,15 +512,6 @@ FresnelData mx_init_fresnel_conductor(vec3 ior, vec3 extinction) return fd; } -FresnelData mx_init_fresnel_schlick(vec3 F0) -{ - FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK); - fd.F0 = F0; - fd.F90 = vec3(1.0); - fd.exponent = 5.0f; - return fd; -} - FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F82, vec3 F90, float exponent) { FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK); @@ -577,13 +565,11 @@ vec3 mx_compute_fresnel(float cosTheta, FresnelData fd) } else if (fd.model == FRESNEL_MODEL_SCHLICK) { - return mx_fresnel_hoffman_schlick(cosTheta, fd.F0, fd.F82, fd.F90, fd.exponent); + return mx_fresnel_hoffman_schlick(cosTheta, fd); } else { - return mx_fresnel_airy(cosTheta, fd.ior, fd.extinction, fd.tf_thickness, fd.tf_ior, - fd.F0, fd.F82, fd.F90, fd.exponent, - fd.model == FRESNEL_MODEL_SCHLICK_AIRY); + return mx_fresnel_airy(cosTheta, fd); } } From fc43d3e71952c0ccba0fa3721f7b948f9c1883f0 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 8 Mar 2024 16:08:42 -0800 Subject: [PATCH 06/14] Optimizations to GLSL FresnelData - Simplify mode selection and initialization for the FresnelData struct in GLSL. - Remove an unneeded dynamic branch in mx_fresnel_dielectric_polarized. - Remove unused temporaries in mx_fresnel_airy. --- .../genglsl/lib/mx_microfacet_specular.glsl | 144 ++++++------------ .../pbrlib/genglsl/mx_conductor_bsdf.glsl | 14 +- .../pbrlib/genglsl/mx_dielectric_bsdf.glsl | 30 +--- .../genglsl/mx_generalized_schlick_bsdf.glsl | 30 +--- 4 files changed, 55 insertions(+), 163 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index c2811d31cc..53b55e259a 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -1,16 +1,15 @@ #include "mx_microfacet.glsl" -// Fresnel model options. const int FRESNEL_MODEL_DIELECTRIC = 0; const int FRESNEL_MODEL_CONDUCTOR = 1; const int FRESNEL_MODEL_SCHLICK = 2; -const int FRESNEL_MODEL_AIRY = 3; -const int FRESNEL_MODEL_SCHLICK_AIRY = 4; -// Parameters for Fresnel calculations. +// Parameters for Fresnel calculations struct FresnelData { + // Fresnel model int model; + bool airy; // Physical Fresnel vec3 ior; @@ -28,32 +27,6 @@ struct FresnelData // Refraction bool refraction; - -#ifdef __METAL__ -FresnelData(int _model = 0, - vec3 _ior = vec3(0.0f), - vec3 _extinction = vec3(0.0f), - vec3 _F0 = vec3(0.0f), - vec3 _F82 = vec3(0.0f), - vec3 _F90 = vec3(0.0f), - float _exponent = 0.0f, - float _tf_thickness = 0.0f, - float _tf_ior = 0.0f, - bool _refraction = false) : - model(_model), - ior(_ior), - extinction(_extinction), - F0(_F0), - F82(_F82), - F90(_F90), - exponent(_exponent), - tf_thickness(_tf_thickness), - tf_ior(_tf_ior), - refraction(_refraction) -{ -} -#endif - }; // https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf @@ -225,7 +198,6 @@ float mx_f0_to_ior(float F0) float sqrtF0 = sqrt(clamp(F0, 0.01, 0.99)); return (1.0 + sqrtF0) / (1.0 - sqrtF0); } - vec3 mx_f0_to_ior(vec3 F0) { vec3 sqrtF0 = sqrt(clamp(F0, 0.01, 0.99)); @@ -269,14 +241,7 @@ float mx_fresnel_dielectric(float cosTheta, float ior) void mx_fresnel_dielectric_polarized(float cosTheta, float ior, out float Rp, out float Rs) { - if (cosTheta < 0.0) - { - Rp = 1.0; - Rs = 1.0; - return; - } - - float cosTheta2 = cosTheta * cosTheta; + float cosTheta2 = mx_square(clamp(cosTheta, 0.0, 1.0)); float sinTheta2 = 1.0 - cosTheta2; float t0 = max(ior * ior - sinTheta2, 0.0); @@ -375,17 +340,14 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) // XYZ to CIE 1931 RGB color space (using neutral E illuminant) const mat3 XYZ_TO_RGB = mat3(2.3706743, -0.5138850, 0.0052982, -0.9000405, 1.4253036, -0.0146949, -0.4706338, 0.0885814, 1.0093968); - // Select between Schlick and physical models. - bool useSchlickAiry = fd.model == FRESNEL_MODEL_SCHLICK_AIRY; - // Convert nm -> m float d = fd.tf_thickness * 1.0e-9; // Assume vacuum on the outside float eta1 = 1.0; float eta2 = max(fd.tf_ior, eta1); - vec3 eta3 = useSchlickAiry ? mx_f0_to_ior(fd.F0) : fd.ior; - vec3 kappa3 = useSchlickAiry ? vec3(0.0) : fd.extinction; + vec3 eta3 = (fd.model == FRESNEL_MODEL_SCHLICK) ? mx_f0_to_ior(fd.F0) : fd.ior; + vec3 kappa3 = (fd.model == FRESNEL_MODEL_SCHLICK) ? vec3(0.0) : fd.extinction; // Compute the Spectral versions of the Fresnel reflectance and // transmitance for each interface. @@ -399,7 +361,7 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) float scale = eta1 / eta2; float cosThetaTSqr = 1.0 - (1.0-cosTheta*cosTheta) * scale*scale; float cosTheta2 = sqrt(cosThetaTSqr); - if (useSchlickAiry) + if (fd.model == FRESNEL_MODEL_SCHLICK) { vec3 f = mx_fresnel_hoffman_schlick(cosTheta2, fd); R23p = 0.5 * f; @@ -429,7 +391,7 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) // Evaluate the phase shift mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2, phi21p, phi21s); - if (useSchlickAiry) + if (fd.model == FRESNEL_MODEL_SCHLICK) { phi23p = vec3((eta3[0] < eta2) ? M_PI : 0.0, (eta3[1] < eta2) ? M_PI : 0.0, @@ -449,14 +411,13 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) // Evaluate iridescence term vec3 I = vec3(0.0); - vec3 C0, Cm, Sm; + vec3 Cm, Sm; // Iridescence term using spectral antialiasing for Parallel polarization // Reflectance term for m=0 (DC term amplitude) vec3 Rs = (T121p*T121p*R23p) / (vec3(1.0) - R12p*R23p); - C0 = R12p + Rs; - I += C0; + I += R12p + Rs; // Reflectance term for m>0 (pairs of diracs) Cm = Rs - T121p; @@ -471,8 +432,7 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) // Reflectance term for m=0 (DC term amplitude) vec3 Rp = (T121s*T121s*R23s) / (vec3(1.0) - R12s*R23s); - C0 = R12s + Rp; - I += C0; + I += R12s + Rp; // Reflectance term for m>0 (pairs of diracs) Cm = Rp - T121s; @@ -492,70 +452,64 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) return I; } -FresnelData mx_init_fresnel_data(int model) +FresnelData mx_init_fresnel_dielectric(float ior, float tf_thickness, float tf_ior) { - return FresnelData(model, vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), 0.0, 0.0, 0.0, false); -} - -FresnelData mx_init_fresnel_dielectric(float ior) -{ - FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_DIELECTRIC); + FresnelData fd; + fd.model = FRESNEL_MODEL_DIELECTRIC; + fd.airy = tf_thickness > 0.0; fd.ior = vec3(ior); + fd.extinction = vec3(0.0); + fd.F0 = vec3(0.0); + fd.F82 = vec3(0.0); + fd.F90 = vec3(0.0); + fd.exponent = 0.0; + fd.tf_thickness = tf_thickness; + fd.tf_ior = tf_ior; + fd.refraction = false; return fd; } -FresnelData mx_init_fresnel_conductor(vec3 ior, vec3 extinction) +FresnelData mx_init_fresnel_conductor(vec3 ior, vec3 extinction, float tf_thickness, float tf_ior) { - FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_CONDUCTOR); + FresnelData fd; + fd.model = FRESNEL_MODEL_CONDUCTOR; + fd.airy = tf_thickness > 0.0; fd.ior = ior; fd.extinction = extinction; + fd.F0 = vec3(0.0); + fd.F82 = vec3(0.0); + fd.F90 = vec3(0.0); + fd.exponent = 0.0; + fd.tf_thickness = tf_thickness; + fd.tf_ior = tf_ior; + fd.refraction = false; return fd; } -FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F82, vec3 F90, float exponent) -{ - FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK); - fd.F0 = F0; - fd.F82 = F82; - fd.F90 = F90; - fd.exponent = exponent; - return fd; -} - -FresnelData mx_init_fresnel_schlick_airy(vec3 F0, vec3 F82, vec3 F90, float exponent, float tf_thickness, float tf_ior) +FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F82, vec3 F90, float exponent, float tf_thickness, float tf_ior) { - FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK_AIRY); + FresnelData fd; + fd.model = FRESNEL_MODEL_SCHLICK; + fd.airy = tf_thickness > 0.0; + fd.ior = vec3(0.0); + fd.extinction = vec3(0.0); fd.F0 = F0; fd.F82 = F82; fd.F90 = F90; fd.exponent = exponent; fd.tf_thickness = tf_thickness; fd.tf_ior = tf_ior; - return fd; -} - -FresnelData mx_init_fresnel_dielectric_airy(float ior, float tf_thickness, float tf_ior) -{ - FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_AIRY); - fd.ior = vec3(ior); - fd.tf_thickness = tf_thickness; - fd.tf_ior = tf_ior; - return fd; -} - -FresnelData mx_init_fresnel_conductor_airy(vec3 ior, vec3 extinction, float tf_thickness, float tf_ior) -{ - FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_AIRY); - fd.ior = ior; - fd.extinction = extinction; - fd.tf_thickness = tf_thickness; - fd.tf_ior = tf_ior; + fd.refraction = false; return fd; } vec3 mx_compute_fresnel(float cosTheta, FresnelData fd) { - if (fd.model == FRESNEL_MODEL_DIELECTRIC) + if (fd.airy) + { + return mx_fresnel_airy(cosTheta, fd); + } + else if (fd.model == FRESNEL_MODEL_DIELECTRIC) { return vec3(mx_fresnel_dielectric(cosTheta, fd.ior.x)); } @@ -563,13 +517,9 @@ vec3 mx_compute_fresnel(float cosTheta, FresnelData fd) { return mx_fresnel_conductor(cosTheta, fd.ior, fd.extinction); } - else if (fd.model == FRESNEL_MODEL_SCHLICK) - { - return mx_fresnel_hoffman_schlick(cosTheta, fd); - } else { - return mx_fresnel_airy(cosTheta, fd); + return mx_fresnel_hoffman_schlick(cosTheta, fd); } } diff --git a/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl b/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl index 04bbe42dbb..6b25fd4cbc 100644 --- a/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl @@ -23,12 +23,7 @@ void mx_conductor_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float float avgAlpha = mx_average_alpha(safeAlpha); vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); - FresnelData fd; - if (thinfilm_thickness > 0.0) - fd = mx_init_fresnel_conductor_airy(ior_n, ior_k, thinfilm_thickness, thinfilm_ior); - else - fd = mx_init_fresnel_conductor(ior_n, ior_k); - + FresnelData fd = mx_init_fresnel_conductor(ior_n, ior_k, thinfilm_thickness, thinfilm_ior); vec3 F = mx_compute_fresnel(VdotH, fd); float D = mx_ggx_NDF(Ht, safeAlpha); float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); @@ -52,12 +47,7 @@ void mx_conductor_bsdf_indirect(vec3 V, float weight, vec3 ior_n, vec3 ior_k, ve float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - FresnelData fd; - if (thinfilm_thickness > 0.0) - fd = mx_init_fresnel_conductor_airy(ior_n, ior_k, thinfilm_thickness, thinfilm_ior); - else - fd = mx_init_fresnel_conductor(ior_n, ior_k); - + FresnelData fd = mx_init_fresnel_conductor(ior_n, ior_k, thinfilm_thickness, thinfilm_ior); vec3 F = mx_compute_fresnel(NdotV, fd); vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); diff --git a/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl b/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl index 620225335d..0f362ffd79 100644 --- a/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl @@ -21,16 +21,8 @@ void mx_dielectric_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, floa float avgAlpha = mx_average_alpha(safeAlpha); vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); - FresnelData fd; vec3 safeTint = max(tint, 0.0); - if (thinfilm_thickness > 0.0) - { - fd = mx_init_fresnel_dielectric_airy(ior, thinfilm_thickness, thinfilm_ior); - } - else - { - fd = mx_init_fresnel_dielectric(ior); - } + FresnelData fd = mx_init_fresnel_dielectric(ior, thinfilm_thickness, thinfilm_ior); vec3 F = mx_compute_fresnel(VdotH, fd); float D = mx_ggx_NDF(Ht, safeAlpha); float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); @@ -54,16 +46,8 @@ void mx_dielectric_bsdf_transmission(vec3 V, float weight, vec3 tint, float ior, N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - FresnelData fd; vec3 safeTint = max(tint, 0.0); - if (thinfilm_thickness > 0.0) - { - fd = mx_init_fresnel_dielectric_airy(ior, thinfilm_thickness, thinfilm_ior); - } - else - { - fd = mx_init_fresnel_dielectric(ior); - } + FresnelData fd = mx_init_fresnel_dielectric(ior, thinfilm_thickness, thinfilm_ior); vec3 F = mx_compute_fresnel(NdotV, fd); vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); @@ -91,16 +75,8 @@ void mx_dielectric_bsdf_indirect(vec3 V, float weight, vec3 tint, float ior, vec float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - FresnelData fd; vec3 safeTint = max(tint, 0.0); - if (thinfilm_thickness > 0.0) - { - fd = mx_init_fresnel_dielectric_airy(ior, thinfilm_thickness, thinfilm_ior); - } - else - { - fd = mx_init_fresnel_dielectric(ior); - } + FresnelData fd = mx_init_fresnel_dielectric(ior, thinfilm_thickness, thinfilm_ior); vec3 F = mx_compute_fresnel(NdotV, fd); vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); diff --git a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl index f526ee1e0f..764412b90d 100644 --- a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl @@ -21,18 +21,10 @@ void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlus float avgAlpha = mx_average_alpha(safeAlpha); vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); - FresnelData fd; vec3 safeColor0 = max(color0, 0.0); vec3 safeColor82 = max(color82, 0.0); vec3 safeColor90 = max(color90, 0.0); - if (thinfilm_thickness > 0.0) - { - fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); - } - else - { - fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent); - } + FresnelData fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); vec3 F = mx_compute_fresnel(VdotH, fd); float D = mx_ggx_NDF(Ht, safeAlpha); float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); @@ -56,18 +48,10 @@ void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - FresnelData fd; vec3 safeColor0 = max(color0, 0.0); vec3 safeColor82 = max(color82, 0.0); vec3 safeColor90 = max(color90, 0.0); - if (thinfilm_thickness > 0.0) - { - fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_thickness); - } - else - { - fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent); - } + FresnelData fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); vec3 F = mx_compute_fresnel(NdotV, fd); vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); @@ -96,18 +80,10 @@ void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - FresnelData fd; vec3 safeColor0 = max(color0, 0.0); vec3 safeColor82 = max(color82, 0.0); vec3 safeColor90 = max(color90, 0.0); - if (thinfilm_thickness > 0.0) - { - fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); - } - else - { - fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent); - } + FresnelData fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); vec3 F = mx_compute_fresnel(NdotV, fd); vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); From b9c126c0614f389b691ac4ffd1488ec4a48913e8 Mon Sep 17 00:00:00 2001 From: ld-kerley <154285602+ld-kerley@users.noreply.github.com> Date: Mon, 11 Mar 2024 12:07:26 -0700 Subject: [PATCH 07/14] Build API docs using a custom command with dependencies (#1731) I was bumping up against the documentation not building without using a custom target, and then stumbled across this super old issue (#9), and while reading it realized I think there's a way to have the best of both world. Transitioning to using add_custom_command instead of add_custom_target avoids the "always build" issue, and adding DEPENDS arguments allows for the correct dependency tracking for the docs building, so it will only get triggered if necessary. Also for what it's worth it didn't seem that the docs take that long to build anyway. Anyway, just putting this up here for discussion, I don't know how many people are building the docs locally, but having it part of the regular cmake build without the need for an additional target seemed like a nice improvement. I also changed the find_package(Doxygen) to add the REQUIRED keyword that way the cmake configure will fail if doxygen isn't present. I think this is ok as the entire documents/CMakeLists.txt is guarded behind the MATERIALX_BUILD_DOCS option. --- documents/CMakeLists.txt | 71 +++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/documents/CMakeLists.txt b/documents/CMakeLists.txt index 56d2289b99..091c7fbae6 100644 --- a/documents/CMakeLists.txt +++ b/documents/CMakeLists.txt @@ -1,34 +1,45 @@ set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(DOXYGEN_HTML_OUTPUT_DIR ${DOXYGEN_OUTPUT_DIR}/html) -set(DOXYGEN_INPUT_LIST ${CMAKE_SOURCE_DIR}/documents/DeveloperGuide/MainPage.md - ${CMAKE_SOURCE_DIR}/source/MaterialXCore - ${CMAKE_SOURCE_DIR}/source/MaterialXFormat - ${CMAKE_SOURCE_DIR}/source/MaterialXGenShader - ${CMAKE_SOURCE_DIR}/source/MaterialXGenShader/Nodes - ${CMAKE_SOURCE_DIR}/source/MaterialXGenGlsl - ${CMAKE_SOURCE_DIR}/source/MaterialXGenGlsl/Nodes - ${CMAKE_SOURCE_DIR}/source/MaterialXGenOsl - ${CMAKE_SOURCE_DIR}/source/MaterialXGenMdl - ${CMAKE_SOURCE_DIR}/source/MaterialXRender - ${CMAKE_SOURCE_DIR}/source/MaterialXRenderHw - ${CMAKE_SOURCE_DIR}/source/MaterialXRenderGlsl - ${CMAKE_SOURCE_DIR}/source/MaterialXRenderOsl - ) +set(DOXYGEN_INPUT_LIST ${CMAKE_CURRENT_BINARY_DIR}/MainPage.md) + +set(MATERIALX_DOXYGEN_SOURCE_FOLDERS + ${CMAKE_SOURCE_DIR}/source/MaterialXCore + ${CMAKE_SOURCE_DIR}/source/MaterialXFormat + ${CMAKE_SOURCE_DIR}/source/MaterialXGenShader + ${CMAKE_SOURCE_DIR}/source/MaterialXGenShader/Nodes + ${CMAKE_SOURCE_DIR}/source/MaterialXGenGlsl + ${CMAKE_SOURCE_DIR}/source/MaterialXGenGlsl/Nodes + ${CMAKE_SOURCE_DIR}/source/MaterialXGenOsl + ${CMAKE_SOURCE_DIR}/source/MaterialXGenMdl + ${CMAKE_SOURCE_DIR}/source/MaterialXRender + ${CMAKE_SOURCE_DIR}/source/MaterialXRenderHw + ${CMAKE_SOURCE_DIR}/source/MaterialXRenderGlsl + ${CMAKE_SOURCE_DIR}/source/MaterialXRenderOsl) + +find_package(Doxygen REQUIRED) + +foreach(FOLDER ${MATERIALX_DOXYGEN_SOURCE_FOLDERS}) + file(GLOB FOLDER_HEADERS ${FOLDER}/*.h) + list(APPEND DOXYGEN_INPUT_LIST ${FOLDER_HEADERS}) +endforeach() + string (REPLACE ";" " " DOXYGEN_INPUT_STR "${DOXYGEN_INPUT_LIST}") -find_package(Doxygen) - -if(DOXYGEN_FOUND) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - add_custom_target(MaterialXDocs ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating HTML documentation: ${DOXYGEN_HTML_OUTPUT_DIR}/index.html") - add_custom_command(TARGET MaterialXDocs PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/documents/DoxygenAwesome ${CMAKE_CURRENT_BINARY_DIR}) - add_custom_command(TARGET MaterialXDocs PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/documents/Images ${CMAKE_CURRENT_BINARY_DIR}) - install(DIRECTORY ${DOXYGEN_HTML_OUTPUT_DIR} - DESTINATION "documents" MESSAGE_NEVER) -endif(DOXYGEN_FOUND) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/MainPage.md + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/DeveloperGuide/MainPage.md ${CMAKE_CURRENT_BINARY_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/DeveloperGuide/MainPage.md) + +add_custom_command(OUTPUT ${DOXYGEN_HTML_OUTPUT_DIR}/index.html + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenAwesome ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/Images ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${DOXYGEN_INPUT_LIST} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + COMMENT "Generating HTML documentation: ${DOXYGEN_HTML_OUTPUT_DIR}/index.html") +add_custom_target(MaterialXDocs ALL DEPENDS ${DOXYGEN_HTML_OUTPUT_DIR}/index.html) + +install(DIRECTORY ${DOXYGEN_HTML_OUTPUT_DIR} + DESTINATION "documents" MESSAGE_NEVER) From a09b9a49f700f35215a0e1a33866f5b7b872b2dd Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 11 Mar 2024 12:20:18 -0700 Subject: [PATCH 08/14] Additional improvements to GLSL Fresnel - Align mx_fresnel_dielectric with the Lagarde reference implementation. - Align mx_fresnel_airy with the Belcour reference implementation. - Merge mx_fresnel_dielectric_phase_polarized into mx_fresnel_airy and remove unused paths. - Remove an unused code path in mx_fresnel_conductor_phase_polarized. --- .../genglsl/lib/mx_microfacet_specular.glsl | 147 ++++++------------ 1 file changed, 50 insertions(+), 97 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index 53b55e259a..904c9978ec 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -218,28 +218,21 @@ vec3 mx_fresnel_hoffman_schlick(float cosTheta, FresnelData fd) // https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ float mx_fresnel_dielectric(float cosTheta, float ior) { - if (cosTheta < 0.0) + float c = cosTheta; + float g2 = ior*ior + c*c - 1.0; + if (g2 < 0.0) { + // Total internal reflection return 1.0; } - float g = ior*ior + cosTheta*cosTheta - 1.0; - - // Check for total internal reflection - if (g < 0.0) - { - return 1.0; - } - - g = sqrt(g); - float gmc = g - cosTheta; - float gpc = g + cosTheta; - float x = gmc / gpc; - float y = (gpc * cosTheta - 1.0) / (gmc * cosTheta + 1.0); - return 0.5 * x * x * (1.0 + y * y); + float g = sqrt(g2); + return 0.5 * mx_square((g - c) / (g + c)) * + (1.0 + mx_square(((g + c) * c - 1.0) / ((g - c) * c + 1.0))); } -void mx_fresnel_dielectric_polarized(float cosTheta, float ior, out float Rp, out float Rs) +// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ +vec2 mx_fresnel_dielectric_polarized(float cosTheta, float ior) { float cosTheta2 = mx_square(clamp(cosTheta, 0.0, 1.0)); float sinTheta2 = 1.0 - cosTheta2; @@ -247,13 +240,16 @@ void mx_fresnel_dielectric_polarized(float cosTheta, float ior, out float Rp, ou float t0 = max(ior * ior - sinTheta2, 0.0); float t1 = t0 + cosTheta2; float t2 = 2.0 * sqrt(t0) * cosTheta; - Rs = (t1 - t2) / (t1 + t2); + float Rs = (t1 - t2) / (t1 + t2); float t3 = cosTheta2 * t0 + sinTheta2 * sinTheta2; float t4 = t2 * sinTheta2; - Rp = Rs * (t3 - t4) / (t3 + t4); + float Rp = Rs * (t3 - t4) / (t3 + t4); + + return vec2(Rp, Rs); } +// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ void mx_fresnel_conductor_polarized(float cosTheta, vec3 n, vec3 k, out vec3 Rp, out vec3 Rs) { float cosTheta2 = mx_square(clamp(cosTheta, 0.0, 1.0)); @@ -280,34 +276,9 @@ vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k) return 0.5 * (Rp + Rs); } -// Phase shift due to a dielectric material -void mx_fresnel_dielectric_phase_polarized(float cosTheta, float eta1, float eta2, out float phiP, out float phiS) -{ - float cosB = cos(atan(eta2 / eta1)); // Brewster's angle - if (eta2 > eta1) - { - phiP = cosTheta < cosB ? M_PI : 0.0f; - phiS = 0.0f; - } - else - { - phiP = cosTheta < cosB ? 0.0f : M_PI; - phiS = M_PI; - } -} - -// Phase shift due to a conducting material +// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS) { - if (dot(kappa2, kappa2) == 0.0 && eta2.x == eta2.y && eta2.y == eta2.z) - { - // Use dielectric formula to increase performance - float phiPx, phiSx; - mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2.x, phiPx, phiSx); - phiP = vec3(phiPx, phiPx, phiPx); - phiS = vec3(phiSx, phiSx, phiSx); - return; - } vec3 k2 = kappa2 / eta2; vec3 sinThetaSqr = vec3(1.0) - cosTheta * cosTheta; vec3 A = eta2*eta2*(vec3(1.0)-k2*k2) - eta1*eta1*sinThetaSqr; @@ -320,7 +291,7 @@ void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, mx_square(eta2*eta2*(vec3(1.0)+k2*k2)*cosTheta) - eta1*eta1*(U*U+V*V)); } -// Evaluation XYZ sensitivity curves in Fourier space +// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html vec3 mx_eval_sensitivity(float opd, vec3 shift) { // Use Gaussian fits, given by 3 parameters: val, pos and var @@ -340,57 +311,39 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) // XYZ to CIE 1931 RGB color space (using neutral E illuminant) const mat3 XYZ_TO_RGB = mat3(2.3706743, -0.5138850, 0.0052982, -0.9000405, 1.4253036, -0.0146949, -0.4706338, 0.0885814, 1.0093968); - // Convert nm -> m - float d = fd.tf_thickness * 1.0e-9; - // Assume vacuum on the outside float eta1 = 1.0; float eta2 = max(fd.tf_ior, eta1); vec3 eta3 = (fd.model == FRESNEL_MODEL_SCHLICK) ? mx_f0_to_ior(fd.F0) : fd.ior; vec3 kappa3 = (fd.model == FRESNEL_MODEL_SCHLICK) ? vec3(0.0) : fd.extinction; + float cosThetaT = sqrt(1.0 - (1.0 - mx_square(cosTheta)) * mx_square(eta1 / eta2)); - // Compute the Spectral versions of the Fresnel reflectance and - // transmitance for each interface. - float R12p, T121p, R12s, T121s; + // First interface + vec2 R12 = mx_fresnel_dielectric_polarized(cosTheta, eta2 / eta1); + if (cosThetaT <= 0.0) + { + // Total internal reflection + R12 = vec2(1.0); + } + vec2 T121 = vec2(1.0) - R12; + + // Second interface vec3 R23p, R23s; - - // Reflected and transmitted parts in the thin film - mx_fresnel_dielectric_polarized(cosTheta, eta2 / eta1, R12p, R12s); - - // Reflected part by the base - float scale = eta1 / eta2; - float cosThetaTSqr = 1.0 - (1.0-cosTheta*cosTheta) * scale*scale; - float cosTheta2 = sqrt(cosThetaTSqr); if (fd.model == FRESNEL_MODEL_SCHLICK) { - vec3 f = mx_fresnel_hoffman_schlick(cosTheta2, fd); + vec3 f = mx_fresnel_hoffman_schlick(cosThetaT, fd); R23p = 0.5 * f; R23s = 0.5 * f; } else { - mx_fresnel_conductor_polarized(cosTheta2, eta3 / eta2, kappa3 / eta2, R23p, R23s); - } - - // Check for total internal reflection - if (cosThetaTSqr <= 0.0f) - { - R12p = 1.0; - R12s = 1.0; + mx_fresnel_conductor_polarized(cosThetaT, eta3 / eta2, kappa3 / eta2, R23p, R23s); } - // Compute the transmission coefficients - T121p = 1.0 - R12p; - T121s = 1.0 - R12s; - - // Optical path difference - float D = 2.0 * eta2 * d * cosTheta2; - - float phi21p, phi21s; - vec3 phi23p, phi23s, r123s, r123p; - - // Evaluate the phase shift - mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2, phi21p, phi21s); + // Phase shift + float cosB = cos(atan(eta2 / eta1)); + vec2 phi21 = vec2(cosTheta < cosB ? 0.0 : M_PI, M_PI); + vec3 phi23p, phi23s; if (fd.model == FRESNEL_MODEL_SCHLICK) { phi23p = vec3((eta3[0] < eta2) ? M_PI : 0.0, @@ -400,46 +353,46 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) } else { - mx_fresnel_conductor_phase_polarized(cosTheta2, eta2, eta3, kappa3, phi23p, phi23s); + mx_fresnel_conductor_phase_polarized(cosThetaT, eta2, eta3, kappa3, phi23p, phi23s); } + vec3 r123p = max(sqrt(R12.x*R23p), 0.0); + vec3 r123s = max(sqrt(R12.y*R23s), 0.0); - phi21p = M_PI - phi21p; - phi21s = M_PI - phi21s; - - r123p = max(vec3(0.0), sqrt(R12p*R23p)); - r123s = max(vec3(0.0), sqrt(R12s*R23s)); - - // Evaluate iridescence term + // Iridescence term vec3 I = vec3(0.0); vec3 Cm, Sm; + // Optical path difference + float distMeters = fd.tf_thickness * 1.0e-9; + float opd = 2.0 * eta2 * cosThetaT * distMeters; + // Iridescence term using spectral antialiasing for Parallel polarization // Reflectance term for m=0 (DC term amplitude) - vec3 Rs = (T121p*T121p*R23p) / (vec3(1.0) - R12p*R23p); - I += R12p + Rs; + vec3 Rs = (mx_square(T121.x) * R23p) / (vec3(1.0) - R12.x*R23p); + I += R12.x + Rs; // Reflectance term for m>0 (pairs of diracs) - Cm = Rs - T121p; + Cm = Rs - T121.x; for (int m=1; m<=2; m++) { Cm *= r123p; - Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23p+vec3(phi21p))); + Sm = 2.0 * mx_eval_sensitivity(float(m) * opd, float(m)*(phi23p+vec3(phi21.x))); I += Cm*Sm; } // Iridescence term using spectral antialiasing for Perpendicular polarization // Reflectance term for m=0 (DC term amplitude) - vec3 Rp = (T121s*T121s*R23s) / (vec3(1.0) - R12s*R23s); - I += R12s + Rp; + vec3 Rp = (mx_square(T121.y) * R23s) / (vec3(1.0) - R12.y*R23s); + I += R12.y + Rp; // Reflectance term for m>0 (pairs of diracs) - Cm = Rp - T121s; + Cm = Rp - T121.y; for (int m=1; m<=2; m++) { Cm *= r123s; - Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23s+vec3(phi21s))); + Sm = 2.0 * mx_eval_sensitivity(float(m) * opd, float(m)*(phi23s+vec3(phi21.y))); I += Cm*Sm; } @@ -447,7 +400,7 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) I *= 0.5; // Convert back to RGB reflectance - I = clamp(XYZ_TO_RGB * I, vec3(0.0), vec3(1.0)); + I = clamp(XYZ_TO_RGB * I, 0.0, 1.0); return I; } From 78fab2ca397a80f739326b1d0bfe7f0832a9a324 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 12 Mar 2024 13:38:10 -0700 Subject: [PATCH 09/14] Add frame timing option to viewer This changelist adds a frame timing option to the MaterialX Viewer, allowing basic performance profiling from within the application. To enable frame timing, launch the MaterialX Viewer with "--frameTiming true". --- source/MaterialXView/Main.cpp | 11 +++++++ source/MaterialXView/RenderPipelineGL.cpp | 3 ++ source/MaterialXView/RenderPipelineMetal.mm | 3 ++ source/MaterialXView/Viewer.cpp | 33 ++++++++++++++++++++- source/MaterialXView/Viewer.h | 24 +++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) diff --git a/source/MaterialXView/Main.cpp b/source/MaterialXView/Main.cpp index c703e48883..6524172610 100644 --- a/source/MaterialXView/Main.cpp +++ b/source/MaterialXView/Main.cpp @@ -41,6 +41,7 @@ const std::string options = " --bakeHeight [INTEGER] Specify the target height for texture baking (defaults to maximum image height of the source document)\n" " --bakeFilename [STRING] Specify the output document filename for texture baking\n" " --refresh [FLOAT] Specify the refresh period for the viewer in milliseconds (defaults to 50, set to -1 to disable)\n" + " --frameTiming [BOOLEAN] Specify whether the frame timing display is enabled (defaults to false)\n" " --remap [TOKEN1:TOKEN2] Specify the remapping from one token to another when MaterialX document is loaded\n" " --skip [NAME] Specify to skip elements matching the given name attribute\n" " --terminator [STRING] Specify to enforce the given terminator string for file prefixes\n" @@ -99,6 +100,7 @@ int main(int argc, char* const argv[]) int bakeHeight = 0; std::string bakeFilename; float refresh = 50.0f; + bool frameTiming = false; for (size_t i = 0; i < tokens.size(); i++) { @@ -212,6 +214,14 @@ int main(int argc, char* const argv[]) { parseToken(nextToken, "float", refresh); } + else if (token == "--frameTiming") + { + parseToken(nextToken, "boolean", frameTiming); + if (frameTiming) + { + refresh = 0; + } + } else if (token == "--remap") { mx::StringVec vec = mx::splitString(nextToken, ":"); @@ -285,6 +295,7 @@ int main(int argc, char* const argv[]) viewer->setBakeWidth(bakeWidth); viewer->setBakeHeight(bakeHeight); viewer->setBakeFilename(bakeFilename); + viewer->setFrameTiming(frameTiming); viewer->initialize(); if (!captureFilename.empty()) diff --git a/source/MaterialXView/RenderPipelineGL.cpp b/source/MaterialXView/RenderPipelineGL.cpp index 68ac0be040..eeb23868f7 100644 --- a/source/MaterialXView/RenderPipelineGL.cpp +++ b/source/MaterialXView/RenderPipelineGL.cpp @@ -296,6 +296,9 @@ mx::ImagePtr GLRenderPipeline::getShadowMap(int shadowMapSize) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glDrawBuffer(GL_BACK); } + + // Reset frame timing after shadow generation. + _viewer->resetFrameTiming(); } return _viewer->_shadowMap; diff --git a/source/MaterialXView/RenderPipelineMetal.mm b/source/MaterialXView/RenderPipelineMetal.mm index 0dc85b8aa4..ccd8fbd5f8 100644 --- a/source/MaterialXView/RenderPipelineMetal.mm +++ b/source/MaterialXView/RenderPipelineMetal.mm @@ -387,6 +387,9 @@ [renderpassDesc release]; } + + // Reset frame timing after shadow generation. + _viewer->resetFrameTiming(); } _viewer->_shadowMap = _shadowMap[_viewer->_shadowSoftness % 2]; diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index c6a810c2d4..a9b66dd452 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -225,7 +225,12 @@ Viewer::Viewer(const std::string& materialFilename, _bakeRequested(false), _bakeWidth(0), _bakeHeight(0), - _bakeDocumentPerMaterial(false) + _bakeDocumentPerMaterial(false), + _frameTiming(false), + _timingLabel(nullptr), + _timingPanel(nullptr), + _timingText(nullptr), + _avgFrameTime(0.0) { // Resolve input filenames, taking both the provided search path and // current working directory into account. @@ -327,6 +332,21 @@ void Viewer::initialize() } }); + // Create frame timing display + if (_frameTiming) + { + _timingLabel = new ng::Label(_window, "Timing"); + _timingPanel = new ng::Widget(_window); + _timingPanel->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal, + ng::Alignment::Middle, 0, 6)); + new ng::Label(_timingPanel, "Frame time:"); + _timingText = new ng::TextBox(_timingPanel); + _timingText->set_value("0"); + _timingText->set_units(" ms"); + _timingText->set_fixed_size(ng::Vector2i(80, 25)); + _timingText->set_alignment(ng::TextBox::Alignment::Right); + } + // Create geometry handler. mx::TinyObjLoaderPtr objLoader = mx::TinyObjLoader::create(); mx::CgltfLoaderPtr gltfLoader = mx::CgltfLoader::create(); @@ -2078,6 +2098,17 @@ void Viewer::draw_contents() #endif } + // Update frame timing. + if (_frameTiming) + { + const double DEFAULT_SMOOTHING_BIAS = 0.9; + double elapsedTime = _frameTimer.elapsedTime() * 1000.0; + double bias = (_avgFrameTime > 0.0) ? DEFAULT_SMOOTHING_BIAS : 0.0; + _avgFrameTime = bias * _avgFrameTime + (1.0 - bias) * elapsedTime; + _timingText->set_value(std::to_string((int) _avgFrameTime)); + _frameTimer.startTimer(); + } + // Capture the current frame. if (_captureRequested && !_turntableEnabled) { diff --git a/source/MaterialXView/Viewer.h b/source/MaterialXView/Viewer.h index ff0827d12a..2b9c0bec71 100644 --- a/source/MaterialXView/Viewer.h +++ b/source/MaterialXView/Viewer.h @@ -151,6 +151,22 @@ class Viewer : public ng::Screen _bakeFilename = bakeFilename; } + // Enable or disable frame timing. + void setFrameTiming(bool enable) + { + _frameTiming = enable; + } + + // Reset frame timing after a blocking event. + void resetFrameTiming() + { + if (_frameTiming) + { + _frameTimer.startTimer(); + _avgFrameTime = 0.0; + } + } + // Return true if all inputs should be shown in the property editor. bool getShowAllInputs() const { @@ -450,6 +466,14 @@ class Viewer : public ng::Screen unsigned int _bakeHeight; bool _bakeDocumentPerMaterial; mx::FilePath _bakeFilename; + + // Frame timing + bool _frameTiming; + ng::Label* _timingLabel; + ng::Widget* _timingPanel; + ng::TextBox* _timingText; + mx::ScopedTimer _frameTimer; + double _avgFrameTime; }; extern const mx::Vector3 DEFAULT_CAMERA_POSITION; From 839b91932de61040bc18143cf1f5857692066c6a Mon Sep 17 00:00:00 2001 From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:05:16 -0700 Subject: [PATCH 10/14] Integrate MDL enhancements to public repository (#1730) Merge internal enhancements into public repository. This PR includes: - Enable `multiscatter_tint` - Fix bump was not working in `mx_generalized_schlick_bsdf` --- .../MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl | 16 ++++++++++++---- .../MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl | 3 +-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl index fbd6b5c1dd..631f214bbc 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl @@ -176,6 +176,7 @@ export material mx_dielectric_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, tint: mxp_tint, + multiscatter_tint: mxp_tint, tangent_u: mxp_tangent, mode: df::scatter_reflect), base: mxp_base.surface.scattering, @@ -187,6 +188,7 @@ export material mx_dielectric_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, tint: mxp_tint, + multiscatter_tint: mxp_tint, tangent_u: mxp_tangent, mode: df::scatter_transmit), normal: mxp_normal); @@ -200,6 +202,7 @@ export material mx_dielectric_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, tint: mxp_tint, + multiscatter_tint: mxp_tint, tangent_u: mxp_tangent, mode: df::scatter_reflect_transmit)), normal: mxp_normal); @@ -235,6 +238,8 @@ export material mx_conductor_bsdf( 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, @@ -280,6 +285,7 @@ export material mx_generalized_schlick_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, tint: color(1.0), + multiscatter_tint: color(1.0), tangent_u: mxp_tangent, mode: df::scatter_reflect); @@ -287,6 +293,7 @@ export material mx_generalized_schlick_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, tint: color(1.0), + multiscatter_tint: color(1.0), tangent_u: mxp_tangent, mode: df::scatter_transmit); } in material( @@ -299,7 +306,8 @@ export material mx_generalized_schlick_bsdf( grazing_reflectivity: mxp_color90, exponent: mxp_exponent, layer: bsdf(), - base: ggx_model_T) + base: ggx_model_T, + normal: mxp_normal) : df::thin_film( thickness: mxp_thinfilm_thickness, ior: color(coatIor), @@ -310,9 +318,9 @@ export material mx_generalized_schlick_bsdf( layer: ggx_model_R, base: mxp_scatter_mode == mx_scatter_mode_R ? mxp_base.surface.scattering - : ggx_model_T)), - base: mxp_base.surface.scattering, - normal: mxp_normal + : ggx_model_T, + normal: mxp_normal)), + base: mxp_base.surface.scattering ) ), // we can't use the computed ior here because it's varying diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl index 0173cfcf7d..da22210c42 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl @@ -425,8 +425,7 @@ export float4 mx_geompropvalue_vector4( export float3 mx_viewdirection_vector3( uniform core::mx_coordinatespace_type mxp_space = core::mx_coordinatespace_type_world [[ - anno::description("Enumeration {model,object,world}."), - anno::unused() + anno::description("Enumeration {model,object,world}.") ]] ) [[ From c0e640ee208b227cf8dd2323491c25cd37f00ecb Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 13 Mar 2024 22:43:17 -0700 Subject: [PATCH 11/14] Update dynamic analysis build This changelist updates the dynamic analysis build from Clang 15 to Clang 10, in order to work around a recent issue in GitHub Actions environments. --- .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 95ed463b34..e204a3f32f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -64,9 +64,9 @@ jobs: clang_format: ON - name: Linux_Clang_DynamicAnalysis - os: ubuntu-22.04 + os: ubuntu-20.04 compiler: clang - compiler_version: "15" + compiler_version: "10" python: None cmake_config: -DMATERIALX_DYNAMIC_ANALYSIS=ON dynamic_analysis: ON From 7ede137cc4e1d510c47cfa2a629cdb23aa96339e Mon Sep 17 00:00:00 2001 From: Dhruv Govil Date: Sat, 16 Mar 2024 11:32:29 -0700 Subject: [PATCH 12/14] Use framework linkage for OpenGL on macOS (#1741) This commit fixes the output of the MaterialXTargets.cmake to have proper system linkage for OpenGL in the cmake config. Without this change, downstream projects on a Mac like USD cannot build against MaterialX properly. --- source/MaterialXRenderGlsl/CMakeLists.txt | 2 +- source/MaterialXRenderMsl/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/MaterialXRenderGlsl/CMakeLists.txt b/source/MaterialXRenderGlsl/CMakeLists.txt index 067cc5d016..27934bf5db 100644 --- a/source/MaterialXRenderGlsl/CMakeLists.txt +++ b/source/MaterialXRenderGlsl/CMakeLists.txt @@ -70,7 +70,7 @@ if(WIN32) elseif(APPLE) target_link_libraries( ${MATERIALX_MODULE_NAME} - OpenGL::GL + "-framework OpenGL" "-framework Foundation" "-framework Cocoa" "-framework Metal") diff --git a/source/MaterialXRenderMsl/CMakeLists.txt b/source/MaterialXRenderMsl/CMakeLists.txt index 41e00d4b9f..3d980fa44b 100644 --- a/source/MaterialXRenderMsl/CMakeLists.txt +++ b/source/MaterialXRenderMsl/CMakeLists.txt @@ -57,7 +57,7 @@ elseif(APPLE) target_link_libraries( ${MATERIALX_MODULE_NAME} "-framework Cocoa" - OpenGL::GL) + "-framework OpenGL") endif() target_link_libraries( ${MATERIALX_MODULE_NAME} From 0067b5747701e8a8c3f63b955be5101739899c70 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 17 Mar 2024 11:16:25 -0700 Subject: [PATCH 13/14] Static analysis fixes This changelist addresses a handful of static analysis warnings flagged by Cppcheck and MSVC. --- source/MaterialXGenShader/Syntax.cpp | 4 ++-- source/MaterialXRender/GeometryHandler.cpp | 8 +++++++- source/MaterialXRenderHw/SimpleWindowWindows.cpp | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index 2917164417..8308f31ffa 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -151,7 +151,7 @@ string Syntax::getSwizzledVariable(const string& srcName, TypeDesc srcType, cons else { const size_t channelIndex = it->second; - if (channelIndex < 0 || channelIndex >= srcMembers.size()) + if (channelIndex >= srcMembers.size()) { throw ExceptionShaderGenError("Given channel index: '" + string(1, ch) + "' in channels pattern is incorrect for type '" + srcType.getName() + "'."); } @@ -197,7 +197,7 @@ ValuePtr Syntax::getSwizzledValue(ValuePtr value, TypeDesc srcType, const string else { const size_t channelIndex = it->second; - if (channelIndex < 0 || channelIndex >= srcMembers.size()) + if (channelIndex >= srcMembers.size()) { throw ExceptionShaderGenError("Given channel index: '" + string(1, ch) + "' in channels pattern is incorrect for type '" + srcType.getName() + "'."); } diff --git a/source/MaterialXRender/GeometryHandler.cpp b/source/MaterialXRender/GeometryHandler.cpp index dfea0b2ceb..f5cd02dcef 100644 --- a/source/MaterialXRender/GeometryHandler.cpp +++ b/source/MaterialXRender/GeometryHandler.cpp @@ -12,6 +12,13 @@ MATERIALX_NAMESPACE_BEGIN +namespace +{ + +const float MAX_FLOAT = std::numeric_limits::max(); + +} // anonymous namespace + void GeometryHandler::addLoader(GeometryLoaderPtr loader) { const StringSet& extensions = loader->supportedExtensions(); @@ -63,7 +70,6 @@ void GeometryHandler::getGeometry(MeshList& meshes, const string& location) void GeometryHandler::computeBounds() { - const float MAX_FLOAT = std::numeric_limits::max(); _minimumBounds = { MAX_FLOAT, MAX_FLOAT, MAX_FLOAT }; _maximumBounds = { -MAX_FLOAT, -MAX_FLOAT, -MAX_FLOAT }; for (const auto& mesh : _meshes) diff --git a/source/MaterialXRenderHw/SimpleWindowWindows.cpp b/source/MaterialXRenderHw/SimpleWindowWindows.cpp index 070950e682..64c36c80a1 100644 --- a/source/MaterialXRenderHw/SimpleWindowWindows.cpp +++ b/source/MaterialXRenderHw/SimpleWindowWindows.cpp @@ -111,9 +111,9 @@ SimpleWindow::~SimpleWindow() if (hWnd) { _windowWrapper->release(); + DestroyWindow(hWnd); } - DestroyWindow(hWnd); UnregisterClass(_windowClassName, GetModuleHandle(NULL)); } From 55df3c8d1cc4f3f9efa722a70efab886094a0f3d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 18 Mar 2024 12:33:56 -0700 Subject: [PATCH 14/14] Move dynamic analysis tests to MacOS (#1743) This changelist moves dynamic analysis tests to MacOS in GitHub Actions, allowing them to take advantage of more recent compiler environments and hardware. --- .github/workflows/main.yml | 16 ++++++++-------- CMakeLists.txt | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e204a3f32f..9bb79a1f3f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,14 +63,6 @@ jobs: test_render: ON clang_format: ON - - name: Linux_Clang_DynamicAnalysis - os: ubuntu-20.04 - compiler: clang - compiler_version: "10" - python: None - cmake_config: -DMATERIALX_DYNAMIC_ANALYSIS=ON - dynamic_analysis: ON - - name: MacOS_Xcode_13_Python37 os: macos-12 compiler: xcode @@ -91,6 +83,14 @@ jobs: python: 3.12 test_shaders: ON + - name: MacOS_Xcode_DynamicAnalysis + os: macos-14 + compiler: xcode + compiler_version: "15.0" + python: None + dynamic_analysis: ON + cmake_config: -DMATERIALX_DYNAMIC_ANALYSIS=ON + - name: iOS_Xcode_15 os: macos-14 compiler: xcode diff --git a/CMakeLists.txt b/CMakeLists.txt index e037d3e3b3..e975cf6df9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,7 +244,7 @@ else() add_link_options(--coverage) endif() if(MATERIALX_DYNAMIC_ANALYSIS) - set(DYNAMIC_ANALYSIS_OPTIONS -fsanitize=address -fsanitize=leak -fsanitize=undefined -fno-sanitize-recover=all) + set(DYNAMIC_ANALYSIS_OPTIONS -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all) add_compile_options(${DYNAMIC_ANALYSIS_OPTIONS}) add_link_options(${DYNAMIC_ANALYSIS_OPTIONS}) endif()