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.
375 lines
15 KiB
375 lines
15 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using UnityEngine; |
|
using UnityEditor.Graphing; |
|
using UnityEditor.ShaderGraph.Internal; |
|
using UnityEditor.ShaderGraph.Serialization; |
|
using UnityEditor.ShaderGraph.Drawing.Slots; |
|
using UnityEngine.UIElements; |
|
|
|
namespace UnityEditor.ShaderGraph |
|
{ |
|
[Serializable] |
|
abstract class MaterialSlot : JsonObject |
|
{ |
|
const string k_NotInit = "Not Initialized"; |
|
|
|
[SerializeField] |
|
int m_Id; |
|
|
|
[SerializeField] |
|
string m_DisplayName = k_NotInit; |
|
|
|
[SerializeField] |
|
SlotType m_SlotType = SlotType.Input; |
|
|
|
[SerializeField] |
|
bool m_Hidden; |
|
|
|
[SerializeField] |
|
string m_ShaderOutputName; |
|
|
|
[SerializeField] |
|
ShaderStageCapability m_StageCapability; |
|
|
|
bool m_HasError; |
|
|
|
protected MaterialSlot() { } |
|
|
|
protected MaterialSlot(int slotId, string displayName, string shaderOutputName, SlotType slotType, ShaderStageCapability stageCapability = ShaderStageCapability.All, bool hidden = false) |
|
{ |
|
m_Id = slotId; |
|
m_DisplayName = displayName; |
|
m_SlotType = slotType; |
|
m_Hidden = hidden; |
|
m_ShaderOutputName = shaderOutputName; |
|
this.stageCapability = stageCapability; |
|
} |
|
|
|
internal void SetInternalData(SlotType slotType, string shaderOutputName) |
|
{ |
|
this.m_SlotType = slotType; |
|
this.shaderOutputName = shaderOutputName; |
|
} |
|
|
|
public bool IsConnectionTestable() |
|
{ |
|
if (owner is SubGraphNode sgNode) |
|
{ |
|
var property = sgNode.GetShaderProperty(id); |
|
if (property != null) |
|
{ |
|
return property.isConnectionTestable; |
|
} |
|
} |
|
else if (owner is PropertyNode propertyNode) |
|
{ |
|
return propertyNode.property.isConnectionTestable; |
|
} |
|
return false; |
|
} |
|
|
|
public VisualElement InstantiateCustomControl() |
|
{ |
|
if (!isConnected && IsConnectionTestable()) |
|
{ |
|
var sgNode = owner as SubGraphNode; |
|
var property = sgNode.GetShaderProperty(id); |
|
return new LabelSlotControlView(property.customSlotLabel); |
|
} |
|
return null; |
|
} |
|
|
|
public virtual VisualElement InstantiateControl() |
|
{ |
|
return null; |
|
} |
|
|
|
static string ConcreteSlotValueTypeAsString(ConcreteSlotValueType type) |
|
{ |
|
switch (type) |
|
{ |
|
case ConcreteSlotValueType.Vector1: |
|
return "(1)"; |
|
case ConcreteSlotValueType.Vector2: |
|
return "(2)"; |
|
case ConcreteSlotValueType.Vector3: |
|
return "(3)"; |
|
case ConcreteSlotValueType.Vector4: |
|
return "(4)"; |
|
case ConcreteSlotValueType.Boolean: |
|
return "(B)"; |
|
case ConcreteSlotValueType.Matrix2: |
|
return "(2x2)"; |
|
case ConcreteSlotValueType.Matrix3: |
|
return "(3x3)"; |
|
case ConcreteSlotValueType.Matrix4: |
|
return "(4x4)"; |
|
case ConcreteSlotValueType.SamplerState: |
|
return "(SS)"; |
|
case ConcreteSlotValueType.Texture2D: |
|
return "(T2)"; |
|
case ConcreteSlotValueType.Texture2DArray: |
|
return "(T2A)"; |
|
case ConcreteSlotValueType.Texture3D: |
|
return "(T3)"; |
|
case ConcreteSlotValueType.Cubemap: |
|
return "(C)"; |
|
case ConcreteSlotValueType.Gradient: |
|
return "(G)"; |
|
case ConcreteSlotValueType.VirtualTexture: |
|
return "(VT)"; |
|
case ConcreteSlotValueType.PropertyConnectionState: |
|
return "(P)"; |
|
default: |
|
return "(E)"; |
|
} |
|
} |
|
|
|
public virtual string displayName |
|
{ |
|
get { return m_DisplayName + ConcreteSlotValueTypeAsString(concreteValueType); } |
|
set { m_DisplayName = value; } |
|
} |
|
|
|
public string RawDisplayName() |
|
{ |
|
return m_DisplayName; |
|
} |
|
|
|
public static MaterialSlot CreateMaterialSlot(SlotValueType type, int slotId, string displayName, string shaderOutputName, SlotType slotType, Vector4 defaultValue, ShaderStageCapability shaderStageCapability = ShaderStageCapability.All, bool hidden = false) |
|
{ |
|
switch (type) |
|
{ |
|
case SlotValueType.SamplerState: |
|
return new SamplerStateMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.DynamicMatrix: |
|
return new DynamicMatrixMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.Matrix4: |
|
return new Matrix4MaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.Matrix3: |
|
return new Matrix3MaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.Matrix2: |
|
return new Matrix2MaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.Texture2D: |
|
return slotType == SlotType.Input |
|
? new Texture2DInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden) |
|
: new Texture2DMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.Texture2DArray: |
|
return slotType == SlotType.Input |
|
? new Texture2DArrayInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden) |
|
: new Texture2DArrayMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.Texture3D: |
|
return slotType == SlotType.Input |
|
? new Texture3DInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden) |
|
: new Texture3DMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.Cubemap: |
|
return slotType == SlotType.Input |
|
? new CubemapInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden) |
|
: new CubemapMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.VirtualTexture: |
|
return slotType == SlotType.Input |
|
? new VirtualTextureInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden) |
|
: new VirtualTextureMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.Gradient: |
|
return slotType == SlotType.Input |
|
? new GradientInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden) |
|
: new GradientMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
case SlotValueType.DynamicVector: |
|
return new DynamicVectorMaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStageCapability, hidden); |
|
case SlotValueType.Vector4: |
|
return new Vector4MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStageCapability, hidden: hidden); |
|
case SlotValueType.Vector3: |
|
return new Vector3MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStageCapability, hidden: hidden); |
|
case SlotValueType.Vector2: |
|
return new Vector2MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStageCapability, hidden: hidden); |
|
case SlotValueType.Vector1: |
|
return new Vector1MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue.x, shaderStageCapability, hidden: hidden); |
|
case SlotValueType.Dynamic: |
|
return new DynamicValueMaterialSlot(slotId, displayName, shaderOutputName, slotType, new Matrix4x4(defaultValue, Vector4.zero, Vector4.zero, Vector4.zero), shaderStageCapability, hidden); |
|
case SlotValueType.Boolean: |
|
return new BooleanMaterialSlot(slotId, displayName, shaderOutputName, slotType, false, shaderStageCapability, hidden); |
|
case SlotValueType.PropertyConnectionState: |
|
return new PropertyConnectionStateMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); |
|
} |
|
|
|
throw new ArgumentOutOfRangeException("type", type, null); |
|
} |
|
|
|
public SlotReference slotReference |
|
{ |
|
get { return new SlotReference(owner, m_Id); } |
|
} |
|
|
|
public AbstractMaterialNode owner { get; set; } |
|
|
|
// if hidden, the slot does not create a port in the UI |
|
public bool hidden |
|
{ |
|
get { return m_Hidden; } |
|
set { m_Hidden = value; } |
|
} |
|
|
|
public int id |
|
{ |
|
get { return m_Id; } |
|
} |
|
|
|
public bool isInputSlot |
|
{ |
|
get { return m_SlotType == SlotType.Input; } |
|
} |
|
|
|
public bool isOutputSlot |
|
{ |
|
get { return m_SlotType == SlotType.Output; } |
|
} |
|
|
|
public SlotType slotType |
|
{ |
|
get { return m_SlotType; } |
|
} |
|
|
|
public bool isConnected |
|
{ |
|
get |
|
{ |
|
// node and graph respectivly |
|
if (owner == null || owner.owner == null) |
|
return false; |
|
|
|
var graph = owner.owner; |
|
var edges = graph.GetEdges(slotReference); |
|
return edges.Any(); |
|
} |
|
} |
|
|
|
public abstract bool isDefaultValue { get; } |
|
|
|
public abstract SlotValueType valueType { get; } |
|
|
|
public abstract ConcreteSlotValueType concreteValueType { get; } |
|
|
|
public string shaderOutputName |
|
{ |
|
get { return m_ShaderOutputName; } |
|
private set { m_ShaderOutputName = value; } |
|
} |
|
|
|
public ShaderStageCapability stageCapability |
|
{ |
|
get { return m_StageCapability; } |
|
set { m_StageCapability = value; } |
|
} |
|
|
|
public bool hasError |
|
{ |
|
get { return m_HasError; } |
|
set { m_HasError = value; } |
|
} |
|
|
|
public bool IsUsingDefaultValue() |
|
{ |
|
if (!isConnected && isDefaultValue) |
|
return true; |
|
else |
|
return false; |
|
} |
|
|
|
public bool IsCompatibleWith(MaterialSlot otherSlot) |
|
{ |
|
return otherSlot != null |
|
&& otherSlot.owner != owner |
|
&& otherSlot.isInputSlot != isInputSlot |
|
&& !hidden |
|
&& !otherSlot.hidden |
|
&& ((isInputSlot |
|
? SlotValueHelper.AreCompatible(valueType, otherSlot.concreteValueType, otherSlot.IsConnectionTestable()) |
|
: SlotValueHelper.AreCompatible(otherSlot.valueType, concreteValueType, IsConnectionTestable()))); |
|
} |
|
|
|
public bool IsCompatibleStageWith(MaterialSlot otherSlot) |
|
{ |
|
var startStage = otherSlot.stageCapability; |
|
if (startStage == ShaderStageCapability.All || otherSlot.owner is SubGraphNode) |
|
startStage = NodeUtils.GetEffectiveShaderStageCapability(otherSlot, true) |
|
& NodeUtils.GetEffectiveShaderStageCapability(otherSlot, false); |
|
return startStage == ShaderStageCapability.All || stageCapability == ShaderStageCapability.All || stageCapability == startStage; |
|
} |
|
|
|
public string GetDefaultValue(GenerationMode generationMode, ConcretePrecision concretePrecision) |
|
{ |
|
string defaultValue = GetDefaultValue(generationMode); |
|
return defaultValue.Replace(PrecisionUtil.Token, concretePrecision.ToShaderString()); |
|
} |
|
|
|
public virtual string GetDefaultValue(GenerationMode generationMode) |
|
{ |
|
var matOwner = owner as AbstractMaterialNode; |
|
if (matOwner == null) |
|
throw new Exception(string.Format("Slot {0} either has no owner, or the owner is not a {1}", this, typeof(AbstractMaterialNode))); |
|
|
|
if (generationMode.IsPreview() && matOwner.isActive) |
|
return matOwner.GetVariableNameForSlot(id); |
|
|
|
return ConcreteSlotValueAsVariable(); |
|
} |
|
|
|
protected virtual string ConcreteSlotValueAsVariable() |
|
{ |
|
return "error"; |
|
} |
|
|
|
public abstract void AddDefaultProperty(PropertyCollector properties, GenerationMode generationMode); |
|
|
|
public virtual void GetPreviewProperties(List<PreviewProperty> properties, string name) |
|
{ |
|
properties.Add(default(PreviewProperty)); |
|
} |
|
|
|
public virtual void AppendHLSLParameterDeclaration(ShaderStringBuilder sb, string paramName) |
|
{ |
|
sb.Append(concreteValueType.ToShaderString()); |
|
sb.Append(" "); |
|
sb.Append(paramName); |
|
} |
|
|
|
public abstract void CopyValuesFrom(MaterialSlot foundSlot); |
|
|
|
public bool Equals(MaterialSlot other) |
|
{ |
|
return m_Id == other.m_Id && owner == other.owner; |
|
} |
|
|
|
public override bool Equals(object obj) |
|
{ |
|
if (ReferenceEquals(null, obj)) return false; |
|
if (ReferenceEquals(this, obj)) return true; |
|
if (obj.GetType() != this.GetType()) return false; |
|
return Equals((MaterialSlot)obj); |
|
} |
|
|
|
public override int GetHashCode() |
|
{ |
|
unchecked |
|
{ |
|
return (m_Id * 397) ^ (owner != null ? owner.GetHashCode() : 0); |
|
} |
|
} |
|
|
|
// this tracks old CustomFunctionNode slots that are expecting the old bare resource inputs |
|
// rather than the new structure-based inputs |
|
internal virtual bool bareResource { get { return false; } set { } } |
|
|
|
public virtual void CopyDefaultValue(MaterialSlot other) |
|
{ |
|
m_Id = other.m_Id; |
|
m_DisplayName = other.m_DisplayName; |
|
m_SlotType = other.m_SlotType; |
|
m_Hidden = other.m_Hidden; |
|
m_ShaderOutputName = other.m_ShaderOutputName; |
|
m_StageCapability = other.m_StageCapability; |
|
} |
|
} |
|
}
|
|
|