A game about forced loneliness, made by TACStudios
at master 25 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Reflection; 5using JetBrains.Annotations; 6using UnityEngine; 7using UnityEditor.Graphing; 8using UnityEditor.ShaderGraph.Internal; 9 10namespace UnityEditor.ShaderGraph 11{ 12 abstract class CodeFunctionNode : AbstractMaterialNode 13 , IGeneratesBodyCode 14 , IGeneratesFunction 15 , IMayRequireNormal 16 , IMayRequireTangent 17 , IMayRequireBitangent 18 , IMayRequireMeshUV 19 , IMayRequireScreenPosition 20 , IMayRequireNDCPosition 21 , IMayRequirePixelPosition 22 , IMayRequireViewDirection 23 , IMayRequirePosition 24 , IMayRequirePositionPredisplacement 25 , IMayRequireVertexColor 26 { 27 [NonSerialized] 28 private List<SlotAttribute> m_Slots = new List<SlotAttribute>(); 29 30 public override bool hasPreview 31 { 32 get { return true; } 33 } 34 35 protected CodeFunctionNode() 36 { 37 UpdateNodeAfterDeserialization(); 38 } 39 40 protected struct Boolean 41 { } 42 43 protected struct Vector1 44 { } 45 46 protected struct Texture2D 47 { } 48 49 protected struct Texture2DArray 50 { } 51 52 protected struct Texture3D 53 { } 54 55 protected struct SamplerState 56 { } 57 58 protected struct Gradient 59 { } 60 61 protected struct DynamicDimensionVector 62 { } 63 64 protected struct ColorRGBA 65 { } 66 67 protected struct ColorRGB 68 { } 69 70 protected struct Matrix3x3 71 { } 72 73 protected struct Matrix2x2 74 { } 75 76 protected struct DynamicDimensionMatrix 77 { } 78 79 protected struct PropertyConnectionState 80 { } 81 82 protected enum Binding 83 { 84 None, 85 ObjectSpaceNormal, 86 ObjectSpaceTangent, 87 ObjectSpaceBitangent, 88 ObjectSpacePosition, 89 ViewSpaceNormal, 90 ViewSpaceTangent, 91 ViewSpaceBitangent, 92 ViewSpacePosition, 93 WorldSpaceNormal, 94 WorldSpaceTangent, 95 WorldSpaceBitangent, 96 WorldSpacePosition, 97 TangentSpaceNormal, 98 TangentSpaceTangent, 99 TangentSpaceBitangent, 100 TangentSpacePosition, 101 MeshUV0, 102 MeshUV1, 103 MeshUV2, 104 MeshUV3, 105 ScreenPosition, 106 ObjectSpaceViewDirection, 107 ViewSpaceViewDirection, 108 WorldSpaceViewDirection, 109 TangentSpaceViewDirection, 110 VertexColor, 111 } 112 113 [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] 114 protected class SlotAttribute : Attribute 115 { 116 public int slotId { get; private set; } 117 public Binding binding { get; private set; } 118 public bool hidden { get; private set; } 119 public Vector4? defaultValue { get; private set; } 120 public ShaderStageCapability stageCapability { get; private set; } 121 122 public SlotAttribute(int mSlotId, Binding mImplicitBinding, ShaderStageCapability mStageCapability = ShaderStageCapability.All) 123 { 124 slotId = mSlotId; 125 binding = mImplicitBinding; 126 defaultValue = null; 127 stageCapability = mStageCapability; 128 } 129 130 public SlotAttribute(int mSlotId, Binding mImplicitBinding, bool mHidden, ShaderStageCapability mStageCapability = ShaderStageCapability.All) 131 { 132 slotId = mSlotId; 133 binding = mImplicitBinding; 134 hidden = mHidden; 135 defaultValue = null; 136 stageCapability = mStageCapability; 137 } 138 139 public SlotAttribute(int mSlotId, Binding mImplicitBinding, float defaultX, float defaultY, float defaultZ, float defaultW, ShaderStageCapability mStageCapability = ShaderStageCapability.All) 140 { 141 slotId = mSlotId; 142 binding = mImplicitBinding; 143 defaultValue = new Vector4(defaultX, defaultY, defaultZ, defaultW); 144 stageCapability = mStageCapability; 145 } 146 } 147 148 protected abstract MethodInfo GetFunctionToConvert(); 149 150 private static SlotValueType ConvertTypeToSlotValueType(ParameterInfo p) 151 { 152 Type t = p.ParameterType; 153 if (p.ParameterType.IsByRef) 154 t = p.ParameterType.GetElementType(); 155 156 if (t == typeof(Boolean)) 157 { 158 return SlotValueType.Boolean; 159 } 160 if (t == typeof(Vector1)) 161 { 162 return SlotValueType.Vector1; 163 } 164 if (t == typeof(Vector2)) 165 { 166 return SlotValueType.Vector2; 167 } 168 if (t == typeof(Vector3)) 169 { 170 return SlotValueType.Vector3; 171 } 172 if (t == typeof(Vector4)) 173 { 174 return SlotValueType.Vector4; 175 } 176 if (t == typeof(Color)) 177 { 178 return SlotValueType.Vector4; 179 } 180 if (t == typeof(ColorRGBA)) 181 { 182 return SlotValueType.Vector4; 183 } 184 if (t == typeof(ColorRGB)) 185 { 186 return SlotValueType.Vector3; 187 } 188 if (t == typeof(Texture2D)) 189 { 190 return SlotValueType.Texture2D; 191 } 192 if (t == typeof(Texture2DArray)) 193 { 194 return SlotValueType.Texture2DArray; 195 } 196 if (t == typeof(Texture3D)) 197 { 198 return SlotValueType.Texture3D; 199 } 200 if (t == typeof(Cubemap)) 201 { 202 return SlotValueType.Cubemap; 203 } 204 if (t == typeof(Gradient)) 205 { 206 return SlotValueType.Gradient; 207 } 208 if (t == typeof(SamplerState)) 209 { 210 return SlotValueType.SamplerState; 211 } 212 if (t == typeof(DynamicDimensionVector)) 213 { 214 return SlotValueType.DynamicVector; 215 } 216 if (t == typeof(Matrix4x4)) 217 { 218 return SlotValueType.Matrix4; 219 } 220 if (t == typeof(Matrix3x3)) 221 { 222 return SlotValueType.Matrix3; 223 } 224 if (t == typeof(Matrix2x2)) 225 { 226 return SlotValueType.Matrix2; 227 } 228 if (t == typeof(DynamicDimensionMatrix)) 229 { 230 return SlotValueType.DynamicMatrix; 231 } 232 if (t == typeof(PropertyConnectionState)) 233 { 234 return SlotValueType.PropertyConnectionState; 235 } 236 237 throw new ArgumentException("Unsupported type " + t); 238 } 239 240 public sealed override void UpdateNodeAfterDeserialization() 241 { 242 var method = GetFunctionToConvert(); 243 244 if (method == null) 245 throw new ArgumentException("Mapped method is null on node" + this); 246 247 if (method.ReturnType != typeof(string)) 248 throw new ArgumentException("Mapped function should return string"); 249 250 // validate no duplicates 251 var slotAtributes = method.GetParameters().Select(GetSlotAttribute).ToList(); 252 if (slotAtributes.Any(x => x == null)) 253 throw new ArgumentException("Missing SlotAttribute on " + method.Name); 254 255 if (slotAtributes.GroupBy(x => x.slotId).Any(x => x.Count() > 1)) 256 throw new ArgumentException("Duplicate SlotAttribute on " + method.Name); 257 258 List<MaterialSlot> slots = new List<MaterialSlot>(); 259 foreach (var par in method.GetParameters()) 260 { 261 var attribute = GetSlotAttribute(par); 262 var name = GraphUtil.ConvertCamelCase(par.Name, true); 263 264 MaterialSlot s; 265 if (attribute.binding == Binding.None && !par.IsOut && par.ParameterType == typeof(Color)) 266 s = new ColorRGBAMaterialSlot(attribute.slotId, name, par.Name, SlotType.Input, attribute.defaultValue ?? Vector4.zero, stageCapability: attribute.stageCapability, hidden: attribute.hidden); 267 else if (attribute.binding == Binding.None && !par.IsOut && par.ParameterType == typeof(ColorRGBA)) 268 s = new ColorRGBAMaterialSlot(attribute.slotId, name, par.Name, SlotType.Input, attribute.defaultValue ?? Vector4.zero, stageCapability: attribute.stageCapability, hidden: attribute.hidden); 269 else if (attribute.binding == Binding.None && !par.IsOut && par.ParameterType == typeof(ColorRGB)) 270 s = new ColorRGBMaterialSlot(attribute.slotId, name, par.Name, SlotType.Input, attribute.defaultValue ?? Vector4.zero, ColorMode.Default, stageCapability: attribute.stageCapability, hidden: attribute.hidden); 271 else if (attribute.binding == Binding.None || par.IsOut) 272 s = MaterialSlot.CreateMaterialSlot( 273 ConvertTypeToSlotValueType(par), 274 attribute.slotId, 275 name, 276 par.Name, 277 par.IsOut ? SlotType.Output : SlotType.Input, 278 attribute.defaultValue ?? Vector4.zero, 279 shaderStageCapability: attribute.stageCapability, 280 hidden: attribute.hidden); 281 else 282 s = CreateBoundSlot(attribute.binding, attribute.slotId, name, par.Name, attribute.stageCapability, attribute.hidden); 283 slots.Add(s); 284 285 m_Slots.Add(attribute); 286 } 287 foreach (var slot in slots) 288 { 289 AddSlot(slot); 290 } 291 RemoveSlotsNameNotMatching(slots.Select(x => x.id), true); 292 } 293 294 private static MaterialSlot CreateBoundSlot(Binding attributeBinding, int slotId, string displayName, string shaderOutputName, ShaderStageCapability shaderStageCapability, bool hidden = false) 295 { 296 switch (attributeBinding) 297 { 298 case Binding.ObjectSpaceNormal: 299 return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability, hidden); 300 case Binding.ObjectSpaceTangent: 301 return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability, hidden); 302 case Binding.ObjectSpaceBitangent: 303 return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability, hidden); 304 case Binding.ObjectSpacePosition: 305 return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability, hidden); 306 case Binding.ViewSpaceNormal: 307 return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability, hidden); 308 case Binding.ViewSpaceTangent: 309 return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability, hidden); 310 case Binding.ViewSpaceBitangent: 311 return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability, hidden); 312 case Binding.ViewSpacePosition: 313 return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability, hidden); 314 case Binding.WorldSpaceNormal: 315 return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability, hidden); 316 case Binding.WorldSpaceTangent: 317 return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability, hidden); 318 case Binding.WorldSpaceBitangent: 319 return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability, hidden); 320 case Binding.WorldSpacePosition: 321 return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability, hidden); 322 case Binding.TangentSpaceNormal: 323 return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability, hidden); 324 case Binding.TangentSpaceTangent: 325 return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability, hidden); 326 case Binding.TangentSpaceBitangent: 327 return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability, hidden); 328 case Binding.TangentSpacePosition: 329 return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability, hidden); 330 case Binding.MeshUV0: 331 return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV0, shaderStageCapability, hidden); 332 case Binding.MeshUV1: 333 return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV1, shaderStageCapability, hidden); 334 case Binding.MeshUV2: 335 return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV2, shaderStageCapability, hidden); 336 case Binding.MeshUV3: 337 return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV3, shaderStageCapability, hidden); 338 case Binding.ScreenPosition: 339 return new ScreenPositionMaterialSlot(slotId, displayName, shaderOutputName, ScreenSpaceType.Default, shaderStageCapability, hidden); 340 case Binding.ObjectSpaceViewDirection: 341 return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability, hidden); 342 case Binding.ViewSpaceViewDirection: 343 return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability, hidden); 344 case Binding.WorldSpaceViewDirection: 345 return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability, hidden); 346 case Binding.TangentSpaceViewDirection: 347 return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability, hidden); 348 case Binding.VertexColor: 349 return new VertexColorMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden); 350 default: 351 throw new ArgumentOutOfRangeException("attributeBinding", attributeBinding, null); 352 } 353 } 354 355 public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) 356 { 357 using (var tempSlots = PooledList<MaterialSlot>.Get()) 358 { 359 GetOutputSlots(tempSlots); 360 foreach (var outSlot in tempSlots) 361 { 362 sb.AppendLine(outSlot.concreteValueType.ToShaderString(PrecisionUtil.Token) + " " + GetVariableNameForSlot(outSlot.id) + ";"); 363 } 364 365 string call = GetFunctionName() + "("; 366 bool first = true; 367 tempSlots.Clear(); 368 GetSlots(tempSlots); 369 tempSlots.Sort((slot1, slot2) => slot1.id.CompareTo(slot2.id)); 370 foreach (var slot in tempSlots) 371 { 372 if (!first) 373 { 374 call += ", "; 375 } 376 first = false; 377 378 if (slot.isInputSlot) 379 call += GetSlotValue(slot.id, generationMode); 380 else 381 call += GetVariableNameForSlot(slot.id); 382 } 383 call += ");"; 384 385 sb.AppendLine(call); 386 } 387 } 388 389 private string GetFunctionName() 390 { 391 var function = GetFunctionToConvert(); 392 return function.Name + (function.IsStatic ? string.Empty : "_" + objectId) + "_$precision" 393 + (this.GetSlots<DynamicVectorMaterialSlot>().Select(s => NodeUtils.GetSlotDimension(s.concreteValueType)).FirstOrDefault() ?? "") 394 + (this.GetSlots<DynamicMatrixMaterialSlot>().Select(s => NodeUtils.GetSlotDimension(s.concreteValueType)).FirstOrDefault() ?? ""); 395 } 396 397 private string GetFunctionHeader() 398 { 399 string header = "void " + GetFunctionName() + "("; 400 401 using (var tempSlots = PooledList<MaterialSlot>.Get()) 402 { 403 GetSlots(tempSlots); 404 tempSlots.Sort((slot1, slot2) => slot1.id.CompareTo(slot2.id)); 405 var first = true; 406 foreach (var slot in tempSlots) 407 { 408 if (!first) 409 header += ", "; 410 411 first = false; 412 413 if (slot.isOutputSlot) 414 header += "out "; 415 416 // always use generic precisions for parameters, they will get concretized by the system 417 header += slot.concreteValueType.ToShaderString(PrecisionUtil.Token) + " " + slot.shaderOutputName; 418 } 419 420 header += ")"; 421 } 422 423 return header; 424 } 425 426 private static object GetDefault(Type type) 427 { 428 return type.IsValueType ? Activator.CreateInstance(type) : null; 429 } 430 431 private string GetFunctionBody(MethodInfo info) 432 { 433 var args = new List<object>(); 434 foreach (var param in info.GetParameters()) 435 args.Add(GetDefault(param.ParameterType)); 436 437 var result = info.Invoke(this, args.ToArray()) as string; 438 439 if (string.IsNullOrEmpty(result)) 440 return string.Empty; 441 442 // stomp any newline differences that might try to sneak in via this path 443 result = result.Replace("\r\n", "\n"); 444 445 using (var tempSlots = PooledList<MaterialSlot>.Get()) 446 { 447 GetSlots(tempSlots); 448 foreach (var slot in tempSlots) 449 { 450 var toReplace = string.Format("{{slot{0}dimension}}", slot.id); 451 var replacement = NodeUtils.GetSlotDimension(slot.concreteValueType); 452 result = result.Replace(toReplace, replacement); 453 } 454 } 455 456 return result; 457 } 458 459 public virtual void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode) 460 { 461 registry.ProvideFunction(GetFunctionName(), s => 462 { 463 s.AppendLine(GetFunctionHeader()); 464 var functionBody = GetFunctionBody(GetFunctionToConvert()); 465 var lines = functionBody.Trim('\r', '\n', '\t', ' '); 466 s.AppendLines(lines); 467 }); 468 } 469 470 private static SlotAttribute GetSlotAttribute([NotNull] ParameterInfo info) 471 { 472 var attrs = info.GetCustomAttributes(typeof(SlotAttribute), false).OfType<SlotAttribute>().ToList(); 473 return attrs.FirstOrDefault(); 474 } 475 476 public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability) 477 { 478 var binding = NeededCoordinateSpace.None; 479 using (var tempSlots = PooledList<MaterialSlot>.Get()) 480 { 481 GetInputSlots(tempSlots); 482 foreach (var slot in tempSlots) 483 binding |= slot.RequiresNormal(); 484 return binding; 485 } 486 } 487 488 public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability) 489 { 490 var binding = NeededCoordinateSpace.None; 491 using (var tempSlots = PooledList<MaterialSlot>.Get()) 492 { 493 GetInputSlots(tempSlots); 494 foreach (var slot in tempSlots) 495 binding |= slot.RequiresViewDirection(); 496 return binding; 497 } 498 } 499 500 public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability) 501 { 502 using (var tempSlots = PooledList<MaterialSlot>.Get()) 503 { 504 GetInputSlots(tempSlots); 505 var binding = NeededCoordinateSpace.None; 506 foreach (var slot in tempSlots) 507 binding |= slot.RequiresPosition(); 508 return binding; 509 } 510 } 511 512 public NeededCoordinateSpace RequiresPositionPredisplacement(ShaderStageCapability stageCapability) 513 { 514 using (var tempSlots = PooledList<MaterialSlot>.Get()) 515 { 516 GetInputSlots(tempSlots); 517 var binding = NeededCoordinateSpace.None; 518 foreach (var slot in tempSlots) 519 binding |= slot.RequiresPositionPredisplacement(); 520 return binding; 521 } 522 } 523 524 public NeededCoordinateSpace RequiresTangent(ShaderStageCapability stageCapability) 525 { 526 using (var tempSlots = PooledList<MaterialSlot>.Get()) 527 { 528 GetInputSlots(tempSlots); 529 var binding = NeededCoordinateSpace.None; 530 foreach (var slot in tempSlots) 531 binding |= slot.RequiresTangent(); 532 return binding; 533 } 534 } 535 536 public NeededCoordinateSpace RequiresBitangent(ShaderStageCapability stageCapability) 537 { 538 using (var tempSlots = PooledList<MaterialSlot>.Get()) 539 { 540 GetInputSlots(tempSlots); 541 var binding = NeededCoordinateSpace.None; 542 foreach (var slot in tempSlots) 543 binding |= slot.RequiresBitangent(); 544 return binding; 545 } 546 } 547 548 public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability) 549 { 550 using (var tempSlots = PooledList<MaterialSlot>.Get()) 551 { 552 GetInputSlots(tempSlots); 553 foreach (var slot in tempSlots) 554 { 555 if (slot.RequiresMeshUV(channel)) 556 return true; 557 } 558 559 return false; 560 } 561 } 562 563 public bool RequiresScreenPosition(ShaderStageCapability stageCapability) 564 { 565 using (var tempSlots = PooledList<MaterialSlot>.Get()) 566 { 567 GetInputSlots(tempSlots); 568 foreach (var slot in tempSlots) 569 { 570 if (slot.RequiresScreenPosition(stageCapability)) 571 return true; 572 } 573 return false; 574 } 575 } 576 577 public bool RequiresNDCPosition(ShaderStageCapability stageCapability) 578 { 579 using (var tempSlots = PooledList<MaterialSlot>.Get()) 580 { 581 GetInputSlots(tempSlots); 582 foreach (var slot in tempSlots) 583 { 584 if (slot.RequiresNDCPosition(stageCapability)) 585 return true; 586 } 587 return false; 588 } 589 } 590 591 public bool RequiresPixelPosition(ShaderStageCapability stageCapability) 592 { 593 using (var tempSlots = PooledList<MaterialSlot>.Get()) 594 { 595 GetInputSlots(tempSlots); 596 foreach (var slot in tempSlots) 597 { 598 if (slot.RequiresPixelPosition(stageCapability)) 599 return true; 600 } 601 return false; 602 } 603 } 604 605 public bool RequiresVertexColor(ShaderStageCapability stageCapability) 606 { 607 using (var tempSlots = PooledList<MaterialSlot>.Get()) 608 { 609 GetInputSlots(tempSlots); 610 foreach (var slot in tempSlots) 611 { 612 if (slot.RequiresVertexColor()) 613 return true; 614 } 615 616 return false; 617 } 618 } 619 } 620}