LinearBlendSkinningNode.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using UnityEngine;
  2. using UnityEditor.Graphing;
  3. using UnityEditor.ShaderGraph.Internal;
  4. namespace UnityEditor.ShaderGraph
  5. {
  6. [Title("Vertex Skinning", "Linear Blend Skinning")]
  7. class LinearBlendSkinningNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequireVertexSkinning, IMayRequirePosition, IMayRequireNormal, IMayRequireTangent
  8. {
  9. public const int kPositionSlotId = 0;
  10. public const int kNormalSlotId = 1;
  11. public const int kTangentSlotId = 2;
  12. public const int kPositionOutputSlotId = 3;
  13. public const int kNormalOutputSlotId = 4;
  14. public const int kTangentOutputSlotId = 5;
  15. public const int kSkinMatricesOffsetSlotId = 6;
  16. public const string kSlotPositionName = "Position";
  17. public const string kSlotNormalName = "Normal";
  18. public const string kSlotTangentName = "Tangent";
  19. public const string kOutputSlotPositionName = "Position";
  20. public const string kOutputSlotNormalName = "Normal";
  21. public const string kOutputSlotTangentName = "Tangent";
  22. public const string kSkinMatricesOffsetName = "Skin Matrix Index Offset";
  23. public LinearBlendSkinningNode()
  24. {
  25. name = "Linear Blend Skinning";
  26. UpdateNodeAfterDeserialization();
  27. }
  28. public sealed override void UpdateNodeAfterDeserialization()
  29. {
  30. AddSlot(new PositionMaterialSlot(kPositionSlotId, kSlotPositionName, kSlotPositionName, CoordinateSpace.Object, ShaderStageCapability.Vertex));
  31. AddSlot(new NormalMaterialSlot(kNormalSlotId, kSlotNormalName, kSlotNormalName, CoordinateSpace.Object, ShaderStageCapability.Vertex));
  32. AddSlot(new TangentMaterialSlot(kTangentSlotId, kSlotTangentName, kSlotTangentName, CoordinateSpace.Object, ShaderStageCapability.Vertex));
  33. AddSlot(new Vector3MaterialSlot(kPositionOutputSlotId, kOutputSlotPositionName, kOutputSlotPositionName, SlotType.Output, Vector3.zero, ShaderStageCapability.Vertex));
  34. AddSlot(new Vector3MaterialSlot(kNormalOutputSlotId, kOutputSlotNormalName, kOutputSlotNormalName, SlotType.Output, Vector3.zero, ShaderStageCapability.Vertex));
  35. AddSlot(new Vector3MaterialSlot(kTangentOutputSlotId, kOutputSlotTangentName, kOutputSlotTangentName, SlotType.Output, Vector3.zero, ShaderStageCapability.Vertex));
  36. AddSlot(new Vector1MaterialSlot(kSkinMatricesOffsetSlotId, kSkinMatricesOffsetName, kSkinMatricesOffsetName, SlotType.Input, 0f, ShaderStageCapability.Vertex));
  37. RemoveSlotsNameNotMatching(new[] { kPositionSlotId, kNormalSlotId, kTangentSlotId, kPositionOutputSlotId, kNormalOutputSlotId, kTangentOutputSlotId, kSkinMatricesOffsetSlotId });
  38. }
  39. public bool RequiresVertexSkinning(ShaderStageCapability stageCapability = ShaderStageCapability.All)
  40. {
  41. return true;
  42. }
  43. public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability = ShaderStageCapability.All)
  44. {
  45. if (stageCapability == ShaderStageCapability.Vertex || stageCapability == ShaderStageCapability.All)
  46. return NeededCoordinateSpace.Object;
  47. else
  48. return NeededCoordinateSpace.None;
  49. }
  50. public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability = ShaderStageCapability.All)
  51. {
  52. if (stageCapability == ShaderStageCapability.Vertex || stageCapability == ShaderStageCapability.All)
  53. return NeededCoordinateSpace.Object;
  54. else
  55. return NeededCoordinateSpace.None;
  56. }
  57. public NeededCoordinateSpace RequiresTangent(ShaderStageCapability stageCapability = ShaderStageCapability.All)
  58. {
  59. if (stageCapability == ShaderStageCapability.Vertex || stageCapability == ShaderStageCapability.All)
  60. return NeededCoordinateSpace.Object;
  61. else
  62. return NeededCoordinateSpace.None;
  63. }
  64. public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
  65. {
  66. sb.AppendLine("$precision3 {0} = 0;", GetVariableNameForSlot(kPositionOutputSlotId));
  67. sb.AppendLine("$precision3 {0} = 0;", GetVariableNameForSlot(kNormalOutputSlotId));
  68. sb.AppendLine("$precision3 {0} = 0;", GetVariableNameForSlot(kTangentOutputSlotId));
  69. if (generationMode == GenerationMode.ForReals)
  70. {
  71. sb.AppendLine("{0}(IN.BoneIndices, (int)(({1})), IN.BoneWeights, {2}, {3}, {4}, {5}, {6}, {7});",
  72. GetFunctionName(),
  73. GetSlotValue(kSkinMatricesOffsetSlotId, generationMode),
  74. GetSlotValue(kPositionSlotId, generationMode),
  75. GetSlotValue(kNormalSlotId, generationMode),
  76. GetSlotValue(kTangentSlotId, generationMode),
  77. GetVariableNameForSlot(kPositionOutputSlotId),
  78. GetVariableNameForSlot(kNormalOutputSlotId),
  79. GetVariableNameForSlot(kTangentOutputSlotId));
  80. }
  81. }
  82. public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
  83. {
  84. registry.ProvideFunction("SkinningMatrices", sb =>
  85. {
  86. sb.AppendLine("uniform StructuredBuffer<float3x4> _SkinMatrices;");
  87. });
  88. registry.ProvideFunction(GetFunctionName(), sb =>
  89. {
  90. sb.AppendLine("void {0}(uint4 indices, int indexOffset, $precision4 weights, $precision3 positionIn, $precision3 normalIn, $precision3 tangentIn, out $precision3 positionOut, out $precision3 normalOut, out $precision3 tangentOut)",
  91. GetFunctionName());
  92. sb.AppendLine("{");
  93. using (sb.IndentScope())
  94. {
  95. sb.AppendLine("for (int i = 0; i < 4; i++)");
  96. sb.AppendLine("{");
  97. using (sb.IndentScope())
  98. {
  99. sb.AppendLine("$precision3x4 skinMatrix = _SkinMatrices[indices[i] + indexOffset];");
  100. sb.AppendLine("$precision3 vtransformed = mul(skinMatrix, $precision4(positionIn, 1));");
  101. sb.AppendLine("$precision3 ntransformed = mul(skinMatrix, $precision4(normalIn, 0));");
  102. sb.AppendLine("$precision3 ttransformed = mul(skinMatrix, $precision4(tangentIn, 0));");
  103. sb.AppendLine("");
  104. sb.AppendLine("positionOut += vtransformed * weights[i];");
  105. sb.AppendLine("normalOut += ntransformed * weights[i];");
  106. sb.AppendLine("tangentOut += ttransformed * weights[i];");
  107. }
  108. sb.AppendLine("}");
  109. }
  110. sb.AppendLine("}");
  111. });
  112. }
  113. string GetFunctionName()
  114. {
  115. return $"Unity_LinearBlendSkinning_{concretePrecision.ToShaderString()}";
  116. }
  117. }
  118. }