A game about forced loneliness, made by TACStudios
at master 249 lines 10 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine; 5using UnityEditor.Graphing; 6using UnityEditor.ShaderGraph.Drawing.Controls; 7using UnityEditor.Graphing.Util; 8using UnityEngine.Pool; 9 10namespace UnityEditor.ShaderGraph 11{ 12 enum MatrixAxis 13 { 14 Row, 15 Column 16 } 17 18 [Title("Math", "Matrix", "Matrix Split")] 19 class MatrixSplitNode : AbstractMaterialNode, IGeneratesBodyCode 20 { 21 const string kInputSlotName = "In"; 22 const string kOutputSlotM0Name = "M0"; 23 const string kOutputSlotM1Name = "M1"; 24 const string kOutputSlotM2Name = "M2"; 25 const string kOutputSlotM3Name = "M3"; 26 27 public const int InputSlotId = 0; 28 public const int OutputSlotRId = 1; 29 public const int OutputSlotGId = 2; 30 public const int OutputSlotBId = 3; 31 public const int OutputSlotAId = 4; 32 33 public MatrixSplitNode() 34 { 35 name = "Matrix Split"; 36 UpdateNodeAfterDeserialization(); 37 } 38 39 [SerializeField] 40 MatrixAxis m_Axis; 41 42 [EnumControl("")] 43 MatrixAxis axis 44 { 45 get { return m_Axis; } 46 set 47 { 48 if (m_Axis.Equals(value)) 49 return; 50 m_Axis = value; 51 Dirty(ModificationScope.Graph); 52 } 53 } 54 55 static string[] s_ComponentList = new string[4] { "r", "g", "b", "a" }; 56 57 public sealed override void UpdateNodeAfterDeserialization() 58 { 59 AddSlot(new DynamicMatrixMaterialSlot(InputSlotId, kInputSlotName, kInputSlotName, SlotType.Input)); 60 AddSlot(new DynamicVectorMaterialSlot(OutputSlotRId, kOutputSlotM0Name, kOutputSlotM0Name, SlotType.Output, Vector4.zero)); 61 AddSlot(new DynamicVectorMaterialSlot(OutputSlotGId, kOutputSlotM1Name, kOutputSlotM1Name, SlotType.Output, Vector4.zero)); 62 AddSlot(new DynamicVectorMaterialSlot(OutputSlotBId, kOutputSlotM2Name, kOutputSlotM2Name, SlotType.Output, Vector4.zero)); 63 AddSlot(new DynamicVectorMaterialSlot(OutputSlotAId, kOutputSlotM3Name, kOutputSlotM3Name, SlotType.Output, Vector4.zero)); 64 RemoveSlotsNameNotMatching(new int[] { InputSlotId, OutputSlotRId, OutputSlotGId, OutputSlotBId, OutputSlotAId }); 65 } 66 67 static int[] s_OutputSlots = { OutputSlotRId, OutputSlotGId, OutputSlotBId, OutputSlotAId }; 68 69 public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) 70 { 71 var inputValue = GetSlotValue(InputSlotId, generationMode); 72 73 var inputSlot = FindInputSlot<MaterialSlot>(InputSlotId); 74 var numInputRows = 0; 75 bool useIndentity = false; 76 77 if (inputSlot != null) 78 { 79 numInputRows = SlotValueHelper.GetMatrixDimension(inputSlot.concreteValueType); 80 if (numInputRows > 4) 81 numInputRows = 0; 82 83 if (!owner.GetEdges(inputSlot.slotReference).Any()) 84 { 85 numInputRows = 0; 86 useIndentity = true; 87 } 88 } 89 90 int concreteRowCount = useIndentity ? 2 : numInputRows; 91 92 for (var r = 0; r < 4; r++) 93 { 94 string outputValue; 95 if (r >= numInputRows) 96 { 97 outputValue = string.Format("$precision{0}(", concreteRowCount); 98 for (int c = 0; c < concreteRowCount; c++) 99 { 100 if (c != 0) 101 outputValue += ", "; 102 outputValue += Matrix4x4.identity.GetRow(r)[c]; 103 } 104 outputValue += ")"; 105 } 106 else 107 { 108 switch (m_Axis) 109 { 110 case MatrixAxis.Column: 111 outputValue = string.Format("$precision{0}(", numInputRows); 112 for (int c = 0; c < numInputRows; c++) 113 { 114 if (c != 0) 115 outputValue += ", "; 116 outputValue += string.Format("{0}[{1}].{2}", inputValue, c, s_ComponentList[r]); 117 } 118 outputValue += ")"; 119 break; 120 default: 121 outputValue = string.Format("{0}[{1}]", inputValue, r); 122 break; 123 } 124 } 125 sb.AppendLine(string.Format("$precision{0} {1} = {2};", concreteRowCount, GetVariableNameForSlot(s_OutputSlots[r]), outputValue)); 126 } 127 } 128 129 public override void EvaluateDynamicMaterialSlots(List<MaterialSlot> inputSlots, List<MaterialSlot> outputSlots) 130 { 131 var dynamicInputSlotsToCompare = DictionaryPool<DynamicVectorMaterialSlot, ConcreteSlotValueType>.Get(); 132 var skippedDynamicSlots = ListPool<DynamicVectorMaterialSlot>.Get(); 133 134 var dynamicMatrixInputSlotsToCompare = DictionaryPool<DynamicMatrixMaterialSlot, ConcreteSlotValueType>.Get(); 135 var skippedDynamicMatrixSlots = ListPool<DynamicMatrixMaterialSlot>.Get(); 136 137 // iterate the input slots 138 { 139 foreach (var inputSlot in inputSlots) 140 { 141 inputSlot.hasError = false; 142 143 // if there is a connection 144 var edges = owner.GetEdges(inputSlot.slotReference).ToList(); 145 if (!edges.Any()) 146 { 147 if (inputSlot is DynamicVectorMaterialSlot) 148 skippedDynamicSlots.Add(inputSlot as DynamicVectorMaterialSlot); 149 if (inputSlot is DynamicMatrixMaterialSlot) 150 skippedDynamicMatrixSlots.Add(inputSlot as DynamicMatrixMaterialSlot); 151 continue; 152 } 153 154 // get the output details 155 var outputSlotRef = edges[0].outputSlot; 156 var outputNode = outputSlotRef.node; 157 if (outputNode == null) 158 continue; 159 160 var outputSlot = outputNode.FindOutputSlot<MaterialSlot>(outputSlotRef.slotId); 161 if (outputSlot == null) 162 continue; 163 164 if (outputSlot.hasError) 165 { 166 inputSlot.hasError = true; 167 continue; 168 } 169 170 var outputConcreteType = outputSlot.concreteValueType; 171 // dynamic input... depends on output from other node. 172 // we need to compare ALL dynamic inputs to make sure they 173 // are compatable. 174 if (inputSlot is DynamicVectorMaterialSlot) 175 { 176 dynamicInputSlotsToCompare.Add((DynamicVectorMaterialSlot)inputSlot, outputConcreteType); 177 continue; 178 } 179 else if (inputSlot is DynamicMatrixMaterialSlot) 180 { 181 dynamicMatrixInputSlotsToCompare.Add((DynamicMatrixMaterialSlot)inputSlot, outputConcreteType); 182 continue; 183 } 184 } 185 186 // and now dynamic matrices 187 var dynamicMatrixType = ConvertDynamicMatrixInputTypeToConcrete(dynamicMatrixInputSlotsToCompare.Values); 188 foreach (var dynamicKvP in dynamicMatrixInputSlotsToCompare) 189 dynamicKvP.Key.SetConcreteType(dynamicMatrixType); 190 foreach (var skippedSlot in skippedDynamicMatrixSlots) 191 skippedSlot.SetConcreteType(dynamicMatrixType); 192 193 // we can now figure out the dynamic slotType 194 // from here set all the 195 var dynamicType = SlotValueHelper.ConvertMatrixToVectorType(dynamicMatrixType); 196 foreach (var dynamicKvP in dynamicInputSlotsToCompare) 197 dynamicKvP.Key.SetConcreteType(dynamicType); 198 foreach (var skippedSlot in skippedDynamicSlots) 199 skippedSlot.SetConcreteType(dynamicType); 200 201 bool inputError = inputSlots.Any(x => x.hasError); 202 if (inputError) 203 { 204 owner.AddConcretizationError(objectId, string.Format("Node {0} had input error", objectId)); 205 hasError = true; 206 } 207 // configure the output slots now 208 // their slotType will either be the default output slotType 209 // or the above dynanic slotType for dynamic nodes 210 // or error if there is an input error 211 foreach (var outputSlot in outputSlots) 212 { 213 outputSlot.hasError = false; 214 215 if (inputError) 216 { 217 outputSlot.hasError = true; 218 continue; 219 } 220 221 if (outputSlot is DynamicVectorMaterialSlot) 222 { 223 (outputSlot as DynamicVectorMaterialSlot).SetConcreteType(dynamicType); 224 continue; 225 } 226 else if (outputSlot is DynamicMatrixMaterialSlot) 227 { 228 (outputSlot as DynamicMatrixMaterialSlot).SetConcreteType(dynamicMatrixType); 229 continue; 230 } 231 } 232 233 if (outputSlots.Any(x => x.hasError)) 234 { 235 owner.AddConcretizationError(objectId, string.Format("Node {0} had output error", objectId)); 236 hasError = true; 237 } 238 } 239 240 CalculateNodeHasError(); 241 242 ListPool<DynamicVectorMaterialSlot>.Release(skippedDynamicSlots); 243 DictionaryPool<DynamicVectorMaterialSlot, ConcreteSlotValueType>.Release(dynamicInputSlotsToCompare); 244 245 ListPool<DynamicMatrixMaterialSlot>.Release(skippedDynamicMatrixSlots); 246 DictionaryPool<DynamicMatrixMaterialSlot, ConcreteSlotValueType>.Release(dynamicMatrixInputSlotsToCompare); 247 } 248 } 249}