PostProcessPass.cs 82 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722
  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. RenderTargetIdentifier 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. private static readonly ProfilingSampler m_ProfilingRenderPostProcessing = new ProfilingSampler(k_RenderPostProcessingTag);
  29. private static readonly ProfilingSampler m_ProfilingRenderFinalPostProcessing = new ProfilingSampler(k_RenderFinalPostProcessingTag);
  30. MaterialLibrary m_Materials;
  31. PostProcessData m_Data;
  32. // Builtin effects settings
  33. DepthOfField m_DepthOfField;
  34. MotionBlur m_MotionBlur;
  35. PaniniProjection m_PaniniProjection;
  36. Bloom m_Bloom;
  37. LensDistortion m_LensDistortion;
  38. ChromaticAberration m_ChromaticAberration;
  39. Vignette m_Vignette;
  40. ColorLookup m_ColorLookup;
  41. ColorAdjustments m_ColorAdjustments;
  42. Tonemapping m_Tonemapping;
  43. FilmGrain m_FilmGrain;
  44. // Misc
  45. const int k_MaxPyramidSize = 16;
  46. readonly GraphicsFormat m_DefaultHDRFormat;
  47. bool m_UseRGBM;
  48. readonly GraphicsFormat m_SMAAEdgeFormat;
  49. readonly GraphicsFormat m_GaussianCoCFormat;
  50. Matrix4x4[] m_PrevViewProjM = new Matrix4x4[2];
  51. bool m_ResetHistory;
  52. int m_DitheringTextureIndex;
  53. RenderTargetIdentifier[] m_MRT2;
  54. Vector4[] m_BokehKernel;
  55. int m_BokehHash;
  56. // Needed if the device changes its render target width/height (ex, Mobile platform allows change of orientation)
  57. float m_BokehMaxRadius;
  58. float m_BokehRCPAspect;
  59. // True when this is the very last pass in the pipeline
  60. bool m_IsFinalPass;
  61. // If there's a final post process pass after this pass.
  62. // If yes, Film Grain and Dithering are setup in the final pass, otherwise they are setup in this pass.
  63. bool m_HasFinalPass;
  64. // Some Android devices do not support sRGB backbuffer
  65. // We need to do the conversion manually on those
  66. bool m_EnableSRGBConversionIfNeeded;
  67. // Option to use procedural draw instead of cmd.blit
  68. bool m_UseDrawProcedural;
  69. // Use Fast conversions between SRGB and Linear
  70. bool m_UseFastSRGBLinearConversion;
  71. // Blit to screen or color frontbuffer at the end
  72. bool m_ResolveToScreen;
  73. // Renderer is using swapbuffer system
  74. bool m_UseSwapBuffer;
  75. // True if there are passes that will run after post processing logic and before final post
  76. bool m_hasExternalPostPasses;
  77. Material m_BlitMaterial;
  78. public PostProcessPass(RenderPassEvent evt, PostProcessData data, Material blitMaterial)
  79. {
  80. base.profilingSampler = new ProfilingSampler(nameof(PostProcessPass));
  81. renderPassEvent = evt;
  82. m_Data = data;
  83. m_Materials = new MaterialLibrary(data);
  84. m_BlitMaterial = blitMaterial;
  85. // Texture format pre-lookup
  86. if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, FormatUsage.Linear | FormatUsage.Render))
  87. {
  88. m_DefaultHDRFormat = GraphicsFormat.B10G11R11_UFloatPack32;
  89. m_UseRGBM = false;
  90. }
  91. else
  92. {
  93. m_DefaultHDRFormat = QualitySettings.activeColorSpace == ColorSpace.Linear
  94. ? GraphicsFormat.R8G8B8A8_SRGB
  95. : GraphicsFormat.R8G8B8A8_UNorm;
  96. m_UseRGBM = true;
  97. }
  98. // Only two components are needed for edge render texture, but on some vendors four components may be faster.
  99. if (SystemInfo.IsFormatSupported(GraphicsFormat.R8G8_UNorm, FormatUsage.Render) && SystemInfo.graphicsDeviceVendor.ToLowerInvariant().Contains("arm"))
  100. m_SMAAEdgeFormat = GraphicsFormat.R8G8_UNorm;
  101. else
  102. m_SMAAEdgeFormat = GraphicsFormat.R8G8B8A8_UNorm;
  103. if (SystemInfo.IsFormatSupported(GraphicsFormat.R16_UNorm, FormatUsage.Linear | FormatUsage.Render))
  104. m_GaussianCoCFormat = GraphicsFormat.R16_UNorm;
  105. else if (SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, FormatUsage.Linear | FormatUsage.Render))
  106. m_GaussianCoCFormat = GraphicsFormat.R16_SFloat;
  107. else // Expect CoC banding
  108. m_GaussianCoCFormat = GraphicsFormat.R8_UNorm;
  109. // Bloom pyramid shader ids - can't use a simple stackalloc in the bloom function as we
  110. // unfortunately need to allocate strings
  111. ShaderConstants._BloomMipUp = new int[k_MaxPyramidSize];
  112. ShaderConstants._BloomMipDown = new int[k_MaxPyramidSize];
  113. for (int i = 0; i < k_MaxPyramidSize; i++)
  114. {
  115. ShaderConstants._BloomMipUp[i] = Shader.PropertyToID("_BloomMipUp" + i);
  116. ShaderConstants._BloomMipDown[i] = Shader.PropertyToID("_BloomMipDown" + i);
  117. }
  118. m_MRT2 = new RenderTargetIdentifier[2];
  119. m_ResetHistory = true;
  120. base.useNativeRenderPass = false;
  121. }
  122. public void Cleanup() => m_Materials.Cleanup();
  123. public void Setup(in RenderTextureDescriptor baseDescriptor, in RenderTargetHandle source, bool resolveToScreen, in RenderTargetHandle depth, in RenderTargetHandle internalLut, bool hasFinalPass, bool enableSRGBConversion, bool hasExternalPostPasses)
  124. {
  125. m_Descriptor = baseDescriptor;
  126. m_Descriptor.useMipMap = false;
  127. m_Descriptor.autoGenerateMips = false;
  128. m_Source = source.id;
  129. m_Depth = depth;
  130. m_InternalLut = internalLut;
  131. m_IsFinalPass = false;
  132. m_HasFinalPass = hasFinalPass;
  133. m_EnableSRGBConversionIfNeeded = enableSRGBConversion;
  134. m_ResolveToScreen = resolveToScreen;
  135. m_Destination = RenderTargetHandle.CameraTarget;
  136. m_UseSwapBuffer = true;
  137. m_hasExternalPostPasses = hasExternalPostPasses;
  138. }
  139. public void Setup(in RenderTextureDescriptor baseDescriptor, in RenderTargetHandle source, RenderTargetHandle destination, in RenderTargetHandle depth, in RenderTargetHandle internalLut, bool hasFinalPass, bool enableSRGBConversion, bool hasExternalPostPasses)
  140. {
  141. m_Descriptor = baseDescriptor;
  142. m_Descriptor.useMipMap = false;
  143. m_Descriptor.autoGenerateMips = false;
  144. m_Source = source.id;
  145. m_Destination = destination;
  146. m_Depth = depth;
  147. m_InternalLut = internalLut;
  148. m_IsFinalPass = false;
  149. m_HasFinalPass = hasFinalPass;
  150. m_EnableSRGBConversionIfNeeded = enableSRGBConversion;
  151. m_UseSwapBuffer = false;
  152. m_hasExternalPostPasses = hasExternalPostPasses;
  153. }
  154. public void SetupFinalPass(in RenderTargetHandle source, bool useSwapBuffer = false, bool hasExternalPostPasses = true)
  155. {
  156. m_Source = source.id;
  157. m_Destination = RenderTargetHandle.CameraTarget;
  158. m_IsFinalPass = true;
  159. m_HasFinalPass = false;
  160. m_EnableSRGBConversionIfNeeded = true;
  161. m_UseSwapBuffer = useSwapBuffer;
  162. m_hasExternalPostPasses = hasExternalPostPasses;
  163. }
  164. /// <inheritdoc/>
  165. public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
  166. {
  167. overrideCameraTarget = true;
  168. if (m_Destination == RenderTargetHandle.CameraTarget)
  169. return;
  170. // If RenderTargetHandle already has a valid internal render target identifier, we shouldn't request a temp
  171. if (m_Destination.HasInternalRenderTargetId())
  172. return;
  173. var desc = GetCompatibleDescriptor();
  174. desc.depthBufferBits = 0;
  175. cmd.GetTemporaryRT(m_Destination.id, desc, FilterMode.Point);
  176. }
  177. /// <inheritdoc/>
  178. public override void OnCameraCleanup(CommandBuffer cmd)
  179. {
  180. if (m_Destination == RenderTargetHandle.CameraTarget)
  181. return;
  182. // Logic here matches the if check in OnCameraSetup
  183. if (m_Destination.HasInternalRenderTargetId())
  184. return;
  185. cmd.ReleaseTemporaryRT(m_Destination.id);
  186. }
  187. public void ResetHistory()
  188. {
  189. m_ResetHistory = true;
  190. }
  191. public bool CanRunOnTile()
  192. {
  193. // Check builtin & user effects here
  194. return false;
  195. }
  196. /// <inheritdoc/>
  197. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  198. {
  199. // Start by pre-fetching all builtin effect settings we need
  200. // Some of the color-grading settings are only used in the color grading lut pass
  201. var stack = VolumeManager.instance.stack;
  202. m_DepthOfField = stack.GetComponent<DepthOfField>();
  203. m_MotionBlur = stack.GetComponent<MotionBlur>();
  204. m_PaniniProjection = stack.GetComponent<PaniniProjection>();
  205. m_Bloom = stack.GetComponent<Bloom>();
  206. m_LensDistortion = stack.GetComponent<LensDistortion>();
  207. m_ChromaticAberration = stack.GetComponent<ChromaticAberration>();
  208. m_Vignette = stack.GetComponent<Vignette>();
  209. m_ColorLookup = stack.GetComponent<ColorLookup>();
  210. m_ColorAdjustments = stack.GetComponent<ColorAdjustments>();
  211. m_Tonemapping = stack.GetComponent<Tonemapping>();
  212. m_FilmGrain = stack.GetComponent<FilmGrain>();
  213. m_UseDrawProcedural = renderingData.cameraData.xr.enabled;
  214. m_UseFastSRGBLinearConversion = renderingData.postProcessingData.useFastSRGBLinearConversion;
  215. if (m_IsFinalPass)
  216. {
  217. var cmd = CommandBufferPool.Get();
  218. using (new ProfilingScope(cmd, m_ProfilingRenderFinalPostProcessing))
  219. {
  220. RenderFinalPass(cmd, ref renderingData);
  221. }
  222. context.ExecuteCommandBuffer(cmd);
  223. CommandBufferPool.Release(cmd);
  224. }
  225. else if (CanRunOnTile())
  226. {
  227. // 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
  228. // Note: we can still work on-tile if FXAA is enabled, it'd be part of the final pass
  229. }
  230. else
  231. {
  232. // Regular render path (not on-tile) - we do everything in a single command buffer as it
  233. // makes it easier to manage temporary targets' lifetime
  234. var cmd = CommandBufferPool.Get();
  235. using (new ProfilingScope(cmd, m_ProfilingRenderPostProcessing))
  236. {
  237. Render(cmd, ref renderingData);
  238. }
  239. context.ExecuteCommandBuffer(cmd);
  240. CommandBufferPool.Release(cmd);
  241. }
  242. m_ResetHistory = false;
  243. }
  244. RenderTextureDescriptor GetCompatibleDescriptor()
  245. => GetCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, m_Descriptor.graphicsFormat);
  246. RenderTextureDescriptor GetCompatibleDescriptor(int width, int height, GraphicsFormat format, int depthBufferBits = 0)
  247. {
  248. var desc = m_Descriptor;
  249. desc.depthBufferBits = depthBufferBits;
  250. desc.msaaSamples = 1;
  251. desc.width = width;
  252. desc.height = height;
  253. desc.graphicsFormat = format;
  254. return desc;
  255. }
  256. bool RequireSRGBConversionBlitToBackBuffer(CameraData cameraData)
  257. {
  258. return cameraData.requireSrgbConversion && m_EnableSRGBConversionIfNeeded;
  259. }
  260. private new void Blit(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material, int passIndex = 0)
  261. {
  262. cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, source);
  263. if (m_UseDrawProcedural)
  264. {
  265. Vector4 scaleBias = new Vector4(1, 1, 0, 0);
  266. cmd.SetGlobalVector(ShaderPropertyId.scaleBias, scaleBias);
  267. cmd.SetRenderTarget(new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1),
  268. RenderBufferLoadAction.Load, RenderBufferStoreAction.Store, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store);
  269. cmd.DrawProcedural(Matrix4x4.identity, material, passIndex, MeshTopology.Quads, 4, 1, null);
  270. }
  271. else
  272. {
  273. cmd.Blit(source, destination, material, passIndex);
  274. }
  275. }
  276. private void DrawFullscreenMesh(CommandBuffer cmd, Material material, int passIndex)
  277. {
  278. if (m_UseDrawProcedural)
  279. {
  280. Vector4 scaleBias = new Vector4(1, 1, 0, 0);
  281. cmd.SetGlobalVector(ShaderPropertyId.scaleBias, scaleBias);
  282. cmd.DrawProcedural(Matrix4x4.identity, material, passIndex, MeshTopology.Quads, 4, 1, null);
  283. }
  284. else
  285. {
  286. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, material, 0, passIndex);
  287. }
  288. }
  289. void Render(CommandBuffer cmd, ref RenderingData renderingData)
  290. {
  291. ref CameraData cameraData = ref renderingData.cameraData;
  292. ref ScriptableRenderer renderer = ref cameraData.renderer;
  293. bool isSceneViewCamera = cameraData.isSceneViewCamera;
  294. //Check amount of swaps we have to do
  295. //We blit back and forth without msaa untill the last blit.
  296. bool useStopNan = cameraData.isStopNaNEnabled && m_Materials.stopNaN != null;
  297. bool useSubPixeMorpAA = cameraData.antialiasing == AntialiasingMode.SubpixelMorphologicalAntiAliasing && SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES2;
  298. var dofMaterial = m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian ? m_Materials.gaussianDepthOfField : m_Materials.bokehDepthOfField;
  299. bool useDepthOfField = m_DepthOfField.IsActive() && !isSceneViewCamera && dofMaterial != null;
  300. bool useLensFlare = !LensFlareCommonSRP.Instance.IsEmpty();
  301. bool useMotionBlur = m_MotionBlur.IsActive() && !isSceneViewCamera;
  302. bool usePaniniProjection = m_PaniniProjection.IsActive() && !isSceneViewCamera;
  303. int amountOfPassesRemaining = (useStopNan ? 1 : 0) + (useSubPixeMorpAA ? 1 : 0) + (useDepthOfField ? 1 : 0) + (useLensFlare ? 1 : 0) + (useMotionBlur ? 1 : 0) + (usePaniniProjection ? 1 : 0);
  304. if (m_UseSwapBuffer && amountOfPassesRemaining > 0)
  305. {
  306. renderer.EnableSwapBufferMSAA(false);
  307. }
  308. // Don't use these directly unless you have a good reason to, use GetSource() and
  309. // GetDestination() instead
  310. bool tempTargetUsed = false;
  311. bool tempTarget2Used = false;
  312. RenderTargetIdentifier source = m_UseSwapBuffer ? renderer.cameraColorTarget : m_Source;
  313. RenderTargetIdentifier destination = m_UseSwapBuffer ? renderer.GetCameraColorFrontBuffer(cmd) : -1;
  314. RenderTargetIdentifier GetSource() => source;
  315. RenderTargetIdentifier GetDestination()
  316. {
  317. if (m_UseSwapBuffer)
  318. return destination;
  319. else
  320. {
  321. if (destination == -1)
  322. {
  323. cmd.GetTemporaryRT(ShaderConstants._TempTarget, GetCompatibleDescriptor(), FilterMode.Bilinear);
  324. destination = ShaderConstants._TempTarget;
  325. tempTargetUsed = true;
  326. }
  327. else if (destination == m_Source && m_Descriptor.msaaSamples > 1)
  328. {
  329. // 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
  330. cmd.GetTemporaryRT(ShaderConstants._TempTarget2, GetCompatibleDescriptor(), FilterMode.Bilinear);
  331. destination = ShaderConstants._TempTarget2;
  332. tempTarget2Used = true;
  333. }
  334. return destination;
  335. }
  336. }
  337. void Swap(ref ScriptableRenderer r)
  338. {
  339. --amountOfPassesRemaining;
  340. if (m_UseSwapBuffer)
  341. {
  342. //we want the last blit to be to MSAA
  343. if (amountOfPassesRemaining == 0 && !m_HasFinalPass)
  344. {
  345. r.EnableSwapBufferMSAA(true);
  346. }
  347. r.SwapColorBuffer(cmd);
  348. source = r.cameraColorTarget;
  349. destination = r.GetCameraColorFrontBuffer(cmd);
  350. }
  351. else
  352. {
  353. CoreUtils.Swap(ref source, ref destination);
  354. }
  355. }
  356. // Setup projection matrix for cmd.DrawMesh()
  357. cmd.SetGlobalMatrix(ShaderConstants._FullscreenProjMat, GL.GetGPUProjectionMatrix(Matrix4x4.identity, true));
  358. // Optional NaN killer before post-processing kicks in
  359. // stopNaN may be null on Adreno 3xx. It doesn't support full shader level 3.5, but SystemInfo.graphicsShaderLevel is 35.
  360. if (useStopNan)
  361. {
  362. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.StopNaNs)))
  363. {
  364. RenderingUtils.Blit(
  365. cmd, GetSource(), GetDestination(), m_Materials.stopNaN, 0, m_UseDrawProcedural,
  366. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
  367. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  368. Swap(ref renderer);
  369. }
  370. }
  371. // Anti-aliasing
  372. if (useSubPixeMorpAA)
  373. {
  374. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.SMAA)))
  375. {
  376. DoSubpixelMorphologicalAntialiasing(ref cameraData, cmd, GetSource(), GetDestination());
  377. Swap(ref renderer);
  378. }
  379. }
  380. // Depth of Field
  381. // Adreno 3xx SystemInfo.graphicsShaderLevel is 35, but instancing support is disabled due to buggy drivers.
  382. // DOF shader uses #pragma target 3.5 which adds requirement for instancing support, thus marking the shader unsupported on those devices.
  383. if (useDepthOfField)
  384. {
  385. var markerName = m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian
  386. ? URPProfileId.GaussianDepthOfField
  387. : URPProfileId.BokehDepthOfField;
  388. using (new ProfilingScope(cmd, ProfilingSampler.Get(markerName)))
  389. {
  390. DoDepthOfField(cameraData.camera, cmd, GetSource(), GetDestination(), cameraData.pixelRect);
  391. Swap(ref renderer);
  392. }
  393. }
  394. // Motion blur
  395. if (useMotionBlur)
  396. {
  397. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.MotionBlur)))
  398. {
  399. DoMotionBlur(cameraData, cmd, GetSource(), GetDestination());
  400. Swap(ref renderer);
  401. }
  402. }
  403. // Panini projection is done as a fullscreen pass after all depth-based effects are done
  404. // and before bloom kicks in
  405. if (usePaniniProjection)
  406. {
  407. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.PaniniProjection)))
  408. {
  409. DoPaniniProjection(cameraData.camera, cmd, GetSource(), GetDestination());
  410. Swap(ref renderer);
  411. }
  412. }
  413. // Lens Flare
  414. if (useLensFlare)
  415. {
  416. bool usePanini;
  417. float paniniDistance;
  418. float paniniCropToFit;
  419. if (m_PaniniProjection.IsActive())
  420. {
  421. usePanini = true;
  422. paniniDistance = m_PaniniProjection.distance.value;
  423. paniniCropToFit = m_PaniniProjection.cropToFit.value;
  424. }
  425. else
  426. {
  427. usePanini = false;
  428. paniniDistance = 1.0f;
  429. paniniCropToFit = 1.0f;
  430. }
  431. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.LensFlareDataDriven)))
  432. {
  433. DoLensFlareDatadriven(cameraData.camera, cmd, GetSource(), usePanini, paniniDistance, paniniCropToFit);
  434. }
  435. }
  436. // Combined post-processing stack
  437. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.UberPostProcess)))
  438. {
  439. // Reset uber keywords
  440. m_Materials.uber.shaderKeywords = null;
  441. // Bloom goes first
  442. bool bloomActive = m_Bloom.IsActive();
  443. if (bloomActive)
  444. {
  445. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.Bloom)))
  446. SetupBloom(cmd, GetSource(), m_Materials.uber);
  447. }
  448. // Setup other effects constants
  449. SetupLensDistortion(m_Materials.uber, isSceneViewCamera);
  450. SetupChromaticAberration(m_Materials.uber);
  451. SetupVignette(m_Materials.uber);
  452. SetupColorGrading(cmd, ref renderingData, m_Materials.uber);
  453. // Only apply dithering & grain if there isn't a final pass.
  454. SetupGrain(cameraData, m_Materials.uber);
  455. SetupDithering(cameraData, m_Materials.uber);
  456. if (RequireSRGBConversionBlitToBackBuffer(cameraData))
  457. m_Materials.uber.EnableKeyword(ShaderKeywordStrings.LinearToSRGBConversion);
  458. // When we're running FSR upscaling and there's no passes after this (including the FXAA pass), we can safely perform color conversion as part of uber post
  459. // When FSR is active, we're required to provide it with input in a perceptual color space. Ideally, we can just do the color conversion as part of UberPost
  460. // since FSR will *usually* be executed right after it. Unfortunately, there are a couple of situations where this is not true:
  461. // 1. It's possible for users to add their own passes between UberPost and FinalPost. When user passes are present, we're unable to perform the conversion
  462. // here since it'd change the color space that the passes operate in which could lead to incorrect results.
  463. // 2. When FXAA is enabled with FSR, FXAA is moved to an earlier pass to ensure that FSR sees fully anti-aliased input. The moved FXAA pass sits between
  464. // UberPost and FSR so we can no longer perform color conversion here without affecting other passes.
  465. bool doEarlyFsrColorConversion = (!m_hasExternalPostPasses &&
  466. (((cameraData.imageScalingMode == ImageScalingMode.Upscaling) && (cameraData.upscalingFilter == ImageUpscalingFilter.FSR)) &&
  467. (cameraData.antialiasing != AntialiasingMode.FastApproximateAntialiasing)));
  468. if (doEarlyFsrColorConversion)
  469. {
  470. m_Materials.uber.EnableKeyword(ShaderKeywordStrings.Gamma20);
  471. }
  472. if (m_UseFastSRGBLinearConversion)
  473. {
  474. m_Materials.uber.EnableKeyword(ShaderKeywordStrings.UseFastSRGBLinearConversion);
  475. }
  476. GetActiveDebugHandler(renderingData)?.UpdateShaderGlobalPropertiesForFinalValidationPass(cmd, ref cameraData, !m_HasFinalPass);
  477. // Done with Uber, blit it
  478. cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, GetSource());
  479. var colorLoadAction = RenderBufferLoadAction.DontCare;
  480. if (m_Destination == RenderTargetHandle.CameraTarget && !cameraData.isDefaultViewport)
  481. colorLoadAction = RenderBufferLoadAction.Load;
  482. RenderTargetIdentifier targetDestination = m_UseSwapBuffer ? destination : m_Destination.id;
  483. // Note: We rendering to "camera target" we need to get the cameraData.targetTexture as this will get the targetTexture of the camera stack.
  484. // Overlay cameras need to output to the target described in the base camera while doing camera stack.
  485. RenderTargetHandle cameraTargetHandle = RenderTargetHandle.GetCameraTarget(cameraData.xr);
  486. RenderTargetIdentifier cameraTarget = (cameraData.targetTexture != null && !cameraData.xr.enabled) ? new RenderTargetIdentifier(cameraData.targetTexture) : cameraTargetHandle.Identifier();
  487. // With camera stacking we not always resolve post to final screen as we might run post-processing in the middle of the stack.
  488. if (m_UseSwapBuffer)
  489. {
  490. cameraTarget = (m_ResolveToScreen) ? cameraTarget : targetDestination;
  491. }
  492. else
  493. {
  494. cameraTarget = (m_Destination == RenderTargetHandle.CameraTarget) ? cameraTarget : m_Destination.Identifier();
  495. m_ResolveToScreen = cameraData.resolveFinalTarget || (m_Destination == cameraTargetHandle || m_HasFinalPass == true);
  496. }
  497. #if ENABLE_VR && ENABLE_XR_MODULE
  498. if (cameraData.xr.enabled)
  499. {
  500. cmd.SetRenderTarget(new RenderTargetIdentifier(cameraTarget, 0, CubemapFace.Unknown, -1),
  501. colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  502. bool isRenderToBackBufferTarget = cameraTarget == cameraData.xr.renderTarget && !cameraData.xr.renderTargetIsRenderTexture;
  503. if (isRenderToBackBufferTarget)
  504. cmd.SetViewport(cameraData.pixelRect);
  505. // We y-flip if
  506. // 1) we are bliting from render texture to back buffer and
  507. // 2) renderTexture starts UV at top
  508. bool yflip = isRenderToBackBufferTarget && SystemInfo.graphicsUVStartsAtTop;
  509. Vector4 scaleBias = yflip ? new Vector4(1, -1, 0, 1) : new Vector4(1, 1, 0, 0);
  510. cmd.SetGlobalVector(ShaderPropertyId.scaleBias, scaleBias);
  511. cmd.DrawProcedural(Matrix4x4.identity, m_Materials.uber, 0, MeshTopology.Quads, 4, 1, null);
  512. //TODO: Implement swapbuffer in 2DRenderer so we can remove this
  513. // For now, when render post - processing in the middle of the camera stack(not resolving to screen)
  514. // 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
  515. // in the pipeline to avoid this extra blit.
  516. if (!m_ResolveToScreen && !m_UseSwapBuffer)
  517. {
  518. cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, cameraTarget);
  519. cmd.SetRenderTarget(new RenderTargetIdentifier(m_Source, 0, CubemapFace.Unknown, -1),
  520. colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  521. scaleBias = new Vector4(1, 1, 0, 0);;
  522. cmd.SetGlobalVector(ShaderPropertyId.scaleBias, scaleBias);
  523. cmd.DrawProcedural(Matrix4x4.identity, m_BlitMaterial, 0, MeshTopology.Quads, 4, 1, null);
  524. }
  525. }
  526. else
  527. #endif
  528. {
  529. cmd.SetRenderTarget(cameraTarget, colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  530. cameraData.renderer.ConfigureCameraTarget(cameraTarget, cameraTarget);
  531. cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
  532. if ((m_Destination == RenderTargetHandle.CameraTarget && !m_UseSwapBuffer) || (m_ResolveToScreen && m_UseSwapBuffer))
  533. cmd.SetViewport(cameraData.pixelRect);
  534. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_Materials.uber);
  535. // TODO: Implement swapbuffer in 2DRenderer so we can remove this
  536. // For now, when render post-processing in the middle of the camera stack (not resolving to screen)
  537. // 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
  538. // in the pipeline to avoid this extra blit.
  539. if (!m_ResolveToScreen && !m_UseSwapBuffer)
  540. {
  541. cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, cameraTarget);
  542. cmd.SetRenderTarget(m_Source, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  543. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_BlitMaterial);
  544. }
  545. cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);
  546. }
  547. if (m_UseSwapBuffer && !m_ResolveToScreen)
  548. {
  549. renderer.SwapColorBuffer(cmd);
  550. }
  551. // Cleanup
  552. if (bloomActive)
  553. cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipUp[0]);
  554. if (tempTargetUsed)
  555. cmd.ReleaseTemporaryRT(ShaderConstants._TempTarget);
  556. if (tempTarget2Used)
  557. cmd.ReleaseTemporaryRT(ShaderConstants._TempTarget2);
  558. cmd.ReleaseTemporaryRT(m_InternalLut.id);
  559. }
  560. }
  561. private BuiltinRenderTextureType BlitDstDiscardContent(CommandBuffer cmd, RenderTargetIdentifier rt)
  562. {
  563. // We set depth to DontCare because rt might be the source of PostProcessing used as a temporary target
  564. // 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
  565. cmd.SetRenderTarget(new RenderTargetIdentifier(rt, 0, CubemapFace.Unknown, -1),
  566. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
  567. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  568. return BuiltinRenderTextureType.CurrentActive;
  569. }
  570. #region Sub-pixel Morphological Anti-aliasing
  571. void DoSubpixelMorphologicalAntialiasing(ref CameraData cameraData, CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination)
  572. {
  573. var camera = cameraData.camera;
  574. var pixelRect = cameraData.pixelRect;
  575. var material = m_Materials.subpixelMorphologicalAntialiasing;
  576. const int kStencilBit = 64;
  577. // Globals
  578. material.SetVector(ShaderConstants._Metrics, new Vector4(1f / m_Descriptor.width, 1f / m_Descriptor.height, m_Descriptor.width, m_Descriptor.height));
  579. material.SetTexture(ShaderConstants._AreaTexture, m_Data.textures.smaaAreaTex);
  580. material.SetTexture(ShaderConstants._SearchTexture, m_Data.textures.smaaSearchTex);
  581. material.SetFloat(ShaderConstants._StencilRef, (float)kStencilBit);
  582. material.SetFloat(ShaderConstants._StencilMask, (float)kStencilBit);
  583. // Quality presets
  584. material.shaderKeywords = null;
  585. switch (cameraData.antialiasingQuality)
  586. {
  587. case AntialiasingQuality.Low:
  588. material.EnableKeyword(ShaderKeywordStrings.SmaaLow);
  589. break;
  590. case AntialiasingQuality.Medium:
  591. material.EnableKeyword(ShaderKeywordStrings.SmaaMedium);
  592. break;
  593. case AntialiasingQuality.High:
  594. material.EnableKeyword(ShaderKeywordStrings.SmaaHigh);
  595. break;
  596. }
  597. // Intermediate targets
  598. RenderTargetIdentifier stencil; // We would only need stencil, no depth. But Unity doesn't support that.
  599. int tempDepthBits;
  600. if (m_Depth == RenderTargetHandle.CameraTarget || m_Descriptor.msaaSamples > 1)
  601. {
  602. // In case m_Depth is CameraTarget it may refer to the backbuffer and we can't use that as an attachment on all platforms
  603. stencil = ShaderConstants._EdgeTexture;
  604. tempDepthBits = 24;
  605. }
  606. else
  607. {
  608. stencil = m_Depth.Identifier();
  609. tempDepthBits = 0;
  610. }
  611. cmd.GetTemporaryRT(ShaderConstants._EdgeTexture, GetCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, m_SMAAEdgeFormat, tempDepthBits), FilterMode.Bilinear);
  612. cmd.GetTemporaryRT(ShaderConstants._BlendTexture, GetCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, GraphicsFormat.R8G8B8A8_UNorm), FilterMode.Point);
  613. // Prepare for manual blit
  614. cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
  615. cmd.SetViewport(pixelRect);
  616. // Pass 1: Edge detection
  617. cmd.SetRenderTarget(new RenderTargetIdentifier(ShaderConstants._EdgeTexture, 0, CubemapFace.Unknown, -1),
  618. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, stencil,
  619. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
  620. cmd.ClearRenderTarget(RTClearFlags.ColorStencil, Color.clear, 1.0f, 0);
  621. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, source);
  622. DrawFullscreenMesh(cmd, material, 0);
  623. // Pass 2: Blend weights
  624. cmd.SetRenderTarget(new RenderTargetIdentifier(ShaderConstants._BlendTexture, 0, CubemapFace.Unknown, -1),
  625. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, stencil,
  626. RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare);
  627. cmd.ClearRenderTarget(false, true, Color.clear);
  628. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, ShaderConstants._EdgeTexture);
  629. DrawFullscreenMesh(cmd, material, 1);
  630. // Pass 3: Neighborhood blending
  631. cmd.SetRenderTarget(new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1),
  632. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
  633. RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  634. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, source);
  635. cmd.SetGlobalTexture(ShaderConstants._BlendTexture, ShaderConstants._BlendTexture);
  636. DrawFullscreenMesh(cmd, material, 2);
  637. // Cleanup
  638. cmd.ReleaseTemporaryRT(ShaderConstants._EdgeTexture);
  639. cmd.ReleaseTemporaryRT(ShaderConstants._BlendTexture);
  640. cmd.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix);
  641. }
  642. #endregion
  643. #region Depth Of Field
  644. // TODO: CoC reprojection once TAA gets in LW
  645. // TODO: Proper LDR/gamma support
  646. void DoDepthOfField(Camera camera, CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Rect pixelRect)
  647. {
  648. if (m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian)
  649. DoGaussianDepthOfField(camera, cmd, source, destination, pixelRect);
  650. else if (m_DepthOfField.mode.value == DepthOfFieldMode.Bokeh)
  651. DoBokehDepthOfField(cmd, source, destination, pixelRect);
  652. }
  653. void DoGaussianDepthOfField(Camera camera, CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Rect pixelRect)
  654. {
  655. int downSample = 2;
  656. var material = m_Materials.gaussianDepthOfField;
  657. int wh = m_Descriptor.width / downSample;
  658. int hh = m_Descriptor.height / downSample;
  659. float farStart = m_DepthOfField.gaussianStart.value;
  660. float farEnd = Mathf.Max(farStart, m_DepthOfField.gaussianEnd.value);
  661. // Assumes a radius of 1 is 1 at 1080p
  662. // Past a certain radius our gaussian kernel will look very bad so we'll clamp it for
  663. // very high resolutions (4K+).
  664. float maxRadius = m_DepthOfField.gaussianMaxRadius.value * (wh / 1080f);
  665. maxRadius = Mathf.Min(maxRadius, 2f);
  666. CoreUtils.SetKeyword(material, ShaderKeywordStrings.HighQualitySampling, m_DepthOfField.highQualitySampling.value);
  667. material.SetVector(ShaderConstants._CoCParams, new Vector3(farStart, farEnd, maxRadius));
  668. // Temporary textures
  669. cmd.GetTemporaryRT(ShaderConstants._FullCoCTexture, GetCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, m_GaussianCoCFormat), FilterMode.Bilinear);
  670. cmd.GetTemporaryRT(ShaderConstants._HalfCoCTexture, GetCompatibleDescriptor(wh, hh, m_GaussianCoCFormat), FilterMode.Bilinear);
  671. cmd.GetTemporaryRT(ShaderConstants._PingTexture, GetCompatibleDescriptor(wh, hh, m_DefaultHDRFormat), FilterMode.Bilinear);
  672. cmd.GetTemporaryRT(ShaderConstants._PongTexture, GetCompatibleDescriptor(wh, hh, m_DefaultHDRFormat), FilterMode.Bilinear);
  673. // Note: fresh temporary RTs don't require explicit RenderBufferLoadAction.DontCare, only when they are reused (such as PingTexture)
  674. PostProcessUtils.SetSourceSize(cmd, m_Descriptor);
  675. cmd.SetGlobalVector(ShaderConstants._DownSampleScaleFactor, new Vector4(1.0f / downSample, 1.0f / downSample, downSample, downSample));
  676. // Compute CoC
  677. Blit(cmd, source, ShaderConstants._FullCoCTexture, material, 0);
  678. // Downscale & prefilter color + coc
  679. m_MRT2[0] = ShaderConstants._HalfCoCTexture;
  680. m_MRT2[1] = ShaderConstants._PingTexture;
  681. cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
  682. cmd.SetViewport(pixelRect);
  683. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, source);
  684. cmd.SetGlobalTexture(ShaderConstants._FullCoCTexture, ShaderConstants._FullCoCTexture);
  685. cmd.SetRenderTarget(m_MRT2, ShaderConstants._HalfCoCTexture, 0, CubemapFace.Unknown, -1);
  686. DrawFullscreenMesh(cmd, material, 1);
  687. cmd.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix);
  688. // Blur
  689. cmd.SetGlobalTexture(ShaderConstants._HalfCoCTexture, ShaderConstants._HalfCoCTexture);
  690. Blit(cmd, ShaderConstants._PingTexture, ShaderConstants._PongTexture, material, 2);
  691. Blit(cmd, ShaderConstants._PongTexture, BlitDstDiscardContent(cmd, ShaderConstants._PingTexture), material, 3);
  692. // Composite
  693. cmd.SetGlobalTexture(ShaderConstants._ColorTexture, ShaderConstants._PingTexture);
  694. cmd.SetGlobalTexture(ShaderConstants._FullCoCTexture, ShaderConstants._FullCoCTexture);
  695. Blit(cmd, source, BlitDstDiscardContent(cmd, destination), material, 4);
  696. // Cleanup
  697. cmd.ReleaseTemporaryRT(ShaderConstants._FullCoCTexture);
  698. cmd.ReleaseTemporaryRT(ShaderConstants._HalfCoCTexture);
  699. cmd.ReleaseTemporaryRT(ShaderConstants._PingTexture);
  700. cmd.ReleaseTemporaryRT(ShaderConstants._PongTexture);
  701. }
  702. void PrepareBokehKernel(float maxRadius, float rcpAspect)
  703. {
  704. const int kRings = 4;
  705. const int kPointsPerRing = 7;
  706. // Check the existing array
  707. if (m_BokehKernel == null)
  708. m_BokehKernel = new Vector4[42];
  709. // Fill in sample points (concentric circles transformed to rotated N-Gon)
  710. int idx = 0;
  711. float bladeCount = m_DepthOfField.bladeCount.value;
  712. float curvature = 1f - m_DepthOfField.bladeCurvature.value;
  713. float rotation = m_DepthOfField.bladeRotation.value * Mathf.Deg2Rad;
  714. const float PI = Mathf.PI;
  715. const float TWO_PI = Mathf.PI * 2f;
  716. for (int ring = 1; ring < kRings; ring++)
  717. {
  718. float bias = 1f / kPointsPerRing;
  719. float radius = (ring + bias) / (kRings - 1f + bias);
  720. int points = ring * kPointsPerRing;
  721. for (int point = 0; point < points; point++)
  722. {
  723. // Angle on ring
  724. float phi = 2f * PI * point / points;
  725. // Transform to rotated N-Gon
  726. // Adapted from "CryEngine 3 Graphics Gems" [Sousa13]
  727. float nt = Mathf.Cos(PI / bladeCount);
  728. float dt = Mathf.Cos(phi - (TWO_PI / bladeCount) * Mathf.Floor((bladeCount * phi + Mathf.PI) / TWO_PI));
  729. float r = radius * Mathf.Pow(nt / dt, curvature);
  730. float u = r * Mathf.Cos(phi - rotation);
  731. float v = r * Mathf.Sin(phi - rotation);
  732. float uRadius = u * maxRadius;
  733. float vRadius = v * maxRadius;
  734. float uRadiusPowTwo = uRadius * uRadius;
  735. float vRadiusPowTwo = vRadius * vRadius;
  736. float kernelLength = Mathf.Sqrt((uRadiusPowTwo + vRadiusPowTwo));
  737. float uRCP = uRadius * rcpAspect;
  738. m_BokehKernel[idx] = new Vector4(uRadius, vRadius, kernelLength, uRCP);
  739. idx++;
  740. }
  741. }
  742. }
  743. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  744. static float GetMaxBokehRadiusInPixels(float viewportHeight)
  745. {
  746. // Estimate the maximum radius of bokeh (empirically derived from the ring count)
  747. const float kRadiusInPixels = 14f;
  748. return Mathf.Min(0.05f, kRadiusInPixels / viewportHeight);
  749. }
  750. void DoBokehDepthOfField(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Rect pixelRect)
  751. {
  752. int downSample = 2;
  753. var material = m_Materials.bokehDepthOfField;
  754. int wh = m_Descriptor.width / downSample;
  755. int hh = m_Descriptor.height / downSample;
  756. // "A Lens and Aperture Camera Model for Synthetic Image Generation" [Potmesil81]
  757. float F = m_DepthOfField.focalLength.value / 1000f;
  758. float A = m_DepthOfField.focalLength.value / m_DepthOfField.aperture.value;
  759. float P = m_DepthOfField.focusDistance.value;
  760. float maxCoC = (A * F) / (P - F);
  761. float maxRadius = GetMaxBokehRadiusInPixels(m_Descriptor.height);
  762. float rcpAspect = 1f / (wh / (float)hh);
  763. CoreUtils.SetKeyword(material, ShaderKeywordStrings.UseFastSRGBLinearConversion, m_UseFastSRGBLinearConversion);
  764. cmd.SetGlobalVector(ShaderConstants._CoCParams, new Vector4(P, maxCoC, maxRadius, rcpAspect));
  765. // Prepare the bokeh kernel constant buffer
  766. int hash = m_DepthOfField.GetHashCode();
  767. if (hash != m_BokehHash || maxRadius != m_BokehMaxRadius || rcpAspect != m_BokehRCPAspect)
  768. {
  769. m_BokehHash = hash;
  770. m_BokehMaxRadius = maxRadius;
  771. m_BokehRCPAspect = rcpAspect;
  772. PrepareBokehKernel(maxRadius, rcpAspect);
  773. }
  774. cmd.SetGlobalVectorArray(ShaderConstants._BokehKernel, m_BokehKernel);
  775. // Temporary textures
  776. cmd.GetTemporaryRT(ShaderConstants._FullCoCTexture, GetCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, GraphicsFormat.R8_UNorm), FilterMode.Bilinear);
  777. cmd.GetTemporaryRT(ShaderConstants._PingTexture, GetCompatibleDescriptor(wh, hh, GraphicsFormat.R16G16B16A16_SFloat), FilterMode.Bilinear);
  778. cmd.GetTemporaryRT(ShaderConstants._PongTexture, GetCompatibleDescriptor(wh, hh, GraphicsFormat.R16G16B16A16_SFloat), FilterMode.Bilinear);
  779. PostProcessUtils.SetSourceSize(cmd, m_Descriptor);
  780. cmd.SetGlobalVector(ShaderConstants._DownSampleScaleFactor, new Vector4(1.0f / downSample, 1.0f / downSample, downSample, downSample));
  781. float uvMargin = (1.0f / m_Descriptor.height) * downSample;
  782. cmd.SetGlobalVector(ShaderConstants._BokehConstants, new Vector4(uvMargin, uvMargin * 2.0f));
  783. // Compute CoC
  784. Blit(cmd, source, ShaderConstants._FullCoCTexture, material, 0);
  785. cmd.SetGlobalTexture(ShaderConstants._FullCoCTexture, ShaderConstants._FullCoCTexture);
  786. // Downscale & prefilter color + coc
  787. Blit(cmd, source, ShaderConstants._PingTexture, material, 1);
  788. // Bokeh blur
  789. Blit(cmd, ShaderConstants._PingTexture, ShaderConstants._PongTexture, material, 2);
  790. // Post-filtering
  791. Blit(cmd, ShaderConstants._PongTexture, BlitDstDiscardContent(cmd, ShaderConstants._PingTexture), material, 3);
  792. // Composite
  793. cmd.SetGlobalTexture(ShaderConstants._DofTexture, ShaderConstants._PingTexture);
  794. Blit(cmd, source, BlitDstDiscardContent(cmd, destination), material, 4);
  795. // Cleanup
  796. cmd.ReleaseTemporaryRT(ShaderConstants._FullCoCTexture);
  797. cmd.ReleaseTemporaryRT(ShaderConstants._PingTexture);
  798. cmd.ReleaseTemporaryRT(ShaderConstants._PongTexture);
  799. }
  800. #endregion
  801. #region LensFlareDataDriven
  802. static float GetLensFlareLightAttenuation(Light light, Camera cam, Vector3 wo)
  803. {
  804. // Must always be true
  805. if (light != null)
  806. {
  807. switch (light.type)
  808. {
  809. case LightType.Directional:
  810. return LensFlareCommonSRP.ShapeAttenuationDirLight(light.transform.forward, wo);
  811. case LightType.Point:
  812. return LensFlareCommonSRP.ShapeAttenuationPointLight();
  813. case LightType.Spot:
  814. return LensFlareCommonSRP.ShapeAttenuationSpotConeLight(light.transform.forward, wo, light.spotAngle, light.innerSpotAngle / 180.0f);
  815. default:
  816. return 1.0f;
  817. }
  818. }
  819. return 1.0f;
  820. }
  821. void DoLensFlareDatadriven(Camera camera, CommandBuffer cmd, RenderTargetIdentifier source, bool usePanini, float paniniDistance, float paniniCropToFit)
  822. {
  823. var gpuView = camera.worldToCameraMatrix;
  824. var gpuNonJitteredProj = GL.GetGPUProjectionMatrix(camera.projectionMatrix, true);
  825. // Zero out the translation component.
  826. gpuView.SetColumn(3, new Vector4(0, 0, 0, 1));
  827. var gpuVP = gpuNonJitteredProj * camera.worldToCameraMatrix;
  828. LensFlareCommonSRP.DoLensFlareDataDrivenCommon(m_Materials.lensFlareDataDriven, LensFlareCommonSRP.Instance, camera, (float)m_Descriptor.width, (float)m_Descriptor.height,
  829. usePanini, paniniDistance, paniniCropToFit,
  830. true,
  831. camera.transform.position,
  832. gpuVP,
  833. cmd, source,
  834. (Light light, Camera cam, Vector3 wo) => { return GetLensFlareLightAttenuation(light, cam, wo); },
  835. ShaderConstants._FlareOcclusionTex, ShaderConstants._FlareOcclusionIndex,
  836. ShaderConstants._FlareTex, ShaderConstants._FlareColorValue,
  837. ShaderConstants._FlareData0, ShaderConstants._FlareData1, ShaderConstants._FlareData2, ShaderConstants._FlareData3, ShaderConstants._FlareData4,
  838. false);
  839. }
  840. #endregion
  841. #region Motion Blur
  842. #if ENABLE_VR && ENABLE_XR_MODULE
  843. // Hold the stereo matrices to avoid allocating arrays every frame
  844. internal static readonly Matrix4x4[] viewProjMatrixStereo = new Matrix4x4[2];
  845. #endif
  846. void DoMotionBlur(CameraData cameraData, CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination)
  847. {
  848. var material = m_Materials.cameraMotionBlur;
  849. #if ENABLE_VR && ENABLE_XR_MODULE
  850. if (cameraData.xr.enabled && cameraData.xr.singlePassEnabled)
  851. {
  852. var viewProj0 = GL.GetGPUProjectionMatrix(cameraData.GetProjectionMatrix(0), true) * cameraData.GetViewMatrix(0);
  853. var viewProj1 = GL.GetGPUProjectionMatrix(cameraData.GetProjectionMatrix(1), true) * cameraData.GetViewMatrix(1);
  854. if (m_ResetHistory)
  855. {
  856. viewProjMatrixStereo[0] = viewProj0;
  857. viewProjMatrixStereo[1] = viewProj1;
  858. material.SetMatrixArray("_PrevViewProjMStereo", viewProjMatrixStereo);
  859. }
  860. else
  861. material.SetMatrixArray("_PrevViewProjMStereo", m_PrevViewProjM);
  862. m_PrevViewProjM[0] = viewProj0;
  863. m_PrevViewProjM[1] = viewProj1;
  864. }
  865. else
  866. #endif
  867. {
  868. int prevViewProjMIdx = 0;
  869. #if ENABLE_VR && ENABLE_XR_MODULE
  870. if (cameraData.xr.enabled)
  871. prevViewProjMIdx = cameraData.xr.multipassId;
  872. #endif
  873. // This is needed because Blit will reset viewproj matrices to identity and UniversalRP currently
  874. // relies on SetupCameraProperties instead of handling its own matrices.
  875. // TODO: We need get rid of SetupCameraProperties and setup camera matrices in Universal
  876. var proj = cameraData.GetProjectionMatrix();
  877. var view = cameraData.GetViewMatrix();
  878. var viewProj = proj * view;
  879. material.SetMatrix("_ViewProjM", viewProj);
  880. if (m_ResetHistory)
  881. material.SetMatrix("_PrevViewProjM", viewProj);
  882. else
  883. material.SetMatrix("_PrevViewProjM", m_PrevViewProjM[prevViewProjMIdx]);
  884. m_PrevViewProjM[prevViewProjMIdx] = viewProj;
  885. }
  886. material.SetFloat("_Intensity", m_MotionBlur.intensity.value);
  887. material.SetFloat("_Clamp", m_MotionBlur.clamp.value);
  888. PostProcessUtils.SetSourceSize(cmd, m_Descriptor);
  889. Blit(cmd, source, BlitDstDiscardContent(cmd, destination), material, (int)m_MotionBlur.quality.value);
  890. }
  891. #endregion
  892. #region Panini Projection
  893. // Back-ported & adapted from the work of the Stockholm demo team - thanks Lasse!
  894. void DoPaniniProjection(Camera camera, CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination)
  895. {
  896. float distance = m_PaniniProjection.distance.value;
  897. var viewExtents = CalcViewExtents(camera);
  898. var cropExtents = CalcCropExtents(camera, distance);
  899. float scaleX = cropExtents.x / viewExtents.x;
  900. float scaleY = cropExtents.y / viewExtents.y;
  901. float scaleF = Mathf.Min(scaleX, scaleY);
  902. float paniniD = distance;
  903. float paniniS = Mathf.Lerp(1f, Mathf.Clamp01(scaleF), m_PaniniProjection.cropToFit.value);
  904. var material = m_Materials.paniniProjection;
  905. material.SetVector(ShaderConstants._Params, new Vector4(viewExtents.x, viewExtents.y, paniniD, paniniS));
  906. material.EnableKeyword(
  907. 1f - Mathf.Abs(paniniD) > float.Epsilon
  908. ? ShaderKeywordStrings.PaniniGeneric : ShaderKeywordStrings.PaniniUnitDistance
  909. );
  910. Blit(cmd, source, BlitDstDiscardContent(cmd, destination), material);
  911. }
  912. Vector2 CalcViewExtents(Camera camera)
  913. {
  914. float fovY = camera.fieldOfView * Mathf.Deg2Rad;
  915. float aspect = m_Descriptor.width / (float)m_Descriptor.height;
  916. float viewExtY = Mathf.Tan(0.5f * fovY);
  917. float viewExtX = aspect * viewExtY;
  918. return new Vector2(viewExtX, viewExtY);
  919. }
  920. Vector2 CalcCropExtents(Camera camera, float d)
  921. {
  922. // given
  923. // S----------- E--X-------
  924. // | ` ~. /,´
  925. // |-- --- Q
  926. // | ,/ `
  927. // 1 | ,´/ `
  928. // | ,´ / ´
  929. // | ,´ / ´
  930. // |,` / ,
  931. // O /
  932. // | / ,
  933. // d | /
  934. // | / ,
  935. // |/ .
  936. // P
  937. // | ´
  938. // | , ´
  939. // +- ´
  940. //
  941. // have X
  942. // want to find E
  943. float viewDist = 1f + d;
  944. var projPos = CalcViewExtents(camera);
  945. var projHyp = Mathf.Sqrt(projPos.x * projPos.x + 1f);
  946. float cylDistMinusD = 1f / projHyp;
  947. float cylDist = cylDistMinusD + d;
  948. var cylPos = projPos * cylDistMinusD;
  949. return cylPos * (viewDist / cylDist);
  950. }
  951. #endregion
  952. #region Bloom
  953. void SetupBloom(CommandBuffer cmd, RenderTargetIdentifier source, Material uberMaterial)
  954. {
  955. // Start at half-res
  956. int tw = m_Descriptor.width >> 1;
  957. int th = m_Descriptor.height >> 1;
  958. // Determine the iteration count
  959. int maxSize = Mathf.Max(tw, th);
  960. int iterations = Mathf.FloorToInt(Mathf.Log(maxSize, 2f) - 1);
  961. iterations -= m_Bloom.skipIterations.value;
  962. int mipCount = Mathf.Clamp(iterations, 1, k_MaxPyramidSize);
  963. // Pre-filtering parameters
  964. float clamp = m_Bloom.clamp.value;
  965. float threshold = Mathf.GammaToLinearSpace(m_Bloom.threshold.value);
  966. float thresholdKnee = threshold * 0.5f; // Hardcoded soft knee
  967. // Material setup
  968. float scatter = Mathf.Lerp(0.05f, 0.95f, m_Bloom.scatter.value);
  969. var bloomMaterial = m_Materials.bloom;
  970. bloomMaterial.SetVector(ShaderConstants._Params, new Vector4(scatter, clamp, threshold, thresholdKnee));
  971. CoreUtils.SetKeyword(bloomMaterial, ShaderKeywordStrings.BloomHQ, m_Bloom.highQualityFiltering.value);
  972. CoreUtils.SetKeyword(bloomMaterial, ShaderKeywordStrings.UseRGBM, m_UseRGBM);
  973. // Prefilter
  974. var desc = GetCompatibleDescriptor(tw, th, m_DefaultHDRFormat);
  975. cmd.GetTemporaryRT(ShaderConstants._BloomMipDown[0], desc, FilterMode.Bilinear);
  976. cmd.GetTemporaryRT(ShaderConstants._BloomMipUp[0], desc, FilterMode.Bilinear);
  977. Blit(cmd, source, ShaderConstants._BloomMipDown[0], bloomMaterial, 0);
  978. // Downsample - gaussian pyramid
  979. int lastDown = ShaderConstants._BloomMipDown[0];
  980. for (int i = 1; i < mipCount; i++)
  981. {
  982. tw = Mathf.Max(1, tw >> 1);
  983. th = Mathf.Max(1, th >> 1);
  984. int mipDown = ShaderConstants._BloomMipDown[i];
  985. int mipUp = ShaderConstants._BloomMipUp[i];
  986. desc.width = tw;
  987. desc.height = th;
  988. cmd.GetTemporaryRT(mipDown, desc, FilterMode.Bilinear);
  989. cmd.GetTemporaryRT(mipUp, desc, FilterMode.Bilinear);
  990. // Classic two pass gaussian blur - use mipUp as a temporary target
  991. // First pass does 2x downsampling + 9-tap gaussian
  992. // Second pass does 9-tap gaussian using a 5-tap filter + bilinear filtering
  993. Blit(cmd, lastDown, mipUp, bloomMaterial, 1);
  994. Blit(cmd, mipUp, mipDown, bloomMaterial, 2);
  995. lastDown = mipDown;
  996. }
  997. // Upsample (bilinear by default, HQ filtering does bicubic instead
  998. for (int i = mipCount - 2; i >= 0; i--)
  999. {
  1000. int lowMip = (i == mipCount - 2) ? ShaderConstants._BloomMipDown[i + 1] : ShaderConstants._BloomMipUp[i + 1];
  1001. int highMip = ShaderConstants._BloomMipDown[i];
  1002. int dst = ShaderConstants._BloomMipUp[i];
  1003. cmd.SetGlobalTexture(ShaderConstants._SourceTexLowMip, lowMip);
  1004. Blit(cmd, highMip, BlitDstDiscardContent(cmd, dst), bloomMaterial, 3);
  1005. }
  1006. // Cleanup
  1007. for (int i = 0; i < mipCount; i++)
  1008. {
  1009. cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipDown[i]);
  1010. if (i > 0) cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipUp[i]);
  1011. }
  1012. // Setup bloom on uber
  1013. var tint = m_Bloom.tint.value.linear;
  1014. var luma = ColorUtils.Luminance(tint);
  1015. tint = luma > 0f ? tint * (1f / luma) : Color.white;
  1016. var bloomParams = new Vector4(m_Bloom.intensity.value, tint.r, tint.g, tint.b);
  1017. uberMaterial.SetVector(ShaderConstants._Bloom_Params, bloomParams);
  1018. uberMaterial.SetFloat(ShaderConstants._Bloom_RGBM, m_UseRGBM ? 1f : 0f);
  1019. cmd.SetGlobalTexture(ShaderConstants._Bloom_Texture, ShaderConstants._BloomMipUp[0]);
  1020. // Setup lens dirtiness on uber
  1021. // Keep the aspect ratio correct & center the dirt texture, we don't want it to be
  1022. // stretched or squashed
  1023. var dirtTexture = m_Bloom.dirtTexture.value == null ? Texture2D.blackTexture : m_Bloom.dirtTexture.value;
  1024. float dirtRatio = dirtTexture.width / (float)dirtTexture.height;
  1025. float screenRatio = m_Descriptor.width / (float)m_Descriptor.height;
  1026. var dirtScaleOffset = new Vector4(1f, 1f, 0f, 0f);
  1027. float dirtIntensity = m_Bloom.dirtIntensity.value;
  1028. if (dirtRatio > screenRatio)
  1029. {
  1030. dirtScaleOffset.x = screenRatio / dirtRatio;
  1031. dirtScaleOffset.z = (1f - dirtScaleOffset.x) * 0.5f;
  1032. }
  1033. else if (screenRatio > dirtRatio)
  1034. {
  1035. dirtScaleOffset.y = dirtRatio / screenRatio;
  1036. dirtScaleOffset.w = (1f - dirtScaleOffset.y) * 0.5f;
  1037. }
  1038. uberMaterial.SetVector(ShaderConstants._LensDirt_Params, dirtScaleOffset);
  1039. uberMaterial.SetFloat(ShaderConstants._LensDirt_Intensity, dirtIntensity);
  1040. uberMaterial.SetTexture(ShaderConstants._LensDirt_Texture, dirtTexture);
  1041. // Keyword setup - a bit convoluted as we're trying to save some variants in Uber...
  1042. if (m_Bloom.highQualityFiltering.value)
  1043. uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomHQDirt : ShaderKeywordStrings.BloomHQ);
  1044. else
  1045. uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomLQDirt : ShaderKeywordStrings.BloomLQ);
  1046. }
  1047. #endregion
  1048. #region Lens Distortion
  1049. void SetupLensDistortion(Material material, bool isSceneView)
  1050. {
  1051. float amount = 1.6f * Mathf.Max(Mathf.Abs(m_LensDistortion.intensity.value * 100f), 1f);
  1052. float theta = Mathf.Deg2Rad * Mathf.Min(160f, amount);
  1053. float sigma = 2f * Mathf.Tan(theta * 0.5f);
  1054. var center = m_LensDistortion.center.value * 2f - Vector2.one;
  1055. var p1 = new Vector4(
  1056. center.x,
  1057. center.y,
  1058. Mathf.Max(m_LensDistortion.xMultiplier.value, 1e-4f),
  1059. Mathf.Max(m_LensDistortion.yMultiplier.value, 1e-4f)
  1060. );
  1061. var p2 = new Vector4(
  1062. m_LensDistortion.intensity.value >= 0f ? theta : 1f / theta,
  1063. sigma,
  1064. 1f / m_LensDistortion.scale.value,
  1065. m_LensDistortion.intensity.value * 100f
  1066. );
  1067. material.SetVector(ShaderConstants._Distortion_Params1, p1);
  1068. material.SetVector(ShaderConstants._Distortion_Params2, p2);
  1069. if (m_LensDistortion.IsActive() && !isSceneView)
  1070. material.EnableKeyword(ShaderKeywordStrings.Distortion);
  1071. }
  1072. #endregion
  1073. #region Chromatic Aberration
  1074. void SetupChromaticAberration(Material material)
  1075. {
  1076. material.SetFloat(ShaderConstants._Chroma_Params, m_ChromaticAberration.intensity.value * 0.05f);
  1077. if (m_ChromaticAberration.IsActive())
  1078. material.EnableKeyword(ShaderKeywordStrings.ChromaticAberration);
  1079. }
  1080. #endregion
  1081. #region Vignette
  1082. void SetupVignette(Material material)
  1083. {
  1084. var color = m_Vignette.color.value;
  1085. var center = m_Vignette.center.value;
  1086. var aspectRatio = m_Descriptor.width / (float)m_Descriptor.height;
  1087. var v1 = new Vector4(
  1088. color.r, color.g, color.b,
  1089. m_Vignette.rounded.value ? aspectRatio : 1f
  1090. );
  1091. var v2 = new Vector4(
  1092. center.x, center.y,
  1093. m_Vignette.intensity.value * 3f,
  1094. m_Vignette.smoothness.value * 5f
  1095. );
  1096. material.SetVector(ShaderConstants._Vignette_Params1, v1);
  1097. material.SetVector(ShaderConstants._Vignette_Params2, v2);
  1098. }
  1099. #endregion
  1100. #region Color Grading
  1101. void SetupColorGrading(CommandBuffer cmd, ref RenderingData renderingData, Material material)
  1102. {
  1103. ref var postProcessingData = ref renderingData.postProcessingData;
  1104. bool hdr = postProcessingData.gradingMode == ColorGradingMode.HighDynamicRange;
  1105. int lutHeight = postProcessingData.lutSize;
  1106. int lutWidth = lutHeight * lutHeight;
  1107. // Source material setup
  1108. float postExposureLinear = Mathf.Pow(2f, m_ColorAdjustments.postExposure.value);
  1109. cmd.SetGlobalTexture(ShaderConstants._InternalLut, m_InternalLut.Identifier());
  1110. material.SetVector(ShaderConstants._Lut_Params, new Vector4(1f / lutWidth, 1f / lutHeight, lutHeight - 1f, postExposureLinear));
  1111. material.SetTexture(ShaderConstants._UserLut, m_ColorLookup.texture.value);
  1112. material.SetVector(ShaderConstants._UserLut_Params, !m_ColorLookup.IsActive()
  1113. ? Vector4.zero
  1114. : new Vector4(1f / m_ColorLookup.texture.value.width,
  1115. 1f / m_ColorLookup.texture.value.height,
  1116. m_ColorLookup.texture.value.height - 1f,
  1117. m_ColorLookup.contribution.value)
  1118. );
  1119. if (hdr)
  1120. {
  1121. material.EnableKeyword(ShaderKeywordStrings.HDRGrading);
  1122. }
  1123. else
  1124. {
  1125. switch (m_Tonemapping.mode.value)
  1126. {
  1127. case TonemappingMode.Neutral: material.EnableKeyword(ShaderKeywordStrings.TonemapNeutral); break;
  1128. case TonemappingMode.ACES: material.EnableKeyword(ShaderKeywordStrings.TonemapACES); break;
  1129. default: break; // None
  1130. }
  1131. }
  1132. }
  1133. #endregion
  1134. #region Film Grain
  1135. void SetupGrain(in CameraData cameraData, Material material)
  1136. {
  1137. if (!m_HasFinalPass && m_FilmGrain.IsActive())
  1138. {
  1139. material.EnableKeyword(ShaderKeywordStrings.FilmGrain);
  1140. PostProcessUtils.ConfigureFilmGrain(
  1141. m_Data,
  1142. m_FilmGrain,
  1143. cameraData.pixelWidth, cameraData.pixelHeight,
  1144. material
  1145. );
  1146. }
  1147. }
  1148. #endregion
  1149. #region 8-bit Dithering
  1150. void SetupDithering(in CameraData cameraData, Material material)
  1151. {
  1152. if (!m_HasFinalPass && cameraData.isDitheringEnabled)
  1153. {
  1154. material.EnableKeyword(ShaderKeywordStrings.Dithering);
  1155. m_DitheringTextureIndex = PostProcessUtils.ConfigureDithering(
  1156. m_Data,
  1157. m_DitheringTextureIndex,
  1158. cameraData.pixelWidth, cameraData.pixelHeight,
  1159. material
  1160. );
  1161. }
  1162. }
  1163. #endregion
  1164. #region Final pass
  1165. void RenderFinalPass(CommandBuffer cmd, ref RenderingData renderingData)
  1166. {
  1167. ref var cameraData = ref renderingData.cameraData;
  1168. var material = m_Materials.finalPass;
  1169. material.shaderKeywords = null;
  1170. PostProcessUtils.SetSourceSize(cmd, cameraData.cameraTargetDescriptor);
  1171. SetupGrain(cameraData, material);
  1172. SetupDithering(cameraData, material);
  1173. if (RequireSRGBConversionBlitToBackBuffer(cameraData))
  1174. material.EnableKeyword(ShaderKeywordStrings.LinearToSRGBConversion);
  1175. GetActiveDebugHandler(renderingData)?.UpdateShaderGlobalPropertiesForFinalValidationPass(cmd, ref cameraData, m_IsFinalPass);
  1176. if (!m_UseSwapBuffer)
  1177. {
  1178. cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, m_Source);
  1179. }
  1180. else if (m_Source == cameraData.renderer.GetCameraColorFrontBuffer(cmd))
  1181. {
  1182. m_Source = cameraData.renderer.cameraColorTarget;
  1183. }
  1184. cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, m_Source);
  1185. var colorLoadAction = cameraData.isDefaultViewport ? RenderBufferLoadAction.DontCare : RenderBufferLoadAction.Load;
  1186. bool isScalingSetupUsed = false;
  1187. bool isUpscaledTextureUsed = false;
  1188. bool isFxaaEnabled = (cameraData.antialiasing == AntialiasingMode.FastApproximateAntialiasing);
  1189. if (cameraData.imageScalingMode != ImageScalingMode.None)
  1190. {
  1191. // FSR is only considered "enabled" when we're performing upscaling. (downscaling uses a linear filter unconditionally)
  1192. bool isFsrEnabled = ((cameraData.imageScalingMode == ImageScalingMode.Upscaling) && (cameraData.upscalingFilter == ImageUpscalingFilter.FSR));
  1193. bool doLateFsrColorConversion = (isFsrEnabled && (isFxaaEnabled || m_hasExternalPostPasses));
  1194. // When FXAA is enabled in scaled renders, we execute it in a separate blit since it's not designed to be used in
  1195. // situations where the input and output resolutions do not match.
  1196. // When FSR is active and we didn't perform color conversion earlier, we do it now as part of the setup blit.
  1197. bool isSetupRequired = (isFxaaEnabled || doLateFsrColorConversion);
  1198. // Make sure to remove any MSAA and attached depth buffers from the temporary render targets
  1199. var tempRtDesc = cameraData.cameraTargetDescriptor;
  1200. tempRtDesc.msaaSamples = 1;
  1201. tempRtDesc.depthBufferBits = 0;
  1202. m_Materials.scalingSetup.shaderKeywords = null;
  1203. var sourceRtId = m_Source;
  1204. if (isSetupRequired)
  1205. {
  1206. if (isFxaaEnabled)
  1207. {
  1208. m_Materials.scalingSetup.EnableKeyword(ShaderKeywordStrings.Fxaa);
  1209. }
  1210. if (doLateFsrColorConversion)
  1211. {
  1212. m_Materials.scalingSetup.EnableKeyword(ShaderKeywordStrings.Gamma20);
  1213. }
  1214. cmd.GetTemporaryRT(ShaderConstants._ScalingSetupTexture, tempRtDesc, FilterMode.Point);
  1215. isScalingSetupUsed = true;
  1216. Blit(cmd, m_Source, ShaderConstants._ScalingSetupTexture, m_Materials.scalingSetup);
  1217. cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, ShaderConstants._ScalingSetupTexture);
  1218. sourceRtId = ShaderConstants._ScalingSetupTexture;
  1219. }
  1220. switch (cameraData.imageScalingMode)
  1221. {
  1222. case ImageScalingMode.Upscaling:
  1223. {
  1224. // In the upscaling case, set material keywords based on the selected upscaling filter
  1225. // Note: If FSR is enabled, we go down this path regardless of the current render scale. We do this because
  1226. // FSR still provides visual benefits at 100% scale. This will also make the transition between 99% and 100%
  1227. // scale less obvious for cases where FSR is used with dynamic resolution scaling.
  1228. switch (cameraData.upscalingFilter)
  1229. {
  1230. case ImageUpscalingFilter.Point:
  1231. {
  1232. material.EnableKeyword(ShaderKeywordStrings.PointSampling);
  1233. break;
  1234. }
  1235. case ImageUpscalingFilter.Linear:
  1236. {
  1237. // Do nothing as linear is the default filter in the shader
  1238. break;
  1239. }
  1240. case ImageUpscalingFilter.FSR:
  1241. {
  1242. m_Materials.easu.shaderKeywords = null;
  1243. var upscaleRtDesc = tempRtDesc;
  1244. upscaleRtDesc.width = cameraData.pixelWidth;
  1245. upscaleRtDesc.height = cameraData.pixelHeight;
  1246. // EASU
  1247. cmd.GetTemporaryRT(ShaderConstants._UpscaledTexture, upscaleRtDesc, FilterMode.Point);
  1248. isUpscaledTextureUsed = true;
  1249. var fsrInputSize = new Vector2(cameraData.cameraTargetDescriptor.width, cameraData.cameraTargetDescriptor.height);
  1250. var fsrOutputSize = new Vector2(cameraData.pixelWidth, cameraData.pixelHeight);
  1251. FSRUtils.SetEasuConstants(cmd, fsrInputSize, fsrInputSize, fsrOutputSize);
  1252. Blit(cmd, sourceRtId, ShaderConstants._UpscaledTexture, m_Materials.easu);
  1253. // RCAS
  1254. // Use the override value if it's available, otherwise use the default.
  1255. float sharpness = cameraData.fsrOverrideSharpness ? cameraData.fsrSharpness : FSRUtils.kDefaultSharpnessLinear;
  1256. // Set up the parameters for the RCAS pass unless the sharpness value indicates that it wont have any effect.
  1257. if (cameraData.fsrSharpness > 0.0f)
  1258. {
  1259. // RCAS is performed during the final post blit, but we set up the parameters here for better logical grouping.
  1260. material.EnableKeyword(ShaderKeywordStrings.Rcas);
  1261. FSRUtils.SetRcasConstantsLinear(cmd, sharpness);
  1262. }
  1263. // Update the source texture for the next operation
  1264. cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, ShaderConstants._UpscaledTexture);
  1265. PostProcessUtils.SetSourceSize(cmd, upscaleRtDesc);
  1266. break;
  1267. }
  1268. }
  1269. break;
  1270. }
  1271. case ImageScalingMode.Downscaling:
  1272. {
  1273. // In the downscaling case, we don't perform any sort of filter override logic since we always want linear filtering
  1274. // and it's already the default option in the shader.
  1275. break;
  1276. }
  1277. }
  1278. }
  1279. else if (isFxaaEnabled)
  1280. {
  1281. // In unscaled renders, FXAA can be safely performed in the FinalPost shader
  1282. material.EnableKeyword(ShaderKeywordStrings.Fxaa);
  1283. }
  1284. RenderTargetHandle cameraTargetHandle = RenderTargetHandle.GetCameraTarget(cameraData.xr);
  1285. #if ENABLE_VR && ENABLE_XR_MODULE
  1286. if (cameraData.xr.enabled)
  1287. {
  1288. RenderTargetIdentifier cameraTarget = cameraTargetHandle.Identifier();
  1289. //Blit(cmd, m_Source.Identifier(), BuiltinRenderTextureType.CurrentActive, material);
  1290. bool isRenderToBackBufferTarget = cameraTarget == cameraData.xr.renderTarget && !cameraData.xr.renderTargetIsRenderTexture;
  1291. // We y-flip if
  1292. // 1) we are bliting from render texture to back buffer and
  1293. // 2) renderTexture starts UV at top
  1294. bool yflip = isRenderToBackBufferTarget && SystemInfo.graphicsUVStartsAtTop;
  1295. Vector4 scaleBias = yflip ? new Vector4(1, -1, 0, 1) : new Vector4(1, 1, 0, 0);
  1296. cmd.SetRenderTarget(new RenderTargetIdentifier(cameraTarget, 0, CubemapFace.Unknown, -1),
  1297. colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  1298. cmd.SetViewport(cameraData.pixelRect);
  1299. cmd.SetGlobalVector(ShaderPropertyId.scaleBias, scaleBias);
  1300. cmd.DrawProcedural(Matrix4x4.identity, material, 0, MeshTopology.Quads, 4, 1, null);
  1301. }
  1302. else
  1303. #endif
  1304. {
  1305. // Note: We need to get the cameraData.targetTexture as this will get the targetTexture of the camera stack.
  1306. // Overlay cameras need to output to the target described in the base camera while doing camera stack.
  1307. RenderTargetIdentifier cameraTarget = (cameraData.targetTexture != null) ? new RenderTargetIdentifier(cameraData.targetTexture) : cameraTargetHandle.Identifier();
  1308. cmd.SetRenderTarget(cameraTarget, colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  1309. cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
  1310. cmd.SetViewport(cameraData.pixelRect);
  1311. cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, material);
  1312. cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);
  1313. cameraData.renderer.ConfigureCameraTarget(cameraTarget, cameraTarget);
  1314. }
  1315. if (isUpscaledTextureUsed)
  1316. {
  1317. cmd.ReleaseTemporaryRT(ShaderConstants._UpscaledTexture);
  1318. }
  1319. if (isScalingSetupUsed)
  1320. {
  1321. cmd.ReleaseTemporaryRT(ShaderConstants._ScalingSetupTexture);
  1322. }
  1323. }
  1324. #endregion
  1325. #region Internal utilities
  1326. class MaterialLibrary
  1327. {
  1328. public readonly Material stopNaN;
  1329. public readonly Material subpixelMorphologicalAntialiasing;
  1330. public readonly Material gaussianDepthOfField;
  1331. public readonly Material bokehDepthOfField;
  1332. public readonly Material cameraMotionBlur;
  1333. public readonly Material paniniProjection;
  1334. public readonly Material bloom;
  1335. public readonly Material scalingSetup;
  1336. public readonly Material easu;
  1337. public readonly Material uber;
  1338. public readonly Material finalPass;
  1339. public readonly Material lensFlareDataDriven;
  1340. public MaterialLibrary(PostProcessData data)
  1341. {
  1342. stopNaN = Load(data.shaders.stopNanPS);
  1343. subpixelMorphologicalAntialiasing = Load(data.shaders.subpixelMorphologicalAntialiasingPS);
  1344. gaussianDepthOfField = Load(data.shaders.gaussianDepthOfFieldPS);
  1345. bokehDepthOfField = Load(data.shaders.bokehDepthOfFieldPS);
  1346. cameraMotionBlur = Load(data.shaders.cameraMotionBlurPS);
  1347. paniniProjection = Load(data.shaders.paniniProjectionPS);
  1348. bloom = Load(data.shaders.bloomPS);
  1349. scalingSetup = Load(data.shaders.scalingSetupPS);
  1350. easu = Load(data.shaders.easuPS);
  1351. uber = Load(data.shaders.uberPostPS);
  1352. finalPass = Load(data.shaders.finalPostPassPS);
  1353. lensFlareDataDriven = Load(data.shaders.LensFlareDataDrivenPS);
  1354. }
  1355. Material Load(Shader shader)
  1356. {
  1357. if (shader == null)
  1358. {
  1359. Debug.LogErrorFormat($"Missing shader. {GetType().DeclaringType.Name} render pass will not execute. Check for missing reference in the renderer resources.");
  1360. return null;
  1361. }
  1362. else if (!shader.isSupported)
  1363. {
  1364. return null;
  1365. }
  1366. return CoreUtils.CreateEngineMaterial(shader);
  1367. }
  1368. internal void Cleanup()
  1369. {
  1370. CoreUtils.Destroy(stopNaN);
  1371. CoreUtils.Destroy(subpixelMorphologicalAntialiasing);
  1372. CoreUtils.Destroy(gaussianDepthOfField);
  1373. CoreUtils.Destroy(bokehDepthOfField);
  1374. CoreUtils.Destroy(cameraMotionBlur);
  1375. CoreUtils.Destroy(paniniProjection);
  1376. CoreUtils.Destroy(bloom);
  1377. CoreUtils.Destroy(scalingSetup);
  1378. CoreUtils.Destroy(easu);
  1379. CoreUtils.Destroy(uber);
  1380. CoreUtils.Destroy(finalPass);
  1381. }
  1382. }
  1383. // Precomputed shader ids to same some CPU cycles (mostly affects mobile)
  1384. static class ShaderConstants
  1385. {
  1386. public static readonly int _TempTarget = Shader.PropertyToID("_TempTarget");
  1387. public static readonly int _TempTarget2 = Shader.PropertyToID("_TempTarget2");
  1388. public static readonly int _StencilRef = Shader.PropertyToID("_StencilRef");
  1389. public static readonly int _StencilMask = Shader.PropertyToID("_StencilMask");
  1390. public static readonly int _FullCoCTexture = Shader.PropertyToID("_FullCoCTexture");
  1391. public static readonly int _HalfCoCTexture = Shader.PropertyToID("_HalfCoCTexture");
  1392. public static readonly int _DofTexture = Shader.PropertyToID("_DofTexture");
  1393. public static readonly int _CoCParams = Shader.PropertyToID("_CoCParams");
  1394. public static readonly int _BokehKernel = Shader.PropertyToID("_BokehKernel");
  1395. public static readonly int _BokehConstants = Shader.PropertyToID("_BokehConstants");
  1396. public static readonly int _PongTexture = Shader.PropertyToID("_PongTexture");
  1397. public static readonly int _PingTexture = Shader.PropertyToID("_PingTexture");
  1398. public static readonly int _Metrics = Shader.PropertyToID("_Metrics");
  1399. public static readonly int _AreaTexture = Shader.PropertyToID("_AreaTexture");
  1400. public static readonly int _SearchTexture = Shader.PropertyToID("_SearchTexture");
  1401. public static readonly int _EdgeTexture = Shader.PropertyToID("_EdgeTexture");
  1402. public static readonly int _BlendTexture = Shader.PropertyToID("_BlendTexture");
  1403. public static readonly int _ColorTexture = Shader.PropertyToID("_ColorTexture");
  1404. public static readonly int _Params = Shader.PropertyToID("_Params");
  1405. public static readonly int _SourceTexLowMip = Shader.PropertyToID("_SourceTexLowMip");
  1406. public static readonly int _Bloom_Params = Shader.PropertyToID("_Bloom_Params");
  1407. public static readonly int _Bloom_RGBM = Shader.PropertyToID("_Bloom_RGBM");
  1408. public static readonly int _Bloom_Texture = Shader.PropertyToID("_Bloom_Texture");
  1409. public static readonly int _LensDirt_Texture = Shader.PropertyToID("_LensDirt_Texture");
  1410. public static readonly int _LensDirt_Params = Shader.PropertyToID("_LensDirt_Params");
  1411. public static readonly int _LensDirt_Intensity = Shader.PropertyToID("_LensDirt_Intensity");
  1412. public static readonly int _Distortion_Params1 = Shader.PropertyToID("_Distortion_Params1");
  1413. public static readonly int _Distortion_Params2 = Shader.PropertyToID("_Distortion_Params2");
  1414. public static readonly int _Chroma_Params = Shader.PropertyToID("_Chroma_Params");
  1415. public static readonly int _Vignette_Params1 = Shader.PropertyToID("_Vignette_Params1");
  1416. public static readonly int _Vignette_Params2 = Shader.PropertyToID("_Vignette_Params2");
  1417. public static readonly int _Lut_Params = Shader.PropertyToID("_Lut_Params");
  1418. public static readonly int _UserLut_Params = Shader.PropertyToID("_UserLut_Params");
  1419. public static readonly int _InternalLut = Shader.PropertyToID("_InternalLut");
  1420. public static readonly int _UserLut = Shader.PropertyToID("_UserLut");
  1421. public static readonly int _DownSampleScaleFactor = Shader.PropertyToID("_DownSampleScaleFactor");
  1422. public static readonly int _FlareOcclusionTex = Shader.PropertyToID("_FlareOcclusionTex");
  1423. public static readonly int _FlareOcclusionIndex = Shader.PropertyToID("_FlareOcclusionIndex");
  1424. public static readonly int _FlareTex = Shader.PropertyToID("_FlareTex");
  1425. public static readonly int _FlareColorValue = Shader.PropertyToID("_FlareColorValue");
  1426. public static readonly int _FlareData0 = Shader.PropertyToID("_FlareData0");
  1427. public static readonly int _FlareData1 = Shader.PropertyToID("_FlareData1");
  1428. public static readonly int _FlareData2 = Shader.PropertyToID("_FlareData2");
  1429. public static readonly int _FlareData3 = Shader.PropertyToID("_FlareData3");
  1430. public static readonly int _FlareData4 = Shader.PropertyToID("_FlareData4");
  1431. public static readonly int _FlareData5 = Shader.PropertyToID("_FlareData5");
  1432. public static readonly int _FullscreenProjMat = Shader.PropertyToID("_FullscreenProjMat");
  1433. public static readonly int _ScalingSetupTexture = Shader.PropertyToID("_ScalingSetupTexture");
  1434. public static readonly int _UpscaledTexture = Shader.PropertyToID("_UpscaledTexture");
  1435. public static int[] _BloomMipUp;
  1436. public static int[] _BloomMipDown;
  1437. }
  1438. #endregion
  1439. }
  1440. }