|
|
|
|
|
|
using System.Linq; |
|
|
|
using UnityEngine; |
|
|
|
using UnityEditor.Graphing; |
|
|
|
using UnityEditor.Graphing.Util; |
|
|
|
|
|
|
|
namespace UnityEditor.ShaderGraph |
|
|
|
{ |
|
|
|
|
|
|
base.OnAfterDeserialize(); |
|
|
|
} |
|
|
|
|
|
|
|
protected static ShaderGraphRequirements GetRequierments(AbstractMaterialNode nodeForRequirements) |
|
|
|
protected static ShaderGraphRequirements GetRequirements(List<INode> nodes) |
|
|
|
if (nodeForRequirements == null) |
|
|
|
return ShaderGraphRequirements.none; |
|
|
|
|
|
|
|
var activeNodeList = ListPool<INode>.Get(); |
|
|
|
NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, nodeForRequirements); |
|
|
|
|
|
|
|
NeededCoordinateSpace requiresNormal = activeNodeList.OfType<IMayRequireNormal>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresNormal()); |
|
|
|
NeededCoordinateSpace requiresBitangent = activeNodeList.OfType<IMayRequireBitangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresBitangent()); |
|
|
|
NeededCoordinateSpace requiresTangent = activeNodeList.OfType<IMayRequireTangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresTangent()); |
|
|
|
NeededCoordinateSpace requiresViewDir = activeNodeList.OfType<IMayRequireViewDirection>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresViewDirection()); |
|
|
|
NeededCoordinateSpace requiresPosition = activeNodeList.OfType<IMayRequirePosition>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresPosition()); |
|
|
|
bool requiresScreenPosition = activeNodeList.OfType<IMayRequireScreenPosition>().Any(x => x.RequiresScreenPosition()); |
|
|
|
bool requiresVertexColor = activeNodeList.OfType<IMayRequireVertexColor>().Any(x => x.RequiresVertexColor()); |
|
|
|
NeededCoordinateSpace requiresNormal = nodes.OfType<IMayRequireNormal>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresNormal()); |
|
|
|
NeededCoordinateSpace requiresBitangent = nodes.OfType<IMayRequireBitangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresBitangent()); |
|
|
|
NeededCoordinateSpace requiresTangent = nodes.OfType<IMayRequireTangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresTangent()); |
|
|
|
NeededCoordinateSpace requiresViewDir = nodes.OfType<IMayRequireViewDirection>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresViewDirection()); |
|
|
|
NeededCoordinateSpace requiresPosition = nodes.OfType<IMayRequirePosition>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresPosition()); |
|
|
|
bool requiresScreenPosition = nodes.OfType<IMayRequireScreenPosition>().Any(x => x.RequiresScreenPosition()); |
|
|
|
bool requiresVertexColor = nodes.OfType<IMayRequireVertexColor>().Any(x => x.RequiresVertexColor()); |
|
|
|
if (activeNodeList.OfType<IMayRequireMeshUV>().Any(x => x.RequiresMeshUV(channel))) |
|
|
|
if (nodes.OfType<IMayRequireMeshUV>().Any(x => x.RequiresMeshUV(channel))) |
|
|
|
meshUV.Add(channel); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
requiresMeshUVs = meshUV |
|
|
|
}; |
|
|
|
|
|
|
|
ListPool<INode>.Release(activeNodeList); |
|
|
|
return reqs; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
return GetShader(node, GenerationMode.Preview, string.Format("hidden/preview/{0}", node.GetVariableNameForNode()), out configuredTextures, out previewMode); |
|
|
|
} |
|
|
|
|
|
|
|
protected static void GenerateSurfaceDescriptionStruct(ShaderGenerator surfaceDescriptionStruct, AbstractMaterialNode node, bool isMasterNode) |
|
|
|
protected static void GenerateSurfaceDescriptionStruct(ShaderGenerator surfaceDescriptionStruct, List<MaterialSlot> slots) |
|
|
|
if (isMasterNode) |
|
|
|
foreach (var slot in slots) |
|
|
|
foreach (var slot in node.GetInputSlots<MaterialSlot>()) |
|
|
|
if (slot.isInputSlot) |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
foreach (var slot in node.GetOutputSlots<MaterialSlot>()) |
|
|
|
surfaceDescriptionStruct.AddShaderChunk(string.Format("{0} {1};", AbstractMaterialNode.ConvertConcreteSlotValueTypeToString(AbstractMaterialNode.OutputPrecision.@float, slot.concreteValueType), node.GetVariableNameForSlot(slot.id)), false); |
|
|
|
else |
|
|
|
surfaceDescriptionStruct.AddShaderChunk(string.Format("{0} {1};", AbstractMaterialNode.ConvertConcreteSlotValueTypeToString(AbstractMaterialNode.OutputPrecision.@float, slot.concreteValueType), ((AbstractMaterialNode) slot.owner).GetVariableNameForSlot(slot.id)), false); |
|
|
|
} |
|
|
|
surfaceDescriptionStruct.Deindent(); |
|
|
|
surfaceDescriptionStruct.AddShaderChunk("};", false); |
|
|
|
|
|
|
if (isMasterNode) |
|
|
|
foreach (var slot in slots) |
|
|
|
foreach (var slot in node.GetInputSlots<MaterialSlot>()) |
|
|
|
surfaceDescriptionStruct.AddShaderChunk( string.Format("surface.{0} = scale * surface.{0};", slot.shaderOutputName), false); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
foreach (var slot in node.GetOutputSlots<MaterialSlot>()) |
|
|
|
surfaceDescriptionStruct.AddShaderChunk(string.Format("surface.{0} = scale * surface.{0};", node.GetVariableNameForSlot(slot.id)), false); |
|
|
|
if (slot.isInputSlot) |
|
|
|
surfaceDescriptionStruct.AddShaderChunk(string.Format("surface.{0} = scale * surface.{0};", slot.shaderOutputName), false); |
|
|
|
else |
|
|
|
surfaceDescriptionStruct.AddShaderChunk(string.Format("surface.{0} = scale * surface.{0};", ((AbstractMaterialNode) slot.owner).GetVariableNameForSlot(slot.id)), false); |
|
|
|
} |
|
|
|
surfaceDescriptionStruct.Deindent(); |
|
|
|
surfaceDescriptionStruct.AddShaderChunk("};", false); |
|
|
|
|
|
|
if (isMasterNode) |
|
|
|
{ |
|
|
|
foreach (var slot in node.GetInputSlots<MaterialSlot>()) |
|
|
|
{ |
|
|
|
var str = string.Format("base.{0} = base.{0} + add.{0};", slot.shaderOutputName); |
|
|
|
surfaceDescriptionStruct.AddShaderChunk(str, false); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
foreach (var slot in slots) |
|
|
|
foreach (var slot in node.GetOutputSlots<MaterialSlot>()) |
|
|
|
{ |
|
|
|
var str = string.Format("base.{0} = base.{0} + add.{0};", node.GetVariableNameForSlot(slot.id)); |
|
|
|
surfaceDescriptionStruct.AddShaderChunk(str, false); |
|
|
|
} |
|
|
|
if (slot.isInputSlot) |
|
|
|
surfaceDescriptionStruct.AddShaderChunk(string.Format("base.{0} = base.{0} + add.{0};", slot.shaderOutputName), false); |
|
|
|
else |
|
|
|
surfaceDescriptionStruct.AddShaderChunk(string.Format("base.{0} = base.{0} + add.{0};", ((AbstractMaterialNode) slot.owner).GetVariableNameForSlot(slot.id)), false); |
|
|
|
} |
|
|
|
surfaceDescriptionStruct.Deindent(); |
|
|
|
surfaceDescriptionStruct.AddShaderChunk("};", false); |
|
|
|
|
|
|
List<INode> activeNodeList, |
|
|
|
AbstractMaterialNode node, |
|
|
|
ShaderGenerator surfaceDescriptionFunction, |
|
|
|
ShaderGenerator shaderFunctionVisitor, |
|
|
|
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("{0} {1}(SurfaceInputs IN) {{", surfaceDescriptionName, functionName), false); |
|
|
|
surfaceDescriptionFunction.Indent(); |
|
|
|
|
|
|
|
if ((requirements.requiresNormal & NeededCoordinateSpace.Object) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Object.ToVariableName(InterpolatorType.Normal)), false); |
|
|
|
if ((requirements.requiresNormal & NeededCoordinateSpace.View) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.View.ToVariableName(InterpolatorType.Normal)), false); |
|
|
|
if ((requirements.requiresNormal & NeededCoordinateSpace.World) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.World.ToVariableName(InterpolatorType.Normal)), false); |
|
|
|
if ((requirements.requiresNormal & NeededCoordinateSpace.Tangent) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Tangent.ToVariableName(InterpolatorType.Normal)), false); |
|
|
|
|
|
|
|
if ((requirements.requiresTangent & NeededCoordinateSpace.Object) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Object.ToVariableName(InterpolatorType.Tangent)), false); |
|
|
|
if ((requirements.requiresTangent & NeededCoordinateSpace.View) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.View.ToVariableName(InterpolatorType.Tangent)), false); |
|
|
|
if ((requirements.requiresTangent & NeededCoordinateSpace.World) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.World.ToVariableName(InterpolatorType.Tangent)), false); |
|
|
|
if ((requirements.requiresTangent & NeededCoordinateSpace.Tangent) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Tangent.ToVariableName(InterpolatorType.Tangent)), false); |
|
|
|
|
|
|
|
if ((requirements.requiresBitangent & NeededCoordinateSpace.Object) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Object.ToVariableName(InterpolatorType.BiTangent)), false); |
|
|
|
if ((requirements.requiresBitangent & NeededCoordinateSpace.View) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.View.ToVariableName(InterpolatorType.BiTangent)), false); |
|
|
|
if ((requirements.requiresBitangent & NeededCoordinateSpace.World) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.World.ToVariableName(InterpolatorType.BiTangent)), false); |
|
|
|
if ((requirements.requiresBitangent & NeededCoordinateSpace.Tangent) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Tangent.ToVariableName(InterpolatorType.BiTangent)), false); |
|
|
|
if ((requirements.requiresViewDir & NeededCoordinateSpace.Object) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Object.ToVariableName(InterpolatorType.ViewDirection)), false); |
|
|
|
if ((requirements.requiresViewDir & NeededCoordinateSpace.View) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.View.ToVariableName(InterpolatorType.ViewDirection)), false); |
|
|
|
if ((requirements.requiresViewDir & NeededCoordinateSpace.World) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.World.ToVariableName(InterpolatorType.ViewDirection)), false); |
|
|
|
if ((requirements.requiresViewDir & NeededCoordinateSpace.Tangent) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Tangent.ToVariableName(InterpolatorType.ViewDirection)), false); |
|
|
|
|
|
|
|
if ((requirements.requiresPosition & NeededCoordinateSpace.Object) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Object.ToVariableName(InterpolatorType.Position)), false); |
|
|
|
if ((requirements.requiresPosition & NeededCoordinateSpace.View) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.View.ToVariableName(InterpolatorType.Position)), false); |
|
|
|
if ((requirements.requiresPosition & NeededCoordinateSpace.World) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.World.ToVariableName(InterpolatorType.Position)), false); |
|
|
|
if ((requirements.requiresPosition & NeededCoordinateSpace.Tangent) > 0) |
|
|
|
surfaceDescriptionFunction.AddShaderChunk(string.Format("float3 {0} = IN.{0};", CoordinateSpace.Tangent.ToVariableName(InterpolatorType.Position)), 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); |
|
|
|
|
|
|
|
|
|
|
graph.CollectShaderProperties(shaderProperties, mode); |
|
|
|
|
|
|
|
var activeNodeList = ListPool<INode>.Get(); |
|
|
|
NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, node); |
|
|
|
foreach (var activeNode in activeNodeList.OfType<AbstractMaterialNode>()) |
|
|
|
{ |
|
|
|
if (activeNode is IGeneratesFunction) |
|
|
|
|
|
|
surfaceDescriptionFunction.AddShaderChunk("return surface;", false); |
|
|
|
surfaceDescriptionFunction.Deindent(); |
|
|
|
surfaceDescriptionFunction.AddShaderChunk("}", false); |
|
|
|
ListPool<INode>.Release(activeNodeList); |
|
|
|
public string GetShader(AbstractMaterialNode node, GenerationMode mode, string name, out List<PropertyCollector.TextureInfo> configuredTextures, out PreviewMode previewMode) |
|
|
|
static void Visit(List<INode> outputList, Dictionary<Guid, INode> unmarkedNodes, INode node) |
|
|
|
{ |
|
|
|
if (!unmarkedNodes.ContainsKey(node.guid)) |
|
|
|
return; |
|
|
|
foreach (var slot in node.GetInputSlots<ISlot>()) |
|
|
|
{ |
|
|
|
foreach (var edge in node.owner.GetEdges(slot.slotReference)) |
|
|
|
{ |
|
|
|
var inputNode = node.owner.GetNodeFromGuid(edge.outputSlot.nodeGuid); |
|
|
|
Visit(outputList, unmarkedNodes, inputNode); |
|
|
|
} |
|
|
|
} |
|
|
|
unmarkedNodes.Remove(node.guid); |
|
|
|
outputList.Add(node); |
|
|
|
} |
|
|
|
|
|
|
|
public string GetShader(AbstractMaterialNode node, GenerationMode mode, string name, out List<PropertyCollector.TextureInfo> configuredTextures, out PreviewMode previewMode, bool isUber = false) |
|
|
|
{ |
|
|
|
if (node == null) |
|
|
|
throw new ArgumentNullException("node"); |
|
|
|
|
|
|
|
|
|
|
surfaceInputs.AddShaderChunk("struct SurfaceInputs{", false); |
|
|
|
surfaceInputs.Indent(); |
|
|
|
var requirements = GetRequierments(node); |
|
|
|
|
|
|
|
var activeNodeList = ListPool<INode>.Get(); |
|
|
|
if (isUber) |
|
|
|
{ |
|
|
|
var unmarkedNodes = node.owner.GetNodes<INode>().ToDictionary(x => x.guid); |
|
|
|
while (unmarkedNodes.Any()) |
|
|
|
{ |
|
|
|
var unmarkedNode = unmarkedNodes.FirstOrDefault(); |
|
|
|
Visit(activeNodeList, unmarkedNodes, unmarkedNode.Value); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, node); |
|
|
|
} |
|
|
|
|
|
|
|
var requirements = GetRequirements(activeNodeList); |
|
|
|
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, surfaceInputs); |
|
|
|
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, surfaceInputs); |
|
|
|
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, surfaceInputs); |
|
|
|
|
|
|
if (requirements.requiresScreenPosition) |
|
|
|
surfaceInputs.AddShaderChunk(string.Format("float4 {0};", ShaderGeneratorNames.ScreenPosition), false); |
|
|
|
|
|
|
|
var activeNodeList = ListPool<INode>.Get(); |
|
|
|
NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, node); |
|
|
|
previewMode = PreviewMode.Preview2D; |
|
|
|
foreach (var pNode in activeNodeList.OfType<AbstractMaterialNode>()) |
|
|
|
previewMode = PreviewMode.Preview3D; |
|
|
|
if (!isUber) |
|
|
|
if (pNode.previewMode == PreviewMode.Preview3D) |
|
|
|
foreach (var pNode in activeNodeList.OfType<AbstractMaterialNode>()) |
|
|
|
previewMode = PreviewMode.Preview3D; |
|
|
|
break; |
|
|
|
if (pNode.previewMode == PreviewMode.Preview3D) |
|
|
|
{ |
|
|
|
previewMode = PreviewMode.Preview3D; |
|
|
|
break; |
|
|
|
} |
|
|
|
ListPool<INode>.Release(activeNodeList); |
|
|
|
|
|
|
|
foreach (var channel in requirements.requiresMeshUVs.Distinct()) |
|
|
|
surfaceInputs.AddShaderChunk(string.Format("half4 {0};", channel.GetUVName()), false); |
|
|
|
|
|
|
vertexShader.Deindent(); |
|
|
|
vertexShader.AddShaderChunk("}", false); |
|
|
|
|
|
|
|
GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, node, node is IMasterNode); |
|
|
|
var slots = new List<MaterialSlot>(); |
|
|
|
foreach (var activeNode in isUber ? activeNodeList.Where(n => ((AbstractMaterialNode)n).hasPreview) : ((INode)node).ToEnumerable()) |
|
|
|
{ |
|
|
|
if (activeNode is IMasterNode) |
|
|
|
slots.AddRange(activeNode.GetInputSlots<MaterialSlot>()); |
|
|
|
else |
|
|
|
slots.AddRange(activeNode.GetOutputSlots<MaterialSlot>()); |
|
|
|
} |
|
|
|
GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots); |
|
|
|
activeNodeList, |
|
|
|
node, |
|
|
|
surfaceDescriptionFunction, |
|
|
|
shaderFunctionVisitor, |
|
|
|
|
|
|
node is IMasterNode); |
|
|
|
ListPool<INode>.Release(activeNodeList); |
|
|
|
|
|
|
|
var finalShader = new ShaderGenerator(); |
|
|
|
finalShader.AddShaderChunk(string.Format(@"Shader ""{0}""", name), false); |
|
|
|