public override void Render(PostProcessRenderContext context) { var colorFormat = RenderTextureFormat.DefaultHDR; var cocFormat = SelectFormat(RenderTextureFormat.R8, RenderTextureFormat.RHalf); // Avoid using R8 on OSX with Metal. #896121, https://goo.gl/MgKqu6 #if (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX) && !UNITY_2017_1_OR_NEWER if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Metal) { cocFormat = SelectFormat(RenderTextureFormat.RHalf, RenderTextureFormat.Default); } #endif // Material setup float scaledFilmHeight = k_FilmHeight * (context.height / 1080f); var f = settings.focalLength.value / 1000f; var s1 = Mathf.Max(settings.focusDistance.value, f); var aspect = (float)context.screenWidth / (float)context.screenHeight; var coeff = f * f / (settings.aperture.value * (s1 - f) * scaledFilmHeight * 2f); var maxCoC = CalculateMaxCoCRadius(context.screenHeight); var sheet = context.propertySheets.Get(context.resources.shaders.depthOfField); sheet.properties.Clear(); sheet.properties.SetFloat(ShaderIDs.Distance, s1); sheet.properties.SetFloat(ShaderIDs.LensCoeff, coeff); sheet.properties.SetFloat(ShaderIDs.MaxCoC, maxCoC); sheet.properties.SetFloat(ShaderIDs.RcpMaxCoC, 1f / maxCoC); sheet.properties.SetFloat(ShaderIDs.RcpAspect, 1f / aspect); var cmd = context.command; cmd.BeginSample("DepthOfField"); // CoC calculation pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.CoCTex, 0, cocFormat, RenderTextureReadWrite.Linear); cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, ShaderIDs.CoCTex, sheet, (int)Pass.CoCCalculation); // Downsampling and prefiltering pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTex, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2); cmd.BlitFullscreenTriangle(context.source, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.DownsampleAndPrefilter); // Bokeh simulation pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTemp, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2); cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTex, ShaderIDs.DepthOfFieldTemp, sheet, (int)Pass.BokehSmallKernel + (int)settings.kernelSize.value); // Postfilter pass cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTemp, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.PostFilter); cmd.ReleaseTemporaryRT(ShaderIDs.DepthOfFieldTemp); // Debug overlay pass if (context.IsDebugOverlayEnabled(DebugOverlay.DepthOfField)) { context.PushDebugOverlay(cmd, context.source, sheet, (int)Pass.DebugOverlay); } // Combine pass cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Combine); cmd.ReleaseTemporaryRT(ShaderIDs.DepthOfFieldTex); cmd.ReleaseTemporaryRT(ShaderIDs.CoCTex); cmd.EndSample("DepthOfField"); m_ResetHistory = false; }
int RenderBuiltins(PostProcessRenderContext context, bool isFinalPass, int releaseTargetAfterUse = -1) { var uberSheet = context.propertySheets.Get(context.resources.shaders.uber); uberSheet.ClearKeywords(); uberSheet.properties.Clear(); context.uberSheet = uberSheet; context.autoExposureTexture = RuntimeUtilities.whiteTexture; context.bloomBufferNameID = -1; var cmd = context.command; cmd.BeginSample("BuiltinStack"); int tempTarget = -1; var finalDestination = context.destination; if (!isFinalPass) { // Render to an intermediate target as this won't be the final pass tempTarget = m_TargetPool.Get(); context.GetScreenSpaceTemporaryRT(cmd, tempTarget, 0, context.sourceFormat); context.destination = tempTarget; // Handle FXAA's keep alpha mode if (antialiasingMode == Antialiasing.FastApproximateAntialiasing && !fastApproximateAntialiasing.keepAlpha) { uberSheet.properties.SetFloat(ShaderIDs.LumaInAlpha, 1f); } } // Depth of field final combination pass used to be done in Uber which led to artifacts // when used at the same time as Bloom (because both effects used the same source, so // the stronger bloom was, the more DoF was eaten away in out of focus areas) int depthOfFieldTarget = RenderEffect <DepthOfField>(context, true); // Motion blur is a separate pass - could potentially be done after DoF depending on the // kind of results you're looking for... int motionBlurTarget = RenderEffect <MotionBlur>(context, true); // Prepare exposure histogram if needed if (ShouldGenerateLogHistogram(context)) { m_LogHistogram.Generate(context); } // Uber effects RenderEffect <AutoExposure>(context); uberSheet.properties.SetTexture(ShaderIDs.AutoExposureTex, context.autoExposureTexture); RenderEffect <LensDistortion>(context); RenderEffect <ChromaticAberration>(context); RenderEffect <Bloom>(context); RenderEffect <Vignette>(context); RenderEffect <Grain>(context); if (!breakBeforeColorGrading) { RenderEffect <ColorGrading>(context); } if (isFinalPass) { uberSheet.EnableKeyword("FINALPASS"); dithering.Render(context); ApplyFlip(context, uberSheet.properties); } else { ApplyDefaultFlip(uberSheet.properties); } cmd.BlitFullscreenTriangle(context.source, context.destination, uberSheet, 0); context.source = context.destination; context.destination = finalDestination; if (releaseTargetAfterUse > -1) { cmd.ReleaseTemporaryRT(releaseTargetAfterUse); } if (motionBlurTarget > -1) { cmd.ReleaseTemporaryRT(motionBlurTarget); } if (depthOfFieldTarget > -1) { cmd.ReleaseTemporaryRT(depthOfFieldTarget); } if (context.bloomBufferNameID > -1) { cmd.ReleaseTemporaryRT(context.bloomBufferNameID); } cmd.EndSample("BuiltinStack"); return(tempTarget); }
public override void Render(PostProcessRenderContext context) { var colorFormat = RenderTextureFormat.DefaultHDR; var cocFormat = SelectFormat(RenderTextureFormat.R8, RenderTextureFormat.RHalf); // Avoid using R8 on OSX with Metal. #896121, https://goo.gl/MgKqu6 #if (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX) && !UNITY_2017_1_OR_NEWER if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Metal) { cocFormat = SelectFormat(RenderTextureFormat.RHalf, RenderTextureFormat.Default); } #endif // Material setup float scaledFilmHeight = k_FilmHeight * (context.height / 1080f); var f = settings.focalLength.value / 1000f; var s1 = Mathf.Max(settings.focusDistance.value, f); var aspect = (float)context.screenWidth / (float)context.screenHeight; var coeff = f * f / (settings.aperture.value * (s1 - f) * scaledFilmHeight * 2f); var maxCoC = CalculateMaxCoCRadius(context.screenHeight); var sheet = context.propertySheets.Get(context.resources.shaders.depthOfField); sheet.properties.Clear(); sheet.properties.SetFloat(ShaderIDs.Distance, s1); sheet.properties.SetFloat(ShaderIDs.LensCoeff, coeff); sheet.properties.SetFloat(ShaderIDs.MaxCoC, maxCoC); sheet.properties.SetFloat(ShaderIDs.RcpMaxCoC, 1f / maxCoC); sheet.properties.SetFloat(ShaderIDs.RcpAspect, 1f / aspect); var cmd = context.command; cmd.BeginSample("DepthOfField"); //custom-begin: autofocus if (context.depthOfFieldAutoFocus != null) { context.depthOfFieldAutoFocus.SetUpAutoFocusParams(cmd, f, k_FilmHeight, context.camera, m_ResetHistory); } //custom-end // CoC calculation pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.CoCTex, 0, cocFormat, RenderTextureReadWrite.Linear); cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, ShaderIDs.CoCTex, sheet, (int)Pass.CoCCalculation); // CoC temporal filter pass when TAA is enabled if (context.IsTemporalAntialiasingActive()) { float motionBlending = context.temporalAntialiasing.motionBlending; float blend = m_ResetHistory ? 0f : motionBlending; // Handles first frame blending var jitter = context.temporalAntialiasing.jitter; sheet.properties.SetVector(ShaderIDs.TaaParams, new Vector3(jitter.x, jitter.y, blend)); int pp = m_HistoryPingPong[context.xrActiveEye]; var historyRead = CheckHistory(context.xrActiveEye, ++pp % 2, context, cocFormat); var historyWrite = CheckHistory(context.xrActiveEye, ++pp % 2, context, cocFormat); m_HistoryPingPong[context.xrActiveEye] = ++pp % 2; cmd.BlitFullscreenTriangle(historyRead, historyWrite, sheet, (int)Pass.CoCTemporalFilter); cmd.ReleaseTemporaryRT(ShaderIDs.CoCTex); cmd.SetGlobalTexture(ShaderIDs.CoCTex, historyWrite); } // Downsampling and prefiltering pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTex, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2); cmd.BlitFullscreenTriangle(context.source, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.DownsampleAndPrefilter); // Bokeh simulation pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTemp, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2); cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTex, ShaderIDs.DepthOfFieldTemp, sheet, (int)Pass.BokehSmallKernel + (int)settings.kernelSize.value); // Postfilter pass cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTemp, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.PostFilter); cmd.ReleaseTemporaryRT(ShaderIDs.DepthOfFieldTemp); // Debug overlay pass if (context.IsDebugOverlayEnabled(DebugOverlay.DepthOfField)) { context.PushDebugOverlay(cmd, context.source, sheet, (int)Pass.DebugOverlay); } // Combine pass cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Combine); cmd.ReleaseTemporaryRT(ShaderIDs.DepthOfFieldTex); if (!context.IsTemporalAntialiasingActive()) { cmd.ReleaseTemporaryRT(ShaderIDs.CoCTex); } cmd.EndSample("DepthOfField"); m_ResetHistory = false; }
// Renders everything not opaque-only // // Current order of operation is as following: // 1. Pre-stack // 2. Built-in stack // 3. Post-stack // 4. Built-in final pass // // Final pass should be skipped when outputting to a HDR display. public void Render(PostProcessRenderContext context) { if (RuntimeUtilities.scriptableRenderPipelineActive) { SetupContext(context); } TextureLerper.instance.BeginFrame(context); var cmd = context.command; // Update & override layer settings first (volume blending) if the opaque only pass // hasn't been called this frame. UpdateSettingsIfNeeded(context); // Do a NaN killing pass if needed int lastTarget = -1; if (stopNaNPropagation && !m_NaNKilled) { lastTarget = m_TargetPool.Get(); context.GetScreenSpaceTemporaryRT(cmd, lastTarget, 0, context.sourceFormat); cmd.BlitFullscreenTriangle(context.source, lastTarget, RuntimeUtilities.copySheet, 1); context.source = lastTarget; m_NaNKilled = true; } // Do temporal anti-aliasing first if (context.IsTemporalAntialiasingActive()) { if (!RuntimeUtilities.scriptableRenderPipelineActive) { if (context.stereoActive) { // We only need to configure all of this once for stereo, during OnPreCull if (context.camera.stereoActiveEye != Camera.MonoOrStereoscopicEye.Right) { temporalAntialiasing.ConfigureStereoJitteredProjectionMatrices(context); } } else { temporalAntialiasing.ConfigureJitteredProjectionMatrix(context); } } var taaTarget = m_TargetPool.Get(); var finalDestination = context.destination; context.GetScreenSpaceTemporaryRT(cmd, taaTarget, 0, context.sourceFormat); context.destination = taaTarget; temporalAntialiasing.Render(context); context.source = taaTarget; context.destination = finalDestination; if (lastTarget > -1) { cmd.ReleaseTemporaryRT(lastTarget); } lastTarget = taaTarget; } bool hasBeforeStackEffects = HasActiveEffects(PostProcessEvent.BeforeStack, context); bool hasAfterStackEffects = HasActiveEffects(PostProcessEvent.AfterStack, context) && !breakBeforeColorGrading; bool needsFinalPass = (hasAfterStackEffects || (antialiasingMode == Antialiasing.FastApproximateAntialiasing) || (antialiasingMode == Antialiasing.SubpixelMorphologicalAntialiasing && subpixelMorphologicalAntialiasing.IsSupported())) && !breakBeforeColorGrading; // Right before the builtin stack if (hasBeforeStackEffects) { lastTarget = RenderInjectionPoint(PostProcessEvent.BeforeStack, context, "BeforeStack", lastTarget); } // Builtin stack lastTarget = RenderBuiltins(context, !needsFinalPass, lastTarget); // After the builtin stack but before the final pass (before FXAA & Dithering) if (hasAfterStackEffects) { lastTarget = RenderInjectionPoint(PostProcessEvent.AfterStack, context, "AfterStack", lastTarget); } // And close with the final pass if (needsFinalPass) { RenderFinalPass(context, lastTarget); } // Render debug monitors & overlay if requested debugLayer.RenderSpecialOverlays(context); debugLayer.RenderMonitors(context); // End frame cleanup TextureLerper.instance.EndFrame(); debugLayer.EndFrame(); m_SettingsUpdateNeeded = true; m_NaNKilled = false; }
void RenderList(List <SerializedBundleRef> list, PostProcessRenderContext context, string marker) { var cmd = context.command; cmd.BeginSample(marker); // First gather active effects - we need this to manage render targets more efficiently m_ActiveEffects.Clear(); for (int i = 0; i < list.Count; i++) { var effect = list[i].bundle; if (effect.settings.IsEnabledAndSupported(context)) { if (!context.isSceneView || (context.isSceneView && effect.attribute.allowInSceneView)) { m_ActiveEffects.Add(effect.renderer); } } } int count = m_ActiveEffects.Count; // If there's only one active effect, we can simply execute it and skip the rest if (count == 1) { m_ActiveEffects[0].Render(context); } else { // Else create the target chain m_Targets.Clear(); m_Targets.Add(context.source); // First target is always source int tempTarget1 = m_TargetPool.Get(); int tempTarget2 = m_TargetPool.Get(); for (int i = 0; i < count - 1; i++) { m_Targets.Add(i % 2 == 0 ? tempTarget1 : tempTarget2); } m_Targets.Add(context.destination); // Last target is always destination // Render context.GetScreenSpaceTemporaryRT(cmd, tempTarget1, 0, context.sourceFormat); if (count > 2) { context.GetScreenSpaceTemporaryRT(cmd, tempTarget2, 0, context.sourceFormat); } for (int i = 0; i < count; i++) { context.source = m_Targets[i]; context.destination = m_Targets[i + 1]; m_ActiveEffects[i].Render(context); } cmd.ReleaseTemporaryRT(tempTarget1); if (count > 2) { cmd.ReleaseTemporaryRT(tempTarget2); } } cmd.EndSample(marker); }
public override void Render(PostProcessRenderContext context) { var cmd = context.command; cmd.BeginSample("BloomPyramid"); var sheet = context.propertySheets.Get(context.resources.shaders.bloom); // Apply auto exposure adjustment in the prefiltering pass sheet.properties.SetTexture(ShaderIDs.AutoExposureTex, context.autoExposureTexture); // Negative anamorphic ratio values distort vertically - positive is horizontal float ratio = Mathf.Clamp(settings.anamorphicRatio, -1, 1); float rw = ratio < 0 ? -ratio : 0f; float rh = ratio > 0 ? ratio : 0f; // Do bloom on a half-res buffer, full-res doesn't bring much and kills performances on // fillrate limited platforms int tw = Mathf.FloorToInt(context.screenWidth / (2f - rw)); int th = Mathf.FloorToInt(context.screenHeight / (2f - rh)); bool singlePassDoubleWide = (context.stereoActive && (context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass) && (context.camera.stereoTargetEye == StereoTargetEyeMask.Both)); int tw_stereo = singlePassDoubleWide ? tw * 2 : tw; // Determine the iteration count int s = Mathf.Max(tw, th); float logs = Mathf.Log(s, 2f) + Mathf.Min(settings.diffusion.value, 10f) - 10f; int logs_i = Mathf.FloorToInt(logs); int iterations = Mathf.Clamp(logs_i, 1, k_MaxPyramidSize); float sampleScale = 0.5f + logs - logs_i; sheet.properties.SetFloat(ShaderIDs.SampleScale, sampleScale); // Prefiltering parameters float lthresh = Mathf.GammaToLinearSpace(settings.threshold.value); float knee = lthresh * settings.softKnee.value + 1e-5f; var threshold = new Vector4(lthresh, lthresh - knee, knee * 2f, 0.25f / knee); sheet.properties.SetVector(ShaderIDs.Threshold, threshold); float lclamp = Mathf.GammaToLinearSpace(settings.clamp.value); sheet.properties.SetVector(ShaderIDs.Params, new Vector4(lclamp, 0f, 0f, 0f)); int qualityOffset = settings.fastMode ? 1 : 0; // Downsample var lastDown = context.source; for (int i = 0; i < iterations; i++) { int mipDown = m_Pyramid[i].down; int mipUp = m_Pyramid[i].up; int pass = i == 0 ? (int)Pass.Prefilter13 + qualityOffset : (int)Pass.Downsample13 + qualityOffset; context.GetScreenSpaceTemporaryRT(cmd, mipDown, 0, context.sourceFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, tw_stereo, th); context.GetScreenSpaceTemporaryRT(cmd, mipUp, 0, context.sourceFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, tw_stereo, th); cmd.BlitFullscreenTriangle(lastDown, mipDown, sheet, pass); lastDown = mipDown; tw_stereo = (singlePassDoubleWide && ((tw_stereo / 2) % 2 > 0)) ? 1 + tw_stereo / 2 : tw_stereo / 2; tw_stereo = Mathf.Max(tw_stereo, 1); th = Mathf.Max(th / 2, 1); } // Upsample int lastUp = m_Pyramid[iterations - 1].down; for (int i = iterations - 2; i >= 0; i--) { int mipDown = m_Pyramid[i].down; int mipUp = m_Pyramid[i].up; cmd.SetGlobalTexture(ShaderIDs.BloomTex, mipDown); cmd.BlitFullscreenTriangle(lastUp, mipUp, sheet, (int)Pass.UpsampleTent + qualityOffset); lastUp = mipUp; } var linearColor = settings.color.value.linear; float intensity = RuntimeUtilities.Exp2(settings.intensity.value / 10f) - 1f; var shaderSettings = new Vector4(sampleScale, intensity, settings.dirtIntensity.value, iterations); // Debug overlays if (context.IsDebugOverlayEnabled(DebugOverlay.BloomThreshold)) { context.PushDebugOverlay(cmd, context.source, sheet, (int)Pass.DebugOverlayThreshold); } else if (context.IsDebugOverlayEnabled(DebugOverlay.BloomBuffer)) { sheet.properties.SetVector(ShaderIDs.ColorIntensity, new Vector4(linearColor.r, linearColor.g, linearColor.b, intensity)); context.PushDebugOverlay(cmd, m_Pyramid[0].up, sheet, (int)Pass.DebugOverlayTent + qualityOffset); } // Lens dirtiness // Keep the aspect ratio correct & center the dirt texture, we don't want it to be // stretched or squashed var dirtTexture = settings.dirtTexture.value == null ? RuntimeUtilities.blackTexture : settings.dirtTexture.value; var dirtRatio = (float)dirtTexture.width / (float)dirtTexture.height; var screenRatio = (float)context.screenWidth / (float)context.screenHeight; var dirtTileOffset = new Vector4(1f, 1f, 0f, 0f); if (dirtRatio > screenRatio) { dirtTileOffset.x = screenRatio / dirtRatio; dirtTileOffset.z = (1f - dirtTileOffset.x) * 0.5f; } else if (screenRatio > dirtRatio) { dirtTileOffset.y = dirtRatio / screenRatio; dirtTileOffset.w = (1f - dirtTileOffset.y) * 0.5f; } // Shader properties var uberSheet = context.uberSheet; if (settings.fastMode) { uberSheet.EnableKeyword("BLOOM_LOW"); } else { uberSheet.EnableKeyword("BLOOM"); } uberSheet.properties.SetVector(ShaderIDs.Bloom_DirtTileOffset, dirtTileOffset); uberSheet.properties.SetVector(ShaderIDs.Bloom_Settings, shaderSettings); uberSheet.properties.SetColor(ShaderIDs.Bloom_Color, linearColor); uberSheet.properties.SetTexture(ShaderIDs.Bloom_DirtTex, dirtTexture); cmd.SetGlobalTexture(ShaderIDs.BloomTex, lastUp); // Cleanup for (int i = 0; i < iterations; i++) { if (m_Pyramid[i].down != lastUp) { cmd.ReleaseTemporaryRT(m_Pyramid[i].down); } if (m_Pyramid[i].up != lastUp) { cmd.ReleaseTemporaryRT(m_Pyramid[i].up); } } cmd.EndSample("BloomPyramid"); context.bloomBufferNameID = lastUp; }
void Render(PostProcessRenderContext context, CommandBuffer cmd, int occlusionSource) { DoLazyInitialization(context); m_Settings.radius.value = Mathf.Max(m_Settings.radius.value, 1e-4f); // Material setup // Always use a quater-res AO buffer unless High/Ultra quality is set. bool downsampling = (int)m_Settings.quality.value < (int)AmbientOcclusionQuality.High; float px = m_Settings.intensity.value; float py = m_Settings.radius.value; float pz = downsampling ? 0.5f : 1f; float pw = m_SampleCount[(int)m_Settings.quality.value]; var sheet = m_PropertySheet; sheet.ClearKeywords(); sheet.properties.SetVector(ShaderIDs.AOParams, new Vector4(px, py, pz, pw)); sheet.properties.SetVector(ShaderIDs.AOColor, Color.white - m_Settings.color.value); // In forward fog is applied at the object level in the grometry pass so we need to // apply it to AO as well or it'll drawn on top of the fog effect. // Not needed in Deferred. if (context.camera.actualRenderingPath == RenderingPath.Forward && RenderSettings.fog) { sheet.EnableKeyword("APPLY_FORWARD_FOG"); sheet.properties.SetVector( ShaderIDs.FogParams, new Vector3(RenderSettings.fogDensity, RenderSettings.fogStartDistance, RenderSettings.fogEndDistance) ); } // Texture setup int ts = downsampling ? 2 : 1; const RenderTextureFormat kFormat = RenderTextureFormat.ARGB32; const RenderTextureReadWrite kRWMode = RenderTextureReadWrite.Linear; const FilterMode kFilter = FilterMode.Bilinear; // AO buffer var rtMask = ShaderIDs.OcclusionTexture1; int scaledWidth = context.width / ts; int scaledHeight = context.height / ts; context.GetScreenSpaceTemporaryRT(cmd, rtMask, 0, kFormat, kRWMode, kFilter, scaledWidth, scaledHeight); // AO estimation cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, rtMask, sheet, (int)Pass.OcclusionEstimationForward + occlusionSource); // Blur buffer var rtBlur = ShaderIDs.OcclusionTexture2; context.GetScreenSpaceTemporaryRT(cmd, rtBlur, 0, kFormat, kRWMode, kFilter); // Separable blur (horizontal pass) cmd.BlitFullscreenTriangle(rtMask, rtBlur, sheet, (int)Pass.HorizontalBlurForward + occlusionSource); cmd.ReleaseTemporaryRT(rtMask); // Separable blur (vertical pass) cmd.BlitFullscreenTriangle(rtBlur, m_Result, sheet, (int)Pass.VerticalBlur); cmd.ReleaseTemporaryRT(rtBlur); if (context.IsDebugOverlayEnabled(DebugOverlay.AmbientOcclusion)) { context.PushDebugOverlay(cmd, m_Result, sheet, (int)Pass.DebugOverlay); } }
public override void Render(PostProcessRenderContext context) { // The coc is stored in alpha so we need a 4 channels target. Note that using ARGB32 // will result in a very weak near-blur. var colorFormat = context.camera.allowHDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32; var cocFormat = SelectFormat(RenderTextureFormat.R8, RenderTextureFormat.RHalf); // Material setup float scaledFilmHeight = k_FilmHeight * (context.height / 1080f); var f = settings.focalLength.value / 1000f; var s1 = Mathf.Max(settings.focusDistance.value, f); var aspect = (float)context.screenWidth / (float)context.screenHeight; var coeff = f * f / (settings.aperture.value * (s1 - f) * scaledFilmHeight * 2f); var maxCoC = CalculateMaxCoCRadius(context.screenHeight); var sheet = context.propertySheets.Get(context.resources.shaders.depthOfField); sheet.properties.Clear(); sheet.properties.SetFloat(ShaderIDs.Distance, s1); sheet.properties.SetFloat(ShaderIDs.LensCoeff, coeff); sheet.properties.SetFloat(ShaderIDs.MaxCoC, maxCoC); sheet.properties.SetFloat(ShaderIDs.RcpMaxCoC, 1f / maxCoC); sheet.properties.SetFloat(ShaderIDs.RcpAspect, 1f / aspect); var cmd = context.command; cmd.BeginSample("DepthOfField"); // CoC calculation pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.CoCTex, 0, cocFormat, RenderTextureReadWrite.Linear); cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, ShaderIDs.CoCTex, sheet, (int)Pass.CoCCalculation); // CoC temporal filter pass when TAA is enabled if (context.IsTemporalAntialiasingActive()) { float motionBlending = context.temporalAntialiasing.motionBlending; float blend = m_ResetHistory ? 0f : motionBlending; // Handles first frame blending var jitter = context.temporalAntialiasing.jitter; sheet.properties.SetVector(ShaderIDs.TaaParams, new Vector3(jitter.x, jitter.y, blend)); int pp = m_HistoryPingPong[context.xrActiveEye]; var historyRead = CheckHistory(context.xrActiveEye, ++pp % 2, context, cocFormat); var historyWrite = CheckHistory(context.xrActiveEye, ++pp % 2, context, cocFormat); m_HistoryPingPong[context.xrActiveEye] = ++pp % 2; cmd.BlitFullscreenTriangle(historyRead, historyWrite, sheet, (int)Pass.CoCTemporalFilter); cmd.ReleaseTemporaryRT(ShaderIDs.CoCTex); cmd.SetGlobalTexture(ShaderIDs.CoCTex, historyWrite); } // Downsampling and prefiltering pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTex, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2); cmd.BlitFullscreenTriangle(context.source, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.DownsampleAndPrefilter); // Bokeh simulation pass context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTemp, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2); cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTex, ShaderIDs.DepthOfFieldTemp, sheet, (int)Pass.BokehSmallKernel + (int)settings.kernelSize.value); // Postfilter pass cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTemp, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.PostFilter); cmd.ReleaseTemporaryRT(ShaderIDs.DepthOfFieldTemp); // Debug overlay pass if (context.IsDebugOverlayEnabled(DebugOverlay.DepthOfField)) { context.PushDebugOverlay(cmd, context.source, sheet, (int)Pass.DebugOverlay); } // Combine pass cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Combine); cmd.ReleaseTemporaryRT(ShaderIDs.DepthOfFieldTex); if (!context.IsTemporalAntialiasingActive()) { cmd.ReleaseTemporaryRT(ShaderIDs.CoCTex); } cmd.EndSample("DepthOfField"); m_ResetHistory = false; }
// This pass will have to be disabled for HDR screen output as it's an LDR pass private void RenderFinalPass(PostProcessRenderContext context, int releaseTargetAfterUse = -1) { var cmd = context.command; cmd.BeginSample("FinalPass"); if (breakBeforeColorGrading) { var sheet = context.propertySheets.Get(context.resources.shaders.discardAlpha); cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, 0); } else { var uberSheet = context.propertySheets.Get(context.resources.shaders.finalPass); uberSheet.ClearKeywords(); uberSheet.properties.Clear(); context.uberSheet = uberSheet; var tempTarget = -1; if (antialiasingMode == Antialiasing.FastApproximateAntialiasing) { uberSheet.EnableKeyword(fastApproximateAntialiasing.fastMode ? "FXAA_LOW" : "FXAA" ); if (fastApproximateAntialiasing.keepAlpha) { uberSheet.EnableKeyword("FXAA_KEEP_ALPHA"); } } else if (antialiasingMode == Antialiasing.SubpixelMorphologicalAntialiasing && subpixelMorphologicalAntialiasing.IsSupported()) { tempTarget = m_TargetPool.Get(); var finalDestination = context.destination; context.GetScreenSpaceTemporaryRT(context.command, tempTarget, 24, context.sourceFormat); context.destination = tempTarget; subpixelMorphologicalAntialiasing.Render(context); context.source = tempTarget; context.destination = finalDestination; } dithering.Render(context); cmd.BlitFullscreenTriangle(context.source, context.destination, uberSheet, context.flip && !context.isSceneView ? 1 : 0); if (tempTarget > -1) { cmd.ReleaseTemporaryRT(tempTarget); } } if (releaseTargetAfterUse > -1) { cmd.ReleaseTemporaryRT(releaseTargetAfterUse); } cmd.EndSample("FinalPass"); }
// This pass will have to be disabled for HDR screen output as it's an LDR pass void RenderFinalPass(PostProcessRenderContext context, int releaseTargetAfterUse = -1, int eye = -1) { var cmd = context.command; cmd.BeginSample("FinalPass"); if (breakBeforeColorGrading) { var sheet = context.propertySheets.Get(context.resources.shaders.discardAlpha); if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced) { sheet.EnableKeyword("STEREO_INSTANCING_ENABLED"); } if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced) { sheet.properties.SetInt(ShaderIDs.DepthSlice, eye); cmd.BlitFullscreenTriangleToTexArray(context.source, context.destination, sheet, 0, false, eye); } else { cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, 0); } } else { var uberSheet = context.propertySheets.Get(context.resources.shaders.finalPass); uberSheet.ClearKeywords(); uberSheet.properties.Clear(); context.uberSheet = uberSheet; int tempTarget = -1; if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced) { uberSheet.EnableKeyword("STEREO_INSTANCING_ENABLED"); } if (antialiasingMode == Antialiasing.FastApproximateAntialiasing) { uberSheet.EnableKeyword(fastApproximateAntialiasing.fastMode ? "FXAA_LOW" : "FXAA" ); if (fastApproximateAntialiasing.keepAlpha) { uberSheet.EnableKeyword("FXAA_KEEP_ALPHA"); } } else if (antialiasingMode == Antialiasing.SubpixelMorphologicalAntialiasing && subpixelMorphologicalAntialiasing.IsSupported()) { tempTarget = m_TargetPool.Get(); var finalDestination = context.destination; context.GetScreenSpaceTemporaryRT(context.command, tempTarget, 0, context.sourceFormat); context.destination = tempTarget; subpixelMorphologicalAntialiasing.Render(context); context.source = tempTarget; context.destination = finalDestination; } dithering.Render(context); ApplyFlip(context, uberSheet.properties); if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced) { uberSheet.properties.SetInt(ShaderIDs.DepthSlice, eye); cmd.BlitFullscreenTriangleToTexArray(context.source, context.destination, uberSheet, 0, false, eye); } else { cmd.BlitFullscreenTriangle(context.source, context.destination, uberSheet, 0); } if (tempTarget > -1) { cmd.ReleaseTemporaryRT(tempTarget); } } if (releaseTargetAfterUse > -1) { cmd.ReleaseTemporaryRT(releaseTargetAfterUse); } cmd.EndSample("FinalPass"); }