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

144 lines
6.2 KiB
C++

//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//
#include <MaterialXGenShader/Nodes/CombineNode.h>
#include <MaterialXGenShader/GenContext.h>
#include <MaterialXGenShader/ShaderNode.h>
#include <MaterialXGenShader/ShaderStage.h>
#include <MaterialXGenShader/ShaderGenerator.h>
MATERIALX_NAMESPACE_BEGIN
ShaderNodeImplPtr CombineNode::create()
{
return std::make_shared<CombineNode>();
}
void CombineNode::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const
{
DEFINE_SHADER_STAGE(stage, Stage::PIXEL)
{
const ShaderGenerator& shadergen = context.getShaderGenerator();
const ShaderInput* in1 = node.getInput(0);
const ShaderOutput* out = node.getOutput();
if (!in1 || !out)
{
throw ExceptionShaderGenError("Node '" + node.getName() + "' is not a valid convert node");
}
// Check the node signature to determine which
// type conversion to perform, and get the value
// components to use for constructing the new value.
//
StringVec valueComponents;
if (*in1->getType() == *Type::FLOAT)
{
// Get the components of the input values.
const size_t numInputs = node.numInputs();
valueComponents.resize(numInputs);
for (size_t i = 0; i < numInputs; ++i)
{
const ShaderInput* input = node.getInput(i);
valueComponents[i] = shadergen.getUpstreamResult(input, context);
}
}
else if (*in1->getType() == *Type::COLOR3 || *in1->getType() == *Type::VECTOR3)
{
const ShaderInput* in2 = node.getInput(1);
if (!in2 || in2->getType() != Type::FLOAT)
{
throw ExceptionShaderGenError("Node '" + node.getName() + "' is not a valid convert node");
}
// If in1 is unconnected we must declare a local variable
// for it first, in order to access components from it below.
string in1Variable = in1->getConnection() ? in1->getConnection()->getVariable() : in1->getVariable();
if (!in1->getConnection())
{
string variableValue = in1->getValue() ? shadergen.getSyntax().getValue(in1->getType(), *in1->getValue()) : shadergen.getSyntax().getDefaultValue(in1->getType());
shadergen.emitLine(shadergen.getSyntax().getTypeName(in1->getType()) + " " + in1Variable + " = " + variableValue, stage);
}
// Get components from in1
const StringVec& in1Members = shadergen.getSyntax().getTypeSyntax(in1->getType()).getMembers();
size_t memberSize = in1Members.size();
// Get the components of the input values.
if (memberSize)
{
valueComponents.resize(memberSize + 1);
for (size_t i = 0; i < memberSize; i++)
{
valueComponents[i] = in1Variable + in1Members[i];
}
}
else
{
memberSize = 1;
valueComponents.resize(2);
valueComponents[0] = in1Variable;
}
// Get component from in2
valueComponents[memberSize] = shadergen.getUpstreamResult(in2, context);
}
else if (*in1->getType() == *Type::VECTOR2)
{
const ShaderInput* in2 = node.getInput(1);
if (!in2 || (in2->getType() != Type::VECTOR2))
{
throw ExceptionShaderGenError("Node '" + node.getName() + "' is not a valid convert node");
}
// If in1 is unconnected we must declare a local variable
// for it first, in order to access components from it below.
string in1Variable = in1->getConnection() ? in1->getConnection()->getVariable() : in1->getVariable();
if (!in1->getConnection())
{
string variableValue = in1->getValue() ? shadergen.getSyntax().getValue(in1->getType(), *in1->getValue()) : shadergen.getSyntax().getDefaultValue(in1->getType());
shadergen.emitLine(shadergen.getSyntax().getTypeName(in1->getType()) + " " + in1Variable + " = " + variableValue, stage);
}
// If in2 is unconnected we must declare a local variable
// for it first, in order to access components from it below.
string in2Variable = in2->getConnection() ? in2->getConnection()->getVariable() : in2->getVariable();
if (!in2->getConnection())
{
string variableValue = in2->getValue() ? shadergen.getSyntax().getValue(in2->getType(), *in2->getValue()) : shadergen.getSyntax().getDefaultValue(in2->getType());
shadergen.emitLine(shadergen.getSyntax().getTypeName(in2->getType()) + " " + in2Variable + " = " + variableValue, stage);
}
// Get the components of the input values.
valueComponents.resize(4);
// Get components from in1.
const StringVec& in1Members = shadergen.getSyntax().getTypeSyntax(in1->getType()).getMembers();
valueComponents[0] = in1Variable + in1Members[0];
valueComponents[1] = in1Variable + in1Members[1];
// Get components from in2.
const StringVec& in2Members = shadergen.getSyntax().getTypeSyntax(in2->getType()).getMembers();
valueComponents[2] = in2Variable + in2Members[0];
valueComponents[3] = in2Variable + in2Members[1];
}
if (valueComponents.empty())
{
throw ExceptionShaderGenError("Node '" + node.getName() + "' is not a valid convert node");
}
// Let the TypeSyntax construct the value from the components.
const TypeSyntax& outTypeSyntax = shadergen.getSyntax().getTypeSyntax(out->getType());
const string result = outTypeSyntax.getValue(valueComponents, false);
shadergen.emitLineBegin(stage);
shadergen.emitOutput(node.getOutput(), true, false, context, stage);
shadergen.emitString(" = " + result, stage);
shadergen.emitLineEnd(stage);
}
}
MATERIALX_NAMESPACE_END