浏览代码

[Material Graph]Refactoring graph architecture.

/main
Tim Cooper 8 年前
当前提交
418682b1
共有 26 个文件被更改,包括 1444 次插入102 次删除
  1. 10
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/DrawableMaterialNode.cs
  2. 16
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/MaterialGraphDataSource.cs
  3. 12
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/MaterialWindow.cs
  4. 6
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/NodeAnchor.cs
  5. 6
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/NullInputProxy.cs
  6. 26
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Light/BaseLightFunction.cs
  7. 2
      UnityProject/Assets/UnityShaderEditor/Editor/Source/MaterialGraph.cs
  8. 2
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/AddNode.cs
  9. 16
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/Function2Input.cs
  10. 20
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/PixelShaderNode.cs
  11. 8
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/PropertyNode.cs
  12. 34
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/SlotValue.cs
  13. 7
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/Vector4Node.cs
  14. 8
      UnityProject/Assets/UnityShaderEditor/Editor/Source/PixelGraph.cs
  15. 26
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Util/NodeUtils.cs
  16. 8
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Util/ShaderGenerator.cs
  17. 56
      UnityProject/Assets/UnityShaderEditor/Editor/Source/AbstractMaterialGraph.cs
  18. 8
      UnityProject/Assets/UnityShaderEditor/Editor/Source/AbstractMaterialGraph.cs.meta
  19. 709
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/AbstractMaterialNode.cs
  20. 8
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/AbstractMaterialNode.cs.meta
  21. 139
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/MaterialSlot.cs
  22. 12
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/MaterialSlot.cs.meta
  23. 116
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/SerializableNode.cs
  24. 61
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/SerializableSlot.cs
  25. 134
      UnityProject/Assets/UnityShaderEditor/Editor/Source/SerializableGraph.cs
  26. 96
      UnityProject/Assets/UnityShaderEditor/Editor/Source/Util/SerializationHelper.cs

10
UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/DrawableMaterialNode.cs


public sealed class DrawableMaterialNode : CanvasElement
{
private readonly MaterialGraphDataSource m_Data;
public BaseMaterialNode m_Node;
public AbstractMaterialNode m_Node;
public DrawableMaterialNode(BaseMaterialNode node, float width, MaterialGraphDataSource data)
public DrawableMaterialNode(AbstractMaterialNode node, float width, MaterialGraphDataSource data)
{
translation = node.position.min;
scale = new Vector2(width, width);

private bool MarkDirtyIfNeedsTime(CanvasElement element, Event e, Canvas2D parent)
{
var childrenNodes = ListPool<BaseMaterialNode>.Get();
var childrenNodes = ListPool<AbstractMaterialNode>.Get();
ListPool<BaseMaterialNode>.Release(childrenNodes);
ListPool<AbstractMaterialNode>.Release(childrenNodes);
return true;
}

base.Render(parentRect, canvas);
}
public static void RepaintDependentNodes(BaseMaterialNode bmn)
public static void RepaintDependentNodes(AbstractMaterialNode bmn)
{
var dependentNodes = bmn.CollectDependentNodes();
foreach (var node in dependentNodes)

16
UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/MaterialGraphDataSource.cs


foreach (var node in pixelGraph.nodes)
{
// add the nodes
var bmn = node as BaseMaterialNode;
var bmn = node as AbstractMaterialNode;
m_DrawableNodes.Add(new DrawableMaterialNode(bmn, (bmn is PixelShaderNode) ? 600.0f : 200.0f, this));
}

var edges = baseNode.owner.GetEdges(slot);
foreach (var edge in edges)
{
var toNode = baseNode.owner.GetNodeFromGUID(edge.inputSlot.nodeGuid);
var toNode = baseNode.owner.GetNodeFromGuid(edge.inputSlot.nodeGuid);
var toSlot = toNode.FindInputSlot(edge.inputSlot.slotName);
var targetNode = m_DrawableNodes.FirstOrDefault(x => x.m_Node == toNode);
var targetAnchor = (NodeAnchor)targetNode.Children().FirstOrDefault(x => x is NodeAnchor && ((NodeAnchor) x).m_Slot == toSlot);

{
//find the edge
var localEdge = (Edge<NodeAnchor>) e;
var edge = graph.currentGraph.edges.FirstOrDefault(x => graph.currentGraph.GetNodeFromGUID(x.outputSlot.nodeGuid).FindOutputSlot(x.outputSlot.slotName) == localEdge.Left.m_Slot
&& graph.currentGraph.GetNodeFromGUID(x.inputSlot.nodeGuid).FindInputSlot(x.inputSlot.slotName) == localEdge.Right.m_Slot);
var edge = graph.currentGraph.edges.FirstOrDefault(x => graph.currentGraph.GetNodeFromGuid(x.outputSlot.nodeGuid).FindOutputSlot(x.outputSlot.slotName) == localEdge.Left.m_Slot
&& graph.currentGraph.GetNodeFromGuid(x.inputSlot.nodeGuid).FindInputSlot(x.inputSlot.slotName) == localEdge.Right.m_Slot);
Debug.Log("Deleting edge " + edge);
graph.currentGraph.RemoveEdgeNoRevalidate(edge);

Debug.Log("Deleting node " + e + " " + node);
graph.currentGraph.RemoveNodeNoRevalidate(node);
}
graph.currentGraph.RevalidateGraph();
graph.currentGraph.ValidateGraph();
}
public void Connect(NodeAnchor a, NodeAnchor b)

public class FloatingPreview : CanvasElement
{
private BaseMaterialNode m_Node;
private AbstractMaterialNode m_Node;
public FloatingPreview(Rect position, BaseMaterialNode node)
public FloatingPreview(Rect position, AbstractMaterialNode node)
m_Node = node as BaseMaterialNode;
m_Node = node as AbstractMaterialNode;
m_Translation = new Vector2(position.x, position.y);
m_Scale = new Vector3(position.width, position.height, 1);
m_Caps |= Capabilities.Floating | Capabilities.Unselectable;

12
UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/MaterialWindow.cs


if (posObj == null)
return;
BaseMaterialNode node = null;
AbstractMaterialNode node = null;
var constructorInfo = posObj.m_Type.GetConstructor(new[] {typeof(BaseMaterialGraph)});
node = (BaseMaterialNode)constructorInfo.Invoke(new object[] { m_MaterialGraph.currentGraph });
var constructorInfo = posObj.m_Type.GetConstructor(new[] {typeof(AbstractMaterialGraph)});
node = (AbstractMaterialNode)constructorInfo.Invoke(new object[] { m_MaterialGraph.currentGraph });
Debug.LogWarningFormat("Could not construct instance of: {0} as there is no single argument constuctor that takes a BaseMaterialGraph", posObj.m_Type);
Debug.LogWarningFormat("Could not construct instance of: {0} as there is no single argument constuctor that takes a AbstractMaterialGraph", posObj.m_Type);
return;
}

protected bool DoAddNodeMenu(Event @event, Canvas2D parent, Object customData)
{
var gm = new GenericMenu();
foreach (Type type in Assembly.GetAssembly(typeof(BaseMaterialNode)).GetTypes())
foreach (Type type in Assembly.GetAssembly(typeof(AbstractMaterialNode)).GetTypes())
if (type.IsClass && !type.IsAbstract && (type.IsSubclassOf(typeof(BaseMaterialNode))))
if (type.IsClass && !type.IsAbstract && (type.IsSubclassOf(typeof(AbstractMaterialNode))))
{
var attrs = type.GetCustomAttributes(typeof(TitleAttribute), false) as TitleAttribute[];
if (attrs != null && attrs.Length > 0 && CanAddToNodeMenu(type))

6
UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/NodeAnchor.cs


protected object m_Source;
protected Direction m_Direction;
private MaterialGraphDataSource m_Data;
public Slot m_Slot;
public BaseMaterialNode m_Node;
public MaterialSlot m_Slot;
public AbstractMaterialNode m_Node;
public NodeAnchor(Vector3 position, Type type, BaseMaterialNode node, Slot slot, MaterialGraphDataSource data, Direction direction)
public NodeAnchor(Vector3 position, Type type, AbstractMaterialNode node, MaterialSlot slot, MaterialGraphDataSource data, Direction direction)
{
m_Type = type;
scale = new Vector3(15.0f, 15.0f, 1.0f);

6
UnityProject/Assets/UnityShaderEditor/Editor/Source/Drawing/NullInputProxy.cs


{
public class NullInputProxy : CanvasElement
{
private Slot m_InputSlot;
private BaseMaterialNode m_Node;
private MaterialSlot m_InputSlot;
private AbstractMaterialNode m_Node;
public NullInputProxy(BaseMaterialNode node, Slot inputSlot, NodeAnchor nodeAnchor)
public NullInputProxy(AbstractMaterialNode node, MaterialSlot inputSlot, NodeAnchor nodeAnchor)
{
m_InputSlot = inputSlot;
m_Node = node;

26
UnityProject/Assets/UnityShaderEditor/Editor/Source/Light/BaseLightFunction.cs


public override string GetSurfaceOutputStructureName() { return "SurfaceOutputStandard"; }
public override void DoSlotsForConfiguration(PixelShaderNode node)
{
node.AddSlot(new Slot(node, kAlbedoSlotName, kAlbedoSlotName, Slot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new Slot(node, kNormalSlotName, kNormalSlotName, Slot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new Slot(node, kMetallicSlotName, kMetallicSlotName, Slot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new Slot(node, kSmoothnessSlotName, kSmoothnessSlotName, Slot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new Slot(node, kOcclusion, kOcclusion, Slot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new Slot(node, kAlphaSlotName, kAlphaSlotName, Slot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kAlbedoSlotName, kAlbedoSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kNormalSlotName, kNormalSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kMetallicSlotName, kMetallicSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kSmoothnessSlotName, kSmoothnessSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kOcclusion, kOcclusion, MaterialSlot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kAlphaSlotName, kAlphaSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
// clear out slot names that do not match the slots
// we support

public override string GetSurfaceOutputStructureName() { return "SurfaceOutputStandardSpecular"; }
public override void DoSlotsForConfiguration(PixelShaderNode node)
{
node.AddSlot(new Slot(node, kAlbedoSlotName, kAlbedoSlotName, Slot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new Slot(node, kNormalSlotName, kNormalSlotName, Slot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new Slot(node, kSpecularSlotName, kSpecularSlotName, Slot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new Slot(node, kEmissionSlotName, kEmissionSlotName, Slot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new Slot(node, kSmoothnessSlotName, kSmoothnessSlotName, Slot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new Slot(node, kOcclusion, kOcclusion, Slot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new Slot(node, kAlphaSlotName, kAlphaSlotName, Slot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kAlbedoSlotName, kAlbedoSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kNormalSlotName, kNormalSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kSpecularSlotName, kSpecularSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kEmissionSlotName, kEmissionSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector3, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kSmoothnessSlotName, kSmoothnessSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kOcclusion, kOcclusion, MaterialSlot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
node.AddSlot(new MaterialSlot(node, kAlphaSlotName, kAlphaSlotName, MaterialSlot.SlotType.Input, SlotValueType.Vector1, Vector4.zero));
// clear out slot names that do not match the slots
// we support

2
UnityProject/Assets/UnityShaderEditor/Editor/Source/MaterialGraph.cs


get { return m_MaterialOptions; }
}
public BaseMaterialGraph currentGraph
public AbstractMaterialGraph currentGraph
{
get { return m_PixelGraph; }
}

2
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/AddNode.cs


[Title("Math/Add Node")]
public class AddNode : Function2Input, IGeneratesFunction
{
public AddNode(BaseMaterialGraph owner)
public AddNode(AbstractMaterialGraph owner)
: base(owner)
{
name = "AddNode";

16
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/Function2Input.cs


namespace UnityEditor.MaterialGraph
{
public abstract class Function2Input : BaseMaterialNode, IGeneratesBodyCode
public abstract class Function2Input : AbstractMaterialNode, IGeneratesBodyCode
{
public override bool hasPreview
{

protected Function2Input(BaseMaterialGraph owner)
protected Function2Input(AbstractMaterialGraph owner)
: base(owner)
{
AddSlot(GetInputSlot1());

get { return new[] {GetInputSlot1Name(), GetInputSlot2Name(), GetOutputSlotName()}; }
}
protected virtual Slot GetInputSlot1()
protected virtual MaterialSlot GetInputSlot1()
return new Slot(this, GetInputSlot1Name(), GetInputSlot1Name(), Slot.SlotType.Input, SlotValueType.Dynamic, Vector4.zero);
return new MaterialSlot(this, GetInputSlot1Name(), GetInputSlot1Name(), MaterialSlot.SlotType.Input, SlotValueType.Dynamic, Vector4.zero);
protected virtual Slot GetInputSlot2()
protected virtual MaterialSlot GetInputSlot2()
return new Slot(this, GetInputSlot2Name(), GetInputSlot2Name(), Slot.SlotType.Input, SlotValueType.Dynamic, Vector4.zero);
return new MaterialSlot(this, GetInputSlot2Name(), GetInputSlot2Name(), MaterialSlot.SlotType.Input, SlotValueType.Dynamic, Vector4.zero);
protected virtual Slot GetOutputSlot()
protected virtual MaterialSlot GetOutputSlot()
return new Slot(this, GetOutputSlotName(), GetOutputSlotName(), Slot.SlotType.Output, SlotValueType.Dynamic, Vector4.zero);
return new MaterialSlot(this, GetOutputSlotName(), GetOutputSlotName(), MaterialSlot.SlotType.Output, SlotValueType.Dynamic, Vector4.zero);
}
protected virtual string GetInputSlot1Name()

20
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/PixelShaderNode.cs


namespace UnityEditor.MaterialGraph
{
[Serializable]
public class PixelShaderNode : BaseMaterialNode, IGeneratesBodyCode
public class PixelShaderNode : AbstractMaterialNode, IGeneratesBodyCode
{
[SerializeField]
public string m_LightFunctionClassName;

private static List<BaseLightFunction> s_LightFunctions;
public PixelShaderNode(BaseMaterialGraph owner)
public PixelShaderNode(AbstractMaterialGraph owner)
: base(owner)
{
name = "PixelMaster";

var firstPassSlotName = lightFunction.GetFirstPassSlotName();
// do the normal slot first so that it can be used later in the shader :)
var firstPassSlot = FindInputSlot(firstPassSlotName);
var nodes = ListPool<BaseMaterialNode>.Get();
var nodes = ListPool<AbstractMaterialNode>.Get();
CollectChildNodesByExecutionOrder(nodes, firstPassSlot, false);
for (int index = 0; index < nodes.Count; index++)

foreach (var edge in owner.GetEdges(firstPassSlot))
{
var outputRef = edge.outputSlot;
var fromNode = owner.GetNodeFromGUID(outputRef.nodeGuid);
var fromNode = owner.GetNodeFromGuid(outputRef.nodeGuid);
var fromSlot = fromNode.FindOutputSlot(outputRef.slotName);
shaderBody.AddShaderChunk("o." + firstPassSlot.name + " = " + fromNode.GetOutputVariableNameForSlot(fromSlot, generationMode) + ";", true);
}

(node as IGeneratesBodyCode).GenerateNodeCode(shaderBody, generationMode);
}
ListPool<BaseMaterialNode>.Release(nodes);
ListPool<AbstractMaterialNode>.Release(nodes);
foreach (var slot in inputSlots)
{

foreach (var edge in owner.GetEdges(slot))
{
var outputRef = edge.outputSlot;
var fromNode = owner.GetNodeFromGUID(outputRef.nodeGuid);
var fromNode = owner.GetNodeFromGuid(outputRef.nodeGuid);
var fromSlot = fromNode.FindOutputSlot(outputRef.slotName);
shaderBody.AddShaderChunk("o." + slot.name + " = " + fromNode.GetOutputVariableNameForSlot(fromSlot, generationMode) + ";", true);
}

public override string GetOutputVariableNameForSlot(Slot s, GenerationMode generationMode)
public override string GetOutputVariableNameForSlot(MaterialSlot s, GenerationMode generationMode)
{
return GetOutputVariableNameForNode();
}

{
var function = GetLightFunction();
function.DoSlotsForConfiguration(this);
owner.RevalidateGraph();
owner.ValidateGraph();
public override IEnumerable<Slot> GetDrawableInputProxies()
public override IEnumerable<MaterialSlot> GetDrawableInputProxies()
return new List<Slot>();
return new List<MaterialSlot>();
}
public override bool hasPreview

8
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/PropertyNode.cs


namespace UnityEditor.MaterialGraph
{
public abstract class PropertyNode : BaseMaterialNode
public abstract class PropertyNode : AbstractMaterialNode
{
[SerializeField]
public string m_PropertyName;

[SerializeField]
public bool m_Exposed;
public PropertyNode(BaseMaterialGraph owner) : base(owner)
public PropertyNode(AbstractMaterialGraph owner) : base(owner)
{}
public bool exposed

public abstract PreviewProperty GetPreviewProperty();
public override string GetOutputVariableNameForSlot(Slot s, GenerationMode generationMode)
public override string GetOutputVariableNameForSlot(MaterialSlot s, GenerationMode generationMode)
{
return propertyName;
}

var modified = EditorGUI.EndChangeCheck();
if (modified)
{
owner.RevalidateGraph();
owner.ValidateGraph();
}
if (m_Exposed)

34
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/SlotValue.cs


{
/* public static class SlotExtensions
{
public static bool Editable (this Slot slot)
public static bool Editable (this MaterialSlot slot)
var node = slot.node as BaseMaterialNode;
var node = slot.node as AbstractMaterialNode;
if (node == null)
return false;
var properties = node[slot];

}
public static bool Removable (this Slot slot)
public static bool Removable (this MaterialSlot slot)
var node = slot.node as BaseMaterialNode;
var node = slot.node as AbstractMaterialNode;
if (node == null)
return false;
var properties = node[slot];

}
public static bool SupportsDefault (this Slot slot)
public static bool SupportsDefault (this MaterialSlot slot)
var node = slot.node as BaseMaterialNode;
var node = slot.node as AbstractMaterialNode;
if (node == null)
return true;
var properties = node[slot];

}
public static ShaderProperty GetDefaultValue (this Slot slot)
public static ShaderProperty GetDefaultValue (this MaterialSlot slot)
var node = slot.node as BaseMaterialNode;
var node = slot.node as AbstractMaterialNode;
if (node == null)
return null;
var properties = node[slot];

}
public static void SetDefaultValue (this Slot slot, ShaderProperty value)
public static void SetDefaultValue (this MaterialSlot slot, ShaderProperty value)
var node = slot.node as BaseMaterialNode;
var node = slot.node as AbstractMaterialNode;
if (node == null)
return;
var properties = node[slot];

public static SlotProperties GetSlotProperties (this Slot slot)
public static SlotProperties GetSlotProperties (this MaterialSlot slot)
var node = slot.node as BaseMaterialNode;
var node = slot.node as AbstractMaterialNode;
if (node == null)
return null;
int index = node.m_SlotPropertiesIndexes.FindIndex (x => x == slot.name);

}
public static void SetDefaultValueForSlot (this Slot slot, ShaderProperty value)
public static void SetDefaultValueForSlot (this MaterialSlot slot, ShaderProperty value)
var node = slot.node as BaseMaterialNode;
var node = slot.node as AbstractMaterialNode;
if (node == null)
return;
var properties = node[slot];

}
}
public static void SetPropertiesForSlot (this Slot slot, SlotProperties property)
public static void SetPropertiesForSlot (this MaterialSlot slot, SlotProperties property)
var node = slot.node as BaseMaterialNode;
var node = slot.node as AbstractMaterialNode;
if (node == null)
return;
int index = node.m_SlotPropertiesIndexes.FindIndex (x => x == slot.name);

}
}
public static void ClearDefaultValue (this Slot slot)
public static void ClearDefaultValue (this MaterialSlot slot)
{
slot.SetDefaultValueForSlot (null);
}

7
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/Vector4Node.cs


private void InternalValidate()
{
AddSlot(new Slot(this, kOutputSlotName, kOutputSlotName, Slot.SlotType.Output, SlotValueType.Vector4, Vector4.zero));
AddSlot(new MaterialSlot(this, kOutputSlotName, kOutputSlotName, MaterialSlot.SlotType.Output, SlotValueType.Vector4, Vector4.zero));
}
private const string kOutputSlotName = "Value";

public Vector4Node(BaseMaterialGraph owner) : base(owner)
public Vector4Node(AbstractMaterialGraph owner) : base(owner)
{
name = "V4Node";
InternalValidate();

EditorGUI.BeginChangeCheck();
m_Value = EditorGUI.Vector4Field(new Rect(drawArea.x, drawArea.y, drawArea.width, EditorGUIUtility.singleLineHeight), "Value", m_Value);
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(owner.owner);
}
return GUIModificationType.None;
}

8
UnityProject/Assets/UnityShaderEditor/Editor/Source/PixelGraph.cs


namespace UnityEditor.MaterialGraph
{
[Serializable]
public class PixelGraph : BaseMaterialGraph
public class PixelGraph : AbstractMaterialGraph
{
[NonSerialized]
private PixelShaderNode m_PixelMasterNode;

[NonSerialized]
private List<BaseMaterialNode> m_ActiveNodes = new List<BaseMaterialNode>();
public IEnumerable<BaseMaterialNode> activeNodes
private List<AbstractMaterialNode> m_ActiveNodes = new List<AbstractMaterialNode>();
public IEnumerable<AbstractMaterialNode> activeNodes
{
get
{

return null;
var material = pixelMasterNode.previewMaterial;
BaseMaterialNode.UpdateMaterialProperties(pixelMasterNode, material);
AbstractMaterialNode.UpdateMaterialProperties(pixelMasterNode, material);
return material;
}
}

26
UnityProject/Assets/UnityShaderEditor/Editor/Source/Util/NodeUtils.cs


// GetSlotsThatOutputToNodeRecurse returns a list of output slots on from node that
// manage to connect to toNode... they may go via some other nodes to reach there.
// This is done by working backwards from the toNode to the fromNode as graph is one directional
public static List<Slot> GetSlotsThatOutputToNodeRecurse(BaseMaterialNode fromNode, BaseMaterialNode toNode)
public static List<MaterialSlot> GetSlotsThatOutputToNodeRecurse(AbstractMaterialNode fromNode, AbstractMaterialNode toNode)
var foundUsedOutputSlots = new List<Slot>();
var foundUsedOutputSlots = new List<MaterialSlot>();
public static void RecurseNodesToFindValidOutputSlots(BaseMaterialNode fromNode, BaseMaterialNode currentNode, ICollection<Slot> foundUsedOutputSlots)
public static void RecurseNodesToFindValidOutputSlots(AbstractMaterialNode fromNode, AbstractMaterialNode currentNode, ICollection<MaterialSlot> foundUsedOutputSlots)
{
if (fromNode == null || currentNode == null)
{

var validSlots = ListPool<Slot>.Get();
var validSlots = ListPool<MaterialSlot>.Get();
validSlots.AddRange(currentNode.inputSlots);
for (int index = 0; index < validSlots.Count; index++)
{

{
var outputNode = currentNode.owner.GetNodeFromGUID(edge.outputSlot.nodeGuid);
var outputNode = currentNode.owner.GetNodeFromGuid(edge.outputSlot.nodeGuid);
var outputSlot = outputNode.FindOutputSlot(edge.outputSlot.slotName);
if (outputNode == fromNode && !foundUsedOutputSlots.Contains(outputSlot))
foundUsedOutputSlots.Add(outputSlot);

}
ListPool<Slot>.Release(validSlots);
ListPool<MaterialSlot>.Release(validSlots);
public static void CollectChildNodesByExecutionOrder(ICollection<BaseMaterialNode> nodeList, BaseMaterialNode node, Slot slotToUse)
public static void CollectChildNodesByExecutionOrder(ICollection<AbstractMaterialNode> nodeList, AbstractMaterialNode node, MaterialSlot slotToUse)
{
if (node == null)
return;

var validSlots = ListPool<Slot>.Get();
var validSlots = ListPool<MaterialSlot>.Get();
ListPool<Slot>.Release(validSlots);
ListPool<MaterialSlot>.Release(validSlots);
return;
}

var edges = node.owner.GetEdges(slot);
foreach (var edge in edges)
{
var outputNode = node.owner.GetNodeFromGUID(edge.outputSlot.nodeGuid);
var outputNode = node.owner.GetNodeFromGuid(edge.outputSlot.nodeGuid);
ListPool<Slot>.Release(validSlots);
ListPool<MaterialSlot>.Release(validSlots);
public static void CollectDependentNodes(ICollection<BaseMaterialNode> nodeList, BaseMaterialNode node)
public static void CollectDependentNodes(ICollection<AbstractMaterialNode> nodeList, AbstractMaterialNode node)
{
if (node == null)
return;

{
foreach (var edge in node.owner.GetEdges(slot))
{
var inputNode = node.owner.GetNodeFromGUID(edge.inputSlot.nodeGuid);
var inputNode = node.owner.GetNodeFromGuid(edge.inputSlot.nodeGuid);
CollectDependentNodes(nodeList, inputNode);
}
}

8
UnityProject/Assets/UnityShaderEditor/Editor/Source/Util/ShaderGenerator.cs


}
private const string kErrorString = @"ERROR!";
public static string AdaptNodeOutput(BaseMaterialNode node, Slot outputSlot, GenerationMode mode, ConcreteSlotValueType convertToType, bool textureSampleUVHack = false)
public static string AdaptNodeOutput(AbstractMaterialNode node, MaterialSlot outputSlot, GenerationMode mode, ConcreteSlotValueType convertToType, bool textureSampleUVHack = false)
{
if (outputSlot == null)
return kErrorString;

}
}
private static string AdaptNodeOutputForPreview(BaseMaterialNode node, Slot outputSlot, GenerationMode mode, ConcreteSlotValueType convertToType)
private static string AdaptNodeOutputForPreview(AbstractMaterialNode node, MaterialSlot outputSlot, GenerationMode mode, ConcreteSlotValueType convertToType)
{
if (outputSlot == null)
return kErrorString;

}
}
public static string GeneratePreviewShader(BaseMaterialNode node, out PreviewMode generatedShaderMode)
public static string GeneratePreviewShader(AbstractMaterialNode node, out PreviewMode generatedShaderMode)
var activeNodeList = ListPool<BaseMaterialNode>.Get();
var activeNodeList = ListPool<AbstractMaterialNode>.Get();
node.CollectChildNodesByExecutionOrder(activeNodeList);
var generationMode = GenerationMode.Preview2D;
generatedShaderMode = PreviewMode.Preview2D;

56
UnityProject/Assets/UnityShaderEditor/Editor/Source/AbstractMaterialGraph.cs


using System;
using System.Collections.Generic;
using System.Linq;
namespace UnityEditor.MaterialGraph
{
[Serializable]
public abstract class AbstractMaterialGraph : SerializableGraph
{
private PreviewRenderUtility m_PreviewUtility;
private MaterialGraph m_Owner;
protected AbstractMaterialGraph(MaterialGraph owner)
{
m_Owner = owner;
}
public MaterialGraph owner
{
get { return m_Owner; }
}
public IEnumerable<AbstractMaterialNode> materialNodes
{
get { return nodes.Where(x => x is AbstractMaterialNode).Cast<AbstractMaterialNode>(); }
}
public PreviewRenderUtility previewUtility
{
get
{
if (m_PreviewUtility == null)
{
m_PreviewUtility = new PreviewRenderUtility();
// EditorUtility.SetCameraAnimateMaterials(m_PreviewUtility.m_Camera, true);
}
return m_PreviewUtility;
}
}
public bool requiresRepaint
{
get { return nodes.Any(x => x is IRequiresTime); }
}
public override void ValidateGraph()
{
base.ValidateGraph();
foreach (var node in materialNodes)
node.ValidateNode();
}
}
}

8
UnityProject/Assets/UnityShaderEditor/Editor/Source/AbstractMaterialGraph.cs.meta


fileFormatVersion: 2
guid: 6567c9f37c0aaa94e9083ffc63612ecf
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

709
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/AbstractMaterialNode.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditorInternal;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityEditor.MaterialGraph
{
[Serializable]
public abstract class AbstractMaterialNode : SerializableNode, IGenerateProperties
{
private static readonly Mesh[] s_Meshes = {null, null, null, null};
[SerializeField]
private DrawMode m_DrawMode = DrawMode.Full;
protected PreviewMode m_GeneratedShaderMode = PreviewMode.Preview2D;
[NonSerialized]
private bool m_HasError;
[SerializeField]
private string m_LastShader;
[NonSerialized]
private Material m_PreviewMaterial;
[NonSerialized]
private Shader m_PreviewShader;
public NeedsRepaint onNeedsRepaint;
protected AbstractMaterialNode(AbstractMaterialGraph theOwner) : base(theOwner)
{}
public string precision
{
get { return "half"; }
}
public string[] m_PrecisionNames = { "half" };
// Nodes that want to have a preview area can override this and return true
public virtual bool hasPreview
{
get { return false; }
}
public virtual PreviewMode previewMode
{
get { return PreviewMode.Preview2D; }
}
public DrawMode drawMode
{
get { return m_DrawMode; }
set { m_DrawMode = value; }
}
protected virtual bool generateDefaultInputs
{
get { return true; }
}
public Material previewMaterial
{
get
{
if (m_PreviewMaterial == null)
{
m_PreviewMaterial = new Material(m_PreviewShader) {hideFlags = HideFlags.HideInHierarchy};
m_PreviewMaterial.hideFlags = HideFlags.HideInHierarchy;
}
return m_PreviewMaterial;
}
}
public bool hasError
{
get
{
return m_HasError;
}
protected set
{
if (m_HasError != value)
{
m_HasError = value;
ExecuteRepaint();
}
}
}
public virtual void GeneratePropertyBlock(PropertyGenerator visitor, GenerationMode generationMode)
{}
public virtual void GeneratePropertyUsages(ShaderGenerator visitor, GenerationMode generationMode, ConcreteSlotValueType slotValueType)
{
if (!generateDefaultInputs)
return;
if (!generationMode.IsPreview())
return;
foreach (var inputSlot in inputSlots)
{
var edges = owner.GetEdges(inputSlot);
if (edges.Any())
continue;
inputSlot.GeneratePropertyUsages(visitor, generationMode, inputSlot.concreteValueType, this);
}
}
protected virtual void OnPreviewGUI()
{
if (!ShaderUtil.hardwareSupportsRectRenderTexture)
return;
GUILayout.BeginHorizontal(GUILayout.MinWidth(previewWidth + 10), GUILayout.MinWidth(previewHeight + 10));
GUILayout.FlexibleSpace();
var rect = GUILayoutUtility.GetRect(previewWidth, previewHeight, GUILayout.ExpandWidth(false));
var preview = RenderPreview(rect);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GL.sRGBWrite = QualitySettings.activeColorSpace == ColorSpace.Linear;
GUI.DrawTexture(rect, preview, ScaleMode.StretchToFill, false);
GL.sRGBWrite = false;
}
public MaterialSlot FindInputSlot(string name)
{
var slot = m_Slots.FirstOrDefault(x => x.isInputSlot && x.name == name);
if (slot == null)
Debug.LogError("Input MaterialSlot: " + name + " could be found on node " + GetOutputVariableNameForNode());
return slot;
}
public MaterialSlot FindOutputSlot(string name)
{
var slot = m_Slots.FirstOrDefault(x => x.isOutputSlot && x.name == name);
if (slot == null)
Debug.LogError("Output MaterialSlot: " + name + " could be found on node " + GetOutputVariableNameForNode());
return slot;
}
protected string GetSlotValue(MaterialSlot inputSlot, GenerationMode generationMode)
{
var edges = owner.GetEdges(inputSlot).ToArray();
if (edges.Length > 0)
{
var fromSocketRef = edges[0].outputSlot;
var fromNode = owner.GetNodeFromGuid(fromSocketRef.nodeGuid);
var slot = fromNode.FindOutputSlot(fromSocketRef.slotName);
return ShaderGenerator.AdaptNodeOutput(this, slot, generationMode, inputSlot.concreteValueType);
}
return inputSlot.GetDefaultValue(generationMode, inputSlot.concreteValueType, this);
}
public void RemoveSlotsNameNotMatching(string[] slotNames)
{
var invalidSlots = m_Slots.Select(x => x.name).Except(slotNames);
foreach (var invalidSlot in invalidSlots.ToList())
{
Debug.LogWarningFormat("Removing Invalid MaterialSlot: {0}", invalidSlot);
RemoveSlot(invalidSlot);
}
}
private ConcreteSlotValueType FindCommonChannelType(ConcreteSlotValueType @from, ConcreteSlotValueType to)
{
if (ImplicitConversionExists(@from, to))
return to;
return ConcreteSlotValueType.Error;
}
private static ConcreteSlotValueType ToConcreteType(SlotValueType svt)
{
switch (svt)
{
case SlotValueType.Vector1:
return ConcreteSlotValueType.Vector1;
case SlotValueType.Vector2:
return ConcreteSlotValueType.Vector2;
case SlotValueType.Vector3:
return ConcreteSlotValueType.Vector3;
case SlotValueType.Vector4:
return ConcreteSlotValueType.Vector4;
}
return ConcreteSlotValueType.Error;
}
private static bool ImplicitConversionExists(ConcreteSlotValueType from, ConcreteSlotValueType to)
{
return from >= to || from == ConcreteSlotValueType.Vector1;
}
protected virtual ConcreteSlotValueType ConvertDynamicInputTypeToConcrete(IEnumerable<ConcreteSlotValueType> inputTypes)
{
var concreteSlotValueTypes = inputTypes as IList<ConcreteSlotValueType> ?? inputTypes.ToList();
if (concreteSlotValueTypes.Any(x => x == ConcreteSlotValueType.Error))
return ConcreteSlotValueType.Error;
var inputTypesDistinct = concreteSlotValueTypes.Distinct().ToList();
switch (inputTypesDistinct.Count)
{
case 0:
return ConcreteSlotValueType.Vector1;
case 1:
return inputTypesDistinct.FirstOrDefault();
default:
// find the 'minumum' channel width excluding 1 as it can promote
inputTypesDistinct.RemoveAll(x => x == ConcreteSlotValueType.Vector1);
var ordered = inputTypesDistinct.OrderBy(x => x);
if (ordered.Any())
return ordered.FirstOrDefault();
break;
}
return ConcreteSlotValueType.Error;
}
public void ValidateNode()
{
var isInError = false;
// all children nodes needs to be updated first
// so do that here
foreach (var inputSlot in inputSlots)
{
var edges = owner.GetEdges(inputSlot);
foreach (var edge in edges)
{
var fromSocketRef = edge.outputSlot;
var outputNode = owner.GetNodeFromGuid(fromSocketRef.nodeGuid);
outputNode.ValidateNode();
if (outputNode.hasError)
isInError = true;
}
}
var dynamicInputSlotsToCompare = new Dictionary<MaterialSlot, ConcreteSlotValueType>();
var skippedDynamicSlots = new List<MaterialSlot>();
// iterate the input slots
foreach (var inputSlot in inputSlots)
{
var inputType = inputSlot.valueType;
// if there is a connection
var edges = owner.GetEdges(inputSlot).ToList();
if (!edges.Any())
{
if (inputType != SlotValueType.Dynamic)
inputSlot.concreteValueType = ToConcreteType(inputType);
else
skippedDynamicSlots.Add(inputSlot);
continue;
}
// get the output details
var outputSlotRef = edges[0].outputSlot;
var outputNode = owner.GetNodeFromGuid(outputSlotRef.nodeGuid);
var outputSlot = outputNode.FindOutputSlot(outputSlotRef.slotName);
var outputConcreteType = outputSlot.concreteValueType;
// if we have a standard connection... just check the types work!
if (inputType != SlotValueType.Dynamic)
{
var inputConcreteType = ToConcreteType(inputType);
inputSlot.concreteValueType = FindCommonChannelType(outputConcreteType, inputConcreteType);
continue;
}
// dynamic input... depends on output from other node.
// we need to compare ALL dynamic inputs to make sure they
// are compatable.
dynamicInputSlotsToCompare.Add(inputSlot, outputConcreteType);
}
// we can now figure out the dynamic slotType
// from here set all the
var dynamicType = ConvertDynamicInputTypeToConcrete(dynamicInputSlotsToCompare.Values);
foreach (var dynamicKvP in dynamicInputSlotsToCompare)
dynamicKvP.Key.concreteValueType= dynamicType;
foreach (var skippedSlot in skippedDynamicSlots)
skippedSlot.concreteValueType = dynamicType;
var inputError = inputSlots.Any(x => x.concreteValueType == ConcreteSlotValueType.Error);
// configure the output slots now
// their slotType will either be the default output slotType
// or the above dynanic slotType for dynamic nodes
// or error if there is an input error
foreach (var outputSlot in outputSlots)
{
if (inputError)
{
outputSlot.concreteValueType = ConcreteSlotValueType.Error;
continue;
}
if (outputSlot.valueType == SlotValueType.Dynamic)
{
outputSlot.concreteValueType = dynamicType;
continue;
}
outputSlot.concreteValueType = ToConcreteType(outputSlot.valueType);
}
isInError |= inputError;
isInError |= outputSlots.Any(x => x.concreteValueType == ConcreteSlotValueType.Error);
isInError |= CalculateNodeHasError();
hasError = isInError;
if (!hasError)
{
previewShaderNeedsUpdate = true;
}
}
public bool previewShaderNeedsUpdate { get; set; }
//True if error
protected virtual bool CalculateNodeHasError()
{
return false;
}
public static string ConvertConcreteSlotValueTypeToString(ConcreteSlotValueType slotValue)
{
switch (slotValue)
{
case ConcreteSlotValueType.Vector1:
return string.Empty;
case ConcreteSlotValueType.Vector2:
return "2";
case ConcreteSlotValueType.Vector3:
return "3";
case ConcreteSlotValueType.Vector4:
return "4";
default:
return "Error";
}
}
public virtual bool OnGUI()
{
GUILayout.Label("MaterialSlot Defaults", EditorStyles.boldLabel);
var modified = false;
foreach (var slot in inputSlots)
{
if (!owner.GetEdges(slot).Any())
modified |= DoSlotUI(this, slot);
}
return modified;
}
public static bool DoSlotUI(AbstractMaterialNode node, MaterialSlot slot)
{
GUILayout.BeginHorizontal( /*EditorStyles.inspectorBig*/);
GUILayout.BeginVertical();
GUILayout.BeginHorizontal();
GUILayout.Label("MaterialSlot " + slot.name, EditorStyles.largeLabel);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndVertical();
GUILayout.EndHorizontal();
return slot.OnGUI();
}
public virtual bool DrawSlotDefaultInput(Rect rect, MaterialSlot inputSlot)
{
var inputSlotType = inputSlot.concreteValueType;
return inputSlot.OnGUI(rect, inputSlotType);
}
public virtual IEnumerable<MaterialSlot> GetDrawableInputProxies()
{
return inputSlots.Where(x => !owner.GetEdges(x).Any());
}
public void ExecuteRepaint()
{
if (onNeedsRepaint != null)
onNeedsRepaint();
}
// CollectDependentNodes looks at the current node and calculates
// which nodes further up the tree (parents) would be effected if this node was changed
// it also includes itself in this list
public IEnumerable<AbstractMaterialNode> CollectDependentNodes()
{
var nodeList = new List<AbstractMaterialNode>();
NodeUtils.CollectDependentNodes(nodeList, this);
return nodeList;
}
// CollectDependentNodes looks at the current node and calculates
// which child nodes it depends on for it's calculation.
// Results are returned depth first so by processing each node in
// order you can generate a valid code block.
public List<AbstractMaterialNode> CollectChildNodesByExecutionOrder(List<AbstractMaterialNode> nodeList, MaterialSlot slotToUse = null, bool includeSelf = true)
{
if (slotToUse != null && !m_Slots.Contains(slotToUse))
{
Debug.LogError("Attempting to collect nodes by execution order with an invalid MaterialSlot on: " + name);
return nodeList;
}
NodeUtils.CollectChildNodesByExecutionOrder(nodeList, this, slotToUse);
if (!includeSelf)
nodeList.Remove(this);
return nodeList;
}
protected virtual bool UpdatePreviewShader()
{
if (hasError)
return false;
var resultShader = ShaderGenerator.GeneratePreviewShader(this, out m_GeneratedShaderMode);
return InternalUpdatePreviewShader(resultShader);
}
private static bool ShaderHasError(Shader shader)
{
var hasErrorsCall = typeof(ShaderUtil).GetMethod("GetShaderErrorCount", BindingFlags.Static | BindingFlags.NonPublic);
var result = hasErrorsCall.Invoke(null, new object[] {shader});
return (int) result != 0;
}
protected bool InternalUpdatePreviewShader(string resultShader)
{
MaterialWindow.DebugMaterialGraph("RecreateShaderAndMaterial : " + name + "_" + guid.ToString().Replace("-","_") + "\n" + resultShader);
// workaround for some internal shader compiler weirdness
// if we are in error we sometimes to not properly clean
// clean out the error flags and will stay in error, even
// if we are now valid
if (m_PreviewShader && ShaderHasError(m_PreviewShader))
{
Object.DestroyImmediate(m_PreviewShader, true);
Object.DestroyImmediate(m_PreviewMaterial, true);
m_PreviewShader = null;
m_PreviewMaterial = null;
}
if (m_PreviewShader == null)
{
m_PreviewShader = ShaderUtil.CreateShaderAsset(resultShader);
m_PreviewShader.hideFlags = HideFlags.HideInHierarchy;
m_LastShader = resultShader;
}
else
{
if (string.CompareOrdinal(resultShader, m_LastShader) != 0)
{
ShaderUtil.UpdateShaderAsset(m_PreviewShader, resultShader);
m_LastShader = resultShader;
}
}
return !ShaderHasError(m_PreviewShader);
}
/// <summary>
/// RenderPreview gets called in OnPreviewGUI. Nodes can override
/// RenderPreview and do their own rendering to the render texture
/// </summary>
public Texture RenderPreview(Rect targetSize)
{
if (hasError)
return null;
if (previewShaderNeedsUpdate)
{
UpdatePreviewShader();
previewShaderNeedsUpdate = false;
}
UpdatePreviewProperties();
if (s_Meshes[0] == null)
{
var handleGo = (GameObject) EditorGUIUtility.LoadRequired("Previews/PreviewMaterials.fbx");
// @TODO: temp workaround to make it not render in the scene
handleGo.SetActive(false);
foreach (Transform t in handleGo.transform)
{
switch (t.name)
{
case "sphere":
s_Meshes[0] = ((MeshFilter) t.GetComponent("MeshFilter")).sharedMesh;
break;
case "cube":
s_Meshes[1] = ((MeshFilter) t.GetComponent("MeshFilter")).sharedMesh;
break;
case "cylinder":
s_Meshes[2] = ((MeshFilter) t.GetComponent("MeshFilter")).sharedMesh;
break;
case "torus":
s_Meshes[3] = ((MeshFilter) t.GetComponent("MeshFilter")).sharedMesh;
break;
default:
Debug.Log("Something is wrong, weird object found: " + t.name);
break;
}
}
}
var previewUtil = owner.previewUtility;
previewUtil.BeginPreview(targetSize, GUIStyle.none);
if (m_GeneratedShaderMode == PreviewMode.Preview3D)
{
previewUtil.m_Camera.transform.position = -Vector3.forward * 5;
previewUtil.m_Camera.transform.rotation = Quaternion.identity;
EditorUtility.SetCameraAnimateMaterialsTime(previewUtil.m_Camera, Time.realtimeSinceStartup);
var amb = new Color(.2f, .2f, .2f, 0);
previewUtil.m_Light[0].intensity = 1.0f;
previewUtil.m_Light[0].transform.rotation = Quaternion.Euler(50f, 50f, 0);
previewUtil.m_Light[1].intensity = 1.0f;
InternalEditorUtility.SetCustomLighting(previewUtil.m_Light, amb);
previewUtil.DrawMesh(s_Meshes[0], Vector3.zero, Quaternion.Euler(-20, 0, 0) * Quaternion.Euler(0, 0, 0), previewMaterial, 0);
var oldFog = RenderSettings.fog;
Unsupported.SetRenderSettingsUseFogNoDirty(false);
previewUtil.m_Camera.Render();
Unsupported.SetRenderSettingsUseFogNoDirty(oldFog);
InternalEditorUtility.RemoveCustomLighting();
}
else
{
EditorUtility.UpdateGlobalShaderProperties(Time.realtimeSinceStartup);
Graphics.Blit(null, previewMaterial);
}
return previewUtil.EndPreview();
}
private static void SetPreviewMaterialProperty(PreviewProperty previewProperty, Material mat)
{
switch (previewProperty.m_PropType)
{
case PropertyType.Texture2D:
mat.SetTexture(previewProperty.m_Name, previewProperty.m_Texture);
break;
case PropertyType.Color:
mat.SetColor(previewProperty.m_Name, previewProperty.m_Color);
break;
case PropertyType.Vector2:
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4);
break;
case PropertyType.Vector3:
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4);
break;
case PropertyType.Vector4:
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4);
break;
case PropertyType.Float:
mat.SetFloat(previewProperty.m_Name, previewProperty.m_Float);
break;
}
}
protected virtual void CollectPreviewMaterialProperties(List<PreviewProperty> properties)
{
var validSlots = inputSlots.ToArray();
for (var index = 0; index < validSlots.Length; index++)
{
var s = validSlots[index];
var edges = owner.GetEdges(s);
if (edges.Any())
continue;
var pp = new PreviewProperty
{
m_Name = s.GetInputName(this),
m_PropType = PropertyType.Vector4,
m_Vector4 = s.currentValue
};
properties.Add(pp);
}
}
public static void UpdateMaterialProperties(AbstractMaterialNode target, Material material)
{
var childNodes = ListPool<AbstractMaterialNode>.Get();
target.CollectChildNodesByExecutionOrder(childNodes);
var pList = ListPool<PreviewProperty>.Get();
for (var index = 0; index < childNodes.Count; index++)
{
var node = childNodes[index];
node.CollectPreviewMaterialProperties(pList);
}
foreach (var prop in pList)
SetPreviewMaterialProperty(prop, material);
ListPool<AbstractMaterialNode>.Release(childNodes);
ListPool<PreviewProperty>.Release(pList);
}
public void UpdatePreviewProperties()
{
if (!hasPreview)
return;
UpdateMaterialProperties(this, previewMaterial);
}
public virtual string GetOutputVariableNameForSlot(MaterialSlot s, GenerationMode generationMode)
{
if (s.isInputSlot) Debug.LogError("Attempting to use input MaterialSlot (" + s + ") for output!");
if (!m_Slots.Contains(s)) Debug.LogError("Attempting to use MaterialSlot (" + s + ") for output on a node that does not have this MaterialSlot!");
return GetOutputVariableNameForNode() + "_" + s.name;
}
public virtual string GetOutputVariableNameForNode()
{
return name + "_" + guid.ToString().Replace("-", "_");
}
public virtual Vector4 GetNewSlotDefaultValue(SlotValueType type)
{
return Vector4.one;
}
public void AddSlot(MaterialSlot slot)
{
if (slot == null)
return;
// new MaterialSlot, just add it, we cool
if (!m_Slots.Contains(slot))
{
m_Slots.Add(slot);
return;
}
// old MaterialSlot found
// update the default value, and the slotType!
var foundSlots = m_Slots.FindAll(x => x.name == slot.name);
// if we are in a bad state (> 1 MaterialSlot with same name, just reset).
if (foundSlots.Count > 1)
{
Debug.LogWarningFormat("Node {0} has more than one MaterialSlot with the same name, removing.");
foundSlots.ForEach(x => m_Slots.Remove(x));
m_Slots.Add(slot);
return;
}
var foundSlot = foundSlots[0];
// if the defualt and current are the same, change the current
// to the new default.
if (foundSlot.defaultValue == foundSlot.currentValue)
foundSlot.currentValue = slot.defaultValue;
foundSlot.defaultValue = slot.defaultValue;
foundSlot.valueType = slot.valueType;
}
public void RemoveSlot(string name)
{
m_Slots.RemoveAll(x => x.name == name);
}
public string GenerateSlotName(SerializableSlot.SlotType type)
{
var slotsToCheck = type == SerializableSlot.SlotType.Input ? inputSlots.ToArray() : outputSlots.ToArray();
var format = type == SerializableSlot.SlotType.Input ? "I{0:00}" : "O{0:00}";
var index = slotsToCheck.Count();
var slotName = string.Format(format, index);
if (slotsToCheck.All(x => x.name != slotName))
return slotName;
index = 0;
do
{
slotName = string.Format(format, index++);
} while (slotsToCheck.Any(x => x.name == slotName));
return slotName;
}
}
public enum GUIModificationType
{
None,
Repaint,
ModelChanged
}
}

8
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/AbstractMaterialNode.cs.meta


fileFormatVersion: 2
guid: a4da4d7c02dcbdd4f9ef2d3b1106879a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

139
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/MaterialSlot.cs


using System;
using UnityEngine;
namespace UnityEditor.MaterialGraph
{
[Serializable]
public class MaterialSlot : SerializableSlot
{
[SerializeField]
private SlotValueType m_ValueType;
[SerializeField]
private Vector4 m_DefaultValue;
[SerializeField]
private Vector4 m_CurrentValue;
[SerializeField]
private ConcreteSlotValueType m_ConcreteValueType;
public MaterialSlot(AbstractMaterialNode owner, string name, string displayName, SlotType slotType, SlotValueType valueType, Vector4 defaultValue)
: base(owner, name, displayName, slotType)
{
m_ValueType = valueType;
m_DefaultValue = defaultValue;
m_CurrentValue = defaultValue;
}
internal MaterialSlot (AbstractMaterialNode owner) : base (owner)
{ }
public Vector4 defaultValue
{
get { return m_DefaultValue; }
set { m_DefaultValue = value; }
}
public SlotValueType valueType
{
get { return m_ValueType; }
set { m_ValueType = value; }
}
public Vector4 currentValue
{
get { return m_CurrentValue; }
set { m_CurrentValue = value; }
}
public ConcreteSlotValueType concreteValueType
{
get { return m_ConcreteValueType; }
set { m_ConcreteValueType = value; }
}
public string GetInputName (AbstractMaterialNode node)
{
return string.Format( "{0}_{1}", node.name, name);
}
public void GeneratePropertyUsages(ShaderGenerator visitor, GenerationMode generationMode, ConcreteSlotValueType slotValueType, AbstractMaterialNode owner)
{
if (!generationMode.IsPreview())
return;
visitor.AddShaderChunk("float" + AbstractMaterialNode.ConvertConcreteSlotValueTypeToString(slotValueType) + " " + GetInputName(owner) + ";", true);
}
public string GetDefaultValue(GenerationMode generationMode, ConcreteSlotValueType slotValueType, AbstractMaterialNode owner)
{
if (generationMode.IsPreview())
return GetInputName(owner);
switch (slotValueType)
{
case ConcreteSlotValueType.Vector1:
return m_CurrentValue.x.ToString();
case ConcreteSlotValueType.Vector2:
return "half2 (" + m_CurrentValue.x + "," + m_CurrentValue.y + ")";
case ConcreteSlotValueType.Vector3:
return "half3 (" + m_CurrentValue.x + "," + m_CurrentValue.y + "," + m_CurrentValue.z + ")";
case ConcreteSlotValueType.Vector4:
return "half4 (" + m_CurrentValue.x + "," + m_CurrentValue.y + "," + m_CurrentValue.z + "," + m_CurrentValue.w + ")";
default:
return "error";
}
}
public bool OnGUI()
{
EditorGUI.BeginChangeCheck();
m_CurrentValue = EditorGUILayout.Vector4Field("Value", m_CurrentValue);
return EditorGUI.EndChangeCheck();
}
public bool OnGUI(Rect rect, ConcreteSlotValueType inputSlotType)
{
EditorGUI.BeginChangeCheck();
var rectXmax = rect.xMax;
switch (inputSlotType)
{
case ConcreteSlotValueType.Vector1:
rect.x = rectXmax - 50;
rect.width = 50;
EditorGUIUtility.labelWidth = 15;
EditorGUI.DrawRect(rect, new Color(0.0f, 0.0f, 0.0f, 0.7f));
m_CurrentValue.x = EditorGUI.FloatField(rect, "X", m_CurrentValue.x);
break;
case ConcreteSlotValueType.Vector2:
rect.x = rectXmax - 90;
rect.width = 90;
EditorGUI.DrawRect(rect, new Color(0.0f, 0.0f, 0.0f, 0.7f));
var result2 = new Vector4(m_CurrentValue.x, m_CurrentValue.y);
result2 = EditorGUI.Vector2Field(rect, GUIContent.none, result2);
m_CurrentValue.x = result2.x;
m_CurrentValue.y = result2.y;
break;
case ConcreteSlotValueType.Vector3:
rect.x = rectXmax - 140;
rect.width = 140;
EditorGUI.DrawRect(rect, new Color(0.0f, 0.0f, 0.0f, 0.7f));
var result3 = new Vector3(m_CurrentValue.x, m_CurrentValue.y, m_CurrentValue.z);
result3 = EditorGUI.Vector3Field(rect, GUIContent.none, result3);
m_CurrentValue.x = result3.x;
m_CurrentValue.y = result3.y;
m_CurrentValue.z = result3.z;
break;
default:
rect.x = rectXmax - 190;
rect.width = 190;
EditorGUI.DrawRect(rect, new Color(0.0f, 0.0f, 0.0f, 0.7f));
m_CurrentValue = EditorGUI.Vector4Field(rect, GUIContent.none, m_CurrentValue);
break;
}
return EditorGUI.EndChangeCheck();
}
}
}

12
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/MaterialSlot.cs.meta


fileFormatVersion: 2
guid: 7d998d7fbd75b97459f63fb4931d14b5
timeCreated: 1463560120
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

116
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/SerializableNode.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UnityEditor.MaterialGraph
{
[Serializable]
public class SerializableNode : ISerializationCallbackReceiver
{
public delegate void NeedsRepaint();
private const int kPreviewWidth = 64;
private const int kPreviewHeight = 64;
[NonSerialized]
private Guid m_Guid;
[SerializeField]
private string m_GuidSerialized;
[SerializeField]
private string m_Name;
[SerializeField]
private Rect m_Position;
[NonSerialized]
private List<SerializableSlot> m_Slots = new List<SerializableSlot>();
[SerializeField]
List<SerializationHelper.JSONSerializedElement> m_SerializableSlots = new List<SerializationHelper.JSONSerializedElement>();
public SerializableGraph owner { get; set; }
public Guid guid
{
get { return m_Guid; }
}
public string name
{
get { return m_Name; }
set { m_Name = value; }
}
public virtual bool canDeleteNode
{
get { return true; }
}
protected virtual int previewWidth
{
get { return kPreviewWidth; }
}
protected virtual int previewHeight
{
get { return kPreviewHeight; }
}
public Rect position
{
get { return m_Position; }
set { m_Position = value; }
}
public IEnumerable<SerializableSlot> inputSlots
{
get { return m_Slots.Where(x => x.isInputSlot); }
}
public IEnumerable<SerializableSlot> outputSlots
{
get { return m_Slots.Where(x => x.isOutputSlot); }
}
public IEnumerable<SerializableSlot> slots
{
get { return m_Slots; }
}
public SerializableNode(SerializableGraph theOwner)
{
owner = theOwner;
m_Guid = Guid.NewGuid();
}
public virtual float GetNodeUIHeight(float width)
{
return 0;
}
public virtual GUIModificationType NodeUI(Rect drawArea)
{
return GUIModificationType.None;
}
public virtual void OnBeforeSerialize()
{
m_GuidSerialized = m_Guid.ToString();
m_SerializableSlots = SerializationHelper.Serialize(m_Slots);
}
public virtual void OnAfterDeserialize()
{
if (!string.IsNullOrEmpty(m_GuidSerialized))
m_Guid = new Guid(m_GuidSerialized);
else
m_Guid = Guid.NewGuid();
m_Slots = SerializationHelper.Deserialize<SerializableSlot>(m_SerializableSlots, new object[] { this });
m_SerializableSlots = null;
}
}
}

61
UnityProject/Assets/UnityShaderEditor/Editor/Source/Nodes/SerializableSlot.cs


using System;
using UnityEngine;
namespace UnityEditor.MaterialGraph
{
[Serializable]
public class SerializableSlot
{
private const string kNotInit = "Not Initilaized";
public enum SlotType
{
Input,
Output
}
[SerializeField]
private string m_Name = kNotInit;
[SerializeField]
private string m_DisplayName = kNotInit;
[SerializeField]
private SlotType m_SlotType;
public SerializableNode owner { get; set; }
public string name
{
get { return m_Name; }
}
public string displayName
{
get { return m_DisplayName; }
}
public bool isInputSlot
{
get { return m_SlotType == SlotType.Input; }
}
public bool isOutputSlot
{
get { return m_SlotType == SlotType.Output; }
}
public SerializableSlot(SerializableNode theOwner, string name, string displayName, SlotType slotType)
{
owner = theOwner;
m_Name = name;
m_DisplayName = displayName;
m_SlotType = slotType;
}
// used via reflection / serialization after deserialize
internal SerializableSlot(SerializableNode theOwner)
{
owner = theOwner;
}
}
}

134
UnityProject/Assets/UnityShaderEditor/Editor/Source/SerializableGraph.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UnityEditor.MaterialGraph
{
[Serializable]
public class SerializableGraph : ISerializationCallbackReceiver
{
[SerializeField]
private List<Edge> m_Edges = new List<Edge>();
[NonSerialized]
private List<SerializableNode> m_Nodes = new List<SerializableNode>();
[SerializeField]
List<SerializationHelper.JSONSerializedElement> m_SerializableNodes = new List<SerializationHelper.JSONSerializedElement>();
public IEnumerable<SerializableNode> nodes
{
get { return m_Nodes; }
}
public IEnumerable<Edge> edges
{
get { return m_Edges; }
}
public virtual void AddNode(SerializableNode node)
{
m_Nodes.Add(node);
ValidateGraph();
}
public virtual void RemoveNode(SerializableNode node)
{
if (!node.canDeleteNode)
return;
m_Nodes.Remove(node);
ValidateGraph();
}
public virtual Edge Connect(SerializableSlot fromSlot, SerializableSlot toSlot)
{
SerializableSlot outputSlot = null;
SerializableSlot inputSlot = null;
// output must connect to input
if (fromSlot.isOutputSlot)
outputSlot = fromSlot;
else if (fromSlot.isInputSlot)
inputSlot = fromSlot;
if (toSlot.isOutputSlot)
outputSlot = toSlot;
else if (toSlot.isInputSlot)
inputSlot = toSlot;
if (inputSlot == null || outputSlot == null)
return null;
var edges = GetEdges(inputSlot).ToList();
// remove any inputs that exits before adding
foreach (var edge in edges)
{
Debug.Log("Removing existing edge:" + edge);
// call base here as we DO NOT want to
// do expensive shader regeneration
RemoveEdge(edge);
}
var newEdge = new Edge(new SlotReference(outputSlot.owner.guid, outputSlot.name), new SlotReference(inputSlot.owner.guid, inputSlot.name));
m_Edges.Add(newEdge);
Debug.Log("Connected edge: " + newEdge);
return newEdge;
}
public virtual void RemoveEdge(Edge e)
{
m_Edges.Remove(e);
ValidateGraph();
}
private void RemoveEdgeNoValidate(Edge e)
{
m_Edges.Remove(e);
}
public SerializableNode GetNodeFromGuid(Guid guid)
{
return m_Nodes.FirstOrDefault(x => x.guid == guid);
}
public IEnumerable<Edge> GetEdges(SerializableSlot s)
{
return m_Edges.Where(x =>
(x.outputSlot.nodeGuid == s.owner.guid && x.outputSlot.slotName == s.name)
|| x.inputSlot.nodeGuid == s.owner.guid && x.inputSlot.slotName == s.name);
}
public virtual void OnBeforeSerialize()
{
m_SerializableNodes = SerializationHelper.Serialize(m_Nodes);
}
public virtual void OnAfterDeserialize()
{
m_Nodes = SerializationHelper.Deserialize<SerializableNode>(m_SerializableNodes, new object[] {this});
m_SerializableNodes = null;
}
public virtual void ValidateGraph()
{
//First validate edges, remove any
//orphans. This can happen if a user
//manually modifies serialized data
//of if they delete a node in the inspector
//debug view.
var allNodeGUIDs = nodes.Select(x => x.guid).ToList();
foreach (var edge in edges.ToArray())
{
if (allNodeGUIDs.Contains(edge.inputSlot.nodeGuid) && allNodeGUIDs.Contains(edge.outputSlot.nodeGuid))
continue;
//orphaned edge
RemoveEdgeNoValidate(edge);
}
}
}
}

96
UnityProject/Assets/UnityShaderEditor/Editor/Source/Util/SerializationHelper.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UnityEditor.MaterialGraph
{
public static class SerializationHelper
{
[Serializable]
public struct JSONSerializedElement
{
[SerializeField]
public string typeName;
[SerializeField]
public string JSONnodeData;
}
private static string GetTypeSerializableAsString(Type type)
{
if (type == null)
return string.Empty;
return string.Format("{0}, {1}", type.FullName, type.Assembly.GetName().Name);
}
private static Type GetTypeFromSerializedString(string type)
{
if (string.IsNullOrEmpty(type))
return null;
return Type.GetType(type);
}
public static List<JSONSerializedElement> Serialize<T>(List<T> list)
{
var result = new List<JSONSerializedElement>(list.Count);
foreach (var element in list)
{
if (element == null)
continue;
var typeName = GetTypeSerializableAsString(element.GetType());
var data = JsonUtility.ToJson(element, true);
if (string.IsNullOrEmpty(typeName) || string.IsNullOrEmpty(data))
continue;
result.Add(new JSONSerializedElement()
{
typeName = typeName,
JSONnodeData = data
});
}
return result;
}
public static List<T> Deserialize<T>(List<JSONSerializedElement> list, object[] constructorArgs)
{
var result = new List<T>();
Type[] types = constructorArgs.Select(x => x.GetType()).ToArray();
foreach (var element in list)
{
if (string.IsNullOrEmpty(element.typeName) || string.IsNullOrEmpty(element.JSONnodeData))
continue;
var type = GetTypeFromSerializedString(element.typeName);
if (type == null)
{
Debug.LogWarningFormat("Could not find node of type {0} in loaded assemblies", element.typeName);
continue;
}
T instance;
try
{
var constructorInfo = type.GetConstructor(types);
instance = (T) constructorInfo.Invoke(constructorArgs);
}
catch
{
Debug.LogWarningFormat("Could not construct instance of: {0} as there is no single argument constuctor that takes a AbstractMaterialGraph", type);
continue;
}
JsonUtility.FromJsonOverwrite(element.JSONnodeData, instance);
result.Add(instance);
}
return result;
}
}
}
正在加载...
取消
保存