RenderingUtils.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. using System.Collections.Generic;
  2. using System.Diagnostics;
  3. using UnityEngine.Experimental.Rendering;
  4. namespace UnityEngine.Rendering.Universal
  5. {
  6. /// <summary>
  7. /// Contains properties and helper functions that you can use when rendering.
  8. /// </summary>
  9. public static class RenderingUtils
  10. {
  11. static List<ShaderTagId> m_LegacyShaderPassNames = new List<ShaderTagId>
  12. {
  13. new ShaderTagId("Always"),
  14. new ShaderTagId("ForwardBase"),
  15. new ShaderTagId("PrepassBase"),
  16. new ShaderTagId("Vertex"),
  17. new ShaderTagId("VertexLMRGBM"),
  18. new ShaderTagId("VertexLM"),
  19. };
  20. static AttachmentDescriptor s_EmptyAttachment = new AttachmentDescriptor(GraphicsFormat.None);
  21. internal static AttachmentDescriptor emptyAttachment
  22. {
  23. get
  24. {
  25. return s_EmptyAttachment;
  26. }
  27. }
  28. static Mesh s_FullscreenMesh = null;
  29. /// <summary>
  30. /// Returns a mesh that you can use with <see cref="CommandBuffer.DrawMesh(Mesh, Matrix4x4, Material)"/> to render full-screen effects.
  31. /// </summary>
  32. public static Mesh fullscreenMesh
  33. {
  34. get
  35. {
  36. if (s_FullscreenMesh != null)
  37. return s_FullscreenMesh;
  38. float topV = 1.0f;
  39. float bottomV = 0.0f;
  40. s_FullscreenMesh = new Mesh { name = "Fullscreen Quad" };
  41. s_FullscreenMesh.SetVertices(new List<Vector3>
  42. {
  43. new Vector3(-1.0f, -1.0f, 0.0f),
  44. new Vector3(-1.0f, 1.0f, 0.0f),
  45. new Vector3(1.0f, -1.0f, 0.0f),
  46. new Vector3(1.0f, 1.0f, 0.0f)
  47. });
  48. s_FullscreenMesh.SetUVs(0, new List<Vector2>
  49. {
  50. new Vector2(0.0f, bottomV),
  51. new Vector2(0.0f, topV),
  52. new Vector2(1.0f, bottomV),
  53. new Vector2(1.0f, topV)
  54. });
  55. s_FullscreenMesh.SetIndices(new[] { 0, 1, 2, 2, 1, 3 }, MeshTopology.Triangles, 0, false);
  56. s_FullscreenMesh.UploadMeshData(true);
  57. return s_FullscreenMesh;
  58. }
  59. }
  60. internal static bool useStructuredBuffer
  61. {
  62. // There are some performance issues with StructuredBuffers in some platforms.
  63. // We fallback to UBO in those cases.
  64. get
  65. {
  66. // TODO: For now disabling SSBO until figure out Vulkan binding issues.
  67. // When enabling this also enable USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA in shader side in Input.hlsl
  68. return false;
  69. // We don't use SSBO in D3D because we can't figure out without adding shader variants if platforms is D3D10.
  70. //GraphicsDeviceType deviceType = SystemInfo.graphicsDeviceType;
  71. //return !Application.isMobilePlatform &&
  72. // (deviceType == GraphicsDeviceType.Metal || deviceType == GraphicsDeviceType.Vulkan ||
  73. // deviceType == GraphicsDeviceType.PlayStation4 || deviceType == GraphicsDeviceType.PlayStation5 || deviceType == GraphicsDeviceType.XboxOne);
  74. }
  75. }
  76. internal static bool SupportsLightLayers(GraphicsDeviceType type)
  77. {
  78. // GLES2 does not support bitwise operations.
  79. return type != GraphicsDeviceType.OpenGLES2;
  80. }
  81. static Material s_ErrorMaterial;
  82. static Material errorMaterial
  83. {
  84. get
  85. {
  86. if (s_ErrorMaterial == null)
  87. {
  88. // TODO: When importing project, AssetPreviewUpdater::CreatePreviewForAsset will be called multiple times.
  89. // This might be in a point that some resources required for the pipeline are not finished importing yet.
  90. // Proper fix is to add a fence on asset import.
  91. try
  92. {
  93. s_ErrorMaterial = new Material(Shader.Find("Hidden/Universal Render Pipeline/FallbackError"));
  94. }
  95. catch { }
  96. }
  97. return s_ErrorMaterial;
  98. }
  99. }
  100. /// <summary>
  101. /// Set view and projection matrices.
  102. /// This function will set <c>UNITY_MATRIX_V</c>, <c>UNITY_MATRIX_P</c>, <c>UNITY_MATRIX_VP</c> to given view and projection matrices.
  103. /// If <c>setInverseMatrices</c> is set to true this function will also set <c>UNITY_MATRIX_I_V</c> and <c>UNITY_MATRIX_I_VP</c>.
  104. /// </summary>
  105. /// <param name="cmd">CommandBuffer to submit data to GPU.</param>
  106. /// <param name="viewMatrix">View matrix to be set.</param>
  107. /// <param name="projectionMatrix">Projection matrix to be set.</param>
  108. /// <param name="setInverseMatrices">Set this to true if you also need to set inverse camera matrices.</param>
  109. public static void SetViewAndProjectionMatrices(CommandBuffer cmd, Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, bool setInverseMatrices)
  110. {
  111. Matrix4x4 viewAndProjectionMatrix = projectionMatrix * viewMatrix;
  112. cmd.SetGlobalMatrix(ShaderPropertyId.viewMatrix, viewMatrix);
  113. cmd.SetGlobalMatrix(ShaderPropertyId.projectionMatrix, projectionMatrix);
  114. cmd.SetGlobalMatrix(ShaderPropertyId.viewAndProjectionMatrix, viewAndProjectionMatrix);
  115. if (setInverseMatrices)
  116. {
  117. Matrix4x4 inverseViewMatrix = Matrix4x4.Inverse(viewMatrix);
  118. Matrix4x4 inverseProjectionMatrix = Matrix4x4.Inverse(projectionMatrix);
  119. Matrix4x4 inverseViewProjection = inverseViewMatrix * inverseProjectionMatrix;
  120. cmd.SetGlobalMatrix(ShaderPropertyId.inverseViewMatrix, inverseViewMatrix);
  121. cmd.SetGlobalMatrix(ShaderPropertyId.inverseProjectionMatrix, inverseProjectionMatrix);
  122. cmd.SetGlobalMatrix(ShaderPropertyId.inverseViewAndProjectionMatrix, inverseViewProjection);
  123. }
  124. }
  125. #if ENABLE_VR && ENABLE_XR_MODULE
  126. internal static readonly int UNITY_STEREO_MATRIX_V = Shader.PropertyToID("unity_StereoMatrixV");
  127. internal static readonly int UNITY_STEREO_MATRIX_IV = Shader.PropertyToID("unity_StereoMatrixInvV");
  128. internal static readonly int UNITY_STEREO_MATRIX_P = Shader.PropertyToID("unity_StereoMatrixP");
  129. internal static readonly int UNITY_STEREO_MATRIX_IP = Shader.PropertyToID("unity_StereoMatrixInvP");
  130. internal static readonly int UNITY_STEREO_MATRIX_VP = Shader.PropertyToID("unity_StereoMatrixVP");
  131. internal static readonly int UNITY_STEREO_MATRIX_PREV_VP = Shader.PropertyToID("unity_StereoMatrixPrevVP");
  132. internal static readonly int UNITY_STEREO_MATRIX_IVP = Shader.PropertyToID("unity_StereoMatrixInvVP");
  133. internal static readonly int UNITY_STEREO_CAMERA_PROJECTION = Shader.PropertyToID("unity_StereoCameraProjection");
  134. internal static readonly int UNITY_STEREO_CAMERA_INV_PROJECTION = Shader.PropertyToID("unity_StereoCameraInvProjection");
  135. internal static readonly int UNITY_STEREO_VECTOR_CAMPOS = Shader.PropertyToID("unity_StereoWorldSpaceCameraPos");
  136. // Hold the stereo matrices in this class to avoid allocating arrays every frame
  137. internal class StereoConstants
  138. {
  139. public Matrix4x4[] viewProjMatrix = new Matrix4x4[2];
  140. public Matrix4x4[] mvViewProjMatrix = new Matrix4x4[2];
  141. public Matrix4x4[] prevMVViewProjMatrix = new Matrix4x4[2];
  142. public Matrix4x4[] invViewMatrix = new Matrix4x4[2];
  143. public Matrix4x4[] invProjMatrix = new Matrix4x4[2];
  144. public Matrix4x4[] invViewProjMatrix = new Matrix4x4[2];
  145. public Matrix4x4[] invCameraProjMatrix = new Matrix4x4[2];
  146. public Vector4[] worldSpaceCameraPos = new Vector4[2];
  147. };
  148. static readonly StereoConstants stereoConstants = new StereoConstants();
  149. /// <summary>
  150. /// Helper function to set all view and projection related matrices
  151. /// Should be called before draw call and after cmd.SetRenderTarget
  152. /// Internal usage only, function name and signature may be subject to change
  153. /// </summary>
  154. /// <param name="cmd">CommandBuffer to submit data to GPU.</param>
  155. /// <param name="viewMatrix">View matrix to be set. Array size is 2.</param>
  156. /// <param name="projectionMatrix">Projection matrix to be set.Array size is 2.</param>
  157. /// <param name="cameraProjectionMatrix">Camera projection matrix to be set.Array size is 2. Does not include platform specific transformations such as depth-reverse, depth range in post-projective space and y-flip. </param>
  158. /// <param name="setInverseMatrices">Set this to true if you also need to set inverse camera matrices.</param>
  159. /// <returns>Void</c></returns>
  160. internal static void SetStereoViewAndProjectionMatrices(CommandBuffer cmd, Matrix4x4[] viewMatrix, Matrix4x4[] projMatrix, Matrix4x4[] cameraProjMatrix, bool setInverseMatrices, bool prevViewValid, Matrix4x4[] prevViewMatrix, bool isOculusMotionVec = false)
  161. {
  162. if (isOculusMotionVec)
  163. stereoConstants.mvViewProjMatrix.CopyTo(stereoConstants.prevMVViewProjMatrix, 0);
  164. for (int i = 0; i < 2; i++)
  165. {
  166. stereoConstants.viewProjMatrix[i] = projMatrix[i] * viewMatrix[i];
  167. if (prevViewValid)
  168. stereoConstants.prevMVViewProjMatrix[i] = projMatrix[i] * prevViewMatrix[i];
  169. if (isOculusMotionVec)
  170. stereoConstants.mvViewProjMatrix[i] = projMatrix[i] * viewMatrix[i];
  171. stereoConstants.invViewMatrix[i] = Matrix4x4.Inverse(viewMatrix[i]);
  172. stereoConstants.invProjMatrix[i] = Matrix4x4.Inverse(projMatrix[i]);
  173. stereoConstants.invViewProjMatrix[i] = Matrix4x4.Inverse(stereoConstants.viewProjMatrix[i]);
  174. stereoConstants.invCameraProjMatrix[i] = Matrix4x4.Inverse(cameraProjMatrix[i]);
  175. stereoConstants.worldSpaceCameraPos[i] = stereoConstants.invViewMatrix[i].GetColumn(3);
  176. }
  177. cmd.SetGlobalMatrixArray(UNITY_STEREO_MATRIX_V, viewMatrix);
  178. cmd.SetGlobalMatrixArray(UNITY_STEREO_MATRIX_P, projMatrix);
  179. cmd.SetGlobalMatrixArray(UNITY_STEREO_MATRIX_VP, stereoConstants.viewProjMatrix);
  180. if (isOculusMotionVec)
  181. cmd.SetGlobalMatrixArray(UNITY_STEREO_MATRIX_PREV_VP, stereoConstants.prevMVViewProjMatrix);
  182. cmd.SetGlobalMatrixArray(UNITY_STEREO_CAMERA_PROJECTION, cameraProjMatrix);
  183. if (setInverseMatrices)
  184. {
  185. cmd.SetGlobalMatrixArray(UNITY_STEREO_MATRIX_IV, stereoConstants.invViewMatrix);
  186. cmd.SetGlobalMatrixArray(UNITY_STEREO_MATRIX_IP, stereoConstants.invProjMatrix);
  187. cmd.SetGlobalMatrixArray(UNITY_STEREO_MATRIX_IVP, stereoConstants.invViewProjMatrix);
  188. cmd.SetGlobalMatrixArray(UNITY_STEREO_CAMERA_INV_PROJECTION, stereoConstants.invCameraProjMatrix);
  189. }
  190. cmd.SetGlobalVectorArray(UNITY_STEREO_VECTOR_CAMPOS, stereoConstants.worldSpaceCameraPos);
  191. }
  192. #endif
  193. internal static void Blit(CommandBuffer cmd,
  194. RenderTargetIdentifier source,
  195. RenderTargetIdentifier destination,
  196. Material material,
  197. int passIndex = 0,
  198. bool useDrawProcedural = false,
  199. RenderBufferLoadAction colorLoadAction = RenderBufferLoadAction.Load,
  200. RenderBufferStoreAction colorStoreAction = RenderBufferStoreAction.Store,
  201. RenderBufferLoadAction depthLoadAction = RenderBufferLoadAction.Load,
  202. RenderBufferStoreAction depthStoreAction = RenderBufferStoreAction.Store)
  203. {
  204. cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, source);
  205. if (useDrawProcedural)
  206. {
  207. Vector4 scaleBias = new Vector4(1, 1, 0, 0);
  208. Vector4 scaleBiasRt = new Vector4(1, 1, 0, 0);
  209. cmd.SetGlobalVector(ShaderPropertyId.scaleBias, scaleBias);
  210. cmd.SetGlobalVector(ShaderPropertyId.scaleBiasRt, scaleBiasRt);
  211. cmd.SetRenderTarget(new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1),
  212. colorLoadAction, colorStoreAction, depthLoadAction, depthStoreAction);
  213. cmd.DrawProcedural(Matrix4x4.identity, material, passIndex, MeshTopology.Quads, 4, 1, null);
  214. }
  215. else
  216. {
  217. cmd.SetRenderTarget(destination, colorLoadAction, colorStoreAction, depthLoadAction, depthStoreAction);
  218. cmd.Blit(source, BuiltinRenderTextureType.CurrentActive, material, passIndex);
  219. }
  220. }
  221. // This is used to render materials that contain built-in shader passes not compatible with URP.
  222. // It will render those legacy passes with error/pink shader.
  223. [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
  224. internal static void RenderObjectsWithError(ScriptableRenderContext context, ref CullingResults cullResults, Camera camera, FilteringSettings filterSettings, SortingCriteria sortFlags)
  225. {
  226. // TODO: When importing project, AssetPreviewUpdater::CreatePreviewForAsset will be called multiple times.
  227. // This might be in a point that some resources required for the pipeline are not finished importing yet.
  228. // Proper fix is to add a fence on asset import.
  229. if (errorMaterial == null)
  230. return;
  231. SortingSettings sortingSettings = new SortingSettings(camera) { criteria = sortFlags };
  232. DrawingSettings errorSettings = new DrawingSettings(m_LegacyShaderPassNames[0], sortingSettings)
  233. {
  234. perObjectData = PerObjectData.None,
  235. overrideMaterial = errorMaterial,
  236. overrideMaterialPassIndex = 0
  237. };
  238. for (int i = 1; i < m_LegacyShaderPassNames.Count; ++i)
  239. errorSettings.SetShaderPassName(i, m_LegacyShaderPassNames[i]);
  240. context.DrawRenderers(cullResults, ref errorSettings, ref filterSettings);
  241. }
  242. // Caches render texture format support. SystemInfo.SupportsRenderTextureFormat and IsFormatSupported allocate memory due to boxing.
  243. static Dictionary<RenderTextureFormat, bool> m_RenderTextureFormatSupport = new Dictionary<RenderTextureFormat, bool>();
  244. static Dictionary<GraphicsFormat, Dictionary<FormatUsage, bool>> m_GraphicsFormatSupport = new Dictionary<GraphicsFormat, Dictionary<FormatUsage, bool>>();
  245. internal static void ClearSystemInfoCache()
  246. {
  247. m_RenderTextureFormatSupport.Clear();
  248. m_GraphicsFormatSupport.Clear();
  249. }
  250. /// <summary>
  251. /// Checks if a render texture format is supported by the run-time system.
  252. /// Similar to <see cref="SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat)"/>, but doesn't allocate memory.
  253. /// </summary>
  254. /// <param name="format">The format to look up.</param>
  255. /// <returns>Returns true if the graphics card supports the given <c>RenderTextureFormat</c></returns>
  256. public static bool SupportsRenderTextureFormat(RenderTextureFormat format)
  257. {
  258. if (!m_RenderTextureFormatSupport.TryGetValue(format, out var support))
  259. {
  260. support = SystemInfo.SupportsRenderTextureFormat(format);
  261. m_RenderTextureFormatSupport.Add(format, support);
  262. }
  263. return support;
  264. }
  265. /// <summary>
  266. /// Checks if a texture format is supported by the run-time system.
  267. /// Similar to <see cref="SystemInfo.IsFormatSupported"/>, but doesn't allocate memory.
  268. /// </summary>
  269. /// <param name="format">The format to look up.</param>
  270. /// <param name="usage">The format usage to look up.</param>
  271. /// <returns>Returns true if the graphics card supports the given <c>GraphicsFormat</c></returns>
  272. public static bool SupportsGraphicsFormat(GraphicsFormat format, FormatUsage usage)
  273. {
  274. bool support = false;
  275. if (!m_GraphicsFormatSupport.TryGetValue(format, out var uses))
  276. {
  277. uses = new Dictionary<FormatUsage, bool>();
  278. support = SystemInfo.IsFormatSupported(format, usage);
  279. uses.Add(usage, support);
  280. m_GraphicsFormatSupport.Add(format, uses);
  281. }
  282. else
  283. {
  284. if (!uses.TryGetValue(usage, out support))
  285. {
  286. support = SystemInfo.IsFormatSupported(format, usage);
  287. uses.Add(usage, support);
  288. }
  289. }
  290. return support;
  291. }
  292. /// <summary>
  293. /// Return the last colorBuffer index actually referring to an existing RenderTarget
  294. /// </summary>
  295. /// <param name="colorBuffers"></param>
  296. /// <returns></returns>
  297. internal static int GetLastValidColorBufferIndex(RenderTargetIdentifier[] colorBuffers)
  298. {
  299. int i = colorBuffers.Length - 1;
  300. for (; i >= 0; --i)
  301. {
  302. if (colorBuffers[i] != 0)
  303. break;
  304. }
  305. return i;
  306. }
  307. /// <summary>
  308. /// Return the number of items in colorBuffers actually referring to an existing RenderTarget
  309. /// </summary>
  310. /// <param name="colorBuffers"></param>
  311. /// <returns></returns>
  312. internal static uint GetValidColorBufferCount(RenderTargetIdentifier[] colorBuffers)
  313. {
  314. uint nonNullColorBuffers = 0;
  315. if (colorBuffers != null)
  316. {
  317. foreach (var identifier in colorBuffers)
  318. {
  319. if (identifier != 0)
  320. ++nonNullColorBuffers;
  321. }
  322. }
  323. return nonNullColorBuffers;
  324. }
  325. /// <summary>
  326. /// Return true if colorBuffers is an actual MRT setup
  327. /// </summary>
  328. /// <param name="colorBuffers"></param>
  329. /// <returns></returns>
  330. internal static bool IsMRT(RenderTargetIdentifier[] colorBuffers)
  331. {
  332. return GetValidColorBufferCount(colorBuffers) > 1;
  333. }
  334. /// <summary>
  335. /// Return true if value can be found in source (without recurring to Linq)
  336. /// </summary>
  337. /// <param name="source"></param>
  338. /// <param name="value"></param>
  339. /// <returns></returns>
  340. internal static bool Contains(RenderTargetIdentifier[] source, RenderTargetIdentifier value)
  341. {
  342. foreach (var identifier in source)
  343. {
  344. if (identifier == value)
  345. return true;
  346. }
  347. return false;
  348. }
  349. /// <summary>
  350. /// Return the index where value was found source. Otherwise, return -1. (without recurring to Linq)
  351. /// </summary>
  352. /// <param name="source"></param>
  353. /// <param name="value"></param>
  354. /// <returns></returns>
  355. internal static int IndexOf(RenderTargetIdentifier[] source, RenderTargetIdentifier value)
  356. {
  357. for (int i = 0; i < source.Length; ++i)
  358. {
  359. if (source[i] == value)
  360. return i;
  361. }
  362. return -1;
  363. }
  364. /// <summary>
  365. /// Return the number of RenderTargetIdentifiers in "source" that are valid (not 0) and different from "value" (without recurring to Linq)
  366. /// </summary>
  367. /// <param name="source"></param>
  368. /// <param name="value"></param>
  369. /// <returns></returns>
  370. internal static uint CountDistinct(RenderTargetIdentifier[] source, RenderTargetIdentifier value)
  371. {
  372. uint count = 0;
  373. for (int i = 0; i < source.Length; ++i)
  374. {
  375. if (source[i] != value && source[i] != 0)
  376. ++count;
  377. }
  378. return count;
  379. }
  380. /// <summary>
  381. /// Return the index of last valid (i.e different from 0) RenderTargetIdentifiers in "source" (without recurring to Linq)
  382. /// </summary>
  383. /// <param name="source"></param>
  384. /// <returns></returns>
  385. internal static int LastValid(RenderTargetIdentifier[] source)
  386. {
  387. for (int i = source.Length - 1; i >= 0; --i)
  388. {
  389. if (source[i] != 0)
  390. return i;
  391. }
  392. return -1;
  393. }
  394. /// <summary>
  395. /// Return true if ClearFlag a contains ClearFlag b
  396. /// </summary>
  397. /// <param name="a"></param>
  398. /// <param name="b"></param>
  399. /// <returns></returns>
  400. internal static bool Contains(ClearFlag a, ClearFlag b)
  401. {
  402. return (a & b) == b;
  403. }
  404. /// <summary>
  405. /// Return true if "left" and "right" are the same (without recurring to Linq)
  406. /// </summary>
  407. /// <param name="left"></param>
  408. /// <param name="right"></param>
  409. /// <returns></returns>
  410. internal static bool SequenceEqual(RenderTargetIdentifier[] left, RenderTargetIdentifier[] right)
  411. {
  412. if (left.Length != right.Length)
  413. return false;
  414. for (int i = 0; i < left.Length; ++i)
  415. if (left[i] != right[i])
  416. return false;
  417. return true;
  418. }
  419. }
  420. }