浏览代码

Changing sub graphs to use functions instead of inlining.

/main
Tim Cooper 7 年前
当前提交
259c7ce1
共有 38 个文件被更改,包括 416 次插入497 次删除
  1. 10
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/AbstractMaterialGraph.cs
  2. 7
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/AbstractShaderProperty.cs
  3. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/BitangentMaterialSlot.cs
  4. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/ColorShaderProperty.cs
  5. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/CubemapShaderProperty.cs
  6. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/FloatShaderProperty.cs
  7. 3
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/IShaderProperty.cs
  8. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/NormalMaterialSlot.cs
  9. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/PositionMaterialSlot.cs
  10. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/SamplerStateShaderProperty.cs
  11. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/ScreenPositionMaterialSlot.cs
  12. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/TangentMaterialSlot.cs
  13. 11
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/TextureShaderProperty.cs
  14. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/UVMaterialSlot.cs
  15. 6
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/Vector2ShaderProperty.cs
  16. 7
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/Vector3ShaderProperty.cs
  17. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/VectorShaderProperty.cs
  18. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/VertexColorMaterialSlot.cs
  19. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/ViewDirectionMaterialSlot.cs
  20. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Interfaces/NeededCoordinateSpace.cs
  21. 7
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/AbstractMaterialNode.cs
  22. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Artistic/Normal/NormalUnpackNode.cs
  23. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/BitangentVectorNode.cs
  24. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/NormalVectorNode.cs
  25. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/PositionNode.cs
  26. 10
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/ScreenPositionNode.cs
  27. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/TangentVectorNode.cs
  28. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/UVNode.cs
  29. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/VertexColorNode.cs
  30. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/ViewDirectionNode.cs
  31. 323
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Utility/SubGraphNode.cs
  32. 103
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/SubGraph/SubGraph.cs
  33. 17
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/SubGraph/SubGraphOutputNode.cs
  34. 34
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Util/GraphUtil.cs
  35. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Util/ShaderGenerator.cs
  36. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/MaterialGraphEditWindow.cs
  37. 65
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/SubGraph/AbstractSubGraph.cs
  38. 250
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/SubGraph/AbstractSubGraphNode.cs

10
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/AbstractMaterialGraph.cs


using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor.Compilation;
using UnityEditor.Graphing.Util;
namespace UnityEditor.ShaderGraph
{

public IEnumerable<Guid> removedProperties
{
get { return m_RemovedProperties; }
}
[SerializeField]
SerializableGuid m_GUID = new SerializableGuid();
public Guid guid
{
get { return m_GUID.guid; }
}
#endregion

7
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/AbstractShaderProperty.cs


public abstract Vector4 defaultValue { get; }
public abstract string GetPropertyBlockString();
public abstract string GetPropertyDeclarationString();
public virtual string GetInlinePropertyDeclarationString()
{
return GetPropertyDeclarationString();
}
public abstract string GetPropertyDeclarationString(string delimiter = ";");
public abstract PreviewProperty GetPreviewMaterialProperty();
public abstract INode ToConcreteNode();

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/BitangentMaterialSlot.cs


public override string GetDefaultValue(GenerationMode generationMode)
{
return space.ToVariableName(InterpolatorType.BiTangent);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.BiTangent));
}
public NeededCoordinateSpace RequiresBitangent()

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/ColorShaderProperty.cs


return result.ToString();
}
public override string GetPropertyDeclarationString()
public override string GetPropertyDeclarationString(string delimiter = ";")
return "float4 " + referenceName + ";";
return string.Format("float4 {0}{1}", referenceName, delimiter);
}
public override PreviewProperty GetPreviewMaterialProperty()

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/CubemapShaderProperty.cs


return result.ToString();
}
public override string GetPropertyDeclarationString()
public override string GetPropertyDeclarationString(string delimiter = ";")
return string.Format("TEXTURECUBE({0});\nSAMPLER(sampler{0});", referenceName);
return string.Format("TEXTURECUBE({0}){1}\nSAMPLER(sampler{0}){1}", referenceName, delimiter);
}
public override PreviewProperty GetPreviewMaterialProperty()

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/FloatShaderProperty.cs


return result.ToString();
}
public override string GetPropertyDeclarationString()
public override string GetPropertyDeclarationString(string delimiter = ";")
return "float " + referenceName + ";";
return string.Format("float {0}{1}", referenceName, delimiter);
}
public override PreviewProperty GetPreviewMaterialProperty()

3
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/IShaderProperty.cs


string overrideReferenceName { get; set; }
string GetPropertyBlockString();
string GetPropertyDeclarationString();
string GetInlinePropertyDeclarationString();
string GetPropertyDeclarationString(string delimiter = ";");
PreviewProperty GetPreviewMaterialProperty();
INode ToConcreteNode();
}

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/NormalMaterialSlot.cs


public override string GetDefaultValue(GenerationMode generationMode)
{
return space.ToVariableName(InterpolatorType.Normal);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.Normal));
}
public NeededCoordinateSpace RequiresNormal()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/PositionMaterialSlot.cs


public override string GetDefaultValue(GenerationMode generationMode)
{
return space.ToVariableName(InterpolatorType.Position);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.Position));
}
public NeededCoordinateSpace RequiresPosition()

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/SamplerStateShaderProperty.cs


return string.Empty;
}
public override string GetPropertyDeclarationString()
public override string GetPropertyDeclarationString(string delimiter = ";")
return string.Format(@"SAMPLER2D({0});", referenceName);
return string.Format(@"SAMPLER2D({0}){1}", referenceName, delimiter);
}
public override PreviewProperty GetPreviewMaterialProperty()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/ScreenPositionMaterialSlot.cs


public override string GetDefaultValue(GenerationMode generationMode)
{
return ShaderGeneratorNames.ScreenPosition;
return string.Format("IN.{0}", ShaderGeneratorNames.ScreenPosition);
}
public bool RequiresScreenPosition()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/TangentMaterialSlot.cs


public override string GetDefaultValue(GenerationMode generationMode)
{
return space.ToVariableName(InterpolatorType.Tangent);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.Tangent));
}
public NeededCoordinateSpace RequiresTangent()

11
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/TextureShaderProperty.cs


return result.ToString();
}
public override string GetPropertyDeclarationString()
public override string GetPropertyDeclarationString(string delimiter = ";")
return string.Format("TEXTURE2D({0});\nSAMPLER(sampler{0});", referenceName);
return string.Format("TEXTURE2D({0}){1}\nSAMPLER(sampler{0}){1}", referenceName, delimiter);
public override string GetInlinePropertyDeclarationString()
{
return string.Format("TEXTURE2D({0});", referenceName);
}
public override PreviewProperty GetPreviewMaterialProperty()
{
return new PreviewProperty(PropertyType.Texture)

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/UVMaterialSlot.cs


public override string GetDefaultValue(GenerationMode generationMode)
{
return string.Format("{0}.xy", channel.GetUVName());
return string.Format("IN.{0}.xy", channel.GetUVName());
}
public bool RequiresMeshUV(UVChannel channel)

6
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/Vector2ShaderProperty.cs


{
get { return new Vector4(value.x, value.y, 0, 0); }
}
public override string GetInlinePropertyDeclarationString()
{
return "float2 " + referenceName + ";";
}
public override PreviewProperty GetPreviewMaterialProperty()
{

7
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/Vector3ShaderProperty.cs


{
get { return new Vector4(value.x, value.y, value.z, 0); }
}
public override string GetInlinePropertyDeclarationString()
{
return "float3 " + referenceName + ";";
}
public override PreviewProperty GetPreviewMaterialProperty()
{
return new PreviewProperty(PropertyType.Vector3)

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/VectorShaderProperty.cs


return result.ToString();
}
public override string GetPropertyDeclarationString()
public override string GetPropertyDeclarationString(string delimiter = ";")
return "float4 " + referenceName + ";";
return string.Format("float4 {0}{1}", referenceName, delimiter);
}
}
}

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/VertexColorMaterialSlot.cs


public override string GetDefaultValue(GenerationMode generationMode)
{
return ShaderGeneratorNames.VertexColor;
return string.Format("IN.{0}", ShaderGeneratorNames.VertexColor);
}
public bool RequiresScreenPosition()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Graphs/ViewDirectionMaterialSlot.cs


public override string GetDefaultValue(GenerationMode generationMode)
{
return space.ToVariableName(InterpolatorType.ViewDirection);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.ViewDirection));
}
public NeededCoordinateSpace RequiresViewDirection()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Interfaces/NeededCoordinateSpace.cs


Tangent = 1 << 3
}
public enum CoordinateSpace : int
public enum CoordinateSpace
{
Object,
View,

7
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/AbstractMaterialNode.cs


{
get { return true; }
}
public virtual bool allowedInRemapGraph
{
get { return true; }
}
public virtual bool allowedInMainGraph
{
get { return true; }

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Artistic/Normal/NormalUnpackNode.cs


using System.Reflection;
using UnityEngine;
using UnityEditor.Graphing;
namespace UnityEditor.ShaderGraph
{

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/BitangentVectorNode.cs


public override string GetVariableNameForSlot(int slotId)
{
return space.ToVariableName(InterpolatorType.BiTangent);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.BiTangent));
}
public NeededCoordinateSpace RequiresBitangent()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/NormalVectorNode.cs


public override string GetVariableNameForSlot(int slotId)
{
return space.ToVariableName(InterpolatorType.Normal);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.Normal));
}
public NeededCoordinateSpace RequiresNormal()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/PositionNode.cs


public override string GetVariableNameForSlot(int slotId)
{
return space.ToVariableName(InterpolatorType.Position);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.Position));
}
public NeededCoordinateSpace RequiresPosition()

10
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/ScreenPositionNode.cs


switch (m_ScreenSpaceType)
{
case ScreenSpaceType.Raw:
visitor.AddShaderChunk(string.Format("{0}4 {1} = {2};", precision, GetVariableNameForSlot(kOutputSlotId),
visitor.AddShaderChunk(string.Format("{0}4 {1} = In.{2};", precision, GetVariableNameForSlot(kOutputSlotId),
"float4((" + ShaderGeneratorNames.ScreenPosition + ".xy / " + ShaderGeneratorNames.ScreenPosition + ".w) * 2 - 1, 0, 0)"), true);
string.Format("float4((In.{0}.xy / In.{0}.w) * 2 - 1, 0, 0)", ShaderGeneratorNames.ScreenPosition)), true);
"float4((" + ShaderGeneratorNames.ScreenPosition + ".xy / " + ShaderGeneratorNames.ScreenPosition + ".w) * 2 - 1, 0, 0)"), true);
string.Format("float4((In.{0}.xy / In.{0}.w) * 2 - 1, 0, 0)", ShaderGeneratorNames.ScreenPosition)), true);
"float4(" + ShaderGeneratorNames.ScreenPosition + ".x * _ScreenParams.x / _ScreenParams.y, " + ShaderGeneratorNames.ScreenPosition + ".y, 0, 0)"), true);
string.Format("float4(In.{0}.x * _ScreenParams.x / _ScreenParams.y, In.{0}.y, 0, 0)", ShaderGeneratorNames.ScreenPosition)), true);
"float4(" + ShaderGeneratorNames.ScreenPosition + ".xy / " + ShaderGeneratorNames.ScreenPosition + ".w, 0, 0)"), true);
string.Format("float4(In.{0}.xy / In.{0}.w, 0, 0)", ShaderGeneratorNames.ScreenPosition)), true);
break;
}
}

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/TangentVectorNode.cs


public override string GetVariableNameForSlot(int slotId)
{
return space.ToVariableName(InterpolatorType.Tangent);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.Tangent));
}
public NeededCoordinateSpace RequiresTangent()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/UVNode.cs


public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode)
{
visitor.AddShaderChunk(precision + "4 " + GetVariableNameForSlot(OutputSlotId) + " = " + m_OutputChannel.GetUVName() + ";", true);
visitor.AddShaderChunk(string.Format("{0}4 {1} = IN.{2};", precision, GetVariableNameForSlot(OutputSlotId), m_OutputChannel.GetUVName()), true);
}
public bool RequiresMeshUV(UVChannel channel)

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/VertexColorNode.cs


public override string GetVariableNameForSlot(int slotId)
{
return ShaderGeneratorNames.VertexColor;
return string.Format("IN.{0}", ShaderGeneratorNames.VertexColor);
}
public bool RequiresVertexColor()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Input/Geometry/ViewDirectionNode.cs


public override string GetVariableNameForSlot(int slotId)
{
return space.ToVariableName(InterpolatorType.ViewDirection);
return string.Format("IN.{0}", space.ToVariableName(InterpolatorType.ViewDirection));
}
public NeededCoordinateSpace RequiresViewDirection()

323
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Nodes/Utility/SubGraphNode.cs


using System;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEditor.Graphs;
public class SubGraphNode : AbstractSubGraphNode
public class SubGraphNode : AbstractMaterialNode
, IGeneratesFunction
, IMayRequireNormal
, IMayRequireTangent
, IMayRequireBitangent
, IMayRequireMeshUV
, IMayRequireScreenPosition
, IMayRequireViewDirection
, IMayRequirePosition
, IMayRequireVertexColor
, IMayRequireTime
{
[SerializeField]
private string m_SerializedSubGraph = string.Empty;

public MaterialSubGraphAsset subGraph;
}
protected override AbstractSubGraph referencedGraph
protected SubGraph referencedGraph
{
get
{

public MaterialSubGraphAsset subGraphAsset {get; set; }
#endif
public override INode outputNode
public INode outputNode
{
get
{

}
}
public override bool hasPreview
{
get { return referencedGraph != null; }
}
public override PreviewMode previewMode
{
get
{
if (referencedGraph == null)
return PreviewMode.Preview2D;
return PreviewMode.Preview3D;
}
}
public void GenerateNodeCode(ShaderGenerator shaderBodyVisitor, GenerationMode generationMode)
public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode)
var outputString = new ShaderGenerator();
outputString.AddShaderChunk("// Subgraph for node " + GetVariableNameForNode(), false);
foreach (var outSlot in referencedGraph.graphOutputs)
visitor.AddShaderChunk(string.Format("{0} {1};", NodeUtils.ConvertConcreteSlotValueTypeToString(precision, outSlot.concreteValueType), GetVariableNameForSlot(outSlot.id)), true);
// Step 1...
// find out which output slots are actually used
//var validOutputSlots = NodeUtils.GetSlotsThatOutputToNodeRecurse(this, (graph as BaseMaterialGraph).masterNode);
s_TempSlots.Clear();
GetOutputSlots(s_TempSlots);
foreach (var slot in s_TempSlots)
var arguments = new List<string>();
foreach (var prop in referencedGraph.graphInputs)
var outDimension = NodeUtils.ConvertConcreteSlotValueTypeToString(precision, slot.concreteValueType);
outputString.AddShaderChunk(string.Format("{0} {1} = 0;", outDimension, GetVariableNameForSlot(slot.id)), false);
var inSlotId = prop.guid.GetHashCode();
arguments.Add(GetSlotValue(inSlotId, generationMode));
// Step 2...
// Go into the subgraph
outputString.AddShaderChunk("{", false);
outputString.Indent();
// pass surface inputs through
arguments.Add("IN");
// Step 3...
// For each input that is used and connects through we want to generate code.
// First we assign the input variables to the subgraph
// we do this by renaming the properties to be the names of where the variables come from
// weird, but works.
var sSubGraph = SerializationHelper.Serialize(subGraphAsset.subGraph);
var dSubGraph = SerializationHelper.Deserialize<SubGraph>(sSubGraph, null);
foreach (var outSlot in referencedGraph.graphOutputs)
arguments.Add(GetVariableNameForSlot(outSlot.id));
var subGraphInputs = dSubGraph.properties;
visitor.AddShaderChunk(
string.Format("{0}({1});"
, SubGraphFunctionName()
, arguments.Aggregate((current, next) => string.Format("{0}, {1}", current, next)))
, false);
}
var propertyGen = new PropertyCollector();
dSubGraph.CollectShaderProperties(propertyGen, GenerationMode.ForReals);
public void OnEnable()
{
UpdateSlots();
}
public virtual void UpdateSlots()
{
var validNames = new List<int>();
if (referencedGraph == null)
{
RemoveSlotsNameNotMatching(validNames);
return;
}
foreach (var prop in subGraphInputs)
var props = referencedGraph.properties;
foreach (var prop in props)
var inSlotId = prop.guid.GetHashCode();
var inSlot = FindInputSlot<MaterialSlot>(inSlotId);
var propType = prop.propertyType;
SlotValueType slotType;
var edges = owner.GetEdges(inSlot.slotReference).ToArray();
switch (propType)
{
case PropertyType.Color:
slotType = SlotValueType.Vector4;
break;
case PropertyType.Texture:
slotType = SlotValueType.Texture2D;
break;
case PropertyType.Cubemap:
slotType = SlotValueType.Cubemap;
break;
case PropertyType.Float:
slotType = SlotValueType.Vector1;
break;
case PropertyType.Vector2:
slotType = SlotValueType.Vector2;
break;
case PropertyType.Vector3:
slotType = SlotValueType.Vector3;
break;
case PropertyType.Vector4:
slotType = SlotValueType.Vector4;
break;
case PropertyType.Matrix2:
slotType = SlotValueType.Matrix2;
break;
case PropertyType.Matrix3:
slotType = SlotValueType.Matrix3;
break;
case PropertyType.Matrix4:
slotType = SlotValueType.Matrix4;
break;
default:
throw new ArgumentOutOfRangeException();
}
string varValue = inSlot.GetDefaultValue(generationMode);
if (edges.Any())
var id = prop.guid.GetHashCode();
MaterialSlot slot = MaterialSlot.CreateMaterialSlot(slotType, id, prop.displayName, prop.referenceName, SlotType.Input, prop.defaultValue);
// copy default for texture for niceness
if (slotType == SlotValueType.Texture2D && propType == PropertyType.Texture)
var fromSocketRef = edges[0].outputSlot;
var fromNode = owner.GetNodeFromGuid<AbstractMaterialNode>(fromSocketRef.nodeGuid);
if (fromNode != null)
{
var slot = fromNode.FindOutputSlot<MaterialSlot>(fromSocketRef.slotId);
if (slot != null)
prop.overrideReferenceName = fromNode.GetSlotValue(slot.id, generationMode);
}
var tSlot = slot as Texture2DInputMaterialSlot;
var tProp = prop as TextureShaderProperty;
if (tSlot != null && tProp != null)
tSlot.texture = tProp.value.texture;
else if (inSlot is Texture2DInputMaterialSlot)
// copy default for cubemap for niceness
else if (slotType == SlotValueType.Cubemap && propType == PropertyType.Cubemap)
prop.overrideReferenceName = ((Texture2DInputMaterialSlot)inSlot).GetDefaultValue(generationMode);
var tSlot = slot as CubemapInputMaterialSlot;
var tProp = prop as CubemapShaderProperty;
if (tSlot != null && tProp != null)
tSlot.cubemap = tProp.value.cubemap;
else
AddSlot(slot);
validNames.Add(id);
}
var subGraphOutputNode = outputNode;
if (outputNode != null)
{
foreach (var slot in NodeExtensions.GetInputSlots<MaterialSlot>(subGraphOutputNode))
var varName = prop.referenceName;
outputString.AddShaderChunk(NodeUtils.ConvertConcreteSlotValueTypeToString(precision, inSlot.concreteValueType)
+ " "
+ varName
+ " = "
+ varValue
+ ";", false);
AddSlot(MaterialSlot.CreateMaterialSlot(slot.valueType, slot.id, slot.RawDisplayName(), slot.shaderOutputName, SlotType.Output, Vector4.zero));
validNames.Add(slot.id);
// Step 4...
// Using the inputs we can now generate the shader body :)
var bodyGenerator = new ShaderGenerator();
dSubGraph.GenerateNodeCode(bodyGenerator, GenerationMode.ForReals);
var subGraphOutputNode = dSubGraph.outputNode;
outputString.AddShaderChunk(bodyGenerator.GetShaderString(0), false);
RemoveSlotsNameNotMatching(validNames);
}
public override void CollectShaderProperties(PropertyCollector visitor, GenerationMode generationMode)
{
base.CollectShaderProperties(visitor, generationMode);
if (referencedGraph == null)
return;
referencedGraph.CollectShaderProperties(visitor, GenerationMode.ForReals);
}
public override void CollectPreviewMaterialProperties(List<PreviewProperty> properties)
{
base.CollectPreviewMaterialProperties(properties);
if (referencedGraph == null)
return;
properties.AddRange(referencedGraph.GetPreviewProperties());
}
private string SubGraphFunctionName()
{
var functionName = subGraphAsset != null ? NodeUtils.GetHLSLSafeName(subGraphAsset.name) : "ERROR";
return string.Format("{0}_{1}", functionName, GuidEncoder.Encode(referencedGraph.guid));
}
public virtual void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
{
if (subGraphAsset == null || referencedGraph == null)
return;
referencedGraph.GenerateNodeFunction(registry, GenerationMode.ForReals);
referencedGraph.GenerateSubGraphFunction(SubGraphFunctionName(), registry, ShaderGraphRequirements.FromNodes(new List<INode> {this}), GenerationMode.ForReals);
}
public NeededCoordinateSpace RequiresNormal()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
return referencedGraph.activeNodes.OfType<IMayRequireNormal>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
{
mask |= node.RequiresNormal();
return mask;
});
}
public bool RequiresMeshUV(UVChannel channel)
{
if (referencedGraph == null)
return false;
return referencedGraph.activeNodes.OfType<IMayRequireMeshUV>().Any(x => x.RequiresMeshUV(channel));
}
public bool RequiresScreenPosition()
{
if (referencedGraph == null)
return false;
return referencedGraph.activeNodes.OfType<IMayRequireScreenPosition>().Any(x => x.RequiresScreenPosition());
}
// Step 5...
// Copy the outputs to the parent context name);
s_TempSlots.Clear();
GetOutputSlots(s_TempSlots);
foreach (var slot in s_TempSlots)
public NeededCoordinateSpace RequiresViewDirection()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
return referencedGraph.activeNodes.OfType<IMayRequireViewDirection>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
var inputValue = subGraphOutputNode.GetSlotValue(slot.id, GenerationMode.ForReals);
mask |= node.RequiresViewDirection();
return mask;
});
}
outputString.AddShaderChunk(
GetVariableNameForSlot(slot.id)
+ " = "
+ inputValue
+ ";", false);
}
public NeededCoordinateSpace RequiresPosition()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
outputString.Deindent();
outputString.AddShaderChunk("}", false);
outputString.AddShaderChunk("// Subgraph ends", false);
return referencedGraph.activeNodes.OfType<IMayRequirePosition>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
{
mask |= node.RequiresPosition();
return mask;
});
}
shaderBodyVisitor.AddShaderChunk(outputString.GetShaderString(0), true);
public NeededCoordinateSpace RequiresTangent()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
return referencedGraph.activeNodes.OfType<IMayRequireTangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
{
mask |= node.RequiresTangent();
return mask;
});
public void OnEnable()
public bool RequiresTime()
UpdateSlots();
if (referencedGraph == null)
return false;
return referencedGraph.activeNodes.OfType<IMayRequireTime>().Any(x => x.RequiresTime());
}
public NeededCoordinateSpace RequiresBitangent()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
return referencedGraph.activeNodes.OfType<IMayRequireBitangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
{
mask |= node.RequiresBitangent();
return mask;
});
}
public bool RequiresVertexColor()
{
if (referencedGraph == null)
return false;
return referencedGraph.activeNodes.OfType<IMayRequireVertexColor>().Any(x => x.RequiresVertexColor());
}
}
}

103
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/SubGraph/SubGraph.cs


namespace UnityEditor.ShaderGraph
{
[Serializable]
public class SubGraph : AbstractSubGraph
public class SubGraph : AbstractMaterialGraph
, IGeneratesBodyCode
, IGeneratesFunction
{
[NonSerialized]
private SubGraphOutputNode m_OutputNode;

base.AddNode(node);
}
public override IEnumerable<AbstractMaterialNode> activeNodes
public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode)
{
foreach (var node in activeNodes)
{
if (node is IGeneratesBodyCode)
(node as IGeneratesBodyCode).GenerateNodeCode(visitor, generationMode);
}
}
public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
{
foreach (var node in activeNodes)
{
if (node is IGeneratesFunction)
(node as IGeneratesFunction).GenerateNodeFunction(registry, generationMode);
}
}
public IEnumerable<IShaderProperty> graphInputs
{
get { return properties.OrderBy(x => x.guid); }
}
public IEnumerable<MaterialSlot> graphOutputs
{
get
{
return outputNode != null ? outputNode.graphOutputs : new List<MaterialSlot>();
}
}
public void GenerateSubGraphFunction(string functionName, FunctionRegistry registry, ShaderGraphRequirements reqs, GenerationMode generationMode)
{
registry.ProvideFunction(functionName, s =>
{
s.AppendLine("// Subgraph function");
// Generate arguments... first INPUTS
var arguments = new List<string>();
foreach (var prop in graphInputs)
arguments.Add(string.Format("{0}", prop.GetPropertyDeclarationString(string.Empty)));
// now pass surface inputs
arguments.Add("SurfaceInputs IN");
// Now generate outputs
foreach (var slot in graphOutputs)
arguments.Add(string.Format("out {0} {1}", slot.concreteValueType.ToString(outputNode.precision), slot.shaderOutputName));
// Create the function protoype from the arguments
s.AppendLine("void {0}({1})"
, functionName
, arguments.Aggregate((current, next) => string.Format("{0}, {1}", current, next)));
// now generate the function
using (s.BlockScope())
{
// Just grab the body from the active nodes
var bodyGenerator = new ShaderGenerator();
GenerateNodeCode(bodyGenerator, GenerationMode.ForReals);
if (outputNode != null)
outputNode.RemapOutputs(bodyGenerator, GenerationMode.ForReals);
s.Append(bodyGenerator.GetShaderString(1));
}
});
}
public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode)
{
// if we are previewing the graph we need to
// export 'exposed props' if we are 'for real'
// then we are outputting the graph in the
// nested context and the needed values will
// be copied into scope.
if (generationMode == GenerationMode.Preview)
{
foreach (var prop in properties)
collector.AddShaderProperty(prop);
}
foreach (var node in activeNodes)
{
if (node is IGenerateProperties)
(node as IGenerateProperties).CollectShaderProperties(collector, generationMode);
}
}
public IEnumerable<PreviewProperty> GetPreviewProperties()
{
List<PreviewProperty> props = new List<PreviewProperty>();
foreach (var node in activeNodes)
node.CollectPreviewMaterialProperties(props);
return props;
}
public IEnumerable<AbstractMaterialNode> activeNodes
{
get
{

17
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/SubGraph/SubGraphOutputNode.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.ShaderGraph.Drawing.Controls;

RemoveSlot(index);
}
public override bool allowedInRemapGraph { get { return false; } }
public void RemapOutputs(ShaderGenerator visitor, GenerationMode generationMode)
{
foreach (var slot in graphOutputs)
visitor.AddShaderChunk(string.Format("{0} = {1};", slot.shaderOutputName, GetSlotValue(slot.id, generationMode)), true);
}
public IEnumerable<MaterialSlot> graphOutputs
{
get
{
return NodeExtensions.GetInputSlots<MaterialSlot>(this).OrderBy(x=>x.id);
}
}
}
}

34
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Util/GraphUtil.cs


finalBuilder.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariables.hlsl""");
finalBuilder.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariablesFunctions.hlsl""");
finalBuilder.AppendLines(shaderProperties.GetPropertiesDeclaration(0));
finalBuilder.AppendLines(surfaceInputs.GetShaderString(0));
finalBuilder.AppendLines(surfaceInputs.GetShaderString(0));
finalBuilder.AppendLines(shaderProperties.GetPropertiesDeclaration(0));
finalBuilder.AppendLines(vertexShader.GetShaderString(0));
finalBuilder.AppendLines(surfaceDescriptionFunction.GetShaderString(0));
finalBuilder.AppendLine(@"ENDHLSL");

surfaceDescriptionFunction.Indent();
surfaceDescriptionFunction.AddShaderChunk(String.Format("{0} surface = ({0})0;", surfaceDescriptionName), false);
foreach (CoordinateSpace space in Enum.GetValues(typeof(CoordinateSpace)))
{
var neededCoordinateSpace = space.ToNeededCoordinateSpace();
if ((requirements.requiresNormal & neededCoordinateSpace) > 0)
surfaceDescriptionFunction.AddShaderChunk(String.Format("float3 {0} = IN.{0};", space.ToVariableName(InterpolatorType.Normal)), false);
if ((requirements.requiresTangent & neededCoordinateSpace) > 0)
surfaceDescriptionFunction.AddShaderChunk(String.Format("float3 {0} = IN.{0};", space.ToVariableName(InterpolatorType.Tangent)), false);
if ((requirements.requiresBitangent & neededCoordinateSpace) > 0)
surfaceDescriptionFunction.AddShaderChunk(String.Format("float3 {0} = IN.{0};", space.ToVariableName(InterpolatorType.BiTangent)), false);
if ((requirements.requiresViewDir & neededCoordinateSpace) > 0)
surfaceDescriptionFunction.AddShaderChunk(String.Format("float3 {0} = IN.{0};", space.ToVariableName(InterpolatorType.ViewDirection)), false);
if ((requirements.requiresPosition & neededCoordinateSpace) > 0)
surfaceDescriptionFunction.AddShaderChunk(String.Format("float3 {0} = IN.{0};", space.ToVariableName(InterpolatorType.Position)), false);
}
if (requirements.requiresScreenPosition)
surfaceDescriptionFunction.AddShaderChunk(String.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.ScreenPosition), false);
if (requirements.requiresVertexColor)
surfaceDescriptionFunction.AddShaderChunk(String.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.VertexColor), false);
foreach (var channel in requirements.requiresMeshUVs.Distinct())
surfaceDescriptionFunction.AddShaderChunk(String.Format("half4 {0} = IN.{0};", channel.GetUVName()), false);
graph.CollectShaderProperties(shaderProperties, mode);
foreach (var activeNode in activeNodeList.OfType<AbstractMaterialNode>())

{
var outputRef = foundEdges[0].outputSlot;
var fromNode = graph.GetNodeFromGuid<AbstractMaterialNode>(outputRef.nodeGuid);
surfaceDescriptionFunction.AddShaderChunk(String.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), fromNode.GetVariableNameForSlot(outputRef.slotId)), true);
surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), fromNode.GetVariableNameForSlot(outputRef.slotId)), true);
surfaceDescriptionFunction.AddShaderChunk(String.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), input.GetDefaultValue(mode)), true);
surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), input.GetDefaultValue(mode)), true);
}
}
}

surfaceDescriptionFunction.AddShaderChunk(String.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(slot.shaderOutputName), masterNode.GetVariableNameForSlot(slot.id)), true);
surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(slot.shaderOutputName), masterNode.GetVariableNameForSlot(slot.id)), true);
}
}

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/Util/ShaderGenerator.cs


{
interpolators.AddShaderChunk(string.Format("half4 {0} : TEXCOORD{1};", channel.GetUVName(), interpolatorIndex == 0 ? "" : interpolatorIndex.ToString()), false);
vertexShader.AddShaderChunk(string.Format("o.{0} = v.texcoord{1};", channel.GetUVName(), (int)channel), false);
pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", channel.GetUVName()), false);
pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", channel.GetUVName()), false);
interpolatorIndex++;
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/MaterialGraphEditWindow.cs


graphObject.graph.ValidateGraph();
}
void UpdateAbstractSubgraphOnDisk<T>(string path) where T : AbstractSubGraph
void UpdateAbstractSubgraphOnDisk<T>(string path) where T : SubGraph
{
var graph = graphObject.graph as T;
if (graph == null)

{
if (graphObject != null && graphObject.graph != null)
{
var subNodes = graphObject.graph.GetNodes<AbstractSubGraphNode>();
var subNodes = graphObject.graph.GetNodes<SubGraphNode>();
foreach (var node in subNodes)
node.UpdateSlots();
}

65
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/SubGraph/AbstractSubGraph.cs


using System;
using System.Collections.Generic;
using System.Linq;
namespace UnityEditor.ShaderGraph
{
[Serializable]
public class AbstractSubGraph : AbstractMaterialGraph
, IGeneratesBodyCode
, IGeneratesFunction
{
public virtual IEnumerable<AbstractMaterialNode> activeNodes { get { return Enumerable.Empty<AbstractMaterialNode>(); } }
public PreviewMode previewMode
{
get { return activeNodes.Any(x => x.previewMode == PreviewMode.Preview3D) ? PreviewMode.Preview3D : PreviewMode.Preview2D; }
}
public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode)
{
foreach (var node in activeNodes)
{
if (node is IGeneratesBodyCode)
(node as IGeneratesBodyCode).GenerateNodeCode(visitor, generationMode);
}
}
public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
{
foreach (var node in activeNodes)
{
if (node is IGeneratesFunction)
(node as IGeneratesFunction).GenerateNodeFunction(registry, generationMode);
}
}
public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode)
{
// if we are previewing the graph we need to
// export 'exposed props' if we are 'for real'
// then we are outputting the graph in the
// nested context and the needed values will
// be copied into scope.
if (generationMode == GenerationMode.Preview)
{
foreach (var prop in properties)
collector.AddShaderProperty(prop);
}
foreach (var node in activeNodes)
{
if (node is IGenerateProperties)
(node as IGenerateProperties).CollectShaderProperties(collector, generationMode);
}
}
public IEnumerable<PreviewProperty> GetPreviewProperties()
{
List<PreviewProperty> props = new List<PreviewProperty>();
foreach (var node in activeNodes)
node.CollectPreviewMaterialProperties(props);
return props;
}
}
}

250
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Data/SubGraph/AbstractSubGraphNode.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor.Graphing;
namespace UnityEditor.ShaderGraph
{
public abstract class AbstractSubGraphNode : AbstractMaterialNode
, IGeneratesFunction
, IMayRequireNormal
, IMayRequireTangent
, IMayRequireBitangent
, IMayRequireMeshUV
, IMayRequireScreenPosition
, IMayRequireViewDirection
, IMayRequirePosition
, IMayRequireVertexColor
, IMayRequireTime
{
protected abstract AbstractSubGraph referencedGraph { get; }
public override bool hasPreview
{
get { return referencedGraph != null; }
}
public override PreviewMode previewMode
{
get
{
if (referencedGraph == null)
return PreviewMode.Preview2D;
return PreviewMode.Preview3D;
}
}
public virtual INode outputNode
{
get { return null; }
}
public virtual void UpdateSlots()
{
var validNames = new List<int>();
if (referencedGraph == null)
{
RemoveSlotsNameNotMatching(validNames);
return;
}
var props = referencedGraph.properties;
foreach (var prop in props)
{
var propType = prop.propertyType;
SlotValueType slotType;
switch (propType)
{
case PropertyType.Color:
slotType = SlotValueType.Vector4;
break;
case PropertyType.Texture:
slotType = SlotValueType.Texture2D;
break;
case PropertyType.Cubemap:
slotType = SlotValueType.Cubemap;
break;
case PropertyType.Float:
slotType = SlotValueType.Vector1;
break;
case PropertyType.Vector2:
slotType = SlotValueType.Vector2;
break;
case PropertyType.Vector3:
slotType = SlotValueType.Vector3;
break;
case PropertyType.Vector4:
slotType = SlotValueType.Vector4;
break;
case PropertyType.Matrix2:
slotType = SlotValueType.Matrix2;
break;
case PropertyType.Matrix3:
slotType = SlotValueType.Matrix3;
break;
case PropertyType.Matrix4:
slotType = SlotValueType.Matrix4;
break;
default:
throw new ArgumentOutOfRangeException();
}
var id = prop.guid.GetHashCode();
MaterialSlot slot = MaterialSlot.CreateMaterialSlot(slotType, id, prop.displayName, prop.referenceName, SlotType.Input, prop.defaultValue);
// copy default for texture for niceness
if (slotType == SlotValueType.Texture2D && propType == PropertyType.Texture)
{
var tSlot = slot as Texture2DInputMaterialSlot;
var tProp = prop as TextureShaderProperty;
if (tSlot != null && tProp != null)
tSlot.texture = tProp.value.texture;
}
// copy default for cubemap for niceness
else if (slotType == SlotValueType.Cubemap && propType == PropertyType.Cubemap)
{
var tSlot = slot as CubemapInputMaterialSlot;
var tProp = prop as CubemapShaderProperty;
if (tSlot != null && tProp != null)
tSlot.cubemap = tProp.value.cubemap;
}
AddSlot(slot);
validNames.Add(id);
}
var subGraphOutputNode = outputNode;
if (outputNode != null)
{
foreach (var slot in subGraphOutputNode.GetInputSlots<MaterialSlot>())
{
AddSlot(MaterialSlot.CreateMaterialSlot(slot.valueType, slot.id, slot.RawDisplayName(), slot.shaderOutputName, SlotType.Output, Vector4.zero));
validNames.Add(slot.id);
}
}
RemoveSlotsNameNotMatching(validNames);
}
public override void CollectShaderProperties(PropertyCollector visitor, GenerationMode generationMode)
{
base.CollectShaderProperties(visitor, generationMode);
if (referencedGraph == null)
return;
referencedGraph.CollectShaderProperties(visitor, GenerationMode.ForReals);
}
public override void CollectPreviewMaterialProperties(List<PreviewProperty> properties)
{
base.CollectPreviewMaterialProperties(properties);
if (referencedGraph == null)
return;
properties.AddRange(referencedGraph.GetPreviewProperties());
}
public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
{
if (referencedGraph == null)
return;
referencedGraph.GenerateNodeFunction(registry, GenerationMode.ForReals);
}
public NeededCoordinateSpace RequiresNormal()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
return referencedGraph.activeNodes.OfType<IMayRequireNormal>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
{
mask |= node.RequiresNormal();
return mask;
});
}
public bool RequiresMeshUV(UVChannel channel)
{
if (referencedGraph == null)
return false;
return referencedGraph.activeNodes.OfType<IMayRequireMeshUV>().Any(x => x.RequiresMeshUV(channel));
}
public bool RequiresScreenPosition()
{
if (referencedGraph == null)
return false;
return referencedGraph.activeNodes.OfType<IMayRequireScreenPosition>().Any(x => x.RequiresScreenPosition());
}
public NeededCoordinateSpace RequiresViewDirection()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
return referencedGraph.activeNodes.OfType<IMayRequireViewDirection>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
{
mask |= node.RequiresViewDirection();
return mask;
});
}
public NeededCoordinateSpace RequiresPosition()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
return referencedGraph.activeNodes.OfType<IMayRequirePosition>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
{
mask |= node.RequiresPosition();
return mask;
});
}
public NeededCoordinateSpace RequiresTangent()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
return referencedGraph.activeNodes.OfType<IMayRequireTangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
{
mask |= node.RequiresTangent();
return mask;
});
}
public bool RequiresTime()
{
if (referencedGraph == null)
return false;
return referencedGraph.activeNodes.OfType<IMayRequireTime>().Any(x => x.RequiresTime());
}
public NeededCoordinateSpace RequiresBitangent()
{
if (referencedGraph == null)
return NeededCoordinateSpace.None;
return referencedGraph.activeNodes.OfType<IMayRequireBitangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) =>
{
mask |= node.RequiresBitangent();
return mask;
});
}
public bool RequiresVertexColor()
{
if (referencedGraph == null)
return false;
return referencedGraph.activeNodes.OfType<IMayRequireVertexColor>().Any(x => x.RequiresVertexColor());
}
}
}
正在加载...
取消
保存