123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- using System;
- using System.Linq;
- using UnityEngine;
- using UnityEditor.Graphing;
- using UnityEditor.ShaderGraph.Internal;
- using System.Collections.Generic;
- using System.Text.RegularExpressions;
- using UnityEngine.Rendering.ShaderGraph;
-
- namespace UnityEditor.ShaderGraph
- {
- class BlockNode : AbstractMaterialNode
- , IMayRequireNormal
- , IMayRequireTangent
- , IMayRequireBitangent
- , IMayRequireMeshUV
- , IMayRequireScreenPosition
- , IMayRequireNDCPosition
- , IMayRequirePixelPosition
- , IMayRequireViewDirection
- , IMayRequirePosition
- , IMayRequirePositionPredisplacement
- , IMayRequireVertexColor
- {
- [SerializeField]
- string m_SerializedDescriptor;
-
- [NonSerialized]
- ContextData m_ContextData;
-
- [NonSerialized]
- BlockFieldDescriptor m_Descriptor;
-
- public override bool canCutNode => false;
- public override bool canCopyNode => false;
-
- public override string documentationURL => Documentation.GetPageLink("Block-Node");
-
- // Because the GraphData is deserialized after its child elements
- // the descriptor list is not built (and owner is not set)
- // at the time of node deserialization
- // Therefore we need to deserialize this element at GraphData.OnAfterDeserialize
- public string serializedDescriptor => m_SerializedDescriptor;
-
- public ContextData contextData
- {
- get => m_ContextData;
- set => m_ContextData = value;
- }
-
- public int index => contextData.blocks.IndexOf(this);
-
- public BlockFieldDescriptor descriptor
- {
- get => m_Descriptor;
- set => m_Descriptor = value;
- }
-
- const string k_CustomBlockDefaultName = "CustomInterpolator";
-
- internal enum CustomBlockType { Float = 1, Vector2 = 2, Vector3 = 3, Vector4 = 4 }
-
- internal bool isCustomBlock { get => m_Descriptor?.isCustom ?? false; }
-
- internal string customName
- {
- get => m_Descriptor.name;
- set => OnCustomBlockFieldModified(value, customWidth);
- }
-
- internal CustomBlockType customWidth
- {
- get => (CustomBlockType)ControlToWidth(m_Descriptor.control);
- set => OnCustomBlockFieldModified(customName, value);
- }
-
- public void Init(BlockFieldDescriptor fieldDescriptor)
- {
- m_Descriptor = fieldDescriptor;
-
- // custom blocks can be "copied" via a custom Field Descriptor, we'll use the CI name instead though.
- name = !isCustomBlock
- ? $"{fieldDescriptor.tag}.{fieldDescriptor.name}"
- : $"{BlockFields.VertexDescription.name}.{k_CustomBlockDefaultName}";
-
-
- // TODO: This exposes the MaterialSlot API
- // TODO: This needs to be removed but is currently required by HDRP for DiffusionProfileInputMaterialSlot
- if (m_Descriptor is CustomSlotBlockFieldDescriptor customSlotDescriptor)
- {
- var newSlot = customSlotDescriptor.createSlot();
- AddSlot(newSlot);
- RemoveSlotsNameNotMatching(new int[] { 0 });
- return;
- }
-
- AddSlotFromControlType();
- }
-
- internal void InitCustomDefault()
- {
- Init(MakeCustomBlockField(k_CustomBlockDefaultName, CustomBlockType.Vector4));
- }
-
- private void AddSlotFromControlType(bool attemptToModifyExisting = true)
- {
- // TODO: this should really just use callbacks like the CustomSlotBlockFieldDescriptor. then we wouldn't need this switch to make a copy
- var stageCapability = m_Descriptor.shaderStage.GetShaderStageCapability();
- switch (descriptor.control)
- {
- case PositionControl positionControl:
- AddSlot(new PositionMaterialSlot(0, descriptor.displayName, descriptor.name, positionControl.space, stageCapability), attemptToModifyExisting);
- break;
- case NormalControl normalControl:
- AddSlot(new NormalMaterialSlot(0, descriptor.displayName, descriptor.name, normalControl.space, stageCapability), attemptToModifyExisting);
- break;
- case TangentControl tangentControl:
- AddSlot(new TangentMaterialSlot(0, descriptor.displayName, descriptor.name, tangentControl.space, stageCapability), attemptToModifyExisting);
- break;
- case VertexColorControl vertexColorControl:
- AddSlot(new VertexColorMaterialSlot(0, descriptor.displayName, descriptor.name, stageCapability), attemptToModifyExisting);
- break;
- case ColorControl colorControl:
- var colorMode = colorControl.hdr ? ColorMode.HDR : ColorMode.Default;
- AddSlot(new ColorRGBMaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, colorControl.value, colorMode, stageCapability), attemptToModifyExisting);
- break;
- case ColorRGBAControl colorRGBAControl:
- AddSlot(new ColorRGBAMaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, colorRGBAControl.value, stageCapability), attemptToModifyExisting);
- break;
- case FloatControl floatControl:
- AddSlot(new Vector1MaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, floatControl.value, stageCapability), attemptToModifyExisting);
- break;
- case Vector2Control vector2Control:
- AddSlot(new Vector2MaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, vector2Control.value, stageCapability), attemptToModifyExisting);
- break;
- case Vector3Control vector3Control:
- AddSlot(new Vector3MaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, vector3Control.value, stageCapability), attemptToModifyExisting);
- break;
- case Vector4Control vector4Control:
- AddSlot(new Vector4MaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, vector4Control.value, stageCapability), attemptToModifyExisting);
- break;
- }
- RemoveSlotsNameNotMatching(new int[] { 0 });
- }
-
- public override string GetVariableNameForNode()
- {
- // Temporary block nodes have temporary guids that cannot be used to set preview data
- // Since each block is unique anyway we just omit the guid
- return NodeUtils.GetHLSLSafeName(name);
- }
-
- public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return NeededCoordinateSpace.None;
-
- if (m_Descriptor.control == null)
- return NeededCoordinateSpace.None;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresNormal;
- }
-
- public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return NeededCoordinateSpace.None;
-
- if (m_Descriptor.control == null)
- return NeededCoordinateSpace.None;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresViewDir;
- }
-
- public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return NeededCoordinateSpace.None;
-
- if (m_Descriptor.control == null)
- return NeededCoordinateSpace.None;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresPosition;
- }
-
- public NeededCoordinateSpace RequiresPositionPredisplacement(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return NeededCoordinateSpace.None;
-
- if (m_Descriptor.control == null)
- return NeededCoordinateSpace.None;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresPositionPredisplacement;
- }
-
- public NeededCoordinateSpace RequiresTangent(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return NeededCoordinateSpace.None;
-
- if (m_Descriptor.control == null)
- return NeededCoordinateSpace.None;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresTangent;
- }
-
- public NeededCoordinateSpace RequiresBitangent(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return NeededCoordinateSpace.None;
-
- if (m_Descriptor.control == null)
- return NeededCoordinateSpace.None;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresBitangent;
- }
-
- public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return false;
-
- if (m_Descriptor.control == null)
- return false;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresMeshUVs.Contains(channel);
- }
-
- public bool RequiresScreenPosition(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return false;
-
- if (m_Descriptor.control == null)
- return false;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresScreenPosition;
- }
-
- public bool RequiresNDCPosition(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return false;
-
- if (m_Descriptor.control == null)
- return false;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresNDCPosition;
- }
-
- public bool RequiresPixelPosition(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return false;
-
- if (m_Descriptor.control == null)
- return false;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresPixelPosition;
- }
-
- public bool RequiresVertexColor(ShaderStageCapability stageCapability)
- {
- if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability())
- return false;
-
- if (m_Descriptor.control == null)
- return false;
-
- var requirements = m_Descriptor.control.GetRequirements();
- return requirements.requiresVertexColor;
- }
-
- private void OnCustomBlockFieldModified(string name, CustomBlockType width)
- {
- if (!isCustomBlock)
- {
- Debug.LogWarning(String.Format("{0} is not a custom interpolator.", this.name));
- return;
- }
-
- m_Descriptor = MakeCustomBlockField(name, width);
-
- // TODO: Preserve the original slot's value and try to reapply after the slot is updated.
- AddSlotFromControlType(false);
-
- owner?.ValidateGraph();
- }
-
- public override void OnBeforeSerialize()
- {
- base.OnBeforeSerialize();
- if (descriptor != null)
- {
- if (isCustomBlock)
- {
- int width = ControlToWidth(m_Descriptor.control);
- m_SerializedDescriptor = $"{m_Descriptor.tag}.{m_Descriptor.name}#{width}";
- }
- else
- {
- m_SerializedDescriptor = $"{m_Descriptor.tag}.{m_Descriptor.name}";
- }
- }
- }
-
- public override void OnAfterDeserialize()
- {
- // TODO: Go find someone to tell @esme not to do this.
- if (m_SerializedDescriptor.Contains("#"))
- {
- string descName = k_CustomBlockDefaultName;
- CustomBlockType descWidth = CustomBlockType.Vector4;
- var descTag = BlockFields.VertexDescription.name;
-
- name = $"{descTag}.{descName}";
-
- var wsplit = m_SerializedDescriptor.Split(new char[] { '#', '.' });
-
- try
- {
- descWidth = (CustomBlockType)int.Parse(wsplit[2]);
- }
- catch
- {
- Debug.LogWarning(String.Format("Bad width found while deserializing custom interpolator {0}, defaulting to 4.", m_SerializedDescriptor));
- descWidth = CustomBlockType.Vector4;
- }
-
- IControl control;
- try { control = (IControl)FindSlot<MaterialSlot>(0).InstantiateControl(); }
- catch { control = WidthToControl((int)descWidth); }
-
- descName = NodeUtils.ConvertToValidHLSLIdentifier(wsplit[1]);
- m_Descriptor = new BlockFieldDescriptor(descTag, descName, "", control, ShaderStage.Vertex, isCustom: true);
- }
- }
-
- #region CustomInterpolatorHelpers
- private static BlockFieldDescriptor MakeCustomBlockField(string name, CustomBlockType width)
- {
- name = NodeUtils.ConvertToValidHLSLIdentifier(name);
- var referenceName = name;
- var define = "";
- IControl control = WidthToControl((int)width);
- var tag = BlockFields.VertexDescription.name;
-
- return new BlockFieldDescriptor(tag, referenceName, define, control, ShaderStage.Vertex, isCustom: true);
- }
-
- private static IControl WidthToControl(int width)
- {
- switch (width)
- {
- case 1: return new FloatControl(default(float));
- case 2: return new Vector2Control(default(Vector2));
- case 3: return new Vector3Control(default(Vector3));
- case 4: return new Vector4Control(default(Vector4));
- default: return null;
- }
- }
-
- private static int ControlToWidth(IControl control)
- {
- switch (control)
- {
- case FloatControl a: return 1;
- case Vector2Control b: return 2;
- case Vector3Control c: return 3;
- case Vector4Control d: return 4;
- default: return -1;
- }
- }
-
- #endregion
- }
- }
|