ShaderGenerator.cs 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. using UnityEngine;
  8. using UnityEditor.Graphing;
  9. using UnityEditor.ShaderGraph.Internal;
  10. namespace UnityEditor.ShaderGraph
  11. {
  12. class ShaderGenerator
  13. {
  14. private struct ShaderChunk
  15. {
  16. public ShaderChunk(int indentLevel, string shaderChunkString)
  17. {
  18. m_IndentLevel = indentLevel;
  19. m_ShaderChunkString = shaderChunkString;
  20. }
  21. private readonly int m_IndentLevel;
  22. private readonly string m_ShaderChunkString;
  23. public int chunkIndentLevel
  24. {
  25. get { return m_IndentLevel; }
  26. }
  27. public string chunkString
  28. {
  29. get { return m_ShaderChunkString; }
  30. }
  31. }
  32. private readonly List<ShaderChunk> m_ShaderChunks = new List<ShaderChunk>();
  33. private int m_IndentLevel;
  34. private string m_Pragma = string.Empty;
  35. public void AddPragmaChunk(string s)
  36. {
  37. m_Pragma += s;
  38. }
  39. public string GetPragmaString()
  40. {
  41. return m_Pragma;
  42. }
  43. public void AddNewLine()
  44. {
  45. m_ShaderChunks.Add(new ShaderChunk(m_IndentLevel, ""));
  46. }
  47. public void AddShaderChunk(string s, bool unique = false)
  48. {
  49. if (string.IsNullOrEmpty(s))
  50. return;
  51. if (unique && m_ShaderChunks.Any(x => x.chunkString == s))
  52. return;
  53. m_ShaderChunks.Add(new ShaderChunk(m_IndentLevel, s));
  54. }
  55. public void AddGenerator(ShaderGenerator generator)
  56. {
  57. foreach (ShaderChunk chunk in generator.m_ShaderChunks)
  58. {
  59. m_ShaderChunks.Add(new ShaderChunk(m_IndentLevel + chunk.chunkIndentLevel, chunk.chunkString));
  60. }
  61. }
  62. public void Indent()
  63. {
  64. m_IndentLevel++;
  65. }
  66. public void Deindent()
  67. {
  68. m_IndentLevel = Math.Max(0, m_IndentLevel - 1);
  69. }
  70. public string GetShaderString(int baseIndentLevel, bool finalNewline = true)
  71. {
  72. bool appendedNewline = false;
  73. var sb = new StringBuilder();
  74. foreach (var shaderChunk in m_ShaderChunks)
  75. {
  76. // TODO: regex split is a slow way to handle this .. should build an iterator instead
  77. var lines = Regex.Split(shaderChunk.chunkString, Environment.NewLine);
  78. for (int index = 0; index < lines.Length; index++)
  79. {
  80. var line = lines[index];
  81. for (var i = 0; i < shaderChunk.chunkIndentLevel + baseIndentLevel; i++)
  82. {
  83. //sb.Append("\t");
  84. sb.Append(" "); // unity convention use space instead of tab...
  85. }
  86. sb.AppendLine(line);
  87. appendedNewline = true;
  88. }
  89. }
  90. if (appendedNewline && !finalNewline)
  91. {
  92. // remove last newline if we didn't want it
  93. sb.Length -= Environment.NewLine.Length;
  94. }
  95. return sb.ToString();
  96. }
  97. public static string GetTemplatePath(string templateName)
  98. {
  99. var path = new List<string>
  100. {
  101. DefaultShaderIncludes.GetAssetsPackagePath() ?? Path.GetFullPath("Packages/com.unity.shadergraph"),
  102. "Editor",
  103. "Templates"
  104. };
  105. string result = path[0];
  106. for (int i = 1; i < path.Count; i++)
  107. result = Path.Combine(result, path[i]);
  108. result = Path.Combine(result, templateName);
  109. if (File.Exists(result))
  110. return result;
  111. return string.Empty;
  112. }
  113. private const string kErrorString = @"ERROR!";
  114. public static string AdaptNodeOutput(AbstractMaterialNode node, int outputSlotId, ConcreteSlotValueType convertToType)
  115. {
  116. var outputSlot = node.FindOutputSlot<MaterialSlot>(outputSlotId);
  117. if (outputSlot == null)
  118. return kErrorString;
  119. var convertFromType = outputSlot.concreteValueType;
  120. var rawOutput = node.GetVariableNameForSlot(outputSlotId);
  121. if (convertFromType == convertToType)
  122. return rawOutput;
  123. switch (convertToType)
  124. {
  125. case ConcreteSlotValueType.Vector1:
  126. return string.Format("({0}).x", rawOutput);
  127. case ConcreteSlotValueType.Vector2:
  128. switch (convertFromType)
  129. {
  130. case ConcreteSlotValueType.Vector1:
  131. return string.Format("({0}.xx)", rawOutput);
  132. case ConcreteSlotValueType.Vector3:
  133. case ConcreteSlotValueType.Vector4:
  134. return string.Format("({0}.xy)", rawOutput);
  135. default:
  136. return kErrorString;
  137. }
  138. case ConcreteSlotValueType.Vector3:
  139. switch (convertFromType)
  140. {
  141. case ConcreteSlotValueType.Vector1:
  142. return string.Format("({0}.xxx)", rawOutput);
  143. case ConcreteSlotValueType.Vector2:
  144. return string.Format("($precision3({0}, 0.0))", rawOutput);
  145. case ConcreteSlotValueType.Vector4:
  146. return string.Format("({0}.xyz)", rawOutput);
  147. default:
  148. return kErrorString;
  149. }
  150. case ConcreteSlotValueType.Vector4:
  151. switch (convertFromType)
  152. {
  153. case ConcreteSlotValueType.Vector1:
  154. return string.Format("({0}.xxxx)", rawOutput);
  155. case ConcreteSlotValueType.Vector2:
  156. return string.Format("($precision4({0}, 0.0, 1.0))", rawOutput);
  157. case ConcreteSlotValueType.Vector3:
  158. return string.Format("($precision4({0}, 1.0))", rawOutput);
  159. default:
  160. return kErrorString;
  161. }
  162. case ConcreteSlotValueType.Matrix3:
  163. return rawOutput;
  164. case ConcreteSlotValueType.Matrix2:
  165. return rawOutput;
  166. default:
  167. return kErrorString;
  168. }
  169. }
  170. public static string AdaptNodeOutputForPreview(AbstractMaterialNode node, int outputSlotId)
  171. {
  172. var rawOutput = node.GetVariableNameForSlot(outputSlotId);
  173. return AdaptNodeOutputForPreview(node, outputSlotId, rawOutput);
  174. }
  175. public static string AdaptNodeOutputForPreview(AbstractMaterialNode node, int slotId, string variableName)
  176. {
  177. var slot = node.FindSlot<MaterialSlot>(slotId);
  178. if (slot == null)
  179. return kErrorString;
  180. var convertFromType = slot.concreteValueType;
  181. // preview is always dimension 4
  182. switch (convertFromType)
  183. {
  184. case ConcreteSlotValueType.Vector1:
  185. return string.Format("half4({0}, {0}, {0}, 1.0)", variableName);
  186. case ConcreteSlotValueType.Vector2:
  187. return string.Format("half4({0}.x, {0}.y, 0.0, 1.0)", variableName);
  188. case ConcreteSlotValueType.Vector3:
  189. return string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", variableName);
  190. case ConcreteSlotValueType.Vector4:
  191. return string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", variableName);
  192. case ConcreteSlotValueType.Boolean:
  193. return string.Format("half4({0}, {0}, {0}, 1.0)", variableName);
  194. default:
  195. return "half4(0, 0, 0, 0)";
  196. }
  197. }
  198. public int numberOfChunks
  199. {
  200. get { return m_ShaderChunks.Count; }
  201. }
  202. public enum InputType
  203. {
  204. Position,
  205. Vector,
  206. Normal
  207. }
  208. public struct TransformDesc
  209. {
  210. public TransformDesc(string name)
  211. {
  212. this.name = name;
  213. transpose = false;
  214. }
  215. public TransformDesc(string name, bool transpose)
  216. {
  217. this.name = name;
  218. this.transpose = transpose;
  219. }
  220. public string name;
  221. public bool transpose;
  222. }
  223. static TransformDesc[, ][] m_transforms = null;
  224. static TransformDesc[] GetTransformPath(CoordinateSpace from, CoordinateSpace to)
  225. {
  226. if (m_transforms[(int)from, (int)to] != null)
  227. {
  228. return m_transforms[(int)from, (int)to];
  229. }
  230. var distance = new int[5];
  231. var prev = new CoordinateSpace ? [5];
  232. var queue = new List<CoordinateSpace>();
  233. foreach (var space in Enum.GetValues(typeof(CoordinateSpace)))
  234. {
  235. distance[(int)space] = int.MaxValue;
  236. prev[(int)space] = null;
  237. queue.Add((CoordinateSpace)space);
  238. }
  239. distance[(int)from] = 0;
  240. List<CoordinateSpace> path = null;
  241. while (queue.Count != 0)
  242. {
  243. queue.Sort((x, y) => distance[(int)x] - distance[(int)y]);
  244. var min = queue[0];
  245. queue.Remove(min);
  246. if (min == to)
  247. {
  248. path = new List<CoordinateSpace>();
  249. while (prev[(int)min] != null)
  250. {
  251. path.Add(min);
  252. min = prev[(int)min].Value;
  253. }
  254. break;
  255. }
  256. if (distance[(int)min] == int.MaxValue)
  257. {
  258. break;
  259. }
  260. foreach (var space in Enum.GetValues(typeof(CoordinateSpace)))
  261. {
  262. int index = (int)space;
  263. if (m_transforms[(int)min, index] != null)
  264. {
  265. var alt = distance[(int)min] + m_transforms[(int)min, index].Length;
  266. if (alt < distance[index])
  267. {
  268. distance[index] = alt;
  269. prev[index] = min;
  270. }
  271. }
  272. }
  273. }
  274. path.Reverse();
  275. var matrixList = new List<TransformDesc>();
  276. foreach (var node in path)
  277. {
  278. matrixList.AddRange(m_transforms[(int)from, (int)node]);
  279. from = node;
  280. }
  281. return matrixList.ToArray();
  282. }
  283. static void InitTransforms()
  284. {
  285. if (m_transforms == null)
  286. {
  287. m_transforms = new TransformDesc[5, 5][];
  288. m_transforms[(int)CoordinateSpace.Object, (int)CoordinateSpace.Object] = new TransformDesc[] {};
  289. m_transforms[(int)CoordinateSpace.View, (int)CoordinateSpace.View] = new TransformDesc[] {};
  290. m_transforms[(int)CoordinateSpace.World, (int)CoordinateSpace.World] = new TransformDesc[] {};
  291. m_transforms[(int)CoordinateSpace.Tangent, (int)CoordinateSpace.Tangent] = new TransformDesc[] {};
  292. m_transforms[(int)CoordinateSpace.AbsoluteWorld, (int)CoordinateSpace.AbsoluteWorld] = new TransformDesc[] {};
  293. m_transforms[(int)CoordinateSpace.Object, (int)CoordinateSpace.World]
  294. = new TransformDesc[] {new TransformDesc(MatrixNames.Model)};
  295. m_transforms[(int)CoordinateSpace.View, (int)CoordinateSpace.World]
  296. = new TransformDesc[] {new TransformDesc(MatrixNames.ViewInverse) };
  297. m_transforms[(int)CoordinateSpace.World, (int)CoordinateSpace.Object]
  298. = new TransformDesc[] {new TransformDesc(MatrixNames.ModelInverse)};
  299. m_transforms[(int)CoordinateSpace.World, (int)CoordinateSpace.View]
  300. = new TransformDesc[] {new TransformDesc(MatrixNames.View)};
  301. for (var from = CoordinateSpace.Object; from != CoordinateSpace.Tangent; from++)
  302. {
  303. for (var to = CoordinateSpace.Object; to != CoordinateSpace.Tangent; to++)
  304. {
  305. if (m_transforms[(int)from, (int)to] == null)
  306. {
  307. m_transforms[(int)from, (int)to] = GetTransformPath(from, to);
  308. }
  309. }
  310. }
  311. }
  312. for (var k = CoordinateSpace.Object; k != CoordinateSpace.Tangent; k++)
  313. {
  314. m_transforms[(int)CoordinateSpace.Tangent, (int)k] = null;
  315. m_transforms[(int)k, (int)CoordinateSpace.Tangent] = null;
  316. }
  317. }
  318. public static string EmitTransform(TransformDesc[] matrices, TransformDesc[] invMatrices, string variable, bool isAffine, bool noMatrixCast, bool inverseTranspose)
  319. {
  320. // Use inverse transpose for situations where
  321. // scale needs to be considered (normals)
  322. if (inverseTranspose)
  323. matrices = invMatrices;
  324. if (isAffine)
  325. {
  326. variable = string.Format("float4({0},1.0)", variable);
  327. }
  328. foreach (var m in matrices)
  329. {
  330. var matrix = m.name;
  331. if (!isAffine && !noMatrixCast)
  332. {
  333. matrix = "(float3x3)" + matrix;
  334. }
  335. // if the matrix is NOT a transpose type
  336. // invert the order of multiplication
  337. // it is implicit transpose.
  338. if (m.transpose)
  339. inverseTranspose = !inverseTranspose;
  340. variable = inverseTranspose
  341. ? string.Format("mul({1},{0})", matrix, variable)
  342. : string.Format("mul({0},{1})", matrix, variable);
  343. }
  344. return variable;
  345. }
  346. public static string ConvertBetweenSpace(string variable, CoordinateSpace from, CoordinateSpace to,
  347. InputType inputType, CoordinateSpace tangentMatrixSpace = CoordinateSpace.Object)
  348. {
  349. if (from == to)
  350. {
  351. // nothing to do
  352. return variable;
  353. }
  354. // Ensure that the transform graph is initialized
  355. InitTransforms();
  356. bool isNormal = false;
  357. bool affine = (inputType == InputType.Position && to != CoordinateSpace.World);
  358. bool noMatrixCast = (inputType == InputType.Position && to == CoordinateSpace.World);
  359. if (inputType == InputType.Normal)
  360. {
  361. inputType = InputType.Vector;
  362. isNormal = true;
  363. }
  364. m_transforms[(int)CoordinateSpace.Tangent, (int)tangentMatrixSpace] =
  365. new[] {new TransformDesc("tangentSpaceTransform")};
  366. m_transforms[(int)tangentMatrixSpace, (int)CoordinateSpace.Tangent] = new[]
  367. {new TransformDesc("tangentSpaceTransform", true)};
  368. if (from == CoordinateSpace.Tangent)
  369. {
  370. // if converting from tangent space, reuse the underlying space
  371. from = tangentMatrixSpace;
  372. variable = EmitTransform(
  373. GetTransformPath(CoordinateSpace.Tangent, tangentMatrixSpace),
  374. GetTransformPath(tangentMatrixSpace, CoordinateSpace.Tangent),
  375. variable, affine, noMatrixCast, !isNormal);
  376. if (to == tangentMatrixSpace)
  377. {
  378. return variable;
  379. }
  380. }
  381. return EmitTransform(GetTransformPath(from, to), GetTransformPath(to, from), variable, affine, noMatrixCast, isNormal);
  382. }
  383. public static void GenerateSpaceTranslationSurfaceInputs(
  384. NeededCoordinateSpace neededSpaces,
  385. InterpolatorType interpolatorType,
  386. ShaderStringBuilder builder,
  387. string format = "float3 {0};")
  388. {
  389. if ((neededSpaces & NeededCoordinateSpace.Object) > 0)
  390. builder.AppendLine(format, CoordinateSpace.Object.ToVariableName(interpolatorType));
  391. if ((neededSpaces & NeededCoordinateSpace.World) > 0)
  392. builder.AppendLine(format, CoordinateSpace.World.ToVariableName(interpolatorType));
  393. if ((neededSpaces & NeededCoordinateSpace.View) > 0)
  394. builder.AppendLine(format, CoordinateSpace.View.ToVariableName(interpolatorType));
  395. if ((neededSpaces & NeededCoordinateSpace.Tangent) > 0)
  396. builder.AppendLine(format, CoordinateSpace.Tangent.ToVariableName(interpolatorType));
  397. if ((neededSpaces & NeededCoordinateSpace.AbsoluteWorld) > 0)
  398. builder.AppendLine(format, CoordinateSpace.AbsoluteWorld.ToVariableName(interpolatorType));
  399. }
  400. public static void GenerateStandardTransforms(
  401. int interpolatorStartIndex,
  402. int maxInterpolators,
  403. ShaderStringBuilder vertexOutputStruct,
  404. ShaderStringBuilder vertexShader,
  405. ShaderStringBuilder vertexShaderDescriptionInputs,
  406. ShaderStringBuilder vertexShaderOutputs,
  407. ShaderStringBuilder pixelShader,
  408. ShaderStringBuilder pixelShaderSurfaceInputs,
  409. ShaderGraphRequirements pixelRequirements,
  410. ShaderGraphRequirements surfaceRequirements,
  411. ShaderGraphRequirements modelRequiements,
  412. ShaderGraphRequirements vertexRequirements,
  413. CoordinateSpace preferredCoordinateSpace)
  414. {
  415. // ----------------------------------------------------- //
  416. // SETUP //
  417. // ----------------------------------------------------- //
  418. // -------------------------------------
  419. // Tangent space requires going via World space
  420. if (preferredCoordinateSpace == CoordinateSpace.Tangent)
  421. preferredCoordinateSpace = CoordinateSpace.World;
  422. // -------------------------------------
  423. // Generate combined graph requirements
  424. var graphModelRequirements = pixelRequirements.Union(modelRequiements);
  425. var combinedRequirements = vertexRequirements.Union(graphModelRequirements);
  426. int interpolatorIndex = interpolatorStartIndex;
  427. // ----------------------------------------------------- //
  428. // GENERATE VERTEX > PIXEL PIPELINE //
  429. // ----------------------------------------------------- //
  430. // -------------------------------------
  431. // If any stage requires component write into vertex stage
  432. // If model or pixel requires component write into interpolators and pixel stage
  433. // -------------------------------------
  434. // Position
  435. if (combinedRequirements.requiresPosition > 0)
  436. {
  437. var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Position);
  438. var preferredSpacePosition = ConvertBetweenSpace("v.vertex", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Position);
  439. vertexShader.AppendLine("float3 {0} = {1}.xyz;", name, preferredSpacePosition);
  440. if (graphModelRequirements.requiresPosition > 0)
  441. {
  442. vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
  443. vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
  444. pixelShader.AppendLine("float3 {0} = IN.{0};", name);
  445. interpolatorIndex++;
  446. }
  447. }
  448. // -------------------------------------
  449. // Normal
  450. // Bitangent needs Normal for x product
  451. if (combinedRequirements.requiresNormal > 0 || combinedRequirements.requiresBitangent > 0)
  452. {
  453. var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal);
  454. vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.normal", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Normal));
  455. if (graphModelRequirements.requiresNormal > 0 || graphModelRequirements.requiresBitangent > 0)
  456. {
  457. vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
  458. vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
  459. pixelShader.AppendLine("float3 {0} = IN.{0};", name);
  460. interpolatorIndex++;
  461. }
  462. }
  463. // -------------------------------------
  464. // Tangent
  465. if (combinedRequirements.requiresTangent > 0 || combinedRequirements.requiresBitangent > 0)
  466. {
  467. var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent);
  468. vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.tangent.xyz", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Vector));
  469. if (graphModelRequirements.requiresTangent > 0 || graphModelRequirements.requiresBitangent > 0)
  470. {
  471. vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
  472. vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
  473. pixelShader.AppendLine("float3 {0} = IN.{0};", name);
  474. interpolatorIndex++;
  475. }
  476. }
  477. // -------------------------------------
  478. // Bitangent
  479. if (combinedRequirements.requiresBitangent > 0)
  480. {
  481. var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent);
  482. vertexShader.AppendLine("float3 {0} = cross({1}, {2}.xyz) * {3};",
  483. name,
  484. preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal),
  485. preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent),
  486. "v.tangent.w");
  487. if (graphModelRequirements.requiresBitangent > 0)
  488. {
  489. vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
  490. vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
  491. pixelShader.AppendLine("float3 {0} = IN.{0};", name);
  492. interpolatorIndex++;
  493. }
  494. }
  495. // -------------------------------------
  496. // View Direction
  497. if (combinedRequirements.requiresViewDir > 0)
  498. {
  499. var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.ViewDirection);
  500. const string worldSpaceViewDir = "_WorldSpaceCameraPos.xyz - mul(GetObjectToWorldMatrix(), float4(v.vertex.xyz, 1.0)).xyz";
  501. var preferredSpaceViewDir = ConvertBetweenSpace(worldSpaceViewDir, CoordinateSpace.World, preferredCoordinateSpace, InputType.Vector);
  502. vertexShader.AppendLine("float3 {0} = {1};", name, preferredSpaceViewDir);
  503. if (graphModelRequirements.requiresViewDir > 0)
  504. {
  505. vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
  506. vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
  507. pixelShader.AppendLine("float3 {0} = IN.{0};", name);
  508. interpolatorIndex++;
  509. }
  510. }
  511. // -------------------------------------
  512. // Tangent space transform matrix
  513. if (combinedRequirements.NeedsTangentSpace())
  514. {
  515. var tangent = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent);
  516. var bitangent = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent);
  517. var normal = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal);
  518. if (vertexRequirements.NeedsTangentSpace())
  519. vertexShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});",
  520. tangent, bitangent, normal);
  521. if (graphModelRequirements.NeedsTangentSpace())
  522. pixelShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});",
  523. tangent, bitangent, normal);
  524. }
  525. // -------------------------------------
  526. // Vertex Color
  527. if (combinedRequirements.requiresVertexColor)
  528. {
  529. var vertexColor = "v.color";
  530. vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.VertexColor, vertexColor);
  531. if (graphModelRequirements.requiresVertexColor)
  532. {
  533. vertexOutputStruct.AppendLine("float4 {0} : COLOR;", ShaderGeneratorNames.VertexColor);
  534. vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.VertexColor);
  535. pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.VertexColor);
  536. }
  537. }
  538. // -------------------------------------
  539. // Screen Position
  540. if (combinedRequirements.requiresScreenPosition)
  541. {
  542. var screenPosition = "ComputeScreenPos(mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), v.vertex)), _ProjectionParams.x)";
  543. vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.ScreenPosition, screenPosition);
  544. if (graphModelRequirements.requiresScreenPosition)
  545. {
  546. vertexOutputStruct.AppendLine("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ScreenPosition, interpolatorIndex);
  547. vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.ScreenPosition);
  548. pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.ScreenPosition);
  549. interpolatorIndex++;
  550. }
  551. }
  552. // -------------------------------------
  553. // UV
  554. foreach (var channel in combinedRequirements.requiresMeshUVs.Distinct())
  555. vertexShader.AppendLine("float4 {0} = v.texcoord{1};", channel.GetUVName(), (int)channel);
  556. foreach (var channel in graphModelRequirements.requiresMeshUVs.Distinct())
  557. {
  558. vertexOutputStruct.AppendLine("half4 {0} : TEXCOORD{1};", channel.GetUVName(), interpolatorIndex == 0 ? "" : interpolatorIndex.ToString());
  559. vertexShaderOutputs.AppendLine("o.{0} = {0};", channel.GetUVName());
  560. pixelShader.AppendLine("float4 {0} = IN.{0};", channel.GetUVName());
  561. interpolatorIndex++;
  562. }
  563. // ----------------------------------------------------- //
  564. // TRANSLATE NEEDED SPACES //
  565. // ----------------------------------------------------- //
  566. // -------------------------------------
  567. // Generate the space translations needed by the vertex description
  568. GenerateSpaceTranslations(vertexRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace,
  569. InputType.Normal, vertexShader, Dimension.Three);
  570. GenerateSpaceTranslations(vertexRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace,
  571. InputType.Vector, vertexShader, Dimension.Three);
  572. GenerateSpaceTranslations(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace,
  573. InputType.Vector, vertexShader, Dimension.Three);
  574. GenerateSpaceTranslations(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace,
  575. InputType.Vector, vertexShader, Dimension.Three);
  576. GenerateSpaceTranslations(vertexRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace,
  577. InputType.Position, vertexShader, Dimension.Three);
  578. // -------------------------------------
  579. // Generate the space translations needed by the surface description and model
  580. GenerateSpaceTranslations(graphModelRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace,
  581. InputType.Normal, pixelShader, Dimension.Three);
  582. GenerateSpaceTranslations(graphModelRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace,
  583. InputType.Vector, pixelShader, Dimension.Three);
  584. GenerateSpaceTranslations(graphModelRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace,
  585. InputType.Vector, pixelShader, Dimension.Three);
  586. GenerateSpaceTranslations(graphModelRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace,
  587. InputType.Vector, pixelShader, Dimension.Three);
  588. GenerateSpaceTranslations(graphModelRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace,
  589. InputType.Position, pixelShader, Dimension.Three);
  590. // ----------------------------------------------------- //
  591. // START SURFACE DESCRIPTION //
  592. // ----------------------------------------------------- //
  593. // -------------------------------------
  594. // Copy the locally defined values into the surface description
  595. // structure using the requirements for ONLY the shader graph pixel stage
  596. // additional requirements have come from the lighting model
  597. // and are not needed in the shader graph
  598. {
  599. var replaceString = "surfaceInput.{0} = {0};";
  600. GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresNormal, InterpolatorType.Normal, pixelShaderSurfaceInputs, replaceString);
  601. GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresTangent, InterpolatorType.Tangent, pixelShaderSurfaceInputs, replaceString);
  602. GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresBitangent, InterpolatorType.BiTangent, pixelShaderSurfaceInputs, replaceString);
  603. GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresViewDir, InterpolatorType.ViewDirection, pixelShaderSurfaceInputs, replaceString);
  604. GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresPosition, InterpolatorType.Position, pixelShaderSurfaceInputs, replaceString);
  605. }
  606. if (pixelRequirements.requiresVertexColor)
  607. pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.VertexColor);
  608. if (pixelRequirements.requiresScreenPosition)
  609. pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.ScreenPosition);
  610. if (pixelRequirements.requiresFaceSign)
  611. pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.FaceSign);
  612. foreach (var channel in pixelRequirements.requiresMeshUVs.Distinct())
  613. pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.GetUVName(channel));
  614. if (pixelRequirements.requiresTime)
  615. {
  616. pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = _TimeParameters.xyz;", ShaderGeneratorNames.TimeParameters);
  617. }
  618. // ----------------------------------------------------- //
  619. // START VERTEX DESCRIPTION //
  620. // ----------------------------------------------------- //
  621. // -------------------------------------
  622. // Copy the locally defined values into the vertex description
  623. // structure using the requirements for ONLY the shader graph vertex stage
  624. // additional requirements have come from the lighting model
  625. // and are not needed in the shader graph
  626. {
  627. var replaceString = "vdi.{0} = {0};";
  628. GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexShaderDescriptionInputs, replaceString);
  629. GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexShaderDescriptionInputs, replaceString);
  630. GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexShaderDescriptionInputs, replaceString);
  631. GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexShaderDescriptionInputs, replaceString);
  632. GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexShaderDescriptionInputs, replaceString);
  633. }
  634. if (vertexRequirements.requiresVertexColor)
  635. vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.VertexColor);
  636. if (vertexRequirements.requiresScreenPosition)
  637. vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.ScreenPosition);
  638. foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct())
  639. vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", channel.GetUVName(), (int)channel);
  640. if (vertexRequirements.requiresTime)
  641. {
  642. vertexShaderDescriptionInputs.AppendLine("vdi.{0} = _TimeParameters.xyz;", ShaderGeneratorNames.TimeParameters);
  643. }
  644. }
  645. public enum Dimension
  646. {
  647. One,
  648. Two,
  649. Three,
  650. Four
  651. }
  652. private static string DimensionToString(Dimension d)
  653. {
  654. switch (d)
  655. {
  656. case Dimension.One:
  657. return string.Empty;
  658. case Dimension.Two:
  659. return "2";
  660. case Dimension.Three:
  661. return "3";
  662. case Dimension.Four:
  663. return "4";
  664. }
  665. return "error";
  666. }
  667. private static string DimensionToSwizzle(Dimension d)
  668. {
  669. switch (d)
  670. {
  671. case Dimension.One:
  672. return "x";
  673. case Dimension.Two:
  674. return "xy";
  675. case Dimension.Three:
  676. return "xyz";
  677. case Dimension.Four:
  678. return "xyzw";
  679. }
  680. return "error";
  681. }
  682. public static void GenerateSpaceTranslations(
  683. NeededCoordinateSpace neededSpaces,
  684. InterpolatorType type,
  685. CoordinateSpace from,
  686. InputType inputType,
  687. ShaderStringBuilder pixelShader,
  688. Dimension dimension)
  689. {
  690. if ((neededSpaces & NeededCoordinateSpace.Object) > 0 && from != CoordinateSpace.Object)
  691. pixelShader.AppendLine("float{0} {1} = {2}.{3};", DimensionToString(dimension),
  692. CoordinateSpace.Object.ToVariableName(type), ConvertBetweenSpace(from.ToVariableName(type), from, CoordinateSpace.Object, inputType, from),
  693. DimensionToSwizzle(dimension));
  694. if ((neededSpaces & NeededCoordinateSpace.World) > 0 && from != CoordinateSpace.World)
  695. pixelShader.AppendLine("float{0} {1} = {2}.{3};", DimensionToString(dimension),
  696. CoordinateSpace.World.ToVariableName(type), ConvertBetweenSpace(from.ToVariableName(type), from, CoordinateSpace.World, inputType, from),
  697. DimensionToSwizzle(dimension));
  698. if ((neededSpaces & NeededCoordinateSpace.View) > 0 && from != CoordinateSpace.View)
  699. pixelShader.AppendLine("float{0} {1} = {2}.{3};", DimensionToString(dimension),
  700. CoordinateSpace.View.ToVariableName(type),
  701. ConvertBetweenSpace(from.ToVariableName(type), from, CoordinateSpace.View, inputType, from),
  702. DimensionToSwizzle(dimension));
  703. if ((neededSpaces & NeededCoordinateSpace.Tangent) > 0 && from != CoordinateSpace.Tangent)
  704. pixelShader.AppendLine("float{0} {1} = {2}.{3};", DimensionToString(dimension),
  705. CoordinateSpace.Tangent.ToVariableName(type),
  706. ConvertBetweenSpace(from.ToVariableName(type), from, CoordinateSpace.Tangent, inputType, from),
  707. DimensionToSwizzle(dimension));
  708. if ((neededSpaces & NeededCoordinateSpace.AbsoluteWorld) > 0 && from != CoordinateSpace.AbsoluteWorld)
  709. pixelShader.AppendLine("float{0} {1} = GetAbsolutePositionWS({2}).{3};", DimensionToString(dimension),
  710. CoordinateSpace.AbsoluteWorld.ToVariableName(type),
  711. CoordinateSpace.World.ToVariableName(type),
  712. DimensionToSwizzle(dimension));
  713. }
  714. public static string GetPreviewSubShader(AbstractMaterialNode node, ShaderGraphRequirements shaderGraphRequirements)
  715. {
  716. // Should never be called without a node
  717. Debug.Assert(node != null);
  718. var vertexOutputStruct = new ShaderStringBuilder(2);
  719. var vertexShader = new ShaderStringBuilder(2);
  720. var vertexShaderDescriptionInputs = new ShaderStringBuilder(2);
  721. var vertexShaderOutputs = new ShaderStringBuilder(1);
  722. var pixelShader = new ShaderStringBuilder(2);
  723. var pixelShaderSurfaceInputs = new ShaderStringBuilder(2);
  724. var pixelShaderSurfaceRemap = new ShaderStringBuilder(2);
  725. ShaderGenerator.GenerateStandardTransforms(
  726. 0,
  727. 16,
  728. vertexOutputStruct,
  729. vertexShader,
  730. vertexShaderDescriptionInputs,
  731. vertexShaderOutputs,
  732. pixelShader,
  733. pixelShaderSurfaceInputs,
  734. shaderGraphRequirements,
  735. shaderGraphRequirements,
  736. ShaderGraphRequirements.none,
  737. ShaderGraphRequirements.none,
  738. CoordinateSpace.World);
  739. vertexShader.AppendLines(vertexShaderDescriptionInputs.ToString());
  740. vertexShader.AppendLines(vertexShaderOutputs.ToString());
  741. var outputSlot = node.GetOutputSlots<MaterialSlot>().FirstOrDefault();
  742. // Sub Graph Output uses first input slot
  743. if (node is SubGraphOutputNode)
  744. {
  745. outputSlot = node.GetInputSlots<MaterialSlot>().FirstOrDefault();
  746. }
  747. if (outputSlot != null)
  748. {
  749. var result = $"surf.{NodeUtils.GetHLSLSafeName(outputSlot.shaderOutputName)}_{outputSlot.id}";
  750. pixelShaderSurfaceRemap.AppendLine("return all(isfinite({0})) ? {1} : {2};",
  751. result, AdaptNodeOutputForPreview(node, outputSlot.id, result), nanOutput);
  752. }
  753. else
  754. {
  755. // No valid slots to display, so just show black.
  756. // It's up to each node to error or warn as appropriate.
  757. pixelShaderSurfaceRemap.AppendLine("return 0;");
  758. }
  759. // -------------------------------------
  760. // Extra pixel shader work
  761. var faceSign = new ShaderStringBuilder();
  762. if (shaderGraphRequirements.requiresFaceSign)
  763. faceSign.AppendLine(", half FaceSign : VFACE");
  764. var res = subShaderTemplate.Replace("${Interpolators}", vertexOutputStruct.ToString());
  765. res = res.Replace("${VertexShader}", vertexShader.ToString());
  766. res = res.Replace("${FaceSign}", faceSign.ToString());
  767. res = res.Replace("${LocalPixelShader}", pixelShader.ToString());
  768. res = res.Replace("${SurfaceInputs}", pixelShaderSurfaceInputs.ToString());
  769. res = res.Replace("${SurfaceOutputRemap}", pixelShaderSurfaceRemap.ToString());
  770. return res;
  771. }
  772. public static SurfaceMaterialTags BuildMaterialTags(SurfaceType surfaceType)
  773. {
  774. SurfaceMaterialTags materialTags = new SurfaceMaterialTags();
  775. if (surfaceType == SurfaceType.Opaque)
  776. {
  777. materialTags.renderQueue = SurfaceMaterialTags.RenderQueue.Geometry;
  778. materialTags.renderType = SurfaceMaterialTags.RenderType.Opaque;
  779. }
  780. else
  781. {
  782. materialTags.renderQueue = SurfaceMaterialTags.RenderQueue.Transparent;
  783. materialTags.renderType = SurfaceMaterialTags.RenderType.Transparent;
  784. }
  785. return materialTags;
  786. }
  787. public static SurfaceMaterialOptions GetMaterialOptions(SurfaceType surfaceType, AlphaMode alphaMode, bool twoSided, bool offscreenTransparent = false)
  788. {
  789. var materialOptions = new SurfaceMaterialOptions();
  790. switch (surfaceType)
  791. {
  792. case SurfaceType.Opaque:
  793. materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.One;
  794. materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.Zero;
  795. materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
  796. materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
  797. materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.On;
  798. break;
  799. case SurfaceType.Transparent:
  800. switch (alphaMode)
  801. {
  802. case AlphaMode.Alpha:
  803. materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.SrcAlpha;
  804. materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.OneMinusSrcAlpha;
  805. if(offscreenTransparent)
  806. {
  807. materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.Zero;
  808. }
  809. else
  810. {
  811. materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.One;
  812. }
  813. materialOptions.alphaDstBlend = SurfaceMaterialOptions.BlendMode.OneMinusSrcAlpha;
  814. materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
  815. materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
  816. materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off;
  817. break;
  818. case AlphaMode.Premultiply:
  819. materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.One;
  820. materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.OneMinusSrcAlpha;
  821. if (offscreenTransparent)
  822. {
  823. materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.Zero;
  824. }
  825. else
  826. {
  827. materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.One;
  828. }
  829. materialOptions.alphaDstBlend = SurfaceMaterialOptions.BlendMode.OneMinusSrcAlpha;
  830. materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
  831. materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
  832. materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off;
  833. break;
  834. case AlphaMode.Additive:
  835. materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.One;
  836. materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.One;
  837. if (offscreenTransparent)
  838. {
  839. materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.Zero;
  840. }
  841. else
  842. {
  843. materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.One;
  844. }
  845. materialOptions.alphaDstBlend = SurfaceMaterialOptions.BlendMode.One;
  846. materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
  847. materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
  848. materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off;
  849. break;
  850. case AlphaMode.Multiply:
  851. materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.DstColor;
  852. materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.Zero;
  853. materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
  854. materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
  855. materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off;
  856. break;
  857. }
  858. break;
  859. }
  860. return materialOptions;
  861. }
  862. const string nanOutput = "float4(1.0f, 0.0f, 1.0f, 1.0f)";
  863. const string subShaderTemplate = @"
  864. SubShader
  865. {
  866. Tags { ""RenderType""=""Opaque"" }
  867. LOD 100
  868. Pass
  869. {
  870. HLSLPROGRAM
  871. #pragma vertex vert
  872. #pragma fragment frag
  873. struct GraphVertexOutput
  874. {
  875. float4 position : POSITION;
  876. ${Interpolators}
  877. };
  878. GraphVertexOutput vert (GraphVertexInput v)
  879. {
  880. v = PopulateVertexData(v);
  881. GraphVertexOutput o;
  882. float3 positionWS = TransformObjectToWorld(v.vertex);
  883. o.position = TransformWorldToHClip(positionWS);
  884. ${VertexShader}
  885. return o;
  886. }
  887. float4 frag (GraphVertexOutput IN ${FaceSign}) : SV_Target
  888. {
  889. ${LocalPixelShader}
  890. SurfaceDescriptionInputs surfaceInput = (SurfaceDescriptionInputs)0;
  891. ${SurfaceInputs}
  892. SurfaceDescription surf = PopulateSurfaceData(surfaceInput);
  893. ${SurfaceOutputRemap}
  894. }
  895. ENDHLSL
  896. }
  897. }";
  898. }
  899. }