暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpaceTransformUtil.cs 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. // using System;
  2. using System.Collections.Generic;
  3. using UnityEditor.ShaderGraph.Internal;
  4. namespace UnityEditor.ShaderGraph
  5. {
  6. enum ConversionType
  7. {
  8. Position,
  9. Direction,
  10. Normal
  11. }
  12. internal struct SpaceTransform
  13. {
  14. public CoordinateSpace from;
  15. public CoordinateSpace to;
  16. public ConversionType type;
  17. public bool normalize;
  18. public int version;
  19. public const int kLatestVersion = 2;
  20. public SpaceTransform(CoordinateSpace from, CoordinateSpace to, ConversionType type, bool normalize = false, int version = kLatestVersion)
  21. {
  22. this.from = from;
  23. this.to = to;
  24. this.type = type;
  25. this.normalize = normalize;
  26. this.version = version;
  27. }
  28. internal string NormalizeString()
  29. {
  30. return normalize ? "true" : "false";
  31. }
  32. // non-identity transforms involving tangent space require the full tangent frame
  33. public NeededCoordinateSpace RequiresNormal =>
  34. (((from == CoordinateSpace.Tangent) || (to == CoordinateSpace.Tangent)) && (from != to)) ?
  35. NeededCoordinateSpace.World : NeededCoordinateSpace.None;
  36. public NeededCoordinateSpace RequiresTangent =>
  37. (((from == CoordinateSpace.Tangent) || (to == CoordinateSpace.Tangent)) && (from != to)) ?
  38. NeededCoordinateSpace.World : NeededCoordinateSpace.None;
  39. public NeededCoordinateSpace RequiresBitangent =>
  40. (((from == CoordinateSpace.Tangent) || (to == CoordinateSpace.Tangent)) && (from != to)) ?
  41. NeededCoordinateSpace.World : NeededCoordinateSpace.None;
  42. // non-identity position transforms involving tangent space require the world position
  43. public NeededCoordinateSpace RequiresPosition =>
  44. ((type == ConversionType.Position) && ((from == CoordinateSpace.Tangent) || (to == CoordinateSpace.Tangent)) && (from != to)) ?
  45. NeededCoordinateSpace.World : NeededCoordinateSpace.None;
  46. public IEnumerable<NeededTransform> RequiresTransform =>
  47. SpaceTransformUtil.ComputeTransformRequirement(this);
  48. };
  49. static class SpaceTransformUtil
  50. {
  51. delegate void TransformFunction(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb);
  52. public static string GenerateTangentTransform(ShaderStringBuilder sb, CoordinateSpace tangentTransformSpace)
  53. {
  54. sb.AddLine("$precision3x3 tangentTransform = $precision3x3(IN.",
  55. tangentTransformSpace.ToString(), "SpaceTangent, IN.",
  56. tangentTransformSpace.ToString(), "SpaceBiTangent, IN.",
  57. tangentTransformSpace.ToString(), "SpaceNormal);");
  58. return "tangentTransform";
  59. }
  60. public static void Identity(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  61. {
  62. // identity didn't normalize before version 2
  63. if ((xform.version > 1) && xform.normalize && (xform.type != ConversionType.Position))
  64. sb.AddLine(outputVariable, " = SafeNormalize(", inputValue, ");");
  65. else
  66. sb.AddLine(outputVariable, " = ", inputValue, ";");
  67. }
  68. private static void ViaWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  69. {
  70. // should never be calling this if one of the spaces is already world space (silly, and could lead to infinite recursions)
  71. if ((xform.from == CoordinateSpace.World) || (xform.to == CoordinateSpace.World))
  72. return;
  73. // this breaks the transform into two parts: (from->world) and (world->to)
  74. var toWorld = new SpaceTransform()
  75. {
  76. from = xform.from,
  77. to = CoordinateSpace.World,
  78. type = xform.type,
  79. normalize = false,
  80. version = xform.version
  81. };
  82. var fromWorld = new SpaceTransform()
  83. {
  84. from = CoordinateSpace.World,
  85. to = xform.to,
  86. type = xform.type,
  87. normalize = xform.normalize,
  88. version = xform.version
  89. };
  90. // Apply Versioning Hacks to match old (incorrect) versions
  91. if (xform.version <= 1)
  92. {
  93. if (xform.type == ConversionType.Direction)
  94. {
  95. switch (xform.from)
  96. {
  97. case CoordinateSpace.AbsoluteWorld:
  98. if ((xform.to == CoordinateSpace.Object) || (xform.to == CoordinateSpace.View))
  99. {
  100. // these transforms were wrong in v0, but correct in v1, so here we
  101. // pretend it is a later version to disable the v1 versioning in the AbsWorldToWorld transform
  102. if (xform.version == 1)
  103. toWorld.version = 2;
  104. }
  105. break;
  106. case CoordinateSpace.View:
  107. if ((xform.to == CoordinateSpace.Tangent) || (xform.to == CoordinateSpace.AbsoluteWorld))
  108. {
  109. // these transforms erroneously used the position view-to-world transform
  110. toWorld.type = ConversionType.Position;
  111. }
  112. break;
  113. case CoordinateSpace.Tangent:
  114. if ((xform.to == CoordinateSpace.Object) || (xform.to == CoordinateSpace.View) || (xform.to == CoordinateSpace.AbsoluteWorld))
  115. {
  116. // manually version to 2, to remove normalization (while keeping Normal type)
  117. toWorld.type = ConversionType.Normal;
  118. toWorld.version = 2;
  119. }
  120. break;
  121. }
  122. }
  123. }
  124. using (sb.BlockScope())
  125. {
  126. sb.AddLine("// Converting ", xform.type.ToString(), " from ", xform.from.ToString(), " to ", xform.to.ToString(), " via world space");
  127. sb.AddLine("float3 world;");
  128. GenerateTransformCodeStatement(toWorld, inputValue, "world", sb);
  129. GenerateTransformCodeStatement(fromWorld, "world", outputVariable, sb);
  130. }
  131. }
  132. public static void WorldToObject(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  133. {
  134. switch (xform.type)
  135. {
  136. case ConversionType.Position:
  137. sb.AddLine(outputVariable, " = TransformWorldToObject(", inputValue, ");");
  138. break;
  139. case ConversionType.Direction:
  140. if (xform.version <= 1)
  141. xform.normalize = true;
  142. sb.AddLine(outputVariable, " = TransformWorldToObjectDir(", inputValue, ", ", xform.NormalizeString(), ");");
  143. break;
  144. case ConversionType.Normal:
  145. sb.AddLine(outputVariable, " = TransformWorldToObjectNormal(", inputValue, ", ", xform.NormalizeString(), ");");
  146. break;
  147. }
  148. }
  149. public static void WorldToTangent(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  150. {
  151. if (xform.version <= 1)
  152. {
  153. // prior to version 2, all transform were normalized, and all transforms were Normal transforms
  154. xform.normalize = true;
  155. xform.type = ConversionType.Normal;
  156. }
  157. using (sb.BlockScope())
  158. {
  159. string tangentTransform = GenerateTangentTransform(sb, xform.from);
  160. switch (xform.type)
  161. {
  162. case ConversionType.Position:
  163. sb.AddLine(outputVariable, " = TransformWorldToTangentDir(", inputValue, " - IN.WorldSpacePosition, ", tangentTransform, ", false);");
  164. break;
  165. case ConversionType.Direction:
  166. sb.AddLine(outputVariable, " = TransformWorldToTangentDir(", inputValue, ", ", tangentTransform, ", ", xform.NormalizeString(), ");");
  167. break;
  168. case ConversionType.Normal:
  169. sb.AddLine(outputVariable, " = TransformWorldToTangent(", inputValue, ", ", tangentTransform, ", ", xform.NormalizeString(), ");");
  170. break;
  171. }
  172. }
  173. }
  174. public static void WorldToView(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  175. {
  176. switch (xform.type)
  177. {
  178. case ConversionType.Position:
  179. sb.AddLine(outputVariable, " = TransformWorldToView(", inputValue, ");");
  180. break;
  181. case ConversionType.Direction:
  182. if (xform.version <= 1)
  183. xform.normalize = false;
  184. sb.AddLine(outputVariable, " = TransformWorldToViewDir(", inputValue, ", ", xform.NormalizeString(), ");");
  185. break;
  186. case ConversionType.Normal:
  187. sb.AddLine(outputVariable, " = TransformWorldToViewNormal(", inputValue, ", ", xform.NormalizeString(), ");");
  188. break;
  189. }
  190. }
  191. public static void WorldToAbsoluteWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  192. {
  193. // prior to version 2 always used Position transform
  194. if (xform.version <= 1)
  195. xform.type = ConversionType.Position;
  196. switch (xform.type)
  197. {
  198. case ConversionType.Position:
  199. sb.AddLine(outputVariable, " = GetAbsolutePositionWS(", inputValue, ");");
  200. break;
  201. case ConversionType.Direction:
  202. case ConversionType.Normal:
  203. // both normal and direction are unchanged
  204. if (xform.normalize)
  205. sb.AddLine(outputVariable, " = SafeNormalize(", inputValue, ");");
  206. else
  207. sb.AddLine(outputVariable, " = ", inputValue, ";");
  208. break;
  209. }
  210. }
  211. public static void ObjectToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  212. {
  213. switch (xform.type)
  214. {
  215. case ConversionType.Position:
  216. sb.AddLine(outputVariable, " = TransformObjectToWorld(", inputValue, ");");
  217. break;
  218. case ConversionType.Direction:
  219. if (xform.version <= 1)
  220. xform.normalize = true;
  221. sb.AddLine(outputVariable, " = TransformObjectToWorldDir(", inputValue, ", ", xform.NormalizeString(), ");");
  222. break;
  223. case ConversionType.Normal:
  224. sb.AddLine(outputVariable, " = TransformObjectToWorldNormal(", inputValue, ", ", xform.NormalizeString(), ");");
  225. break;
  226. }
  227. }
  228. public static void ObjectToAbsoluteWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  229. {
  230. switch (xform.type)
  231. {
  232. case ConversionType.Position:
  233. ViaWorld(xform, inputValue, outputVariable, sb);
  234. break;
  235. case ConversionType.Direction:
  236. if (xform.version <= 1)
  237. xform.normalize = true;
  238. sb.AddLine(outputVariable, " = TransformObjectToWorldDir(", inputValue, ", ", xform.NormalizeString(), ");");
  239. break;
  240. case ConversionType.Normal:
  241. sb.AddLine(outputVariable, " = TransformObjectToWorldNormal(", inputValue, ", ", xform.NormalizeString(), ");");
  242. break;
  243. }
  244. }
  245. public static void TangentToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  246. {
  247. // prior to version 2 all transforms were Normal, and directional transforms were normalized
  248. if (xform.version <= 1)
  249. {
  250. if (xform.type != ConversionType.Position)
  251. xform.normalize = true;
  252. xform.type = ConversionType.Normal;
  253. }
  254. using (sb.BlockScope())
  255. {
  256. string tangentTransform = GenerateTangentTransform(sb, CoordinateSpace.World);
  257. switch (xform.type)
  258. {
  259. case ConversionType.Position:
  260. sb.AddLine(outputVariable, " = TransformTangentToWorldDir(", inputValue, ", ", tangentTransform, ", false).xyz + IN.WorldSpacePosition;");
  261. break;
  262. case ConversionType.Direction:
  263. sb.AddLine(outputVariable, " = TransformTangentToWorldDir(", inputValue, ", ", tangentTransform, ", ", xform.NormalizeString(), ").xyz;");
  264. break;
  265. case ConversionType.Normal:
  266. sb.AddLine(outputVariable, " = TransformTangentToWorld(", inputValue, ", ", tangentTransform, ", ", xform.NormalizeString(), ");");
  267. break;
  268. }
  269. }
  270. }
  271. public static void ViewToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  272. {
  273. switch (xform.type)
  274. {
  275. case ConversionType.Position:
  276. sb.AddLine(outputVariable, " = TransformViewToWorld(", inputValue, ");");
  277. break;
  278. case ConversionType.Direction:
  279. if (xform.version <= 1)
  280. xform.normalize = false;
  281. sb.AddLine(outputVariable, " = TransformViewToWorldDir(", inputValue, ", ", xform.NormalizeString(), ");");
  282. break;
  283. case ConversionType.Normal:
  284. sb.AddLine(outputVariable, " = TransformViewToWorldNormal(", inputValue, ", ", xform.NormalizeString(), ");");
  285. break;
  286. }
  287. }
  288. public static void AbsoluteWorldToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  289. {
  290. // prior to version 2, always used position transform
  291. if (xform.version <= 1)
  292. xform.type = ConversionType.Position;
  293. switch (xform.type)
  294. {
  295. case ConversionType.Position:
  296. sb.AddLine(outputVariable, " = GetCameraRelativePositionWS(", inputValue, ");");
  297. break;
  298. case ConversionType.Direction:
  299. case ConversionType.Normal:
  300. // both normal and direction are unchanged
  301. if (xform.normalize)
  302. sb.AddLine(outputVariable, " = SafeNormalize(", inputValue, ");");
  303. else
  304. sb.AddLine(outputVariable, " = ", inputValue, ";");
  305. break;
  306. }
  307. }
  308. public static void ObjectToHScreen(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  309. {
  310. switch (xform.type)
  311. {
  312. case ConversionType.Position:
  313. using (sb.BlockScope())
  314. {
  315. sb.AddLine("$precision4 ", outputVariable, "_value = TransformObjectToHClip(", inputValue, ");");
  316. sb.AddLine("$precision3 ", outputVariable, "_uv = ", outputVariable, "_value.xyz / ", outputVariable, "_value.w;");
  317. sb.AddLine("#if UNITY_UV_STARTS_AT_TOP");
  318. sb.AddLine(outputVariable, "_uv.y = -", outputVariable, "_uv.y;");
  319. sb.AddLine("#endif");
  320. sb.AddLine(outputVariable, "_uv.xy = ", outputVariable, "_uv.xy * 0.5 + 0.5;");
  321. sb.AddLine(outputVariable, " = ", outputVariable, "_uv;");
  322. }
  323. break;
  324. case ConversionType.Direction:
  325. case ConversionType.Normal:
  326. ViaWorld(xform, inputValue, outputVariable, sb);
  327. break;
  328. }
  329. }
  330. public static void ViewToHScreen(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  331. {
  332. switch (xform.type)
  333. {
  334. case ConversionType.Position:
  335. sb.AddLine("$precision4 ", outputVariable, "_value = TransformWViewToHClip(", inputValue, ");");
  336. sb.AddLine("$precision3 ", outputVariable, "_uv = ", outputVariable, "_value.xyz / ", outputVariable, "_value.w;");
  337. sb.AddLine("#if UNITY_UV_STARTS_AT_TOP");
  338. sb.AddLine(outputVariable, "_uv.y = -", outputVariable, "_uv.y;");
  339. sb.AddLine("#endif");
  340. sb.AddLine(outputVariable, "_uv.xy = ", outputVariable, "_uv.xy * 0.5 + 0.5;");
  341. sb.AddLine(outputVariable, " = ", outputVariable, "_uv;");
  342. break;
  343. case ConversionType.Direction:
  344. case ConversionType.Normal:
  345. ViaWorld(xform, inputValue, outputVariable, sb);
  346. break;
  347. }
  348. }
  349. public static void WorldToHScreen(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  350. {
  351. switch (xform.type)
  352. {
  353. case ConversionType.Position:
  354. sb.AddLine("$precision4 ", outputVariable, "_value = TransformWorldToHClip(", inputValue, ");");
  355. break;
  356. case ConversionType.Direction:
  357. if (xform.version <= 1)
  358. xform.normalize = true;
  359. sb.AddLine("$precision4 ", outputVariable, "_value = $precision4(TransformWorldToHClipDir(", inputValue, ", ", xform.NormalizeString(), "), 1.0f);");
  360. break;
  361. case ConversionType.Normal:
  362. sb.AddLine("$precision4 ", outputVariable, "_value = $precision4(TransformWorldToHClipDir(", inputValue, ", ", xform.NormalizeString(), "), 1.0f);");
  363. break;
  364. }
  365. sb.AddLine("$precision3 ", outputVariable, "_uv = ", outputVariable, "_value.xyz / ", outputVariable, "_value.w;");
  366. sb.AddLine("#if UNITY_UV_STARTS_AT_TOP");
  367. sb.AddLine(outputVariable, "_uv.y = -", outputVariable, "_uv.y;");
  368. sb.AddLine("#endif");
  369. sb.AddLine(outputVariable, "_uv.xy = ", outputVariable, "_uv.xy * 0.5 + 0.5;");
  370. sb.AddLine(outputVariable, " = ", outputVariable, "_uv;");
  371. }
  372. public static void HScreenToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  373. {
  374. switch (xform.type)
  375. {
  376. case ConversionType.Position:
  377. sb.AddLine(outputVariable, " = ComputeWorldSpacePosition(", inputValue, ".xy, ", inputValue, ".z, UNITY_MATRIX_I_VP);");
  378. break;
  379. case ConversionType.Direction:
  380. case ConversionType.Normal:
  381. sb.AddLine("$precision4 ", outputVariable, "_CS = ComputeClipSpacePosition(", inputValue, ".xy, ", inputValue, ".z);");
  382. sb.AddLine(outputVariable, " = mul(UNITY_MATRIX_I_VP, $precision4(", outputVariable, "_CS.xyz, 0.0f)).xyz;");
  383. break;
  384. }
  385. }
  386. static readonly TransformFunction[,] k_TransformFunctions = new TransformFunction[6, 6] // [from, to]
  387. {
  388. { // from CoordinateSpace.Object
  389. Identity, // to CoordinateSpace.Object
  390. ViaWorld, // to CoordinateSpace.View
  391. ObjectToWorld, // to CoordinateSpace.World
  392. ViaWorld, // to CoordinateSpace.Tangent
  393. ObjectToAbsoluteWorld, // to CoordinateSpace.AbsoluteWorld
  394. ObjectToHScreen // to CoordinateSpace.Screen
  395. },
  396. { // from CoordinateSpace.View
  397. ViaWorld, // to CoordinateSpace.Object
  398. Identity, // to CoordinateSpace.View
  399. ViewToWorld, // to CoordinateSpace.World
  400. ViaWorld, // to CoordinateSpace.Tangent
  401. ViaWorld, // to CoordinateSpace.AbsoluteWorld
  402. ViewToHScreen // to CoordinateSpace.Screen
  403. },
  404. { // from CoordinateSpace.World
  405. WorldToObject, // to CoordinateSpace.Object
  406. WorldToView, // to CoordinateSpace.View
  407. Identity, // to CoordinateSpace.World
  408. WorldToTangent, // to CoordinateSpace.Tangent
  409. WorldToAbsoluteWorld, // to CoordinateSpace.AbsoluteWorld
  410. WorldToHScreen // to CoordinateSpace.Screen
  411. },
  412. { // from CoordinateSpace.Tangent
  413. ViaWorld, // to CoordinateSpace.Object
  414. ViaWorld, // to CoordinateSpace.View
  415. TangentToWorld, // to CoordinateSpace.World
  416. Identity, // to CoordinateSpace.Tangent
  417. ViaWorld, // to CoordinateSpace.AbsoluteWorld
  418. ViaWorld // to CoordinateSpace.Screen
  419. },
  420. { // from CoordinateSpace.AbsoluteWorld
  421. ViaWorld, // to CoordinateSpace.Object
  422. ViaWorld, // to CoordinateSpace.View
  423. AbsoluteWorldToWorld, // to CoordinateSpace.World
  424. ViaWorld, // to CoordinateSpace.Tangent
  425. Identity, // to CoordinateSpace.AbsoluteWorld
  426. ViaWorld // to CoordinateSpace.Screen
  427. },
  428. { // from CoordinateSpace.Screen
  429. ViaWorld, // to CoordinateSpace.Object
  430. ViaWorld, // to CoordinateSpace.View
  431. HScreenToWorld, // to CoordinateSpace.World
  432. ViaWorld, // to CoordinateSpace.Tangent
  433. ViaWorld, // to CoordinateSpace.AbsoluteWorld
  434. Identity, // to CoordinateSpace.Screen
  435. }
  436. };
  437. internal static IEnumerable<NeededTransform> ComputeTransformRequirement(SpaceTransform xform)
  438. {
  439. var func = k_TransformFunctions[(int)xform.from, (int)xform.to];
  440. if (func == ViaWorld || func == ObjectToAbsoluteWorld)
  441. {
  442. yield return new NeededTransform(xform.from.ToNeededCoordinateSpace(), NeededCoordinateSpace.World);
  443. yield return new NeededTransform(NeededCoordinateSpace.World, xform.to.ToNeededCoordinateSpace());
  444. }
  445. else
  446. {
  447. yield return new NeededTransform(xform.from.ToNeededCoordinateSpace(), xform.to.ToNeededCoordinateSpace());
  448. }
  449. }
  450. public static void GenerateTransformCodeStatement(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
  451. {
  452. var func = k_TransformFunctions[(int)xform.from, (int)xform.to];
  453. func(xform, inputValue, outputVariable, sb);
  454. }
  455. }
  456. }