PostProcessPass.cs 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198
  1. using System.Runtime.CompilerServices;
  2. using UnityEngine.Experimental.Rendering;
  3. namespace UnityEngine.Rendering.Universal
  4. {
  5. // TODO: xmldoc
  6. public interface IPostProcessComponent
  7. {
  8. bool IsActive();
  9. bool IsTileCompatible();
  10. }
  11. }
  12. namespace UnityEngine.Rendering.Universal.Internal
  13. {
  14. // TODO: TAA
  15. // TODO: Motion blur
  16. /// <summary>
  17. /// Renders the post-processing effect stack.
  18. /// </summary>
  19. public class PostProcessPass : ScriptableRenderPass
  20. {
  21. RenderTextureDescriptor m_Descriptor;
  22. RenderTargetHandle m_Source;
  23. RenderTargetHandle m_Destination;
  24. RenderTargetHandle m_Depth;
  25. RenderTargetHandle m_InternalLut;
  26. const string k_RenderPostProcessingTag = "Render PostProcessing Effects";
  27. const string k_RenderFinalPostProcessingTag = "Render Final PostProcessing Pass";
  28. MaterialLibrary m_Materials;
  29. PostProcessData m_Data;
  30. // Builtin effects settings
  31. DepthOfField m_DepthOfField;
  32. MotionBlur m_MotionBlur;
  33. PaniniProjection m_PaniniProjection;
  34. Bloom m_Bloom;
  35. LensDistortion m_LensDistortion;
  36. ChromaticAberration m_ChromaticAberration;
  37. Vignette m_Vignette;
  38. ColorLookup m_ColorLookup;
  39. ColorAdjustments m_ColorAdjustments;
  40. Tonemapping m_Tonemapping;
  41. FilmGrain m_FilmGrain;
  42. // Misc
  43. const int k_MaxPyramidSize = 16;
  44. readonly GraphicsFormat m_DefaultHDRFormat;
  45. bool m_UseRGBM;
  46. readonly GraphicsFormat m_GaussianCoCFormat;
  47. Matrix4x4 m_PrevViewProjM = Matrix4x4.identity;
  48. bool m_ResetHistory;
  49. int m_DitheringTextureIndex;
  50. RenderTargetIdentifier[] m_MRT2;
  51. Vector4[] m_BokehKernel;
  52. int m_BokehHash;
  53. bool m_IsStereo;
  54. // True when this is the very last pass in the pipeline
  55. bool m_IsFinalPass;
  56. // If there's a final post process pass after this pass.
  57. // If yes, Film Grain and Dithering are setup in the final pass, otherwise they are setup in this pass.
  58. bool m_HasFinalPass;
  59. // Some Android devices do not support sRGB backbuffer
  60. // We need to do the conversion manually on those
  61. bool m_EnableSRGBConversionIfNeeded;
  62. Material m_BlitMaterial;
  63. public PostProcessPass(RenderPassEvent evt, PostProcessData data, Material blitMaterial = null)
  64. {
  65. renderPassEvent = evt;
  66. m_Data = data;
  67. m_Materials = new MaterialLibrary(data);
  68. m_BlitMaterial = blitMaterial;
  69. // Texture format pre-lookup
  70. if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, FormatUsage.Linear | FormatUsage.Render))
  71. {
  72. m_DefaultHDRFormat = GraphicsFormat.B10G11R11_UFloatPack32;
  73. m_UseRGBM = false;
  74. }
  75. else
  76. {
  77. m_DefaultHDRFormat = QualitySettings.activeColorSpace == ColorSpace.Linear
  78. ? GraphicsFormat.R8G8B8A8_SRGB
  79. : GraphicsFormat.R8G8B8A8_UNorm;
  80. m_UseRGBM = true;
  81. }
  82. if (SystemInfo.IsFormatSupported(GraphicsFormat.R16_UNorm, FormatUsage.Linear | FormatUsage.Render))
  83. m_GaussianCoCFormat = GraphicsFormat.R16_UNorm;
  84. else if (SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, FormatUsage.Linear | FormatUsage.Render))
  85. m_GaussianCoCFormat = GraphicsFormat.R16_SFloat;
  86. else // Expect CoC banding
  87. m_GaussianCoCFormat = GraphicsFormat.R8_UNorm;
  88. // Bloom pyramid shader ids - can't use a simple stackalloc in the bloom function as we
  89. // unfortunately need to allocate strings
  90. ShaderConstants._BloomMipUp = new int[k_MaxPyramidSize];
  91. ShaderConstants._BloomMipDown = new int[k_MaxPyramidSize];
  92. for (int i = 0; i < k_MaxPyramidSize; i++)
  93. {
  94. ShaderConstants._BloomMipUp[i] = Shader.PropertyToID("_BloomMipUp" + i);
  95. ShaderConstants._BloomMipDown[i] = Shader.PropertyToID("_BloomMipDown" + i);
  96. }
  97. m_MRT2 = new RenderTargetIdentifier[2];
  98. m_ResetHistory = true;
  99. }
  100. public void Cleanup() => m_Materials.Cleanup();
  101. public void Setup(in RenderTextureDescriptor baseDescriptor, in RenderTargetHandle source, in RenderTargetHandle destination, in RenderTargetHandle depth, in RenderTargetHandle internalLut, bool hasFinalPass, bool enableSRGBConversion)
  102. {
  103. m_Descriptor = baseDescriptor;
  104. m_Source = source;
  105. m_Destination = destination;
  106. m_Depth = depth;
  107. m_InternalLut = internalLut;
  108. m_IsFinalPass = false;
  109. m_HasFinalPass = hasFinalPass;
  110. m_EnableSRGBConversionIfNeeded = enableSRGBConversion;
  111. }
  112. public void SetupFinalPass(in RenderTargetHandle source)
  113. {
  114. m_Source = source;
  115. m_Destination = RenderTargetHandle.CameraTarget;
  116. m_IsFinalPass = true;
  117. m_HasFinalPass = false;
  118. m_EnableSRGBConversionIfNeeded = true;
  119. }
  120. public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
  121. {
  122. if (m_Destination == RenderTargetHandle.CameraTarget)
  123. return;
  124. var desc = cameraTextureDescriptor;
  125. desc.msaaSamples = 1;
  126. desc.depthBufferBits = 0;
  127. cmd.GetTemporaryRT(m_Destination.id, desc, FilterMode.Point);
  128. }
  129. public void ResetHistory()
  130. {
  131. m_ResetHistory = true;
  132. }
  133. public bool CanRunOnTile()
  134. {
  135. // Check builtin & user effects here
  136. return false;
  137. }
  138. /// <inheritdoc/>
  139. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  140. {
  141. // Start by pre-fetching all builtin effect settings we need
  142. // Some of the color-grading settings are only used in the color grading lut pass
  143. var stack = VolumeManager.instance.stack;
  144. m_DepthOfField = stack.GetComponent<DepthOfField>();
  145. m_MotionBlur = stack.GetComponent<MotionBlur>();
  146. m_PaniniProjection = stack.GetComponent<PaniniProjection>();
  147. m_Bloom = stack.GetComponent<Bloom>();
  148. m_LensDistortion = stack.GetComponent<LensDistortion>();
  149. m_ChromaticAberration = stack.GetComponent<ChromaticAberration>();
  150. m_Vignette = stack.GetComponent<Vignette>();
  151. m_ColorLookup = stack.GetComponent<ColorLookup>();
  152. m_ColorAdjustments = stack.GetComponent<ColorAdjustments>();
  153. m_Tonemapping = stack.GetComponent<Tonemapping>();
  154. m_FilmGrain = stack.GetComponent<FilmGrain>();
  155. if (m_IsFinalPass)
  156. {
  157. var cmd = CommandBufferPool.Get(k_RenderFinalPostProcessingTag);
  158. RenderFinalPass(cmd, ref renderingData);
  159. context.ExecuteCommandBuffer(cmd);
  160. CommandBufferPool.Release(cmd);
  161. }
  162. else if (CanRunOnTile())
  163. {
  164. // TODO: Add a fast render path if only on-tile compatible effects are used and we're actually running on a platform that supports it
  165. // Note: we can still work on-tile if FXAA is enabled, it'd be part of the final pass
  166. }
  167. else
  168. {
  169. // Regular render path (not on-tile) - we do everything in a single command buffer as it
  170. // makes it easier to manage temporary targets' lifetime
  171. var cmd = CommandBufferPool.Get(k_RenderPostProcessingTag);
  172. Render(cmd, ref renderingData);
  173. context.ExecuteCommandBuffer(cmd);
  174. CommandBufferPool.Release(cmd);
  175. }
  176. m_ResetHistory = false;
  177. }
  178. RenderTextureDescriptor GetStereoCompatibleDescriptor()
  179. => GetStereoCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, m_Descriptor.graphicsFormat, m_Descriptor.depthBufferBits);
  180. RenderTextureDescriptor GetStereoCompatibleDescriptor(int width, int height, GraphicsFormat format, int depthBufferBits = 0)
  181. {
  182. // Inherit the VR setup from the camera descriptor
  183. var desc = m_Descriptor;
  184. desc.depthBufferBits = depthBufferBits;
  185. desc.msaaSamples = 1;
  186. desc.width = width;
  187. desc.height = height;
  188. desc.graphicsFormat = format;
  189. return desc;
  190. }
  191. bool RequireSRGBConversionBlitToBackBuffer(CameraData cameraData)
  192. {
  193. bool requiresSRGBConversion = Display.main.requiresSrgbBlitToBackbuffer;
  194. // For stereo case, eye texture always want color data in sRGB space.
  195. // If eye texture color format is linear, we do explicit sRGB convertion
  196. #if ENABLE_VR && ENABLE_VR_MODULE
  197. if (cameraData.isStereoEnabled)
  198. requiresSRGBConversion = !XRGraphics.eyeTextureDesc.sRGB;
  199. #endif
  200. return requiresSRGBConversion;
  201. }
  202. void Render(CommandBuffer cmd, ref RenderingData renderingData)
  203. {
  204. ref var cameraData = ref renderingData.cameraData;
  205. m_IsStereo = renderingData.cameraData.isStereoEnabled;
  206. // Don't use these directly unless you have a good reason to, use GetSource() and
  207. // GetDestination() instead
  208. bool tempTargetUsed = false;
  209. bool tempTarget2Used = false;
  210. int source = m_Source.id;
  211. int destination = -1;
  212. // Utilities to simplify intermediate target management
  213. int GetSource() => source;
  214. int GetDestination()
  215. {
  216. if (destination == -1)
  217. {
  218. cmd.GetTemporaryRT(ShaderConstants._TempTarget, GetStereoCompatibleDescriptor(), FilterMode.Bilinear);
  219. destination = ShaderConstants._TempTarget;
  220. tempTargetUsed = true;
  221. }
  222. else if (destination == m_Source.id && m_Descriptor.msaaSamples > 1)
  223. {
  224. // Avoid using m_Source.id as new destination, it may come with a depth buffer that we don't want, may have MSAA that we don't want etc
  225. cmd.GetTemporaryRT(ShaderConstants._TempTarget2, GetStereoCompatibleDescriptor(), FilterMode.Bilinear);
  226. destination = ShaderConstants._TempTarget2;
  227. tempTarget2Used = true;
  228. }
  229. return destination;
  230. }
  231. void Swap() => CoreUtils.Swap(ref source, ref destination);
  232. // Setup projection matrix for cmd.DrawMesh()
  233. cmd.SetGlobalMatrix(ShaderConstants._FullscreenProjMat, GL.GetGPUProjectionMatrix(Matrix4x4.identity, true));
  234. // Optional NaN killer before post-processing kicks in
  235. // stopNaN may be null on Adreno 3xx. It doesn't support full shader level 3.5, but SystemInfo.graphicsShaderLevel is 35.
  236. if (cameraData.isStopNaNEnabled && m_Materials.stopNaN != null)
  237. {
  238. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.StopNaNs)))
  239. {
  240. cmd.Blit(GetSource(), BlitDstDiscardContent(cmd, GetDestination()), m_Materials.stopNaN);
  241. Swap();
  242. }
  243. }
  244. // Anti-aliasing
  245. if (cameraData.antialiasing == AntialiasingMode.SubpixelMorphologicalAntiAliasing && SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES2)
  246. {
  247. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.SMAA)))
  248. {
  249. DoSubpixelMorphologicalAntialiasing(ref cameraData, cmd, GetSource(), GetDestination());
  250. Swap();
  251. }
  252. }
  253. // Depth of Field
  254. if (m_DepthOfField.IsActive() && !cameraData.isSceneViewCamera)
  255. {
  256. var markerName = m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian
  257. ? URPProfileId.GaussianDepthOfField
  258. : URPProfileId.BokehDepthOfField;
  259. using (new ProfilingScope(cmd, ProfilingSampler.Get(markerName)))
  260. {
  261. DoDepthOfField(cameraData.camera, cmd, GetSource(), GetDestination(), cameraData.pixelRect);
  262. Swap();
  263. }
  264. }
  265. // Motion blur
  266. if (m_MotionBlur.IsActive() && !cameraData.isSceneViewCamera)
  267. {
  268. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.MotionBlur)))
  269. {
  270. DoMotionBlur(cameraData.camera, cmd, GetSource(), GetDestination());
  271. Swap();
  272. }
  273. }
  274. // Panini projection is done as a fullscreen pass after all depth-based effects are done
  275. // and before bloom kicks in
  276. if (m_PaniniProjection.IsActive() && !cameraData.isSceneViewCamera)
  277. {
  278. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.PaniniProjection)))
  279. {
  280. DoPaniniProjection(cameraData.camera, cmd, GetSource(), GetDestination());
  281. Swap();
  282. }
  283. }
  284. // Combined post-processing stack
  285. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.UberPostProcess)))
  286. {
  287. // Reset uber keywords
  288. m_Materials.uber.shaderKeywords = null;
  289. // Bloom goes first
  290. bool bloomActive = m_Bloom.IsActive();
  291. if (bloomActive)
  292. {
  293. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.Bloom)))
  294. SetupBloom(cmd, GetSource(), m_Materials.uber);
  295. }
  296. // Setup other effects constants
  297. SetupLensDistortion(m_Materials.uber, cameraData.isSceneViewCamera);
  298. SetupChromaticAberration(m_Materials.uber);
  299. SetupVignette(m_Materials.uber);
  300. SetupColorGrading(cmd, ref renderingData, m_Materials.uber);
  301. // Only apply dithering & grain if there isn't a final pass.
  302. SetupGrain(cameraData, m_Materials.uber);
  303. SetupDithering(cameraData, m_Materials.uber);
  304. if (RequireSRGBConversionBlitToBackBuffer(cameraData) && m_EnableSRGBConversionIfNeeded)
  305. m_Materials.uber.EnableKeyword(ShaderKeywordStrings.LinearToSRGBConversion);
  306. // Done with Uber, blit it
  307. cmd.SetGlobalTexture("_BlitTex", GetSource());
  308. var colorLoadAction = RenderBufferLoadAction.DontCare;
  309. if (m_Destination == RenderTargetHandle.CameraTarget && !cameraData.isDefaultViewport)
  310. colorLoadAction = RenderBufferLoadAction.Load;
  311. // Note: We rendering to "camera target" we need to get the cameraData.targetTexture as this will get the targetTexture of the camera stack.
  312. // Overlay cameras need to output to the target described in the base camera while doing camera stack.
  313. RenderTargetIdentifier cameraTarget = (cameraData.targetTexture != null) ? new RenderTargetIdentifier(cameraData.targetTexture) : BuiltinRenderTextureType.CameraTarget;
  314. cameraTarget = (m_Destination == RenderTargetHandle.CameraTarget) ? cameraTarget : m_Destination.Identifier();
  315. cmd.SetRenderTarget(cameraTarget, colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  316. // With camera stacking we not always resolve post to final screen as we might run post-processing in the middle of the stack.
  317. bool finishPostProcessOnScreen = renderingData.resolveFinalTarget || (m_Destination == RenderTargetHandle.CameraTarget || m_HasFinalPass == true);
  318. if (m_IsStereo)
  319. {
  320. Blit(cmd, GetSource(), BuiltinRenderTextureType.CurrentActive, m_Materials.uber);
  321. // TODO: We need a proper camera texture swap chain in URP.
  322. // For now, when render post-processing in the middle of the camera stack (not resolving to screen)
  323. // we do an extra blit to ping pong results back to color texture. In future we should allow a Swap of the current active color texture
  324. // in the pipeline to avoid this extra blit.
  325. if (!finishPostProcessOnScreen)
  326. {
  327. cmd.SetGlobalTexture("_BlitTex", cameraTarget);
  328. Blit(cmd, BuiltinRenderTextureType.CurrentActive, m_Source.id, m_BlitMaterial);
  329. }
  330. }
  331. else
  332. {
  333. cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
  334. if (m_Destination == RenderTargetHandle.CameraTarget)
  335. cmd.SetViewport(cameraData.pixelRect);
  336. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_Materials.uber);
  337. // TODO: We need a proper camera texture swap chain in URP.
  338. // For now, when render post-processing in the middle of the camera stack (not resolving to screen)
  339. // we do an extra blit to ping pong results back to color texture. In future we should allow a Swap of the current active color texture
  340. // in the pipeline to avoid this extra blit.
  341. if (!finishPostProcessOnScreen)
  342. {
  343. cmd.SetGlobalTexture("_BlitTex", cameraTarget);
  344. cmd.SetRenderTarget(m_Source.id, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  345. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_BlitMaterial);
  346. }
  347. cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);
  348. }
  349. // Cleanup
  350. if (bloomActive)
  351. cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipUp[0]);
  352. if (tempTargetUsed)
  353. cmd.ReleaseTemporaryRT(ShaderConstants._TempTarget);
  354. if (tempTarget2Used)
  355. cmd.ReleaseTemporaryRT(ShaderConstants._TempTarget2);
  356. }
  357. }
  358. private BuiltinRenderTextureType BlitDstDiscardContent(CommandBuffer cmd, RenderTargetIdentifier rt)
  359. {
  360. // We set depth to DontCare because rt might be the source of PostProcessing used as a temporary target
  361. // Source typically comes with a depth buffer and right now we don't have a way to only bind the color attachment of a RenderTargetIdentifier
  362. cmd.SetRenderTarget(new RenderTargetIdentifier(rt, 0, CubemapFace.Unknown, -1),
  363. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
  364. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  365. return BuiltinRenderTextureType.CurrentActive;
  366. }
  367. #region Sub-pixel Morphological Anti-aliasing
  368. void DoSubpixelMorphologicalAntialiasing(ref CameraData cameraData, CommandBuffer cmd, int source, int destination)
  369. {
  370. var camera = cameraData.camera;
  371. var pixelRect = cameraData.pixelRect;
  372. var material = m_Materials.subpixelMorphologicalAntialiasing;
  373. const int kStencilBit = 64;
  374. // Globals
  375. material.SetVector(ShaderConstants._Metrics, new Vector4(1f / m_Descriptor.width, 1f / m_Descriptor.height, m_Descriptor.width, m_Descriptor.height));
  376. material.SetTexture(ShaderConstants._AreaTexture, m_Data.textures.smaaAreaTex);
  377. material.SetTexture(ShaderConstants._SearchTexture, m_Data.textures.smaaSearchTex);
  378. material.SetInt(ShaderConstants._StencilRef, kStencilBit);
  379. material.SetInt(ShaderConstants._StencilMask, kStencilBit);
  380. // Quality presets
  381. material.shaderKeywords = null;
  382. switch (cameraData.antialiasingQuality)
  383. {
  384. case AntialiasingQuality.Low: material.EnableKeyword(ShaderKeywordStrings.SmaaLow);
  385. break;
  386. case AntialiasingQuality.Medium: material.EnableKeyword(ShaderKeywordStrings.SmaaMedium);
  387. break;
  388. case AntialiasingQuality.High: material.EnableKeyword(ShaderKeywordStrings.SmaaHigh);
  389. break;
  390. }
  391. // Intermediate targets
  392. RenderTargetIdentifier stencil; // We would only need stencil, no depth. But Unity doesn't support that.
  393. int tempDepthBits;
  394. if (m_Depth == RenderTargetHandle.CameraTarget || m_Descriptor.msaaSamples > 1)
  395. {
  396. // In case m_Depth is CameraTarget it may refer to the backbuffer and we can't use that as an attachment on all platforms
  397. stencil = ShaderConstants._EdgeTexture;
  398. tempDepthBits = 24;
  399. }
  400. else
  401. {
  402. stencil = m_Depth.Identifier();
  403. tempDepthBits = 0;
  404. }
  405. cmd.GetTemporaryRT(ShaderConstants._EdgeTexture, GetStereoCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, GraphicsFormat.R8G8B8A8_UNorm, tempDepthBits), FilterMode.Point);
  406. cmd.GetTemporaryRT(ShaderConstants._BlendTexture, GetStereoCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, GraphicsFormat.R8G8B8A8_UNorm), FilterMode.Point);
  407. // Prepare for manual blit
  408. cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
  409. cmd.SetViewport(pixelRect);
  410. // Pass 1: Edge detection
  411. cmd.SetRenderTarget(new RenderTargetIdentifier(ShaderConstants._EdgeTexture, 0, CubemapFace.Unknown, -1),
  412. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, stencil,
  413. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
  414. cmd.ClearRenderTarget(true, true, Color.clear);
  415. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, source);
  416. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, material, 0, 0);
  417. // Pass 2: Blend weights
  418. cmd.SetRenderTarget(new RenderTargetIdentifier(ShaderConstants._BlendTexture, 0, CubemapFace.Unknown, -1),
  419. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, stencil,
  420. RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare);
  421. cmd.ClearRenderTarget(false, true, Color.clear);
  422. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, ShaderConstants._EdgeTexture);
  423. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, material, 0, 1);
  424. // Pass 3: Neighborhood blending
  425. cmd.SetRenderTarget(new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1),
  426. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
  427. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  428. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, source);
  429. cmd.SetGlobalTexture(ShaderConstants._BlendTexture, ShaderConstants._BlendTexture);
  430. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, material, 0, 2);
  431. // Cleanup
  432. cmd.ReleaseTemporaryRT(ShaderConstants._EdgeTexture);
  433. cmd.ReleaseTemporaryRT(ShaderConstants._BlendTexture);
  434. cmd.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix);
  435. }
  436. #endregion
  437. #region Depth Of Field
  438. // TODO: CoC reprojection once TAA gets in LW
  439. // TODO: Proper LDR/gamma support
  440. void DoDepthOfField(Camera camera, CommandBuffer cmd, int source, int destination, Rect pixelRect)
  441. {
  442. if (m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian)
  443. DoGaussianDepthOfField(camera, cmd, source, destination, pixelRect);
  444. else if (m_DepthOfField.mode.value == DepthOfFieldMode.Bokeh)
  445. DoBokehDepthOfField(cmd, source, destination, pixelRect);
  446. }
  447. void DoGaussianDepthOfField(Camera camera, CommandBuffer cmd, int source, int destination, Rect pixelRect)
  448. {
  449. var material = m_Materials.gaussianDepthOfField;
  450. int wh = m_Descriptor.width / 2;
  451. int hh = m_Descriptor.height / 2;
  452. float farStart = m_DepthOfField.gaussianStart.value;
  453. float farEnd = Mathf.Max(farStart, m_DepthOfField.gaussianEnd.value);
  454. // Assumes a radius of 1 is 1 at 1080p
  455. // Past a certain radius our gaussian kernel will look very bad so we'll clamp it for
  456. // very high resolutions (4K+).
  457. float maxRadius = m_DepthOfField.gaussianMaxRadius.value * (wh / 1080f);
  458. maxRadius = Mathf.Min(maxRadius, 2f);
  459. CoreUtils.SetKeyword(material, ShaderKeywordStrings.HighQualitySampling, m_DepthOfField.highQualitySampling.value);
  460. material.SetVector(ShaderConstants._CoCParams, new Vector3(farStart, farEnd, maxRadius));
  461. // Temporary textures
  462. cmd.GetTemporaryRT(ShaderConstants._FullCoCTexture, GetStereoCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, m_GaussianCoCFormat), FilterMode.Bilinear);
  463. cmd.GetTemporaryRT(ShaderConstants._HalfCoCTexture, GetStereoCompatibleDescriptor(wh, hh, m_GaussianCoCFormat), FilterMode.Bilinear);
  464. cmd.GetTemporaryRT(ShaderConstants._PingTexture, GetStereoCompatibleDescriptor(wh, hh, m_DefaultHDRFormat), FilterMode.Bilinear);
  465. cmd.GetTemporaryRT(ShaderConstants._PongTexture, GetStereoCompatibleDescriptor(wh, hh, m_DefaultHDRFormat), FilterMode.Bilinear);
  466. // Note: fresh temporary RTs don't require explicit RenderBufferLoadAction.DontCare, only when they are reused (such as PingTexture)
  467. // Compute CoC
  468. cmd.Blit(source, ShaderConstants._FullCoCTexture, material, 0);
  469. // Downscale & prefilter color + coc
  470. m_MRT2[0] = ShaderConstants._HalfCoCTexture;
  471. m_MRT2[1] = ShaderConstants._PingTexture;
  472. cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
  473. cmd.SetViewport(pixelRect);
  474. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, source);
  475. cmd.SetGlobalTexture(ShaderConstants._FullCoCTexture, ShaderConstants._FullCoCTexture);
  476. cmd.SetRenderTarget(m_MRT2, ShaderConstants._HalfCoCTexture, 0, CubemapFace.Unknown, -1);
  477. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, material, 0, 1);
  478. cmd.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix);
  479. // Blur
  480. cmd.SetGlobalTexture(ShaderConstants._HalfCoCTexture, ShaderConstants._HalfCoCTexture);
  481. cmd.Blit(ShaderConstants._PingTexture, ShaderConstants._PongTexture, material, 2);
  482. cmd.Blit(ShaderConstants._PongTexture, BlitDstDiscardContent(cmd, ShaderConstants._PingTexture), material, 3);
  483. // Composite
  484. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, ShaderConstants._PingTexture);
  485. cmd.SetGlobalTexture(ShaderConstants._FullCoCTexture, ShaderConstants._FullCoCTexture);
  486. cmd.Blit(source, BlitDstDiscardContent(cmd, destination), material, 4);
  487. // Cleanup
  488. cmd.ReleaseTemporaryRT(ShaderConstants._FullCoCTexture);
  489. cmd.ReleaseTemporaryRT(ShaderConstants._HalfCoCTexture);
  490. cmd.ReleaseTemporaryRT(ShaderConstants._PingTexture);
  491. cmd.ReleaseTemporaryRT(ShaderConstants._PongTexture);
  492. }
  493. void PrepareBokehKernel()
  494. {
  495. const int kRings = 4;
  496. const int kPointsPerRing = 7;
  497. // Check the existing array
  498. if (m_BokehKernel == null)
  499. m_BokehKernel = new Vector4[42];
  500. // Fill in sample points (concentric circles transformed to rotated N-Gon)
  501. int idx = 0;
  502. float bladeCount = m_DepthOfField.bladeCount.value;
  503. float curvature = 1f - m_DepthOfField.bladeCurvature.value;
  504. float rotation = m_DepthOfField.bladeRotation.value * Mathf.Deg2Rad;
  505. const float PI = Mathf.PI;
  506. const float TWO_PI = Mathf.PI * 2f;
  507. for (int ring = 1; ring < kRings; ring++)
  508. {
  509. float bias = 1f / kPointsPerRing;
  510. float radius = (ring + bias) / (kRings - 1f + bias);
  511. int points = ring * kPointsPerRing;
  512. for (int point = 0; point < points; point++)
  513. {
  514. // Angle on ring
  515. float phi = 2f * PI * point / points;
  516. // Transform to rotated N-Gon
  517. // Adapted from "CryEngine 3 Graphics Gems" [Sousa13]
  518. float nt = Mathf.Cos(PI / bladeCount);
  519. float dt = Mathf.Cos(phi - (TWO_PI / bladeCount) * Mathf.Floor((bladeCount * phi + Mathf.PI) / TWO_PI));
  520. float r = radius * Mathf.Pow(nt / dt, curvature);
  521. float u = r * Mathf.Cos(phi - rotation);
  522. float v = r * Mathf.Sin(phi - rotation);
  523. m_BokehKernel[idx] = new Vector4(u, v);
  524. idx++;
  525. }
  526. }
  527. }
  528. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  529. static float GetMaxBokehRadiusInPixels(float viewportHeight)
  530. {
  531. // Estimate the maximum radius of bokeh (empirically derived from the ring count)
  532. const float kRadiusInPixels = 14f;
  533. return Mathf.Min(0.05f, kRadiusInPixels / viewportHeight);
  534. }
  535. void DoBokehDepthOfField(CommandBuffer cmd, int source, int destination, Rect pixelRect)
  536. {
  537. var material = m_Materials.bokehDepthOfField;
  538. int wh = m_Descriptor.width / 2;
  539. int hh = m_Descriptor.height / 2;
  540. // "A Lens and Aperture Camera Model for Synthetic Image Generation" [Potmesil81]
  541. float F = m_DepthOfField.focalLength.value / 1000f;
  542. float A = m_DepthOfField.focalLength.value / m_DepthOfField.aperture.value;
  543. float P = m_DepthOfField.focusDistance.value;
  544. float maxCoC = (A * F) / (P - F);
  545. float maxRadius = GetMaxBokehRadiusInPixels(m_Descriptor.height);
  546. float rcpAspect = 1f / (wh / (float)hh);
  547. cmd.SetGlobalVector(ShaderConstants._CoCParams, new Vector4(P, maxCoC, maxRadius, rcpAspect));
  548. // Prepare the bokeh kernel constant buffer
  549. int hash = m_DepthOfField.GetHashCode(); // TODO: GC fix
  550. if (hash != m_BokehHash)
  551. {
  552. m_BokehHash = hash;
  553. PrepareBokehKernel();
  554. }
  555. cmd.SetGlobalVectorArray(ShaderConstants._BokehKernel, m_BokehKernel);
  556. // Temporary textures
  557. cmd.GetTemporaryRT(ShaderConstants._FullCoCTexture, GetStereoCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, GraphicsFormat.R8_UNorm), FilterMode.Bilinear);
  558. cmd.GetTemporaryRT(ShaderConstants._PingTexture, GetStereoCompatibleDescriptor(wh, hh, GraphicsFormat.R16G16B16A16_SFloat), FilterMode.Bilinear);
  559. cmd.GetTemporaryRT(ShaderConstants._PongTexture, GetStereoCompatibleDescriptor(wh, hh, GraphicsFormat.R16G16B16A16_SFloat), FilterMode.Bilinear);
  560. // Compute CoC
  561. cmd.Blit(source, ShaderConstants._FullCoCTexture, material, 0);
  562. cmd.SetGlobalTexture(ShaderConstants._FullCoCTexture, ShaderConstants._FullCoCTexture);
  563. // Downscale & prefilter color + coc
  564. cmd.Blit(source, ShaderConstants._PingTexture, material, 1);
  565. // Bokeh blur
  566. cmd.Blit(ShaderConstants._PingTexture, ShaderConstants._PongTexture, material, 2);
  567. // Post-filtering
  568. cmd.Blit(ShaderConstants._PongTexture, BlitDstDiscardContent(cmd, ShaderConstants._PingTexture), material, 3);
  569. // Composite
  570. cmd.SetGlobalTexture(ShaderConstants._DofTexture, ShaderConstants._PingTexture);
  571. cmd.Blit(source, BlitDstDiscardContent(cmd, destination), material, 4);
  572. // Cleanup
  573. cmd.ReleaseTemporaryRT(ShaderConstants._FullCoCTexture);
  574. cmd.ReleaseTemporaryRT(ShaderConstants._PingTexture);
  575. cmd.ReleaseTemporaryRT(ShaderConstants._PongTexture);
  576. }
  577. #endregion
  578. #region Motion Blur
  579. void DoMotionBlur(Camera camera, CommandBuffer cmd, int source, int destination)
  580. {
  581. var material = m_Materials.cameraMotionBlur;
  582. // This is needed because Blit will reset viewproj matrices to identity and UniversalRP currently
  583. // relies on SetupCameraProperties instead of handling its own matrices.
  584. // TODO: We need get rid of SetupCameraProperties and setup camera matrices in Universal
  585. var proj = camera.nonJitteredProjectionMatrix;
  586. var view = camera.worldToCameraMatrix;
  587. var viewProj = proj * view;
  588. material.SetMatrix("_ViewProjM", viewProj);
  589. if (m_ResetHistory)
  590. material.SetMatrix("_PrevViewProjM", viewProj);
  591. else
  592. material.SetMatrix("_PrevViewProjM", m_PrevViewProjM);
  593. material.SetFloat("_Intensity", m_MotionBlur.intensity.value);
  594. material.SetFloat("_Clamp", m_MotionBlur.clamp.value);
  595. cmd.Blit(source, BlitDstDiscardContent(cmd, destination), material, (int)m_MotionBlur.quality.value);
  596. m_PrevViewProjM = viewProj;
  597. }
  598. #endregion
  599. #region Panini Projection
  600. // Back-ported & adapted from the work of the Stockholm demo team - thanks Lasse!
  601. void DoPaniniProjection(Camera camera, CommandBuffer cmd, int source, int destination)
  602. {
  603. float distance = m_PaniniProjection.distance.value;
  604. var viewExtents = CalcViewExtents(camera);
  605. var cropExtents = CalcCropExtents(camera, distance);
  606. float scaleX = cropExtents.x / viewExtents.x;
  607. float scaleY = cropExtents.y / viewExtents.y;
  608. float scaleF = Mathf.Min(scaleX, scaleY);
  609. float paniniD = distance;
  610. float paniniS = Mathf.Lerp(1f, Mathf.Clamp01(scaleF), m_PaniniProjection.cropToFit.value);
  611. var material = m_Materials.paniniProjection;
  612. material.SetVector(ShaderConstants._Params, new Vector4(viewExtents.x, viewExtents.y, paniniD, paniniS));
  613. material.EnableKeyword(
  614. 1f - Mathf.Abs(paniniD) > float.Epsilon
  615. ? ShaderKeywordStrings.PaniniGeneric : ShaderKeywordStrings.PaniniUnitDistance
  616. );
  617. cmd.Blit(source, BlitDstDiscardContent(cmd, destination), material);
  618. }
  619. Vector2 CalcViewExtents(Camera camera)
  620. {
  621. float fovY = camera.fieldOfView * Mathf.Deg2Rad;
  622. float aspect = m_Descriptor.width / (float)m_Descriptor.height;
  623. float viewExtY = Mathf.Tan(0.5f * fovY);
  624. float viewExtX = aspect * viewExtY;
  625. return new Vector2(viewExtX, viewExtY);
  626. }
  627. Vector2 CalcCropExtents(Camera camera, float d)
  628. {
  629. // given
  630. // S----------- E--X-------
  631. // | ` ~. /,´
  632. // |-- --- Q
  633. // | ,/ `
  634. // 1 | ,´/ `
  635. // | ,´ / ´
  636. // | ,´ / ´
  637. // |,` / ,
  638. // O /
  639. // | / ,
  640. // d | /
  641. // | / ,
  642. // |/ .
  643. // P
  644. // | ´
  645. // | , ´
  646. // +- ´
  647. //
  648. // have X
  649. // want to find E
  650. float viewDist = 1f + d;
  651. var projPos = CalcViewExtents(camera);
  652. var projHyp = Mathf.Sqrt(projPos.x * projPos.x + 1f);
  653. float cylDistMinusD = 1f / projHyp;
  654. float cylDist = cylDistMinusD + d;
  655. var cylPos = projPos * cylDistMinusD;
  656. return cylPos * (viewDist / cylDist);
  657. }
  658. #endregion
  659. #region Bloom
  660. void SetupBloom(CommandBuffer cmd, int source, Material uberMaterial)
  661. {
  662. // Start at half-res
  663. int tw = m_Descriptor.width >> 1;
  664. int th = m_Descriptor.height >> 1;
  665. // Determine the iteration count
  666. int maxSize = Mathf.Max(tw, th);
  667. int iterations = Mathf.FloorToInt(Mathf.Log(maxSize, 2f) - 1);
  668. int mipCount = Mathf.Clamp(iterations, 1, k_MaxPyramidSize);
  669. // Pre-filtering parameters
  670. float clamp = m_Bloom.clamp.value;
  671. float threshold = Mathf.GammaToLinearSpace(m_Bloom.threshold.value);
  672. float thresholdKnee = threshold * 0.5f; // Hardcoded soft knee
  673. // Material setup
  674. float scatter = Mathf.Lerp(0.05f, 0.95f, m_Bloom.scatter.value);
  675. var bloomMaterial = m_Materials.bloom;
  676. bloomMaterial.SetVector(ShaderConstants._Params, new Vector4(scatter, clamp, threshold, thresholdKnee));
  677. CoreUtils.SetKeyword(bloomMaterial, ShaderKeywordStrings.BloomHQ, m_Bloom.highQualityFiltering.value);
  678. CoreUtils.SetKeyword(bloomMaterial, ShaderKeywordStrings.UseRGBM, m_UseRGBM);
  679. // Prefilter
  680. var desc = GetStereoCompatibleDescriptor(tw, th, m_DefaultHDRFormat);
  681. cmd.GetTemporaryRT(ShaderConstants._BloomMipDown[0], desc, FilterMode.Bilinear);
  682. cmd.GetTemporaryRT(ShaderConstants._BloomMipUp[0], desc, FilterMode.Bilinear);
  683. cmd.Blit(source, ShaderConstants._BloomMipDown[0], bloomMaterial, 0);
  684. // Downsample - gaussian pyramid
  685. int lastDown = ShaderConstants._BloomMipDown[0];
  686. for (int i = 1; i < mipCount; i++)
  687. {
  688. tw = Mathf.Max(1, tw >> 1);
  689. th = Mathf.Max(1, th >> 1);
  690. int mipDown = ShaderConstants._BloomMipDown[i];
  691. int mipUp = ShaderConstants._BloomMipUp[i];
  692. desc.width = tw;
  693. desc.height = th;
  694. cmd.GetTemporaryRT(mipDown, desc, FilterMode.Bilinear);
  695. cmd.GetTemporaryRT(mipUp, desc, FilterMode.Bilinear);
  696. // Classic two pass gaussian blur - use mipUp as a temporary target
  697. // First pass does 2x downsampling + 9-tap gaussian
  698. // Second pass does 9-tap gaussian using a 5-tap filter + bilinear filtering
  699. cmd.Blit(lastDown, mipUp, bloomMaterial, 1);
  700. cmd.Blit(mipUp, mipDown, bloomMaterial, 2);
  701. lastDown = mipDown;
  702. }
  703. // Upsample (bilinear by default, HQ filtering does bicubic instead
  704. for (int i = mipCount - 2; i >= 0; i--)
  705. {
  706. int lowMip = (i == mipCount - 2) ? ShaderConstants._BloomMipDown[i + 1] : ShaderConstants._BloomMipUp[i + 1];
  707. int highMip = ShaderConstants._BloomMipDown[i];
  708. int dst = ShaderConstants._BloomMipUp[i];
  709. cmd.SetGlobalTexture(ShaderConstants._MainTexLowMip, lowMip);
  710. cmd.Blit(highMip, BlitDstDiscardContent(cmd, dst), bloomMaterial, 3);
  711. }
  712. // Cleanup
  713. for (int i = 0; i < mipCount; i++)
  714. {
  715. cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipDown[i]);
  716. if (i > 0) cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipUp[i]);
  717. }
  718. // Setup bloom on uber
  719. var tint = m_Bloom.tint.value.linear;
  720. var luma = ColorUtils.Luminance(tint);
  721. tint = luma > 0f ? tint * (1f / luma) : Color.white;
  722. var bloomParams = new Vector4(m_Bloom.intensity.value, tint.r, tint.g, tint.b);
  723. uberMaterial.SetVector(ShaderConstants._Bloom_Params, bloomParams);
  724. uberMaterial.SetFloat(ShaderConstants._Bloom_RGBM, m_UseRGBM ? 1f : 0f);
  725. cmd.SetGlobalTexture(ShaderConstants._Bloom_Texture, ShaderConstants._BloomMipUp[0]);
  726. // Setup lens dirtiness on uber
  727. // Keep the aspect ratio correct & center the dirt texture, we don't want it to be
  728. // stretched or squashed
  729. var dirtTexture = m_Bloom.dirtTexture.value == null ? Texture2D.blackTexture : m_Bloom.dirtTexture.value;
  730. float dirtRatio = dirtTexture.width / (float)dirtTexture.height;
  731. float screenRatio = m_Descriptor.width / (float)m_Descriptor.height;
  732. var dirtScaleOffset = new Vector4(1f, 1f, 0f, 0f);
  733. float dirtIntensity = m_Bloom.dirtIntensity.value;
  734. if (dirtRatio > screenRatio)
  735. {
  736. dirtScaleOffset.x = screenRatio / dirtRatio;
  737. dirtScaleOffset.z = (1f - dirtScaleOffset.x) * 0.5f;
  738. }
  739. else if (screenRatio > dirtRatio)
  740. {
  741. dirtScaleOffset.y = dirtRatio / screenRatio;
  742. dirtScaleOffset.w = (1f - dirtScaleOffset.y) * 0.5f;
  743. }
  744. uberMaterial.SetVector(ShaderConstants._LensDirt_Params, dirtScaleOffset);
  745. uberMaterial.SetFloat(ShaderConstants._LensDirt_Intensity, dirtIntensity);
  746. uberMaterial.SetTexture(ShaderConstants._LensDirt_Texture, dirtTexture);
  747. // Keyword setup - a bit convoluted as we're trying to save some variants in Uber...
  748. if (m_Bloom.highQualityFiltering.value)
  749. uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomHQDirt : ShaderKeywordStrings.BloomHQ);
  750. else
  751. uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomLQDirt : ShaderKeywordStrings.BloomLQ);
  752. }
  753. #endregion
  754. #region Lens Distortion
  755. void SetupLensDistortion(Material material, bool isSceneView)
  756. {
  757. float amount = 1.6f * Mathf.Max(Mathf.Abs(m_LensDistortion.intensity.value * 100f), 1f);
  758. float theta = Mathf.Deg2Rad * Mathf.Min(160f, amount);
  759. float sigma = 2f * Mathf.Tan(theta * 0.5f);
  760. var center = m_LensDistortion.center.value * 2f - Vector2.one;
  761. var p1 = new Vector4(
  762. center.x,
  763. center.y,
  764. Mathf.Max(m_LensDistortion.xMultiplier.value, 1e-4f),
  765. Mathf.Max(m_LensDistortion.yMultiplier.value, 1e-4f)
  766. );
  767. var p2 = new Vector4(
  768. m_LensDistortion.intensity.value >= 0f ? theta : 1f / theta,
  769. sigma,
  770. 1f / m_LensDistortion.scale.value,
  771. m_LensDistortion.intensity.value * 100f
  772. );
  773. material.SetVector(ShaderConstants._Distortion_Params1, p1);
  774. material.SetVector(ShaderConstants._Distortion_Params2, p2);
  775. if (m_LensDistortion.IsActive() && !isSceneView)
  776. material.EnableKeyword(ShaderKeywordStrings.Distortion);
  777. }
  778. #endregion
  779. #region Chromatic Aberration
  780. void SetupChromaticAberration(Material material)
  781. {
  782. material.SetFloat(ShaderConstants._Chroma_Params, m_ChromaticAberration.intensity.value * 0.05f);
  783. if (m_ChromaticAberration.IsActive())
  784. material.EnableKeyword(ShaderKeywordStrings.ChromaticAberration);
  785. }
  786. #endregion
  787. #region Vignette
  788. void SetupVignette(Material material)
  789. {
  790. var color = m_Vignette.color.value;
  791. var center = m_Vignette.center.value;
  792. var aspectRatio = m_Descriptor.width / (float)m_Descriptor.height;
  793. if (m_IsStereo && XRGraphics.stereoRenderingMode == XRGraphics.StereoRenderingMode.SinglePass)
  794. aspectRatio *= 0.5f;
  795. var v1 = new Vector4(
  796. color.r, color.g, color.b,
  797. m_Vignette.rounded.value ? aspectRatio : 1f
  798. );
  799. var v2 = new Vector4(
  800. center.x, center.y,
  801. m_Vignette.intensity.value * 3f,
  802. m_Vignette.smoothness.value * 5f
  803. );
  804. material.SetVector(ShaderConstants._Vignette_Params1, v1);
  805. material.SetVector(ShaderConstants._Vignette_Params2, v2);
  806. }
  807. #endregion
  808. #region Color Grading
  809. void SetupColorGrading(CommandBuffer cmd, ref RenderingData renderingData, Material material)
  810. {
  811. ref var postProcessingData = ref renderingData.postProcessingData;
  812. bool hdr = postProcessingData.gradingMode == ColorGradingMode.HighDynamicRange;
  813. int lutHeight = postProcessingData.lutSize;
  814. int lutWidth = lutHeight * lutHeight;
  815. // Source material setup
  816. float postExposureLinear = Mathf.Pow(2f, m_ColorAdjustments.postExposure.value);
  817. cmd.SetGlobalTexture(ShaderConstants._InternalLut, m_InternalLut.Identifier());
  818. material.SetVector(ShaderConstants._Lut_Params, new Vector4(1f / lutWidth, 1f / lutHeight, lutHeight - 1f, postExposureLinear));
  819. material.SetTexture(ShaderConstants._UserLut, m_ColorLookup.texture.value);
  820. material.SetVector(ShaderConstants._UserLut_Params, !m_ColorLookup.IsActive()
  821. ? Vector4.zero
  822. : new Vector4(1f / m_ColorLookup.texture.value.width,
  823. 1f / m_ColorLookup.texture.value.height,
  824. m_ColorLookup.texture.value.height - 1f,
  825. m_ColorLookup.contribution.value)
  826. );
  827. if (hdr)
  828. {
  829. material.EnableKeyword(ShaderKeywordStrings.HDRGrading);
  830. }
  831. else
  832. {
  833. switch (m_Tonemapping.mode.value)
  834. {
  835. case TonemappingMode.Neutral: material.EnableKeyword(ShaderKeywordStrings.TonemapNeutral); break;
  836. case TonemappingMode.ACES: material.EnableKeyword(ShaderKeywordStrings.TonemapACES); break;
  837. default: break; // None
  838. }
  839. }
  840. }
  841. #endregion
  842. #region Film Grain
  843. void SetupGrain(in CameraData cameraData, Material material)
  844. {
  845. if (!m_HasFinalPass && m_FilmGrain.IsActive())
  846. {
  847. material.EnableKeyword(ShaderKeywordStrings.FilmGrain);
  848. PostProcessUtils.ConfigureFilmGrain(
  849. m_Data,
  850. m_FilmGrain,
  851. cameraData.pixelWidth, cameraData.pixelHeight,
  852. material
  853. );
  854. }
  855. }
  856. #endregion
  857. #region 8-bit Dithering
  858. void SetupDithering(in CameraData cameraData, Material material)
  859. {
  860. if (!m_HasFinalPass && cameraData.isDitheringEnabled)
  861. {
  862. material.EnableKeyword(ShaderKeywordStrings.Dithering);
  863. m_DitheringTextureIndex = PostProcessUtils.ConfigureDithering(
  864. m_Data,
  865. m_DitheringTextureIndex,
  866. cameraData.pixelWidth, cameraData.pixelHeight,
  867. material
  868. );
  869. }
  870. }
  871. #endregion
  872. #region Final pass
  873. void RenderFinalPass(CommandBuffer cmd, ref RenderingData renderingData)
  874. {
  875. ref var cameraData = ref renderingData.cameraData;
  876. var material = m_Materials.finalPass;
  877. material.shaderKeywords = null;
  878. // FXAA setup
  879. if (cameraData.antialiasing == AntialiasingMode.FastApproximateAntialiasing)
  880. material.EnableKeyword(ShaderKeywordStrings.Fxaa);
  881. SetupGrain(cameraData, material);
  882. SetupDithering(cameraData, material);
  883. if (RequireSRGBConversionBlitToBackBuffer(cameraData) && m_EnableSRGBConversionIfNeeded)
  884. material.EnableKeyword(ShaderKeywordStrings.LinearToSRGBConversion);
  885. cmd.SetGlobalTexture("_BlitTex", m_Source.Identifier());
  886. var colorLoadAction = cameraData.isDefaultViewport ? RenderBufferLoadAction.DontCare : RenderBufferLoadAction.Load;
  887. // Note: We need to get the cameraData.targetTexture as this will get the targetTexture of the camera stack.
  888. // Overlay cameras need to output to the target described in the base camera while doing camera stack.
  889. RenderTargetIdentifier cameraTarget = (cameraData.targetTexture != null) ? new RenderTargetIdentifier(cameraData.targetTexture) : BuiltinRenderTextureType.CameraTarget;
  890. cmd.SetRenderTarget(cameraTarget, colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  891. if (cameraData.isStereoEnabled)
  892. {
  893. Blit(cmd, m_Source.Identifier(), BuiltinRenderTextureType.CurrentActive, material);
  894. }
  895. else
  896. {
  897. cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
  898. cmd.SetViewport(cameraData.pixelRect);
  899. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, material);
  900. cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);
  901. }
  902. }
  903. #endregion
  904. #region Internal utilities
  905. class MaterialLibrary
  906. {
  907. public readonly Material stopNaN;
  908. public readonly Material subpixelMorphologicalAntialiasing;
  909. public readonly Material gaussianDepthOfField;
  910. public readonly Material bokehDepthOfField;
  911. public readonly Material cameraMotionBlur;
  912. public readonly Material paniniProjection;
  913. public readonly Material bloom;
  914. public readonly Material uber;
  915. public readonly Material finalPass;
  916. public MaterialLibrary(PostProcessData data)
  917. {
  918. stopNaN = Load(data.shaders.stopNanPS);
  919. subpixelMorphologicalAntialiasing = Load(data.shaders.subpixelMorphologicalAntialiasingPS);
  920. gaussianDepthOfField = Load(data.shaders.gaussianDepthOfFieldPS);
  921. bokehDepthOfField = Load(data.shaders.bokehDepthOfFieldPS);
  922. cameraMotionBlur = Load(data.shaders.cameraMotionBlurPS);
  923. paniniProjection = Load(data.shaders.paniniProjectionPS);
  924. bloom = Load(data.shaders.bloomPS);
  925. uber = Load(data.shaders.uberPostPS);
  926. finalPass = Load(data.shaders.finalPostPassPS);
  927. }
  928. Material Load(Shader shader)
  929. {
  930. if (shader == null)
  931. {
  932. Debug.LogErrorFormat($"Missing shader. {GetType().DeclaringType.Name} render pass will not execute. Check for missing reference in the renderer resources.");
  933. return null;
  934. }
  935. else if (!shader.isSupported)
  936. {
  937. return null;
  938. }
  939. return CoreUtils.CreateEngineMaterial(shader);
  940. }
  941. internal void Cleanup()
  942. {
  943. CoreUtils.Destroy(stopNaN);
  944. CoreUtils.Destroy(subpixelMorphologicalAntialiasing);
  945. CoreUtils.Destroy(gaussianDepthOfField);
  946. CoreUtils.Destroy(bokehDepthOfField);
  947. CoreUtils.Destroy(cameraMotionBlur);
  948. CoreUtils.Destroy(paniniProjection);
  949. CoreUtils.Destroy(bloom);
  950. CoreUtils.Destroy(uber);
  951. CoreUtils.Destroy(finalPass);
  952. }
  953. }
  954. // Precomputed shader ids to same some CPU cycles (mostly affects mobile)
  955. static class ShaderConstants
  956. {
  957. public static readonly int _TempTarget = Shader.PropertyToID("_TempTarget");
  958. public static readonly int _TempTarget2 = Shader.PropertyToID("_TempTarget2");
  959. public static readonly int _StencilRef = Shader.PropertyToID("_StencilRef");
  960. public static readonly int _StencilMask = Shader.PropertyToID("_StencilMask");
  961. public static readonly int _FullCoCTexture = Shader.PropertyToID("_FullCoCTexture");
  962. public static readonly int _HalfCoCTexture = Shader.PropertyToID("_HalfCoCTexture");
  963. public static readonly int _DofTexture = Shader.PropertyToID("_DofTexture");
  964. public static readonly int _CoCParams = Shader.PropertyToID("_CoCParams");
  965. public static readonly int _BokehKernel = Shader.PropertyToID("_BokehKernel");
  966. public static readonly int _PongTexture = Shader.PropertyToID("_PongTexture");
  967. public static readonly int _PingTexture = Shader.PropertyToID("_PingTexture");
  968. public static readonly int _Metrics = Shader.PropertyToID("_Metrics");
  969. public static readonly int _AreaTexture = Shader.PropertyToID("_AreaTexture");
  970. public static readonly int _SearchTexture = Shader.PropertyToID("_SearchTexture");
  971. public static readonly int _EdgeTexture = Shader.PropertyToID("_EdgeTexture");
  972. public static readonly int _BlendTexture = Shader.PropertyToID("_BlendTexture");
  973. public static readonly int _ColorTexture = Shader.PropertyToID("_ColorTexture");
  974. public static readonly int _Params = Shader.PropertyToID("_Params");
  975. public static readonly int _MainTexLowMip = Shader.PropertyToID("_MainTexLowMip");
  976. public static readonly int _Bloom_Params = Shader.PropertyToID("_Bloom_Params");
  977. public static readonly int _Bloom_RGBM = Shader.PropertyToID("_Bloom_RGBM");
  978. public static readonly int _Bloom_Texture = Shader.PropertyToID("_Bloom_Texture");
  979. public static readonly int _LensDirt_Texture = Shader.PropertyToID("_LensDirt_Texture");
  980. public static readonly int _LensDirt_Params = Shader.PropertyToID("_LensDirt_Params");
  981. public static readonly int _LensDirt_Intensity = Shader.PropertyToID("_LensDirt_Intensity");
  982. public static readonly int _Distortion_Params1 = Shader.PropertyToID("_Distortion_Params1");
  983. public static readonly int _Distortion_Params2 = Shader.PropertyToID("_Distortion_Params2");
  984. public static readonly int _Chroma_Params = Shader.PropertyToID("_Chroma_Params");
  985. public static readonly int _Vignette_Params1 = Shader.PropertyToID("_Vignette_Params1");
  986. public static readonly int _Vignette_Params2 = Shader.PropertyToID("_Vignette_Params2");
  987. public static readonly int _Lut_Params = Shader.PropertyToID("_Lut_Params");
  988. public static readonly int _UserLut_Params = Shader.PropertyToID("_UserLut_Params");
  989. public static readonly int _InternalLut = Shader.PropertyToID("_InternalLut");
  990. public static readonly int _UserLut = Shader.PropertyToID("_UserLut");
  991. public static readonly int _FullscreenProjMat = Shader.PropertyToID("_FullscreenProjMat");
  992. public static int[] _BloomMipUp;
  993. public static int[] _BloomMipDown;
  994. }
  995. #endregion
  996. }
  997. }