123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using JetBrains.Annotations;
- using UnityEngine;
- using UnityEditor.Graphing;
- using UnityEditor.ShaderGraph.Internal;
- namespace UnityEditor.ShaderGraph
- {
- abstract class CodeFunctionNode : AbstractMaterialNode
- , IGeneratesBodyCode
- , IGeneratesFunction
- , IMayRequireNormal
- , IMayRequireTangent
- , IMayRequireBitangent
- , IMayRequireMeshUV
- , IMayRequireScreenPosition
- , IMayRequireViewDirection
- , IMayRequirePosition
- , IMayRequireVertexColor
- {
- [NonSerialized]
- private List<SlotAttribute> m_Slots = new List<SlotAttribute>();
- public override bool hasPreview
- {
- get { return true; }
- }
- protected CodeFunctionNode()
- {
- UpdateNodeAfterDeserialization();
- }
- protected struct Boolean
- {}
- protected struct Vector1
- {}
- protected struct Texture2D
- {}
- protected struct Texture2DArray
- {}
- protected struct Texture3D
- {}
- protected struct SamplerState
- {}
- protected struct Gradient
- {}
- protected struct DynamicDimensionVector
- {}
- protected struct ColorRGBA
- {}
- protected struct ColorRGB
- {}
- protected struct Matrix3x3
- {}
- protected struct Matrix2x2
- {}
- protected struct DynamicDimensionMatrix
- {}
- protected enum Binding
- {
- None,
- ObjectSpaceNormal,
- ObjectSpaceTangent,
- ObjectSpaceBitangent,
- ObjectSpacePosition,
- ViewSpaceNormal,
- ViewSpaceTangent,
- ViewSpaceBitangent,
- ViewSpacePosition,
- WorldSpaceNormal,
- WorldSpaceTangent,
- WorldSpaceBitangent,
- WorldSpacePosition,
- TangentSpaceNormal,
- TangentSpaceTangent,
- TangentSpaceBitangent,
- TangentSpacePosition,
- MeshUV0,
- MeshUV1,
- MeshUV2,
- MeshUV3,
- ScreenPosition,
- ObjectSpaceViewDirection,
- ViewSpaceViewDirection,
- WorldSpaceViewDirection,
- TangentSpaceViewDirection,
- VertexColor,
- }
- [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
- protected class SlotAttribute : Attribute
- {
- public int slotId { get; private set; }
- public Binding binding { get; private set; }
- public bool hidden { get; private set; }
- public Vector4? defaultValue { get; private set; }
- public ShaderStageCapability stageCapability { get; private set; }
- public SlotAttribute(int mSlotId, Binding mImplicitBinding, ShaderStageCapability mStageCapability = ShaderStageCapability.All)
- {
- slotId = mSlotId;
- binding = mImplicitBinding;
- defaultValue = null;
- stageCapability = mStageCapability;
- }
- public SlotAttribute(int mSlotId, Binding mImplicitBinding, bool mHidden, ShaderStageCapability mStageCapability = ShaderStageCapability.All)
- {
- slotId = mSlotId;
- binding = mImplicitBinding;
- hidden = mHidden;
- defaultValue = null;
- stageCapability = mStageCapability;
- }
- public SlotAttribute(int mSlotId, Binding mImplicitBinding, float defaultX, float defaultY, float defaultZ, float defaultW, ShaderStageCapability mStageCapability = ShaderStageCapability.All)
- {
- slotId = mSlotId;
- binding = mImplicitBinding;
- defaultValue = new Vector4(defaultX, defaultY, defaultZ, defaultW);
- stageCapability = mStageCapability;
- }
- }
- protected abstract MethodInfo GetFunctionToConvert();
- private static SlotValueType ConvertTypeToSlotValueType(ParameterInfo p)
- {
- Type t = p.ParameterType;
- if (p.ParameterType.IsByRef)
- t = p.ParameterType.GetElementType();
- if (t == typeof(Boolean))
- {
- return SlotValueType.Boolean;
- }
- if (t == typeof(Vector1))
- {
- return SlotValueType.Vector1;
- }
- if (t == typeof(Vector2))
- {
- return SlotValueType.Vector2;
- }
- if (t == typeof(Vector3))
- {
- return SlotValueType.Vector3;
- }
- if (t == typeof(Vector4))
- {
- return SlotValueType.Vector4;
- }
- if (t == typeof(Color))
- {
- return SlotValueType.Vector4;
- }
- if (t == typeof(ColorRGBA))
- {
- return SlotValueType.Vector4;
- }
- if (t == typeof(ColorRGB))
- {
- return SlotValueType.Vector3;
- }
- if (t == typeof(Texture2D))
- {
- return SlotValueType.Texture2D;
- }
- if (t == typeof(Texture2DArray))
- {
- return SlotValueType.Texture2DArray;
- }
- if (t == typeof(Texture3D))
- {
- return SlotValueType.Texture3D;
- }
- if (t == typeof(Cubemap))
- {
- return SlotValueType.Cubemap;
- }
- if (t == typeof(Gradient))
- {
- return SlotValueType.Gradient;
- }
- if (t == typeof(SamplerState))
- {
- return SlotValueType.SamplerState;
- }
- if (t == typeof(DynamicDimensionVector))
- {
- return SlotValueType.DynamicVector;
- }
- if (t == typeof(Matrix4x4))
- {
- return SlotValueType.Matrix4;
- }
- if (t == typeof(Matrix3x3))
- {
- return SlotValueType.Matrix3;
- }
- if (t == typeof(Matrix2x2))
- {
- return SlotValueType.Matrix2;
- }
- if (t == typeof(DynamicDimensionMatrix))
- {
- return SlotValueType.DynamicMatrix;
- }
- throw new ArgumentException("Unsupported type " + t);
- }
- public sealed override void UpdateNodeAfterDeserialization()
- {
- var method = GetFunctionToConvert();
- if (method == null)
- throw new ArgumentException("Mapped method is null on node" + this);
- if (method.ReturnType != typeof(string))
- throw new ArgumentException("Mapped function should return string");
- // validate no duplicates
- var slotAtributes = method.GetParameters().Select(GetSlotAttribute).ToList();
- if (slotAtributes.Any(x => x == null))
- throw new ArgumentException("Missing SlotAttribute on " + method.Name);
- if (slotAtributes.GroupBy(x => x.slotId).Any(x => x.Count() > 1))
- throw new ArgumentException("Duplicate SlotAttribute on " + method.Name);
- List<MaterialSlot> slots = new List<MaterialSlot>();
- foreach (var par in method.GetParameters())
- {
- var attribute = GetSlotAttribute(par);
- var name = GraphUtil.ConvertCamelCase(par.Name, true);
- MaterialSlot s;
- if (attribute.binding == Binding.None && !par.IsOut && par.ParameterType == typeof(Color))
- s = new ColorRGBAMaterialSlot(attribute.slotId, name, par.Name, SlotType.Input, attribute.defaultValue ?? Vector4.zero, stageCapability: attribute.stageCapability, hidden: attribute.hidden);
- else if (attribute.binding == Binding.None && !par.IsOut && par.ParameterType == typeof(ColorRGBA))
- s = new ColorRGBAMaterialSlot(attribute.slotId, name, par.Name, SlotType.Input, attribute.defaultValue ?? Vector4.zero, stageCapability: attribute.stageCapability, hidden: attribute.hidden);
- else if (attribute.binding == Binding.None && !par.IsOut && par.ParameterType == typeof(ColorRGB))
- s = new ColorRGBMaterialSlot(attribute.slotId, name, par.Name, SlotType.Input, attribute.defaultValue ?? Vector4.zero, ColorMode.Default, stageCapability: attribute.stageCapability, hidden: attribute.hidden);
- else if (attribute.binding == Binding.None || par.IsOut)
- s = MaterialSlot.CreateMaterialSlot(
- ConvertTypeToSlotValueType(par),
- attribute.slotId,
- name,
- par.Name,
- par.IsOut ? SlotType.Output : SlotType.Input,
- attribute.defaultValue ?? Vector4.zero,
- shaderStageCapability: attribute.stageCapability,
- hidden: attribute.hidden);
- else
- s = CreateBoundSlot(attribute.binding, attribute.slotId, name, par.Name, attribute.stageCapability, attribute.hidden);
- slots.Add(s);
- m_Slots.Add(attribute);
- }
- foreach (var slot in slots)
- {
- AddSlot(slot);
- }
- RemoveSlotsNameNotMatching(slots.Select(x => x.id));
- }
- private static MaterialSlot CreateBoundSlot(Binding attributeBinding, int slotId, string displayName, string shaderOutputName, ShaderStageCapability shaderStageCapability, bool hidden)
- {
- switch (attributeBinding)
- {
- case Binding.ObjectSpaceNormal:
- return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
- case Binding.ObjectSpaceTangent:
- return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
- case Binding.ObjectSpaceBitangent:
- return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
- case Binding.ObjectSpacePosition:
- return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
- case Binding.ViewSpaceNormal:
- return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
- case Binding.ViewSpaceTangent:
- return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
- case Binding.ViewSpaceBitangent:
- return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
- case Binding.ViewSpacePosition:
- return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
- case Binding.WorldSpaceNormal:
- return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
- case Binding.WorldSpaceTangent:
- return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
- case Binding.WorldSpaceBitangent:
- return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
- case Binding.WorldSpacePosition:
- return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
- case Binding.TangentSpaceNormal:
- return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
- case Binding.TangentSpaceTangent:
- return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
- case Binding.TangentSpaceBitangent:
- return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
- case Binding.TangentSpacePosition:
- return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
- case Binding.MeshUV0:
- return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV0, shaderStageCapability);
- case Binding.MeshUV1:
- return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV1, shaderStageCapability);
- case Binding.MeshUV2:
- return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV2, shaderStageCapability);
- case Binding.MeshUV3:
- return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV3, shaderStageCapability);
- case Binding.ScreenPosition:
- return new ScreenPositionMaterialSlot(slotId, displayName, shaderOutputName, ScreenSpaceType.Default, shaderStageCapability);
- case Binding.ObjectSpaceViewDirection:
- return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
- case Binding.ViewSpaceViewDirection:
- return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
- case Binding.WorldSpaceViewDirection:
- return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
- case Binding.TangentSpaceViewDirection:
- return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
- case Binding.VertexColor:
- return new VertexColorMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability);
- default:
- throw new ArgumentOutOfRangeException("attributeBinding", attributeBinding, null);
- }
- }
- public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
- {
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetOutputSlots(tempSlots);
- foreach (var outSlot in tempSlots)
- {
- sb.AppendLine(outSlot.concreteValueType.ToShaderString() + " " + GetVariableNameForSlot(outSlot.id) + ";");
- }
- string call = GetFunctionName() + "(";
- bool first = true;
- tempSlots.Clear();
- GetSlots(tempSlots);
- tempSlots.Sort((slot1, slot2) => slot1.id.CompareTo(slot2.id));
- foreach (var slot in tempSlots)
- {
- if (!first)
- {
- call += ", ";
- }
- first = false;
- if (slot.isInputSlot)
- call += GetSlotValue(slot.id, generationMode);
- else
- call += GetVariableNameForSlot(slot.id);
- }
- call += ");";
- sb.AppendLine(call);
- }
- }
- private string GetFunctionName()
- {
- var function = GetFunctionToConvert();
- return function.Name + (function.IsStatic ? string.Empty : "_" + GuidEncoder.Encode(guid)) + "_" + concretePrecision.ToShaderString()
- + (this.GetSlots<DynamicVectorMaterialSlot>().Select(s => NodeUtils.GetSlotDimension(s.concreteValueType)).FirstOrDefault() ?? "")
- + (this.GetSlots<DynamicMatrixMaterialSlot>().Select(s => NodeUtils.GetSlotDimension(s.concreteValueType)).FirstOrDefault() ?? "");
- }
- private string GetFunctionHeader()
- {
- string header = "void " + GetFunctionName() + "(";
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetSlots(tempSlots);
- tempSlots.Sort((slot1, slot2) => slot1.id.CompareTo(slot2.id));
- var first = true;
- foreach (var slot in tempSlots)
- {
- if (!first)
- header += ", ";
- first = false;
- if (slot.isOutputSlot)
- header += "out ";
- header += slot.concreteValueType.ToShaderString() + " " + slot.shaderOutputName;
- }
- header += ")";
- }
- return header;
- }
- private static object GetDefault(Type type)
- {
- return type.IsValueType ? Activator.CreateInstance(type) : null;
- }
- private string GetFunctionBody(MethodInfo info)
- {
- var args = new List<object>();
- foreach (var param in info.GetParameters())
- args.Add(GetDefault(param.ParameterType));
- var result = info.Invoke(this, args.ToArray()) as string;
- if (string.IsNullOrEmpty(result))
- return string.Empty;
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetSlots(tempSlots);
- foreach (var slot in tempSlots)
- {
- var toReplace = string.Format("{{slot{0}dimension}}", slot.id);
- var replacement = NodeUtils.GetSlotDimension(slot.concreteValueType);
- result = result.Replace(toReplace, replacement);
- }
- }
- return result;
- }
- public virtual void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
- {
- registry.ProvideFunction(GetFunctionName(), s =>
- {
- s.AppendLine(GetFunctionHeader());
- var functionBody = GetFunctionBody(GetFunctionToConvert());
- var lines = functionBody.Trim('\r', '\n', '\t', ' ');
- s.AppendLines(lines);
- });
- }
- private static SlotAttribute GetSlotAttribute([NotNull] ParameterInfo info)
- {
- var attrs = info.GetCustomAttributes(typeof(SlotAttribute), false).OfType<SlotAttribute>().ToList();
- return attrs.FirstOrDefault();
- }
- public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability)
- {
- var binding = NeededCoordinateSpace.None;
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetInputSlots(tempSlots);
- foreach (var slot in tempSlots)
- binding |= slot.RequiresNormal();
- return binding;
- }
- }
- public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability)
- {
- var binding = NeededCoordinateSpace.None;
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetInputSlots(tempSlots);
- foreach (var slot in tempSlots)
- binding |= slot.RequiresViewDirection();
- return binding;
- }
- }
- public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability)
- {
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetInputSlots(tempSlots);
- var binding = NeededCoordinateSpace.None;
- foreach (var slot in tempSlots)
- binding |= slot.RequiresPosition();
- return binding;
- }
- }
- public NeededCoordinateSpace RequiresTangent(ShaderStageCapability stageCapability)
- {
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetInputSlots(tempSlots);
- var binding = NeededCoordinateSpace.None;
- foreach (var slot in tempSlots)
- binding |= slot.RequiresTangent();
- return binding;
- }
- }
- public NeededCoordinateSpace RequiresBitangent(ShaderStageCapability stageCapability)
- {
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetInputSlots(tempSlots);
- var binding = NeededCoordinateSpace.None;
- foreach (var slot in tempSlots)
- binding |= slot.RequiresBitangent();
- return binding;
- }
- }
- public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
- {
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetInputSlots(tempSlots);
- foreach (var slot in tempSlots)
- {
- if (slot.RequiresMeshUV(channel))
- return true;
- }
- return false;
- }
- }
- public bool RequiresScreenPosition(ShaderStageCapability stageCapability)
- {
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetInputSlots(tempSlots);
- foreach (var slot in tempSlots)
- {
- if (slot.RequiresScreenPosition())
- return true;
- }
- return false;
- }
- }
- public bool RequiresVertexColor(ShaderStageCapability stageCapability)
- {
- using (var tempSlots = PooledList<MaterialSlot>.Get())
- {
- GetInputSlots(tempSlots);
- foreach (var slot in tempSlots)
- {
- if (slot.RequiresVertexColor())
- return true;
- }
- return false;
- }
- }
- }
- }
|