Brak opisu
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.

TextureXR.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. using UnityEngine.Experimental.Rendering;
  2. namespace UnityEngine.Rendering
  3. {
  4. /// <summary>
  5. /// Utility class providing default textures compatible in any XR setup.
  6. /// </summary>
  7. public static class TextureXR
  8. {
  9. // Property set by XRSystem
  10. private static int m_MaxViews = 1;
  11. /// <summary>
  12. /// Maximum number of views handled by the XR system.
  13. /// </summary>
  14. public static int maxViews
  15. {
  16. set
  17. {
  18. m_MaxViews = value;
  19. }
  20. }
  21. // Property accessed when allocating a render target
  22. /// <summary>
  23. /// Number of slices used by the XR system.
  24. /// </summary>
  25. public static int slices { get => m_MaxViews; }
  26. // Must be in sync with shader define in TextureXR.hlsl
  27. /// <summary>
  28. /// Returns true if the XR system uses texture arrays.
  29. /// </summary>
  30. public static bool useTexArray
  31. {
  32. get
  33. {
  34. switch (SystemInfo.graphicsDeviceType)
  35. {
  36. case GraphicsDeviceType.Direct3D11:
  37. case GraphicsDeviceType.Direct3D12:
  38. case GraphicsDeviceType.PlayStation4:
  39. case GraphicsDeviceType.PlayStation5:
  40. case GraphicsDeviceType.PlayStation5NGGC:
  41. case GraphicsDeviceType.Vulkan:
  42. case GraphicsDeviceType.Metal:
  43. return true;
  44. default:
  45. return false;
  46. }
  47. }
  48. }
  49. /// <summary>
  50. /// Dimension of XR textures.
  51. /// </summary>
  52. public static TextureDimension dimension
  53. {
  54. get
  55. {
  56. // TEXTURE2D_X macros will now expand to TEXTURE2D or TEXTURE2D_ARRAY
  57. return useTexArray ? TextureDimension.Tex2DArray : TextureDimension.Tex2D;
  58. }
  59. }
  60. // Need to keep both the Texture and the RTHandle in order to be able to track lifetime properly.
  61. static Texture m_BlackUIntTexture2DArray;
  62. static Texture m_BlackUIntTexture;
  63. static RTHandle m_BlackUIntTexture2DArrayRTH;
  64. static RTHandle m_BlackUIntTextureRTH;
  65. /// <summary>
  66. /// Default black unsigned integer texture.
  67. /// </summary>
  68. /// <returns>The default black unsigned integer texture.</returns>
  69. public static RTHandle GetBlackUIntTexture() { return useTexArray ? m_BlackUIntTexture2DArrayRTH : m_BlackUIntTextureRTH; }
  70. static Texture2DArray m_ClearTexture2DArray;
  71. static Texture2D m_ClearTexture;
  72. static RTHandle m_ClearTexture2DArrayRTH;
  73. static RTHandle m_ClearTextureRTH;
  74. /// <summary>
  75. /// Default clear color (0, 0, 0, 1) texture.
  76. /// </summary>
  77. /// <returns>The default clear color texture.</returns>
  78. public static RTHandle GetClearTexture() { return useTexArray ? m_ClearTexture2DArrayRTH : m_ClearTextureRTH; }
  79. static Texture2DArray m_MagentaTexture2DArray;
  80. static Texture2D m_MagentaTexture;
  81. static RTHandle m_MagentaTexture2DArrayRTH;
  82. static RTHandle m_MagentaTextureRTH;
  83. /// <summary>
  84. /// Default magenta texture.
  85. /// </summary>
  86. /// <returns>The default magenta texture.</returns>
  87. public static RTHandle GetMagentaTexture() { return useTexArray ? m_MagentaTexture2DArrayRTH : m_MagentaTextureRTH; }
  88. static Texture2D m_BlackTexture;
  89. static Texture3D m_BlackTexture3D;
  90. static Texture2DArray m_BlackTexture2DArray;
  91. static RTHandle m_BlackTexture2DArrayRTH;
  92. static RTHandle m_BlackTextureRTH;
  93. static RTHandle m_BlackTexture3DRTH;
  94. /// <summary>
  95. /// Default black texture.
  96. /// </summary>
  97. /// <returns>The default black texture.</returns>
  98. public static RTHandle GetBlackTexture() { return useTexArray ? m_BlackTexture2DArrayRTH : m_BlackTextureRTH; }
  99. /// <summary>
  100. /// Default black texture array.
  101. /// </summary>
  102. /// <returns>The default black texture array.</returns>
  103. public static RTHandle GetBlackTextureArray() { return m_BlackTexture2DArrayRTH; }
  104. /// <summary>
  105. /// Default black texture 3D.
  106. /// </summary>
  107. /// <returns>The default black texture 3D.</returns>
  108. public static RTHandle GetBlackTexture3D() { return m_BlackTexture3DRTH; }
  109. static Texture2DArray m_WhiteTexture2DArray;
  110. static RTHandle m_WhiteTexture2DArrayRTH;
  111. static RTHandle m_WhiteTextureRTH;
  112. /// <summary>
  113. /// Default white texture.
  114. /// </summary>
  115. /// <returns>The default white texture.</returns>
  116. public static RTHandle GetWhiteTexture() { return useTexArray ? m_WhiteTexture2DArrayRTH : m_WhiteTextureRTH; }
  117. /// <summary>
  118. /// Initialize XR textures. Must be called at least once.
  119. /// </summary>
  120. /// <param name="cmd">Command Buffer used to initialize textures.</param>
  121. /// <param name="clearR32_UIntShader">Compute shader used to intitialize unsigned integer textures.</param>
  122. public static void Initialize(CommandBuffer cmd, ComputeShader clearR32_UIntShader)
  123. {
  124. if (m_BlackUIntTexture2DArray == null) // We assume that everything is invalid if one is invalid.
  125. {
  126. // Black UINT
  127. RTHandles.Release(m_BlackUIntTexture2DArrayRTH);
  128. m_BlackUIntTexture2DArray = CreateBlackUIntTextureArray(cmd, clearR32_UIntShader);
  129. m_BlackUIntTexture2DArrayRTH = RTHandles.Alloc(m_BlackUIntTexture2DArray);
  130. RTHandles.Release(m_BlackUIntTextureRTH);
  131. m_BlackUIntTexture = CreateBlackUintTexture(cmd, clearR32_UIntShader);
  132. m_BlackUIntTextureRTH = RTHandles.Alloc(m_BlackUIntTexture);
  133. // Clear
  134. RTHandles.Release(m_ClearTextureRTH);
  135. m_ClearTexture = new Texture2D(1, 1, GraphicsFormat.R8G8B8A8_SRGB, TextureCreationFlags.None) { name = "Clear Texture" };
  136. m_ClearTexture.SetPixel(0, 0, Color.clear);
  137. m_ClearTexture.Apply();
  138. m_ClearTextureRTH = RTHandles.Alloc(m_ClearTexture);
  139. RTHandles.Release(m_ClearTexture2DArrayRTH);
  140. m_ClearTexture2DArray = CreateTexture2DArrayFromTexture2D(m_ClearTexture, "Clear Texture2DArray");
  141. m_ClearTexture2DArrayRTH = RTHandles.Alloc(m_ClearTexture2DArray);
  142. // Magenta
  143. RTHandles.Release(m_MagentaTextureRTH);
  144. m_MagentaTexture = new Texture2D(1, 1, GraphicsFormat.R8G8B8A8_SRGB, TextureCreationFlags.None) { name = "Magenta Texture" };
  145. m_MagentaTexture.SetPixel(0, 0, Color.magenta);
  146. m_MagentaTexture.Apply();
  147. m_MagentaTextureRTH = RTHandles.Alloc(m_MagentaTexture);
  148. RTHandles.Release(m_MagentaTexture2DArrayRTH);
  149. m_MagentaTexture2DArray = CreateTexture2DArrayFromTexture2D(m_MagentaTexture, "Magenta Texture2DArray");
  150. m_MagentaTexture2DArrayRTH = RTHandles.Alloc(m_MagentaTexture2DArray);
  151. // Black
  152. RTHandles.Release(m_BlackTextureRTH);
  153. m_BlackTexture = new Texture2D(1, 1, GraphicsFormat.R8G8B8A8_SRGB, TextureCreationFlags.None) { name = "Black Texture" };
  154. m_BlackTexture.SetPixel(0, 0, Color.black);
  155. m_BlackTexture.Apply();
  156. m_BlackTextureRTH = RTHandles.Alloc(m_BlackTexture);
  157. RTHandles.Release(m_BlackTexture2DArrayRTH);
  158. m_BlackTexture2DArray = CreateTexture2DArrayFromTexture2D(m_BlackTexture, "Black Texture2DArray");
  159. m_BlackTexture2DArrayRTH = RTHandles.Alloc(m_BlackTexture2DArray);
  160. RTHandles.Release(m_BlackTexture3DRTH);
  161. m_BlackTexture3D = CreateBlackTexture3D("Black Texture3D");
  162. m_BlackTexture3DRTH = RTHandles.Alloc(m_BlackTexture3D);
  163. // White
  164. RTHandles.Release(m_WhiteTextureRTH);
  165. m_WhiteTextureRTH = RTHandles.Alloc(Texture2D.whiteTexture);
  166. RTHandles.Release(m_WhiteTexture2DArrayRTH);
  167. m_WhiteTexture2DArray = CreateTexture2DArrayFromTexture2D(Texture2D.whiteTexture, "White Texture2DArray");
  168. m_WhiteTexture2DArrayRTH = RTHandles.Alloc(m_WhiteTexture2DArray);
  169. }
  170. }
  171. static Texture2DArray CreateTexture2DArrayFromTexture2D(Texture2D source, string name)
  172. {
  173. Texture2DArray texArray = new Texture2DArray(source.width, source.height, slices, source.format, false) { name = name };
  174. for (int i = 0; i < slices; ++i)
  175. Graphics.CopyTexture(source, 0, 0, texArray, i, 0);
  176. return texArray;
  177. }
  178. static Texture CreateBlackUIntTextureArray(CommandBuffer cmd, ComputeShader clearR32_UIntShader)
  179. {
  180. RenderTexture blackUIntTexture2DArray = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt)
  181. {
  182. dimension = TextureDimension.Tex2DArray,
  183. volumeDepth = slices,
  184. useMipMap = false,
  185. autoGenerateMips = false,
  186. enableRandomWrite = true,
  187. name = "Black UInt Texture Array"
  188. };
  189. blackUIntTexture2DArray.Create();
  190. // Workaround because we currently can't create a Texture2DArray using an R32_UInt format
  191. // So we create a R32_UInt RenderTarget and clear it using a compute shader, because we can't
  192. // Clear this type of target on metal devices (output type nor compatible: float4 vs uint)
  193. int kernel = clearR32_UIntShader.FindKernel("ClearUIntTextureArray");
  194. cmd.SetComputeTextureParam(clearR32_UIntShader, kernel, "_TargetArray", blackUIntTexture2DArray);
  195. cmd.DispatchCompute(clearR32_UIntShader, kernel, 1, 1, slices);
  196. return blackUIntTexture2DArray as Texture;
  197. }
  198. static Texture CreateBlackUintTexture(CommandBuffer cmd, ComputeShader clearR32_UIntShader)
  199. {
  200. RenderTexture blackUIntTexture2D = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt)
  201. {
  202. dimension = TextureDimension.Tex2D,
  203. volumeDepth = 1,
  204. useMipMap = false,
  205. autoGenerateMips = false,
  206. enableRandomWrite = true,
  207. name = "Black UInt Texture"
  208. };
  209. blackUIntTexture2D.Create();
  210. // Workaround because we currently can't create a Texture2D using an R32_UInt format
  211. // So we create a R32_UInt RenderTarget and clear it using a compute shader, because we can't
  212. // Clear this type of target on metal devices (output type nor compatible: float4 vs uint)
  213. int kernel = clearR32_UIntShader.FindKernel("ClearUIntTexture");
  214. cmd.SetComputeTextureParam(clearR32_UIntShader, kernel, "_Target", blackUIntTexture2D);
  215. cmd.DispatchCompute(clearR32_UIntShader, kernel, 1, 1, 1);
  216. return blackUIntTexture2D as Texture;
  217. }
  218. static Texture3D CreateBlackTexture3D(string name)
  219. {
  220. Texture3D texture3D = new Texture3D(width: 1, height: 1, depth: 1, GraphicsFormat.R8G8B8A8_SRGB, TextureCreationFlags.None);
  221. texture3D.name = name;
  222. texture3D.SetPixel(0, 0, 0, Color.black, 0);
  223. texture3D.Apply(updateMipmaps: false);
  224. return texture3D;
  225. }
  226. }
  227. }