You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

184 lines
6.7 KiB

using System;
using System.Collections.Generic;
using UnityEditor.Graphing;
using UnityEngine;
namespace UnityEditor.ShaderGraph
{
[Title("Channel", "Append")]
class AppendVectorNode : AbstractMaterialNode, IGeneratesBodyCode
{
public AppendVectorNode()
{
name = "Append";
synonyms = new string[] { "join", "combine" };
UpdateNodeAfterDeserialization();
}
const int Input1SlotId = 0;
const int Input2SlotId = 1;
const int OutputSlotId = 2;
const string kInput1SlotName = "A";
const string kInput2SlotName = "B";
const string kOutputSlotName = "Out";
public override bool hasPreview => true;
public sealed override void UpdateNodeAfterDeserialization()
{
AddSlot(new DynamicVectorMaterialSlot(Input1SlotId, kInput1SlotName, kInput1SlotName, SlotType.Input, Vector4.zero));
AddSlot(new DynamicVectorMaterialSlot(Input2SlotId, kInput2SlotName, kInput2SlotName, SlotType.Input, Vector4.zero));
AddSlot(new DynamicVectorMaterialSlot(OutputSlotId, kOutputSlotName, kOutputSlotName, SlotType.Output, Vector4.zero));
RemoveSlotsNameNotMatching(new[] { Input1SlotId, Input2SlotId, OutputSlotId });
}
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
{
var input1Value = GetSlotValue(Input1SlotId, generationMode);
var input2Value = GetSlotValue(Input2SlotId, generationMode);
var outputValue = GetSlotValue(OutputSlotId, generationMode);
var outputTypeString = FindOutputSlot<DynamicVectorMaterialSlot>(OutputSlotId).concreteValueType.ToShaderString();
var input1Type = FindInputSlot<DynamicVectorMaterialSlot>(Input1SlotId).concreteValueType;
var input2Type = FindInputSlot<DynamicVectorMaterialSlot>(Input2SlotId).concreteValueType;
var input1Swizzle = SwizzleFromVectorSlotType(input1Type, 3);
var input2Swizzle = SwizzleFromVectorSlotType(input2Type, 3);
sb.AppendLine("{0} {1} = {0}( {2}.{3}, {4}.{5} );",
outputTypeString,
GetVariableNameForSlot(OutputSlotId),
input1Value,
input1Swizzle,
input2Value,
input2Swizzle
);
}
string SwizzleFromVectorSlotType( ConcreteSlotValueType type , uint dimensionLimit = 3)
{
if (dimensionLimit == 0)
dimensionLimit = 4;
uint typeDimension = type switch {
ConcreteSlotValueType.Vector2 => 2,
ConcreteSlotValueType.Vector3 => 3,
ConcreteSlotValueType.Vector4 => 4,
_ => 1,
};
if (typeDimension > dimensionLimit)
typeDimension = dimensionLimit;
return typeDimension switch {
1 => "x",
2 => "xy",
3 => "xyz",
_ => "xyzw",
};
}
uint ProcessInputSlot(MaterialSlot inputSlot, string referenceName, uint maxDimensions = 4)
{
uint dimensions = 0;
if (maxDimensions == 0)
maxDimensions = 4;
inputSlot.hasError = false;
// default input type
var outputConcreteType = ConcreteSlotValueType.Vector1;
// if there is a connection
var edges = owner.GetEdges(inputSlot.slotReference);
foreach(var edge in edges)
{
if (edge != null)
{
// get the output details
var outputSlotRef = edge.outputSlot;
var outputNode = outputSlotRef.node;
if (outputNode != null)
{
var outputSlot = outputNode.FindOutputSlot<MaterialSlot>(outputSlotRef.slotId);
if (outputSlot != null)
{
if (!outputSlot.hasError)
{
outputConcreteType = outputSlot.concreteValueType;
}
}
}
break;
}
}
var dynVectorInputSlot = inputSlot as DynamicVectorMaterialSlot;
// get the connected output dimensions and limit it if needed
dimensions = outputConcreteType switch {
ConcreteSlotValueType.Vector2 => 2,
ConcreteSlotValueType.Vector3 => 3,
ConcreteSlotValueType.Vector4 => 4,
_ => 1,
};
if (dimensions > maxDimensions)
dimensions = maxDimensions;
outputConcreteType = dimensions switch {
2 => ConcreteSlotValueType.Vector2,
3 => ConcreteSlotValueType.Vector3,
4 => ConcreteSlotValueType.Vector4,
_ => ConcreteSlotValueType.Vector1
};
dynVectorInputSlot.SetConcreteType(outputConcreteType);
return dimensions;
}
public override void EvaluateDynamicMaterialSlots(List<MaterialSlot> inputSlots, List<MaterialSlot> outputSlots)
{
uint slot1Dimensions = 1;
uint slot2Dimensions = 1;
uint availableDimensionsForInput2 = 4;
uint outputVectorDimensions = 0;
// iterate over the input slots
int i = 0;
foreach (var inputSlot in inputSlots)
{
if (i == 0)
{
slot1Dimensions = ProcessInputSlot(inputSlot, kInput1SlotName, 3);
availableDimensionsForInput2 -= slot1Dimensions;
}
else if (i == 1)
{
slot2Dimensions = ProcessInputSlot(inputSlot, kInput2SlotName, availableDimensionsForInput2);
}
else
break; // No other input slots should be present
i++;
}
// Set the output vector dimension to the sum of the input
outputVectorDimensions = slot1Dimensions + slot2Dimensions;
foreach (var outputSlot in outputSlots)
{
(outputSlot as DynamicVectorMaterialSlot).SetConcreteType( outputVectorDimensions switch {
2 => ConcreteSlotValueType.Vector2,
3 => ConcreteSlotValueType.Vector3,
4 => ConcreteSlotValueType.Vector4,
_ => ConcreteSlotValueType.Vector1
});
}
CalculateNodeHasError();
}
}
}