SW 중심대학 OSS GIT 서버 박건태, 이승준, 고기완, 이준호 새로운 배포
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.

446 lines
18 KiB

4 years ago
  1. using AOT;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Runtime.InteropServices;
  5. using UnityEngine.Rendering;
  6. using UnityEngine.Serialization;
  7. namespace UnityEngine.XR.ARFoundation
  8. {
  9. /// <summary>
  10. /// <para>Add this component to a <c>Camera</c> to copy the color camera's texture onto the background.</para>
  11. /// <para>If you are using the Lightweight Render Pipeline (version 5.7.2 or later) or the Univerisal Render
  12. /// Pipeline (version 7.0.0 or later), you must also add the <see cref="ARBackgroundRendererFeature"/> to the list
  13. /// of render features for the scriptable renderer.</para>
  14. /// </summary>
  15. /// <remarks>
  16. /// <para>
  17. /// To add the <see cref="ARBackgroundRendererFeature"/> to the list of render features for the scriptable
  18. /// renderer:
  19. /// <list type="bullet">
  20. /// <item><description>In Project Settings -> Graphics, select the render pipeline asset (either
  21. /// <c>LightweightRenderPipelineAsset</c> or <c>UniversalRenderPipelineAsset</c>) that is in the Scriptable Render
  22. /// Pipeline Settings field.</description></item>
  23. /// <item><description>In the Inspector with the render pipeline asset selected, ensure that the Render Type is set
  24. /// to Custom.</description></item>
  25. /// <item><description>In the Inspector with the render pipeline asset selected, select the Render Type -> Data
  26. /// asset which would be of type <c>ForwardRendererData</c>.</description></item>
  27. /// <item><description>In the Inspector with the forward renderer data selected, ensure the Render Features list
  28. /// contains a <see cref="ARBackgroundRendererFeature"/>.</description></item>
  29. /// </list>
  30. /// </para>
  31. /// <para>To customize background rendering with the legacy render pipeline, you may override the
  32. /// <see cref="legacyCameraEvents"/> property and the
  33. /// <see cref="ConfigureLegacyCommandBuffer(CommandBuffer)"/> method to modify the given
  34. /// <c>CommandBuffer</c> with rendering commands and to inject the given <c>CommandBuffer</c> into the camera's
  35. /// rendering.</para>
  36. /// <para>To customize background rendering with a scriptable render pipeline, create a
  37. /// <c>ScriptableRendererFeature</c> with the background rendering commands, and insert the
  38. /// <c>ScriptableRendererFeature</c> into the list of render features for the scriptable renderer.</para>
  39. /// </remarks>
  40. [DisallowMultipleComponent]
  41. [RequireComponent(typeof(Camera))]
  42. [RequireComponent(typeof(ARCameraManager))]
  43. [HelpURL("https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@3.0/api/UnityEngine.XR.ARFoundation.ARCameraBackground.html")]
  44. public class ARCameraBackground : MonoBehaviour
  45. {
  46. /// <summary>
  47. /// Name for the custom rendering command buffer.
  48. /// </summary>
  49. const string k_CustomRenderPassName = "AR Background Pass (LegacyRP)";
  50. /// <summary>
  51. /// Name of the main texture parameter for the material
  52. /// </summary>
  53. internal const string k_MainTexName = "_MainTex";
  54. /// <summary>
  55. /// Name of the shader parameter for the display transform matrix.
  56. /// </summary>
  57. const string k_DisplayTransformName = "_UnityDisplayTransform";
  58. /// <summary>
  59. /// Property ID for the shader parameter for the display transform matrix.
  60. /// </summary>
  61. static readonly int k_DisplayTransformId = Shader.PropertyToID(k_DisplayTransformName);
  62. /// <summary>
  63. /// The camera to which the projection matrix is set on each frame event.
  64. /// </summary>
  65. Camera m_Camera;
  66. /// <summary>
  67. /// The camera manager from which frame information is pulled.
  68. /// </summary>
  69. ARCameraManager m_CameraManager;
  70. /// <summary>
  71. /// Command buffer for any custom rendering commands.
  72. /// </summary>
  73. CommandBuffer m_CommandBuffer;
  74. /// <summary>
  75. /// Whether to use the custom material for rendering the background.
  76. /// </summary>
  77. [SerializeField, FormerlySerializedAs("m_OverrideMaterial")]
  78. bool m_UseCustomMaterial;
  79. /// <summary>
  80. /// A custom material for rendering the background.
  81. /// </summary>
  82. [SerializeField, FormerlySerializedAs("m_Material")]
  83. Material m_CustomMaterial;
  84. /// <summary>
  85. /// The default material for rendering the background.
  86. /// </summary>
  87. Material m_DefaultMaterial;
  88. /// <summary>
  89. /// The previous clear flags for the camera, if any.
  90. /// </summary>
  91. CameraClearFlags? m_PreviousCameraClearFlags;
  92. /// <summary>
  93. /// Whether background rendering is enabled.
  94. /// </summary>
  95. bool m_BackgroundRenderingEnabled;
  96. /// <summary>
  97. /// The camera to which the projection matrix is set on each frame event.
  98. /// </summary>
  99. /// <value>
  100. /// The camera to which the projection matrix is set on each frame event.
  101. /// </value>
  102. #if UNITY_EDITOR
  103. protected new Camera camera => m_Camera;
  104. #else // UNITY_EDITOR
  105. protected Camera camera => m_Camera;
  106. #endif // UNITY_EDITOR
  107. /// <summary>
  108. /// The camera manager from which frame information is pulled.
  109. /// </summary>
  110. /// <value>
  111. /// The camera manager from which frame information is pulled.
  112. /// </value>
  113. protected ARCameraManager cameraManager => m_CameraManager;
  114. /// <summary>
  115. /// The current <c>Material</c> used for background rendering.
  116. /// </summary>
  117. public Material material
  118. {
  119. get { return (useCustomMaterial && (customMaterial != null)) ? customMaterial : defaultMaterial; }
  120. }
  121. /// <summary>
  122. /// Whether to use the custom material for rendering the background.
  123. /// </summary>
  124. /// <value>
  125. /// <c>true</c> if the custom material should be used for rendering the camera background. Otherwise,
  126. /// <c>false</c>.
  127. /// </value>
  128. public bool useCustomMaterial { get => m_UseCustomMaterial; set => m_UseCustomMaterial = value; }
  129. /// <summary>
  130. /// A custom material for rendering the background.
  131. /// </summary>
  132. /// <value>
  133. /// A custom material for rendering the background.
  134. /// </value>
  135. public Material customMaterial { get => m_CustomMaterial; set => m_CustomMaterial = value; }
  136. /// <summary>
  137. /// Whether background rendering is enabled.
  138. /// </summary>
  139. /// <value>
  140. /// <c>true</c> if background rendering is enabled and if at least one camera frame has been received.
  141. /// Otherwise, <c>false</c>.
  142. /// </value>
  143. public bool backgroundRenderingEnabled => m_BackgroundRenderingEnabled;
  144. /// <summary>
  145. /// The default material for rendering the background.
  146. /// </summary>
  147. /// <value>
  148. /// The default material for rendering the background.
  149. /// </value>
  150. Material defaultMaterial => cameraManager.cameraMaterial;
  151. /// <summary>
  152. /// Whether to use the legacy rendering pipeline.
  153. /// </summary>
  154. /// <value>
  155. /// <c>true</c> fi the legacy render pipeline is in use. Otherwise, <c>false</c>.
  156. /// </value>
  157. bool useLegacyRenderPipeline => GraphicsSettings.renderPipelineAsset == null;
  158. /// <summary>
  159. /// Stores the previous culling state (XRCameraSubsystem.invertCulling).
  160. /// If the requested culling state changes, the command buffer must be rebuilt.
  161. /// </summary>
  162. bool m_CommandBufferCullingState;
  163. /// <summary>
  164. /// A function that can be invoked by
  165. /// [CommandBuffer.IssuePluginEvent](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.IssuePluginEvent.html).
  166. /// This function does nothing, but Unity requires a valid function pointer in order to add IssuePluginEvent to a command
  167. /// buffer. Doing so has the side effect of resetting the OpenGL state.
  168. /// </summary>
  169. /// <param name="eventId">The id of the event</param>
  170. /// <seealso cref="AddOpenGLES3ResetStateCommand(CommandBuffer)"/>
  171. [MonoPInvokeCallback(typeof(Action<int>))]
  172. static void ResetGlState(int eventId) {}
  173. /// <summary>
  174. /// A delegate representation of <see cref="ResetGlState(int)"/>. This maintains a strong
  175. /// reference to the delegate, which is converted to an IntPtr by <see cref="s_ResetGlStateFuncPtr"/>.
  176. /// </summary>
  177. /// <seealso cref="AddOpenGLES3ResetStateCommand(CommandBuffer)"/>
  178. static Action<int> s_ResetGlStateDelegate = ResetGlState;
  179. /// <summary>
  180. /// A pointer to <see cref="ResetGlState(int)"/> that can be passed to
  181. /// [CommandBuffer.IssuePluginEvent](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.IssuePluginEvent.html).
  182. /// </summary>
  183. /// <seealso cref="AddOpenGLES3ResetStateCommand(CommandBuffer)"/>
  184. static readonly IntPtr s_ResetGlStateFuncPtr = Marshal.GetFunctionPointerForDelegate(s_ResetGlStateDelegate);
  185. /// <summary>
  186. /// Whether culling should be inverted. Used during command buffer configuration,
  187. /// see [CommandBuffer.SetInvertCulling](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetInvertCulling.html).
  188. /// </summary>
  189. /// <seealso cref="ConfigureLegacyCommandBuffer(CommandBuffer)"/>
  190. protected bool shouldInvertCulling => m_CameraManager?.subsystem?.invertCulling ?? false;
  191. void Awake()
  192. {
  193. m_Camera = GetComponent<Camera>();
  194. m_CameraManager = GetComponent<ARCameraManager>();
  195. }
  196. void OnEnable()
  197. {
  198. // Ensure that background rendering is disabled until the first camera frame is received.
  199. m_BackgroundRenderingEnabled = false;
  200. cameraManager.frameReceived += OnCameraFrameReceived;
  201. }
  202. void OnDisable()
  203. {
  204. cameraManager.frameReceived -= OnCameraFrameReceived;
  205. DisableBackgroundRendering();
  206. }
  207. /// <summary>
  208. /// Enable background rendering by disabling the camera's clear flags, and enabling the legacy RP background
  209. /// rendering if we are in legacy RP mode.
  210. /// </summary>
  211. void EnableBackgroundRendering()
  212. {
  213. m_BackgroundRenderingEnabled = true;
  214. DisableBackgroundClearFlags();
  215. Material material = defaultMaterial;
  216. if (useLegacyRenderPipeline && (material != null))
  217. {
  218. EnableLegacyRenderPipelineBackgroundRendering();
  219. }
  220. }
  221. /// <summary>
  222. /// Disable background rendering by disabling the legacy RP background rendering if we are in legacy RP mode
  223. /// and restoring the camera's clear flags.
  224. /// </summary>
  225. void DisableBackgroundRendering()
  226. {
  227. m_BackgroundRenderingEnabled = false;
  228. DisableLegacyRenderPipelineBackgroundRendering();
  229. RestoreBackgroundClearFlags();
  230. // We are no longer setting the projection matrix so tell the camera to resume its normal projection matrix
  231. // calculations.
  232. camera.ResetProjectionMatrix();
  233. }
  234. /// <summary>
  235. /// Set the camera's clear flags to do nothing while preserving the previous camera clear flags.
  236. /// </summary>
  237. void DisableBackgroundClearFlags()
  238. {
  239. m_PreviousCameraClearFlags = m_Camera.clearFlags;
  240. m_Camera.clearFlags = CameraClearFlags.Nothing;
  241. }
  242. /// <summary>
  243. /// Restore the previous camera's clear flags, if any.
  244. /// </summary>
  245. void RestoreBackgroundClearFlags()
  246. {
  247. if (m_PreviousCameraClearFlags != null)
  248. {
  249. m_Camera.clearFlags = m_PreviousCameraClearFlags.Value;
  250. }
  251. }
  252. /// <summary>
  253. /// The list of [CameraEvent](https://docs.unity3d.com/ScriptReference/Rendering.CameraEvent.html)s
  254. /// to add to the [CommandBuffer](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.html).
  255. /// </summary>
  256. static readonly CameraEvent[] s_DefaultCameraEvents = new[]
  257. {
  258. CameraEvent.BeforeForwardOpaque,
  259. CameraEvent.BeforeGBuffer
  260. };
  261. /// <summary>
  262. /// The list of [CameraEvent](https://docs.unity3d.com/ScriptReference/Rendering.CameraEvent.html)s
  263. /// to add to the [CommandBuffer](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.html).
  264. /// By default, returns
  265. /// [BeforeForwardOpaque](https://docs.unity3d.com/ScriptReference/Rendering.CameraEvent.BeforeForwardOpaque.html)
  266. /// and
  267. /// [BeforeGBuffer](https://docs.unity3d.com/ScriptReference/Rendering.CameraEvent.BeforeGBuffer.html)}.
  268. /// Override to use different camera events.
  269. /// </summary>
  270. protected virtual IEnumerable<CameraEvent> legacyCameraEvents => s_DefaultCameraEvents;
  271. /// <summary>
  272. /// Configures the <paramref name="commandBuffer"/> by first clearing it,
  273. /// and then adding necessary render commands.
  274. /// </summary>
  275. /// <param name="commandBuffer">The command buffer to configure.</param>
  276. protected virtual void ConfigureLegacyCommandBuffer(CommandBuffer commandBuffer)
  277. {
  278. Texture texture = !material.HasProperty(k_MainTexName) ? null : material.GetTexture(k_MainTexName);
  279. commandBuffer.Clear();
  280. AddOpenGLES3ResetStateCommand(commandBuffer);
  281. m_CommandBufferCullingState = shouldInvertCulling;
  282. commandBuffer.SetInvertCulling(m_CommandBufferCullingState);
  283. commandBuffer.ClearRenderTarget(true, false, Color.clear);
  284. commandBuffer.Blit(texture, BuiltinRenderTextureType.CameraTarget, material);
  285. }
  286. /// <summary>
  287. /// Enable background rendering getting a command buffer, and configure it for rendering the background.
  288. /// </summary>
  289. void EnableLegacyRenderPipelineBackgroundRendering()
  290. {
  291. if (m_CommandBuffer == null)
  292. {
  293. m_CommandBuffer = new CommandBuffer();
  294. m_CommandBuffer.name = k_CustomRenderPassName;
  295. ConfigureLegacyCommandBuffer(m_CommandBuffer);
  296. foreach (var cameraEvent in legacyCameraEvents)
  297. {
  298. camera.AddCommandBuffer(cameraEvent, m_CommandBuffer);
  299. }
  300. }
  301. }
  302. /// <summary>
  303. /// Disable background rendering by removing the command buffer from the camera.
  304. /// </summary>
  305. void DisableLegacyRenderPipelineBackgroundRendering()
  306. {
  307. if (m_CommandBuffer != null)
  308. {
  309. foreach (var cameraEvent in legacyCameraEvents)
  310. {
  311. camera.RemoveCommandBuffer(cameraEvent, m_CommandBuffer);
  312. }
  313. m_CommandBuffer = null;
  314. }
  315. }
  316. /// <summary>
  317. /// When using OpenGLES3, this adds a command to the <paramref name="commandBuffer"/>
  318. /// which will force Unity to reset the OpenGL state. This is necessary on devices using OpenGLES3.
  319. /// If OpenGLES3 is not the current graphics device type, this method does nothing. This should be
  320. /// the first command in the command buffer.
  321. /// </summary>
  322. /// <param name="commandBuffer">The [CommandBuffer](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.html)
  323. /// to add the command to.</param>
  324. internal protected static void AddOpenGLES3ResetStateCommand(CommandBuffer commandBuffer)
  325. {
  326. if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3)
  327. {
  328. commandBuffer.IssuePluginEvent(s_ResetGlStateFuncPtr, 0);
  329. }
  330. }
  331. /// <summary>
  332. /// Callback for the camera frame event.
  333. /// </summary>
  334. /// <param name="eventArgs">The camera event arguments.</param>
  335. void OnCameraFrameReceived(ARCameraFrameEventArgs eventArgs)
  336. {
  337. // Enable background rendering when first frame is received.
  338. if (m_BackgroundRenderingEnabled)
  339. {
  340. if (m_CommandBuffer != null && m_CommandBufferCullingState != shouldInvertCulling)
  341. {
  342. ConfigureLegacyCommandBuffer(m_CommandBuffer);
  343. }
  344. }
  345. else
  346. {
  347. EnableBackgroundRendering();
  348. }
  349. Material material = this.material;
  350. if (material != null)
  351. {
  352. var count = eventArgs.textures.Count;
  353. for (int i = 0; i < count; ++i)
  354. {
  355. material.SetTexture(eventArgs.propertyNameIds[i], eventArgs.textures[i]);
  356. }
  357. if (eventArgs.displayMatrix.HasValue)
  358. {
  359. material.SetMatrix(k_DisplayTransformId, eventArgs.displayMatrix.Value);
  360. }
  361. SetMaterialKeywords(material, eventArgs.enabledMaterialKeywords, eventArgs.disabledMaterialKeywords);
  362. }
  363. if (eventArgs.projectionMatrix.HasValue)
  364. {
  365. camera.projectionMatrix = eventArgs.projectionMatrix.Value;
  366. }
  367. }
  368. void SetMaterialKeywords(Material material, List<string> enabledMaterialKeywords,
  369. List<string> disabledMaterialKeywords)
  370. {
  371. if (enabledMaterialKeywords != null)
  372. {
  373. foreach (var materialKeyword in enabledMaterialKeywords)
  374. {
  375. if (!material.IsKeywordEnabled(materialKeyword))
  376. {
  377. material.EnableKeyword(materialKeyword);
  378. }
  379. }
  380. }
  381. if (disabledMaterialKeywords != null)
  382. {
  383. foreach (var materialKeyword in disabledMaterialKeywords)
  384. {
  385. if (material.IsKeywordEnabled(materialKeyword))
  386. {
  387. material.DisableKeyword(materialKeyword);
  388. }
  389. }
  390. }
  391. }
  392. }
  393. }