A game about forced loneliness, made by TACStudios
1using System; 2using System.Linq; 3using UnityEngine; 4using UnityEditor.Graphing; 5using UnityEditor.ShaderGraph.Internal; 6using System.Collections.Generic; 7using System.Text.RegularExpressions; 8using UnityEngine.Rendering.ShaderGraph; 9 10namespace UnityEditor.ShaderGraph 11{ 12 class BlockNode : AbstractMaterialNode 13 , IMayRequireNormal 14 , IMayRequireTangent 15 , IMayRequireBitangent 16 , IMayRequireMeshUV 17 , IMayRequireScreenPosition 18 , IMayRequireNDCPosition 19 , IMayRequirePixelPosition 20 , IMayRequireViewDirection 21 , IMayRequirePosition 22 , IMayRequirePositionPredisplacement 23 , IMayRequireVertexColor 24 { 25 [SerializeField] 26 string m_SerializedDescriptor; 27 28 [NonSerialized] 29 ContextData m_ContextData; 30 31 [NonSerialized] 32 BlockFieldDescriptor m_Descriptor; 33 34 public override string displayName 35 { 36 get 37 { 38 string displayName = ""; 39 if (m_Descriptor != null) 40 { 41 displayName = m_Descriptor.shaderStage.ToString(); 42 if (!string.IsNullOrEmpty(displayName)) 43 displayName += " "; 44 displayName += m_Descriptor.displayName; 45 } 46 47 return displayName; 48 } 49 } 50 51 public override bool canCutNode => false; 52 public override bool canCopyNode => false; 53 54 public override string documentationURL => Documentation.GetPageLink("Block-Node"); 55 56 // Because the GraphData is deserialized after its child elements 57 // the descriptor list is not built (and owner is not set) 58 // at the time of node deserialization 59 // Therefore we need to deserialize this element at GraphData.OnAfterDeserialize 60 public string serializedDescriptor => m_SerializedDescriptor; 61 62 public ContextData contextData 63 { 64 get => m_ContextData; 65 set => m_ContextData = value; 66 } 67 68 public int index => contextData.blocks.IndexOf(this); 69 70 public BlockFieldDescriptor descriptor 71 { 72 get => m_Descriptor; 73 set => m_Descriptor = value; 74 } 75 76 const string k_CustomBlockDefaultName = "CustomInterpolator"; 77 78 internal enum CustomBlockType { Float = 1, Vector2 = 2, Vector3 = 3, Vector4 = 4 } 79 80 internal bool isCustomBlock { get => m_Descriptor?.isCustom ?? false; } 81 82 internal string customName 83 { 84 get => m_Descriptor.name; 85 set => OnCustomBlockFieldModified(value, customWidth); 86 } 87 88 internal CustomBlockType customWidth 89 { 90 get => (CustomBlockType)ControlToWidth(m_Descriptor.control); 91 set => OnCustomBlockFieldModified(customName, value); 92 } 93 94 public void Init(BlockFieldDescriptor fieldDescriptor) 95 { 96 m_Descriptor = fieldDescriptor; 97 98 // custom blocks can be "copied" via a custom Field Descriptor, we'll use the CI name instead though. 99 name = !isCustomBlock 100 ? $"{fieldDescriptor.tag}.{fieldDescriptor.name}" 101 : $"{BlockFields.VertexDescription.name}.{k_CustomBlockDefaultName}"; 102 103 // TODO: This exposes the MaterialSlot API 104 // TODO: This needs to be removed but is currently required by HDRP for DiffusionProfileInputMaterialSlot 105 if (m_Descriptor is CustomSlotBlockFieldDescriptor customSlotDescriptor) 106 { 107 var newSlot = customSlotDescriptor.createSlot(); 108 AddSlot(newSlot); 109 RemoveSlotsNameNotMatching(new int[] { 0 }); 110 return; 111 } 112 113 AddSlotFromControlType(); 114 } 115 116 internal void InitCustomDefault() 117 { 118 Init(MakeCustomBlockField(k_CustomBlockDefaultName, CustomBlockType.Vector4)); 119 } 120 121 private void AddSlotFromControlType(bool attemptToModifyExisting = true) 122 { 123 // TODO: this should really just use callbacks like the CustomSlotBlockFieldDescriptor. then we wouldn't need this switch to make a copy 124 var stageCapability = m_Descriptor.shaderStage.GetShaderStageCapability(); 125 switch (descriptor.control) 126 { 127 case PositionControl positionControl: 128 AddSlot(new PositionMaterialSlot(0, descriptor.displayName, descriptor.name, positionControl.space, stageCapability), attemptToModifyExisting); 129 break; 130 case NormalControl normalControl: 131 AddSlot(new NormalMaterialSlot(0, descriptor.displayName, descriptor.name, normalControl.space, stageCapability), attemptToModifyExisting); 132 break; 133 case TangentControl tangentControl: 134 AddSlot(new TangentMaterialSlot(0, descriptor.displayName, descriptor.name, tangentControl.space, stageCapability), attemptToModifyExisting); 135 break; 136 case VertexColorControl vertexColorControl: 137 AddSlot(new VertexColorMaterialSlot(0, descriptor.displayName, descriptor.name, stageCapability), attemptToModifyExisting); 138 break; 139 case ColorControl colorControl: 140 var colorMode = colorControl.hdr ? ColorMode.HDR : ColorMode.Default; 141 AddSlot(new ColorRGBMaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, colorControl.value, colorMode, stageCapability), attemptToModifyExisting); 142 break; 143 case ColorRGBAControl colorRGBAControl: 144 AddSlot(new ColorRGBAMaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, colorRGBAControl.value, stageCapability), attemptToModifyExisting); 145 break; 146 case FloatControl floatControl: 147 AddSlot(new Vector1MaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, floatControl.value, stageCapability), attemptToModifyExisting); 148 break; 149 case Vector2Control vector2Control: 150 AddSlot(new Vector2MaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, vector2Control.value, stageCapability), attemptToModifyExisting); 151 break; 152 case Vector3Control vector3Control: 153 AddSlot(new Vector3MaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, vector3Control.value, stageCapability), attemptToModifyExisting); 154 break; 155 case Vector4Control vector4Control: 156 AddSlot(new Vector4MaterialSlot(0, descriptor.displayName, descriptor.name, SlotType.Input, vector4Control.value, stageCapability), attemptToModifyExisting); 157 break; 158 } 159 RemoveSlotsNameNotMatching(new int[] { 0 }); 160 } 161 162 public override string GetVariableNameForNode() 163 { 164 // Temporary block nodes have temporary guids that cannot be used to set preview data 165 // Since each block is unique anyway we just omit the guid 166 return NodeUtils.GetHLSLSafeName(name); 167 } 168 169 public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability) 170 { 171 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 172 return NeededCoordinateSpace.None; 173 174 if (m_Descriptor.control == null) 175 return NeededCoordinateSpace.None; 176 177 var requirements = m_Descriptor.control.GetRequirements(); 178 return requirements.requiresNormal; 179 } 180 181 public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability) 182 { 183 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 184 return NeededCoordinateSpace.None; 185 186 if (m_Descriptor.control == null) 187 return NeededCoordinateSpace.None; 188 189 var requirements = m_Descriptor.control.GetRequirements(); 190 return requirements.requiresViewDir; 191 } 192 193 public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability) 194 { 195 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 196 return NeededCoordinateSpace.None; 197 198 if (m_Descriptor.control == null) 199 return NeededCoordinateSpace.None; 200 201 var requirements = m_Descriptor.control.GetRequirements(); 202 return requirements.requiresPosition; 203 } 204 205 public NeededCoordinateSpace RequiresPositionPredisplacement(ShaderStageCapability stageCapability) 206 { 207 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 208 return NeededCoordinateSpace.None; 209 210 if (m_Descriptor.control == null) 211 return NeededCoordinateSpace.None; 212 213 var requirements = m_Descriptor.control.GetRequirements(); 214 return requirements.requiresPositionPredisplacement; 215 } 216 217 public NeededCoordinateSpace RequiresTangent(ShaderStageCapability stageCapability) 218 { 219 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 220 return NeededCoordinateSpace.None; 221 222 if (m_Descriptor.control == null) 223 return NeededCoordinateSpace.None; 224 225 var requirements = m_Descriptor.control.GetRequirements(); 226 return requirements.requiresTangent; 227 } 228 229 public NeededCoordinateSpace RequiresBitangent(ShaderStageCapability stageCapability) 230 { 231 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 232 return NeededCoordinateSpace.None; 233 234 if (m_Descriptor.control == null) 235 return NeededCoordinateSpace.None; 236 237 var requirements = m_Descriptor.control.GetRequirements(); 238 return requirements.requiresBitangent; 239 } 240 241 public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability) 242 { 243 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 244 return false; 245 246 if (m_Descriptor.control == null) 247 return false; 248 249 var requirements = m_Descriptor.control.GetRequirements(); 250 return requirements.requiresMeshUVs.Contains(channel); 251 } 252 253 public bool RequiresScreenPosition(ShaderStageCapability stageCapability) 254 { 255 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 256 return false; 257 258 if (m_Descriptor.control == null) 259 return false; 260 261 var requirements = m_Descriptor.control.GetRequirements(); 262 return requirements.requiresScreenPosition; 263 } 264 265 public bool RequiresNDCPosition(ShaderStageCapability stageCapability) 266 { 267 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 268 return false; 269 270 if (m_Descriptor.control == null) 271 return false; 272 273 var requirements = m_Descriptor.control.GetRequirements(); 274 return requirements.requiresNDCPosition; 275 } 276 277 public bool RequiresPixelPosition(ShaderStageCapability stageCapability) 278 { 279 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 280 return false; 281 282 if (m_Descriptor.control == null) 283 return false; 284 285 var requirements = m_Descriptor.control.GetRequirements(); 286 return requirements.requiresPixelPosition; 287 } 288 289 public bool RequiresVertexColor(ShaderStageCapability stageCapability) 290 { 291 if (stageCapability != m_Descriptor.shaderStage.GetShaderStageCapability()) 292 return false; 293 294 if (m_Descriptor.control == null) 295 return false; 296 297 var requirements = m_Descriptor.control.GetRequirements(); 298 return requirements.requiresVertexColor; 299 } 300 301 private void OnCustomBlockFieldModified(string name, CustomBlockType width) 302 { 303 if (!isCustomBlock) 304 { 305 Debug.LogWarning(String.Format("{0} is not a custom interpolator.", this.name)); 306 return; 307 } 308 309 m_Descriptor = MakeCustomBlockField(name, width); 310 311 // TODO: Preserve the original slot's value and try to reapply after the slot is updated. 312 AddSlotFromControlType(false); 313 314 owner?.ValidateGraph(); 315 } 316 317 public override void OnBeforeSerialize() 318 { 319 base.OnBeforeSerialize(); 320 if (descriptor != null) 321 { 322 if (isCustomBlock) 323 { 324 int width = ControlToWidth(m_Descriptor.control); 325 m_SerializedDescriptor = $"{m_Descriptor.tag}.{m_Descriptor.name}#{width}"; 326 } 327 else 328 { 329 m_SerializedDescriptor = $"{m_Descriptor.tag}.{m_Descriptor.name}"; 330 } 331 } 332 } 333 334 public override void OnAfterDeserialize() 335 { 336 // TODO: Go find someone to tell @esme not to do this. 337 if (m_SerializedDescriptor.Contains("#")) 338 { 339 string descName = k_CustomBlockDefaultName; 340 CustomBlockType descWidth = CustomBlockType.Vector4; 341 var descTag = BlockFields.VertexDescription.name; 342 343 name = $"{descTag}.{descName}"; 344 345 var wsplit = m_SerializedDescriptor.Split(new char[] { '#', '.' }); 346 347 try 348 { 349 descWidth = (CustomBlockType)int.Parse(wsplit[2]); 350 } 351 catch 352 { 353 Debug.LogWarning(String.Format("Bad width found while deserializing custom interpolator {0}, defaulting to 4.", m_SerializedDescriptor)); 354 descWidth = CustomBlockType.Vector4; 355 } 356 357 IControl control; 358 try { control = (IControl)FindSlot<MaterialSlot>(0).InstantiateControl(); } 359 catch { control = WidthToControl((int)descWidth); } 360 361 descName = NodeUtils.ConvertToValidHLSLIdentifier(wsplit[1]); 362 m_Descriptor = new BlockFieldDescriptor(descTag, descName, "", control, ShaderStage.Vertex, isCustom: true); 363 } 364 } 365 366 #region CustomInterpolatorHelpers 367 private static BlockFieldDescriptor MakeCustomBlockField(string name, CustomBlockType width) 368 { 369 name = NodeUtils.ConvertToValidHLSLIdentifier(name); 370 var referenceName = name; 371 var define = ""; 372 IControl control = WidthToControl((int)width); 373 var tag = BlockFields.VertexDescription.name; 374 375 return new BlockFieldDescriptor(tag, referenceName, define, control, ShaderStage.Vertex, isCustom: true); 376 } 377 378 private static IControl WidthToControl(int width) 379 { 380 switch (width) 381 { 382 case 1: return new FloatControl(default(float)); 383 case 2: return new Vector2Control(default(Vector2)); 384 case 3: return new Vector3Control(default(Vector3)); 385 case 4: return new Vector4Control(default(Vector4)); 386 default: return null; 387 } 388 } 389 390 private static int ControlToWidth(IControl control) 391 { 392 switch (control) 393 { 394 case FloatControl a: return 1; 395 case Vector2Control b: return 2; 396 case Vector3Control c: return 3; 397 case Vector4Control d: return 4; 398 default: return -1; 399 } 400 } 401 402 #endregion 403 } 404}