Files
UnrealEngine/Engine/Source/ThirdParty/MaterialX/MaterialX-1.38.10/source/MaterialXGenShader/ShaderNode.h
2025-05-18 13:04:45 +08:00

517 lines
17 KiB
C++

//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//
#ifndef MATERIALX_SHADERNODE_H
#define MATERIALX_SHADERNODE_H
/// @file
/// Classes for nodes created during shader generation
#include <MaterialXGenShader/Export.h>
#include <MaterialXGenShader/ShaderNodeImpl.h>
#include <MaterialXGenShader/TypeDesc.h>
#include <MaterialXGenShader/GenUserData.h>
#include <MaterialXCore/Node.h>
MATERIALX_NAMESPACE_BEGIN
class ShaderNode;
class ShaderPort;
class ShaderInput;
class ShaderOutput;
class ShaderGraph;
/// Shared pointer to a ShaderPort
using ShaderPortPtr = shared_ptr<class ShaderPort>;
/// Shared pointer to a ShaderInput
using ShaderInputPtr = shared_ptr<class ShaderInput>;
/// Shared pointer to a ShaderOutput
using ShaderOutputPtr = shared_ptr<class ShaderOutput>;
/// Shared pointer to a ShaderNode
using ShaderNodePtr = shared_ptr<class ShaderNode>;
/// A vector of ShaderInput pointers
using ShaderInputVec = vector<ShaderInput*>;
/// Metadata to be exported to generated shader.
struct MX_GENSHADER_API ShaderMetadata
{
string name;
const TypeDesc* type;
ValuePtr value;
ShaderMetadata(const string& n, const TypeDesc* t, ValuePtr v = nullptr) :
name(n),
type(t),
value(v)
{
}
};
using ShaderMetadataVec = vector<ShaderMetadata>;
using ShaderMetadataVecPtr = shared_ptr<ShaderMetadataVec>;
/// @class ShaderMetadataRegistry
/// A registry for metadata that will be exported to the generated shader
/// if found on nodes and inputs during shader generation.
class MX_GENSHADER_API ShaderMetadataRegistry : public GenUserData
{
public:
static const string USER_DATA_NAME;
/// 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)
{
if (_entryIndex.count(name) == 0)
{
_entryIndex[name] = _entries.size();
_entries.emplace_back(name, type, value);
}
}
/// Return the metadata registered for the given name, or nullptr
/// if no such entry is found.
const ShaderMetadata* findMetadata(const string& name) const
{
auto it = _entryIndex.find(name);
return it != _entryIndex.end() ? &_entries[it->second] : nullptr;
}
/// Return the metadata registered for the given name, or nullptr
/// if no such entry is found.
ShaderMetadata* findMetadata(const string& name)
{
auto it = _entryIndex.find(name);
return it != _entryIndex.end() ? &_entries[it->second] : nullptr;
}
/// Return all entries in the registry.
const ShaderMetadataVec& getAllMetadata() const
{
return _entries;
}
/// Clear all entries in the registry.
void clear()
{
_entryIndex.clear();
_entries.clear();
}
protected:
vector<ShaderMetadata> _entries;
std::unordered_map<string, size_t> _entryIndex;
};
using ShaderMetadataRegistryPtr = shared_ptr<ShaderMetadataRegistry>;
/// Flags set on shader ports.
class MX_GENSHADER_API ShaderPortFlag
{
public:
static const uint32_t UNIFORM = 1u << 0;
static const uint32_t EMITTED = 1u << 1;
static const uint32_t BIND_INPUT = 1u << 2;
};
/// @class ShaderPort
/// An input or output port on a ShaderNode
class MX_GENSHADER_API ShaderPort : public std::enable_shared_from_this<ShaderPort>
{
public:
/// Constructor.
ShaderPort(ShaderNode* node, const TypeDesc* type, const string& name, ValuePtr value = nullptr);
/// Return a shared pointer instance of this object.
ShaderPortPtr getSelf()
{
return shared_from_this();
}
/// Return the node this port belongs to.
ShaderNode* getNode() { return _node; }
/// Return the node this port belongs to.
const ShaderNode* getNode() const { return _node; }
/// Set the data type for this port.
void setType(const TypeDesc* type) { _type = type; }
/// Return the data type for this port.
const TypeDesc* getType() const { return _type; }
/// Set the name of this port.
void setName(const string& name) { _name = name; }
/// Return the name of this port.
const string& getName() const { return _name; }
/// Return the name of this port.
string getFullName() const;
/// Set the variable name of this port.
void setVariable(const string& name) { _variable = name; }
/// Return the variable name of this port.
const string& getVariable() const { return _variable; }
/// Set the variable semantic of this port.
void setSemantic(const string& semantic) { _semantic = semantic; }
/// Return the variable semantic of this port.
const string& getSemantic() const { return _semantic; }
/// Set a value on this port.
void setValue(ValuePtr value) { _value = value; }
/// Return the value set on this port.
ValuePtr getValue() const { return _value; }
/// Return the value set on this port as a string, or an empty string if there is no value.
string getValueString() const;
/// Set a source color space for the value on this port.
void setColorSpace(const string& colorspace) { _colorspace = colorspace; }
/// Return the source color space for the value on this port.
const string& getColorSpace() const { return _colorspace; }
/// Set a unit type for the value on this port.
void setUnit(const string& unit) { _unit = unit; }
/// Return the unit type for the value on this port.
const string& getUnit() const { return _unit; }
/// Set geomprop name if the input has a default
/// geomprop to be assigned when it is unconnected.
void setGeomProp(const string& geomprop) { _geomprop = geomprop; }
/// Get geomprop name.
const string& getGeomProp() const { return _geomprop; }
/// Set the path to this port.
void setPath(const string& path) { _path = path; }
/// Return the path to this port.
const string& getPath() const { return _path; }
/// Set flags on this port.
void setFlags(uint32_t flags) { _flags = flags; }
/// Return flags set on this port.
uint32_t getFlags() const { return _flags; }
/// Set the on|off state of a given flag.
void setFlag(uint32_t flag, bool value)
{
_flags = value ? (_flags | flag) : (_flags & ~flag);
}
/// Return the on|off state of a given flag.
bool getFlag(uint32_t flag) const
{
return ((_flags & flag) != 0);
}
/// Set the uniform flag this port to true.
void setUniform() { _flags |= ShaderPortFlag::UNIFORM; }
/// Return the uniform flag on this port.
bool isUniform() const { return (_flags & ShaderPortFlag::UNIFORM) != 0; }
/// Set the emitted state on this port to true.
void setEmitted() { _flags |= ShaderPortFlag::EMITTED; }
/// Return the emitted state of this port.
bool isEmitted() const { return (_flags & ShaderPortFlag::EMITTED) != 0; }
/// Set the bind input state on this port to true.
void setBindInput() { _flags |= ShaderPortFlag::BIND_INPUT; }
/// Return the emitted state of this port.
bool isBindInput() const { return (_flags & ShaderPortFlag::BIND_INPUT) != 0; }
/// Set the metadata vector.
void setMetadata(ShaderMetadataVecPtr metadata) { _metadata = metadata; }
/// Get the metadata vector.
ShaderMetadataVecPtr getMetadata() { return _metadata; }
/// Get the metadata vector.
const ShaderMetadataVecPtr& getMetadata() const { return _metadata; }
protected:
ShaderNode* _node;
const TypeDesc* _type;
string _name;
string _path;
string _semantic;
string _variable;
ValuePtr _value;
string _unit;
string _colorspace;
string _geomprop;
ShaderMetadataVecPtr _metadata;
uint32_t _flags;
};
/// @class ShaderInput
/// An input on a ShaderNode
class MX_GENSHADER_API ShaderInput : public ShaderPort
{
public:
ShaderInput(ShaderNode* node, const TypeDesc* type, const string& name);
/// Return a connection to an upstream node output,
/// or nullptr if not connected.
ShaderOutput* getConnection() { return _connection; }
/// Return a connection to an upstream node output,
/// or nullptr if not connected.
const ShaderOutput* getConnection() const { return _connection; }
/// Make a connection from the given source output to this input.
void makeConnection(ShaderOutput* src);
/// Break the connection to this input.
void breakConnection();
/// Set optional channels value
void setChannels(const string& channels) { _channels = channels; }
/// Get optional channels value
const string& getChannels() const { return _channels; }
/// Return the sibling node connected upstream,
/// or nullptr if there is no sibling upstream.
ShaderNode* getConnectedSibling() const;
protected:
ShaderOutput* _connection;
string _channels;
friend class ShaderOutput;
};
/// @class ShaderOutput
/// An output on a ShaderNode
class MX_GENSHADER_API ShaderOutput : public ShaderPort
{
public:
ShaderOutput(ShaderNode* node, const TypeDesc* type, const string& name);
/// Return a set of connections to downstream node inputs,
/// empty if not connected.
const ShaderInputVec& getConnections() const { return _connections; }
/// Make a connection from this output to the given input
void makeConnection(ShaderInput* dst);
/// Break a connection from this output to the given input
void breakConnection(ShaderInput* dst);
/// Break all connections from this output
void breakConnections();
protected:
ShaderInputVec _connections;
friend class ShaderInput;
};
/// @class ShaderNode
/// Class representing a node in the shader generation DAG
class MX_GENSHADER_API ShaderNode
{
public:
virtual ~ShaderNode() { }
/// Flags for classifying nodes into different categories.
class Classification
{
public:
// Node classes
static const uint32_t TEXTURE = 1 << 0; /// Any node that outputs floats, colors, vectors, etc.
static const uint32_t CLOSURE = 1 << 1; /// Any node that represents light integration
static const uint32_t SHADER = 1 << 2; /// Any node that outputs a shader
static const uint32_t MATERIAL = 1 << 3; /// Any node that outputs a material
// Specific texture node types
static const uint32_t FILETEXTURE = 1 << 4; /// A file texture node
static const uint32_t CONDITIONAL = 1 << 5; /// A conditional node
static const uint32_t CONSTANT = 1 << 6; /// A constant node
// Specific closure types
static const uint32_t BSDF = 1 << 7; /// A BSDF node
static const uint32_t BSDF_R = 1 << 8; /// A reflection BSDF node
static const uint32_t BSDF_T = 1 << 9; /// A transmission BSDF node
static const uint32_t EDF = 1 << 10; /// A EDF node
static const uint32_t VDF = 1 << 11; /// A VDF node
static const uint32_t LAYER = 1 << 12; /// A node for vertical layering of other closure nodes
static const uint32_t THINFILM = 1 << 13; /// A node for adding thin-film over microfacet BSDF nodes
// Specific shader types
static const uint32_t SURFACE = 1 << 14; /// A surface shader node
static const uint32_t VOLUME = 1 << 15; /// A volume shader node
static const uint32_t LIGHT = 1 << 16; /// A light shader node
static const uint32_t UNLIT = 1 << 17; /// An unlit surface shader node
// Types based on nodegroup
static const uint32_t SAMPLE2D = 1 << 18; /// Can be sampled in 2D (uv space)
static const uint32_t SAMPLE3D = 1 << 19; /// Can be sampled in 3D (position)
static const uint32_t GEOMETRIC = 1 << 20; /// Geometric input
static const uint32_t DOT = 1 << 21; /// A dot node
};
static const ShaderNodePtr NONE;
static const string CONSTANT;
static const string DOT;
static const string IMAGE;
static const string SURFACESHADER;
static const string SCATTER_MODE;
static const string BSDF_R;
static const string BSDF_T;
static const string TRANSFORM_POINT;
static const string TRANSFORM_VECTOR;
static const string TRANSFORM_NORMAL;
static const string TEXTURE2D_GROUPNAME;
static const string TEXTURE3D_GROUPNAME;
static const string PROCEDURAL2D_GROUPNAME;
static const string PROCEDURAL3D_GROUPNAME;
static const string GEOMETRIC_GROUPNAME;
public:
/// Constructor.
ShaderNode(const ShaderGraph* parent, const string& name);
/// Create a new node from a nodedef.
static ShaderNodePtr create(const ShaderGraph* parent, const string& name, const NodeDef& nodeDef,
GenContext& context);
/// Create a new node from a node implementation.
static ShaderNodePtr create(const ShaderGraph* parent, const string& name, ShaderNodeImplPtr impl,
unsigned int classification = Classification::TEXTURE);
/// Return true if this node is a graph.
virtual bool isAGraph() const { return false; }
/// Return the parent graph that owns this node.
/// If this node is a root graph it has no parent
/// and nullptr will be returned.
const ShaderGraph* getParent() const
{
return _parent;
}
/// Set classification bits for this node,
/// replacing any previous set bits.
void setClassification(uint32_t c)
{
_classification = c;
}
/// Get classification bits set for this node.
uint32_t getClassification() const
{
return _classification;
}
/// Add classification bits to this node.
void addClassification(uint32_t c)
{
_classification |= c;
}
/// Return true if this node matches the given classification.
bool hasClassification(uint32_t c) const
{
return (_classification & c) == c;
}
/// Return the name of this node.
const string& getName() const
{
return _name;
}
/// Return the implementation used for this node.
const ShaderNodeImpl& getImplementation() const
{
return *_impl;
}
/// Initialize this shader node with all required data
/// from the given node and nodedef.
void initialize(const Node& node, const NodeDef& nodeDef, GenContext& context);
/// Add inputs/outputs
ShaderInput* addInput(const string& name, const TypeDesc* type);
ShaderOutput* addOutput(const string& name, const TypeDesc* type);
/// Get number of inputs/outputs
size_t numInputs() const { return _inputOrder.size(); }
size_t numOutputs() const { return _outputOrder.size(); }
/// Get inputs/outputs by index
ShaderInput* getInput(size_t index) { return _inputOrder[index]; }
ShaderOutput* getOutput(size_t index = 0) { return _outputOrder[index]; }
const ShaderInput* getInput(size_t index) const { return _inputOrder[index]; }
const ShaderOutput* getOutput(size_t index = 0) const { return _outputOrder[index]; }
/// Get inputs/outputs by name
ShaderInput* getInput(const string& name);
ShaderOutput* getOutput(const string& name);
const ShaderInput* getInput(const string& name) const;
const ShaderOutput* getOutput(const string& name) const;
/// Get vector of inputs/outputs
const vector<ShaderInput*>& getInputs() const { return _inputOrder; }
const vector<ShaderOutput*>& getOutputs() const { return _outputOrder; }
/// Set the metadata vector.
void setMetadata(ShaderMetadataVecPtr metadata) { _metadata = metadata; }
/// Get the metadata vector.
ShaderMetadataVecPtr getMetadata() { return _metadata; }
/// Get the metadata vector.
const ShaderMetadataVecPtr& getMetadata() const { return _metadata; }
/// Returns true if an input is editable by users.
/// Editable inputs are allowed to be published as shader uniforms
/// and hence must be presentable in a user interface.
bool isEditable(const ShaderInput& input) const
{
return (!_impl || _impl->isEditable(input));
}
/// Returns true if a graph input is accessible by users.
/// Editable inputs are allowed to be published as shader uniforms
/// and hence must be presentable in a user interface.
bool isEditable(const ShaderGraphInputSocket& input) const
{
return (!_impl || _impl->isEditable(input));
}
protected:
/// Create metadata from the nodedef according to registered metadata.
void createMetadata(const NodeDef& nodeDef, GenContext& context);
const ShaderGraph* _parent;
string _name;
uint32_t _classification;
std::unordered_map<string, ShaderInputPtr> _inputMap;
vector<ShaderInput*> _inputOrder;
std::unordered_map<string, ShaderOutputPtr> _outputMap;
vector<ShaderOutput*> _outputOrder;
ShaderNodeImplPtr _impl;
ShaderMetadataVecPtr _metadata;
friend class ShaderGraph;
};
MATERIALX_NAMESPACE_END
#endif