示例#1
0
        public override void Render(PostProcessRenderContext context)
        {
            var cmd = context.command;

            cmd.BeginSample("ScanLine");
            RenderTextureDescriptor desc = new RenderTextureDescriptor(context.width, context.height);

            desc.enableRandomWrite = true;
            //cmd.GetTemporaryRT(tempCanvas, desc);
            desc.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R32G32B32A32_SFloat;
            cmd.GetTemporaryRT(tempRTID1, desc);
            cmd.GetTemporaryRT(tempRTID2, desc);
            cmd.GetTemporaryRT(tempRTID3, desc);


            Matrix4x4 V      = Camera.main.worldToCameraMatrix;
            Matrix4x4 P      = GL.GetGPUProjectionMatrix(Camera.main.projectionMatrix, true);
            Matrix4x4 VP     = P * V;
            Matrix4x4 InvMVP = VP.inverse;

            // depth edge
            cmd.SetComputeIntParam(depthEdgeShader, "Width", context.width - 1);
            cmd.SetComputeIntParam(depthEdgeShader, "Height", context.height - 1);

            cmd.SetComputeFloatParam(depthEdgeShader, "EdgeStrength", settings.DepthEdgeStrength.value);

            cmd.SetComputeTextureParam(depthEdgeShader, sobelForDepthKernelID, "Source", BuiltinRenderTextureType.Depth);// or ResolvedDepth
            cmd.SetComputeTextureParam(depthEdgeShader, sobelForDepthKernelID, "Result", tempRTID1);
            cmd.DispatchCompute(depthEdgeShader, sobelForDepthKernelID, context.width, context.height, 1);


            // distance field
            cmd.SetComputeIntParam(distanceFieldShader, "Width", context.width - 1);
            cmd.SetComputeIntParam(distanceFieldShader, "Height", context.height - 1);
            cmd.SetComputeFloatParam(distanceFieldShader, "DistanceScale", settings.DistanceScale.value);
            cmd.SetComputeMatrixParam(distanceFieldShader, "InvVPMatrix", InvMVP);
            var tar = settings.Target.value;

            cmd.SetComputeFloatParams(distanceFieldShader, "Target", new float[3] {
                tar.x, tar.y, tar.z
            });
            cmd.SetComputeTextureParam(distanceFieldShader, distanceFromTargetKernelID, "Source", BuiltinRenderTextureType.Depth);// or ResolvedDepth
            cmd.SetComputeTextureParam(distanceFieldShader, distanceFromTargetKernelID, "Result", tempRTID2);
            cmd.DispatchCompute(distanceFieldShader, distanceFromTargetKernelID, context.width, context.height, 1);

            // distance field edge
            cmd.SetComputeFloatParam(depthEdgeShader, "EdgeStrength", settings.DistanceEdgeStrength.value);
            cmd.SetComputeFloatParam(depthEdgeShader, "DistanceThresold", settings.DistanceThresold.value);
            cmd.SetComputeTextureParam(depthEdgeShader, sobelForDisatnceKernelID, "Source", tempRTID2);// or ResolvedDepth
            cmd.SetComputeTextureParam(depthEdgeShader, sobelForDisatnceKernelID, "Result", tempRTID3);
            cmd.DispatchCompute(depthEdgeShader, sobelForDisatnceKernelID, context.width, context.height, 1);

            // mix color
            var depthColor = settings.DepthEdgeColor.value;

            cmd.SetComputeFloatParams(colorMixerShader, "DepthEdgeColor", new float[3] {
                depthColor.r, depthColor.g, depthColor.b
            });
            var distanceColor = settings.DistanceEdgeColor.value;

            cmd.SetComputeFloatParams(colorMixerShader, "DistanceEdgeColor", new float[3] {
                distanceColor.r, distanceColor.g, distanceColor.b
            });

            cmd.SetComputeTextureParam(colorMixerShader, colroMixerKernelID, "ColorSource", context.source);
            cmd.SetComputeTextureParam(colorMixerShader, colroMixerKernelID, "DepthSource", tempRTID1);
            cmd.SetComputeTextureParam(colorMixerShader, colroMixerKernelID, "DistanceSource", tempRTID3);

            cmd.SetComputeTextureParam(colorMixerShader, colroMixerKernelID, "Result", tempRTID2);
            cmd.DispatchCompute(colorMixerShader, colroMixerKernelID, context.width, context.height, 1);

            cmd.Blit(tempRTID2, context.destination);
            cmd.ReleaseTemporaryRT(tempRTID1);
            cmd.ReleaseTemporaryRT(tempRTID2);
            cmd.ReleaseTemporaryRT(tempRTID3);

            cmd.EndSample("ScanLine");
        }
示例#2
0
        // HDR color pipeline is rendered to a 2D strip lut (works on HDR platforms without compute
        // and 3D texture support). Precision is sliiiiiiightly lower than when using a 3D texture
        // LUT (33^3 -> 32^3) but most of the time it's imperceptible.
        void RenderHDRPipeline2D(PostProcessRenderContext context)
        {
            // For the same reasons as in RenderHDRPipeline3D, regen LUT on evey frame
            {
                CheckInternalStripLut();

                // Lut setup
                var lutSheet = context.propertySheets.Get(context.resources.shaders.lut2DBaker);
                lutSheet.ClearKeywords();

                lutSheet.properties.SetVector(ShaderIDs.Lut2D_Params, new Vector4(k_Lut2DSize, 0.5f / (k_Lut2DSize * k_Lut2DSize), 0.5f / k_Lut2DSize, k_Lut2DSize / (k_Lut2DSize - 1f)));

                var colorBalance = ColorUtilities.ComputeColorBalance(settings.temperature.value, settings.tint.value);
                lutSheet.properties.SetVector(ShaderIDs.ColorBalance, colorBalance);
                lutSheet.properties.SetVector(ShaderIDs.ColorFilter, settings.colorFilter.value);

                float hue = settings.hueShift.value / 360f;         // Remap to [-0.5;0.5]
                float sat = settings.saturation.value / 100f + 1f;  // Remap to [0;2]
                float con = settings.contrast.value / 100f + 1f;    // Remap to [0;2]
                lutSheet.properties.SetVector(ShaderIDs.HueSatCon, new Vector3(hue, sat, con));

                var channelMixerR = new Vector3(settings.mixerRedOutRedIn, settings.mixerRedOutGreenIn, settings.mixerRedOutBlueIn);
                var channelMixerG = new Vector3(settings.mixerGreenOutRedIn, settings.mixerGreenOutGreenIn, settings.mixerGreenOutBlueIn);
                var channelMixerB = new Vector3(settings.mixerBlueOutRedIn, settings.mixerBlueOutGreenIn, settings.mixerBlueOutBlueIn);
                lutSheet.properties.SetVector(ShaderIDs.ChannelMixerRed, channelMixerR / 100f);            // Remap to [-2;2]
                lutSheet.properties.SetVector(ShaderIDs.ChannelMixerGreen, channelMixerG / 100f);
                lutSheet.properties.SetVector(ShaderIDs.ChannelMixerBlue, channelMixerB / 100f);

                var lift     = ColorUtilities.ColorToLift(settings.lift.value * 0.2f);
                var gain     = ColorUtilities.ColorToGain(settings.gain.value * 0.8f);
                var invgamma = ColorUtilities.ColorToInverseGamma(settings.gamma.value * 0.8f);
                lutSheet.properties.SetVector(ShaderIDs.Lift, lift);
                lutSheet.properties.SetVector(ShaderIDs.InvGamma, invgamma);
                lutSheet.properties.SetVector(ShaderIDs.Gain, gain);

                lutSheet.properties.SetTexture(ShaderIDs.Curves, GetCurveTexture(false));

                var tonemapper = settings.tonemapper.value;
                if (tonemapper == Tonemapper.Custom)
                {
                    lutSheet.EnableKeyword("TONEMAPPING_CUSTOM");

                    m_HableCurve.Init(
                        settings.toneCurveToeStrength.value,
                        settings.toneCurveToeLength.value,
                        settings.toneCurveShoulderStrength.value,
                        settings.toneCurveShoulderLength.value,
                        settings.toneCurveShoulderAngle.value,
                        settings.toneCurveGamma.value
                        );

                    lutSheet.properties.SetVector(ShaderIDs.CustomToneCurve, m_HableCurve.uniforms.curve);
                    lutSheet.properties.SetVector(ShaderIDs.ToeSegmentA, m_HableCurve.uniforms.toeSegmentA);
                    lutSheet.properties.SetVector(ShaderIDs.ToeSegmentB, m_HableCurve.uniforms.toeSegmentB);
                    lutSheet.properties.SetVector(ShaderIDs.MidSegmentA, m_HableCurve.uniforms.midSegmentA);
                    lutSheet.properties.SetVector(ShaderIDs.MidSegmentB, m_HableCurve.uniforms.midSegmentB);
                    lutSheet.properties.SetVector(ShaderIDs.ShoSegmentA, m_HableCurve.uniforms.shoSegmentA);
                    lutSheet.properties.SetVector(ShaderIDs.ShoSegmentB, m_HableCurve.uniforms.shoSegmentB);
                }
                else if (tonemapper == Tonemapper.ACES)
                {
                    lutSheet.EnableKeyword("TONEMAPPING_ACES");
                }
                else if (tonemapper == Tonemapper.Neutral)
                {
                    lutSheet.EnableKeyword("TONEMAPPING_NEUTRAL");
                }

                // Generate the lut
                context.command.BeginSample("HdrColorGradingLut2D");
                context.command.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_InternalLdrLut, lutSheet, (int)Pass.LutGenHDR2D);
                context.command.EndSample("HdrColorGradingLut2D");
            }

            var lut       = m_InternalLdrLut;
            var uberSheet = context.uberSheet;

            uberSheet.EnableKeyword("COLOR_GRADING_HDR_2D");
            uberSheet.properties.SetVector(ShaderIDs.Lut2D_Params, new Vector3(1f / lut.width, 1f / lut.height, lut.height - 1f));
            uberSheet.properties.SetTexture(ShaderIDs.Lut2D, lut);
            uberSheet.properties.SetFloat(ShaderIDs.PostExposure, RuntimeUtilities.Exp2(settings.postExposure.value));
        }
示例#3
0
 /// <summary>
 /// Returns <c>true</c> if the effect is currently enabled and supported.
 /// </summary>
 /// <param name="context">The current post-processing render context</param>
 /// <returns><c>true</c> if the effect is currently enabled and supported</returns>
 public override bool IsEnabledAndSupported(PostProcessRenderContext context)
 {
     return(enabled.value &&
            intensity.value > 0f);
 }
        public override void Render(PostProcessRenderContext context)
        {
            var cmd = context.command;

            cmd.BeginSample("AutoExposureLookup");

            // Prepare autoExpo texture pool
            CheckTexture(context.xrActiveEye, 0);
            CheckTexture(context.xrActiveEye, 1);

            // Make sure filtering values are correct to avoid apocalyptic consequences
            float       lowPercent  = settings.filtering.value.x;
            float       highPercent = settings.filtering.value.y;
            const float kMinDelta   = 1e-2f;

            highPercent = Mathf.Clamp(highPercent, 1f + kMinDelta, 99f);
            lowPercent  = Mathf.Clamp(lowPercent, 1f, highPercent - kMinDelta);

            // Clamp min/max adaptation values as well
            float minLum = settings.minLuminance.value;
            float maxLum = settings.maxLuminance.value;

            settings.minLuminance.value = Mathf.Min(minLum, maxLum);
            settings.maxLuminance.value = Mathf.Max(minLum, maxLum);

            // Compute average luminance & auto exposure
            bool   isStatic   = m_ResetHistory || !Application.isPlaying;
            string adaptation = null;

            if (isStatic)
            {
                adaptation = "KAutoExposureAvgLuminance_fixed";
            }
            else if (settings.eyeAdaptation.value == EyeAdaptation.Progressive)
            {
                adaptation = "KAutoExposureAvgLuminance_progressive";
            }

            var compute = context.resources.computeShaders.autoExposure;
            int kernel  = compute.FindKernel(adaptation);

            cmd.SetComputeBufferParam(compute, kernel, "_HistogramBuffer", context.logHistogram.data);
            cmd.SetComputeVectorParam(compute, "_Params1", new Vector4(lowPercent * 0.01f, highPercent * 0.01f, RuntimeUtilities.Exp2(settings.minLuminance.value), RuntimeUtilities.Exp2(settings.maxLuminance.value)));
            cmd.SetComputeVectorParam(compute, "_Params2", new Vector4(settings.speedDown.value, settings.speedUp.value, settings.keyValue.value, Time.deltaTime));
            cmd.SetComputeVectorParam(compute, "_ScaleOffsetRes", context.logHistogram.GetHistogramScaleOffsetRes(context));

            if (isStatic)
            {
                // We don't want eye adaptation when not in play mode because the GameView isn't
                // animated, thus making it harder to tweak. Just use the final audo exposure value.
                m_CurrentAutoExposure = m_AutoExposurePool[context.xrActiveEye][0];
                cmd.SetComputeTextureParam(compute, kernel, "_Destination", m_CurrentAutoExposure);
                cmd.DispatchCompute(compute, kernel, 1, 1, 1);

                // Copy current exposure to the other pingpong target to avoid adapting from black
                RuntimeUtilities.CopyTexture(cmd, m_AutoExposurePool[context.xrActiveEye][0], m_AutoExposurePool[context.xrActiveEye][1]);
                m_ResetHistory = false;
            }
            else
            {
                int pp  = m_AutoExposurePingPong[context.xrActiveEye];
                var src = m_AutoExposurePool[context.xrActiveEye][++pp % 2];
                var dst = m_AutoExposurePool[context.xrActiveEye][++pp % 2];

                cmd.SetComputeTextureParam(compute, kernel, "_Source", src);
                cmd.SetComputeTextureParam(compute, kernel, "_Destination", dst);
                cmd.DispatchCompute(compute, kernel, 1, 1, 1);

                m_AutoExposurePingPong[context.xrActiveEye] = ++pp % 2;
                m_CurrentAutoExposure = dst;
            }

            cmd.EndSample("AutoExposureLookup");

            context.autoExposureTexture = m_CurrentAutoExposure;
            context.autoExposure        = settings;
        }
示例#5
0
        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;
        }
示例#6
0
 public bool HasOpaqueOnlyEffects(PostProcessRenderContext context)
 {
     return(HasActiveEffects(PostProcessEvent.BeforeTransparent, context));
 }
示例#7
0
        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, 24, context.sourceFormat);
                if (count > 2)
                {
                    context.GetScreenSpaceTemporaryRT(cmd, tempTarget2, 24, 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);
        }
示例#8
0
 public override bool IsEnabledAndSupported(PostProcessRenderContext context)
 {
     return((bool)enabled && context.camera.actualRenderingPath == RenderingPath.DeferredShading && SystemInfo.supportsMotionVectors && SystemInfo.supportsComputeShaders && SystemInfo.copyTextureSupport > CopyTextureSupport.None && (bool)context.resources.shaders.screenSpaceReflections && context.resources.shaders.screenSpaceReflections.isSupported && (bool)context.resources.computeShaders.gaussianDownsample);
 }
示例#9
0
 internal override bool ShaderResourcesAvailable(PostProcessRenderContext context)
 {
     return(context.resources.shaders.lightMeter && context.resources.shaders.lightMeter.isSupported);
 }
示例#10
0
        // Token: 0x06000989 RID: 2441 RVA: 0x00030144 File Offset: 0x0002E344
        public override void Render(PostProcessRenderContext context)
        {
            CommandBuffer command = context.command;

            command.BeginSample("Screen-space Reflections");
            if (base.settings.preset.value != ScreenSpaceReflectionPreset.Custom)
            {
                int value = (int)base.settings.preset.value;
                base.settings.maximumIterationCount.value = this.m_Presets[value].maximumIterationCount;
                base.settings.thickness.value             = this.m_Presets[value].thickness;
                base.settings.resolution.value            = this.m_Presets[value].downsampling;
            }
            base.settings.maximumMarchDistance.value = Mathf.Max(0f, base.settings.maximumMarchDistance.value);
            int num = Mathf.ClosestPowerOfTwo(Mathf.Min(context.width, context.height));

            if (base.settings.resolution.value == ScreenSpaceReflectionResolution.Downsampled)
            {
                num >>= 1;
            }
            else if (base.settings.resolution.value == ScreenSpaceReflectionResolution.Supersampled)
            {
                num <<= 1;
            }
            int num2 = Mathf.FloorToInt(Mathf.Log((float)num, 2f) - 3f);

            num2 = Mathf.Min(num2, 12);
            this.CheckRT(ref this.m_Resolve, num, num, context.sourceFormat, FilterMode.Trilinear, true);
            Texture2D     texture2D     = context.resources.blueNoise256[0];
            PropertySheet propertySheet = context.propertySheets.Get(Shader.Find("Hidden/PostProcessing/HopooSSR"));

            propertySheet.properties.SetTexture(Shader.PropertyToID("_Noise"), texture2D);
            Matrix4x4 matrix4x = default(Matrix4x4);

            matrix4x.SetRow(0, new Vector4((float)num * 0.5f, 0f, 0f, (float)num * 0.5f));
            matrix4x.SetRow(1, new Vector4(0f, (float)num * 0.5f, 0f, (float)num * 0.5f));
            matrix4x.SetRow(2, new Vector4(0f, 0f, 1f, 0f));
            matrix4x.SetRow(3, new Vector4(0f, 0f, 0f, 1f));
            Matrix4x4 gpuprojectionMatrix = GL.GetGPUProjectionMatrix(context.camera.projectionMatrix, false);

            matrix4x *= gpuprojectionMatrix;
            propertySheet.properties.SetMatrix(Shader.PropertyToID("_ViewMatrix"), context.camera.worldToCameraMatrix);
            propertySheet.properties.SetMatrix(Shader.PropertyToID("_InverseViewMatrix"), context.camera.worldToCameraMatrix.inverse);
            propertySheet.properties.SetMatrix(Shader.PropertyToID("_InverseProjectionMatrix"), gpuprojectionMatrix.inverse);
            propertySheet.properties.SetMatrix(Shader.PropertyToID("_ScreenSpaceProjectionMatrix"), matrix4x);
            propertySheet.properties.SetVector(Shader.PropertyToID("_Params"), new Vector4(base.settings.vignette.value, base.settings.distanceFade.value, base.settings.maximumMarchDistance.value, (float)num2));
            propertySheet.properties.SetVector(Shader.PropertyToID("_Params2"), new Vector4((float)context.width / (float)context.height, (float)num / (float)texture2D.width, base.settings.thickness.value, (float)base.settings.maximumIterationCount.value));
            command.GetTemporaryRT(Shader.PropertyToID("_Test"), num, num, 0, FilterMode.Point, context.sourceFormat);
            command.BlitFullscreenTriangle(context.source, Shader.PropertyToID("_Test"), propertySheet, 0, false, null);
            if (context.isSceneView)
            {
                command.BlitFullscreenTriangle(context.source, this.m_Resolve, propertySheet, 1, false, null);
            }
            else
            {
                this.CheckRT(ref this.m_History, num, num, context.sourceFormat, FilterMode.Bilinear, false);
                if (this.m_ResetHistory)
                {
                    context.command.BlitFullscreenTriangle(context.source, this.m_History, false, null);
                    this.m_ResetHistory = false;
                }
                command.GetTemporaryRT(Shader.PropertyToID("_SSRResolveTemp"), num, num, 0, FilterMode.Bilinear, context.sourceFormat);
                command.BlitFullscreenTriangle(context.source, Shader.PropertyToID("_SSRResolveTemp"), propertySheet, 1, false, null);
                propertySheet.properties.SetTexture(Shader.PropertyToID("_History"), this.m_History);
                command.BlitFullscreenTriangle(Shader.PropertyToID("_SSRResolveTemp"), this.m_Resolve, propertySheet, 2, false, null);
                command.CopyTexture(this.m_Resolve, 0, 0, this.m_History, 0, 0);
                command.ReleaseTemporaryRT(Shader.PropertyToID("_SSRResolveTemp"));
            }
            command.ReleaseTemporaryRT(Shader.PropertyToID("_Test"));
            if (this.m_MipIDs == null || this.m_MipIDs.Length == 0)
            {
                this.m_MipIDs = new int[12];
                for (int i = 0; i < 12; i++)
                {
                    this.m_MipIDs[i] = Shader.PropertyToID("_SSRGaussianMip" + i);
                }
            }
            ComputeShader          gaussianDownsample = context.resources.computeShaders.gaussianDownsample;
            int                    kernelIndex        = gaussianDownsample.FindKernel("KMain");
            RenderTargetIdentifier rt = new RenderTargetIdentifier(this.m_Resolve);

            for (int j = 0; j < num2; j++)
            {
                num >>= 1;
                command.GetTemporaryRT(this.m_MipIDs[j], num, num, 0, FilterMode.Bilinear, context.sourceFormat, RenderTextureReadWrite.Default, 1, true);
                command.SetComputeTextureParam(gaussianDownsample, kernelIndex, "_Source", rt);
                command.SetComputeTextureParam(gaussianDownsample, kernelIndex, "_Result", this.m_MipIDs[j]);
                command.SetComputeVectorParam(gaussianDownsample, "_Size", new Vector4((float)num, (float)num, 1f / (float)num, 1f / (float)num));
                command.DispatchCompute(gaussianDownsample, kernelIndex, num / 8, num / 8, 1);
                command.CopyTexture(this.m_MipIDs[j], 0, 0, this.m_Resolve, 0, j + 1);
                rt = this.m_MipIDs[j];
            }
            for (int k = 0; k < num2; k++)
            {
                command.ReleaseTemporaryRT(this.m_MipIDs[k]);
            }
            propertySheet.properties.SetTexture(Shader.PropertyToID("_Resolve"), this.m_Resolve);
            command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 3, false, null);
            command.EndSample("Screen-space Reflections");
        }
 // Unused
 public override void Render(PostProcessRenderContext context)
 {
 }
示例#12
0
        // LDR color pipeline is rendered to a 2D strip lut (works on every platform)
        void RenderLDRPipeline2D(PostProcessRenderContext context)
        {
            // For the same reasons as in RenderHDRPipeline3D, regen LUT on every frame
            {
                CheckInternalStripLut();

                // Lut setup
                var lutSheet = context.propertySheets.Get(context.resources.shaders.lut2DBaker);
                lutSheet.ClearKeywords();

                lutSheet.properties.SetVector(ShaderIDs.Lut2D_Params, new Vector4(k_Lut2DSize, 0.5f / (k_Lut2DSize * k_Lut2DSize), 0.5f / k_Lut2DSize, k_Lut2DSize / (k_Lut2DSize - 1f)));

                var colorBalance = ColorUtilities.ComputeColorBalance(settings.temperature.value, settings.tint.value);
                lutSheet.properties.SetVector(ShaderIDs.ColorBalance, colorBalance);
                lutSheet.properties.SetVector(ShaderIDs.ColorFilter, settings.colorFilter.value);

                float hue = settings.hueShift.value / 360f;         // Remap to [-0.5;0.5]
                float sat = settings.saturation.value / 100f + 1f;  // Remap to [0;2]
                float con = settings.contrast.value / 100f + 1f;    // Remap to [0;2]
                lutSheet.properties.SetVector(ShaderIDs.HueSatCon, new Vector3(hue, sat, con));

                var channelMixerR = new Vector3(settings.mixerRedOutRedIn, settings.mixerRedOutGreenIn, settings.mixerRedOutBlueIn);
                var channelMixerG = new Vector3(settings.mixerGreenOutRedIn, settings.mixerGreenOutGreenIn, settings.mixerGreenOutBlueIn);
                var channelMixerB = new Vector3(settings.mixerBlueOutRedIn, settings.mixerBlueOutGreenIn, settings.mixerBlueOutBlueIn);
                lutSheet.properties.SetVector(ShaderIDs.ChannelMixerRed, channelMixerR / 100f);            // Remap to [-2;2]
                lutSheet.properties.SetVector(ShaderIDs.ChannelMixerGreen, channelMixerG / 100f);
                lutSheet.properties.SetVector(ShaderIDs.ChannelMixerBlue, channelMixerB / 100f);

                var lift     = ColorUtilities.ColorToLift(settings.lift.value);
                var gain     = ColorUtilities.ColorToGain(settings.gain.value);
                var invgamma = ColorUtilities.ColorToInverseGamma(settings.gamma.value);
                lutSheet.properties.SetVector(ShaderIDs.Lift, lift);
                lutSheet.properties.SetVector(ShaderIDs.InvGamma, invgamma);
                lutSheet.properties.SetVector(ShaderIDs.Gain, gain);

                lutSheet.properties.SetFloat(ShaderIDs.Brightness, (settings.brightness.value + 100f) / 100f);
                lutSheet.properties.SetTexture(ShaderIDs.Curves, GetCurveTexture(false));

                // Generate the lut
                context.command.BeginSample("LdrColorGradingLut2D");

                var userLut = settings.ldrLut.value;
                if (userLut == null)
                {
                    context.command.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_InternalLdrLut, lutSheet, (int)Pass.LutGenLDRFromScratch);
                }
                else
                {
                    lutSheet.properties.SetVector(ShaderIDs.UserLut2D_Params, new Vector4(1f / userLut.width, 1f / userLut.height, userLut.height - 1f, settings.ldrLutContribution));
                    context.command.BlitFullscreenTriangle(userLut, m_InternalLdrLut, lutSheet, (int)Pass.LutGenLDR);
                }

                context.command.EndSample("LdrColorGradingLut2D");
            }

            var lut       = m_InternalLdrLut;
            var uberSheet = context.uberSheet;

            uberSheet.EnableKeyword("COLOR_GRADING_LDR_2D", context.command);
            uberSheet.properties.SetVector(ShaderIDs.Lut2D_Params, new Vector3(1f / lut.width, 1f / lut.height, lut.height - 1f));
            uberSheet.properties.SetTexture(ShaderIDs.Lut2D, lut);
        }
 internal override bool ShaderResourcesAvailable(PostProcessRenderContext context)
 {
     return(context.resources.computeShaders.gammaHistogram);
 }
        public override void Render(PostProcessRenderContext context)
        {
            var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/EdgeEnhance3"));

            context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
        }
示例#15
0
        public static Matrix4x4 GenerateJitteredProjectionMatrixFromOriginal(PostProcessRenderContext context, Matrix4x4 origProj, Vector2 jitter)
        {
#if UNITY_2017_2_OR_NEWER
            var planes = origProj.decomposeProjection;

            float vertFov  = Math.Abs(planes.top) + Math.Abs(planes.bottom);
            float horizFov = Math.Abs(planes.left) + Math.Abs(planes.right);

            var planeJitter = new Vector2(jitter.x * horizFov / context.screenWidth,
                                          jitter.y * vertFov / context.screenHeight);

            planes.left   += planeJitter.x;
            planes.right  += planeJitter.x;
            planes.top    += planeJitter.y;
            planes.bottom += planeJitter.y;

            var jitteredMatrix = Matrix4x4.Frustum(planes);

            return(jitteredMatrix);
#else
            var rTan = (1.0f + origProj[0, 2]) / origProj[0, 0];
            var lTan = (-1.0f + origProj[0, 2]) / origProj[0, 0];

            var tTan = (1.0f + origProj[1, 2]) / origProj[1, 1];
            var bTan = (-1.0f + origProj[1, 2]) / origProj[1, 1];

            float tanVertFov  = Math.Abs(tTan) + Math.Abs(bTan);
            float tanHorizFov = Math.Abs(lTan) + Math.Abs(rTan);

            jitter.x *= tanHorizFov / context.screenWidth;
            jitter.y *= tanVertFov / context.screenHeight;

            float left   = jitter.x + lTan;
            float right  = jitter.x + rTan;
            float top    = jitter.y + tTan;
            float bottom = jitter.y + bTan;

            var jitteredMatrix = new Matrix4x4();

            jitteredMatrix[0, 0] = 2f / (right - left);
            jitteredMatrix[0, 1] = 0f;
            jitteredMatrix[0, 2] = (right + left) / (right - left);
            jitteredMatrix[0, 3] = 0f;

            jitteredMatrix[1, 0] = 0f;
            jitteredMatrix[1, 1] = 2f / (top - bottom);
            jitteredMatrix[1, 2] = (top + bottom) / (top - bottom);
            jitteredMatrix[1, 3] = 0f;

            jitteredMatrix[2, 0] = 0f;
            jitteredMatrix[2, 1] = 0f;
            jitteredMatrix[2, 2] = origProj[2, 2];
            jitteredMatrix[2, 3] = origProj[2, 3];

            jitteredMatrix[3, 0] = 0f;
            jitteredMatrix[3, 1] = 0f;
            jitteredMatrix[3, 2] = -1f;
            jitteredMatrix[3, 3] = 0f;

            return(jitteredMatrix);
#endif
        }
示例#16
0
 public override bool IsEnabledAndSupported(PostProcessRenderContext context)
 {
     return(enabled.value &&
            SystemInfo.supportsComputeShaders &&
            SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RFloat));
 }
示例#17
0
        public override void Render(PostProcessRenderContext context)
        {
            var cmd = context.command;

            cmd.BeginSample("Screen-space Reflections");

            // Get quality settings
            if (settings.preset.value != ScreenSpaceReflectionPreset.Custom)
            {
                int id = (int)settings.preset.value;
                settings.maximumIterationCount.value = m_Presets[id].maximumIterationCount;
                settings.thickness.value             = m_Presets[id].thickness;
                settings.resolution.value            = m_Presets[id].downsampling;
            }

            settings.maximumMarchDistance.value = Mathf.Max(0f, settings.maximumMarchDistance.value);

            // Square POT target
            int size = Mathf.ClosestPowerOfTwo(Mathf.Min(context.width, context.height));

            if (settings.resolution.value == ScreenSpaceReflectionResolution.Downsampled)
            {
                size >>= 1;
            }
            else if (settings.resolution.value == ScreenSpaceReflectionResolution.Supersampled)
            {
                size <<= 1;
            }

            // The gaussian pyramid compute works in blocks of 8x8 so make sure the last lod has a
            // minimum size of 8x8
            const int kMaxLods = 12;
            int       lodCount = Mathf.FloorToInt(Mathf.Log(size, 2f) - 3f);

            lodCount = Mathf.Min(lodCount, kMaxLods);

            CheckRT(ref m_Resolve, size, size, FilterMode.Trilinear, true);

            var noiseTex = context.resources.blueNoise256[0];
            var sheet    = context.propertySheets.Get(context.resources.shaders.screenSpaceReflections);

            sheet.properties.SetTexture(ShaderIDs.Noise, noiseTex);

            var screenSpaceProjectionMatrix = new Matrix4x4();

            screenSpaceProjectionMatrix.SetRow(0, new Vector4(size * 0.5f, 0f, 0f, size * 0.5f));
            screenSpaceProjectionMatrix.SetRow(1, new Vector4(0f, size * 0.5f, 0f, size * 0.5f));
            screenSpaceProjectionMatrix.SetRow(2, new Vector4(0f, 0f, 1f, 0f));
            screenSpaceProjectionMatrix.SetRow(3, new Vector4(0f, 0f, 0f, 1f));

            var projectionMatrix = GL.GetGPUProjectionMatrix(context.camera.projectionMatrix, false);

            screenSpaceProjectionMatrix *= projectionMatrix;

            sheet.properties.SetMatrix(ShaderIDs.ViewMatrix, context.camera.worldToCameraMatrix);
            sheet.properties.SetMatrix(ShaderIDs.InverseViewMatrix, context.camera.worldToCameraMatrix.inverse);
            sheet.properties.SetMatrix(ShaderIDs.InverseProjectionMatrix, projectionMatrix.inverse);
            sheet.properties.SetMatrix(ShaderIDs.ScreenSpaceProjectionMatrix, screenSpaceProjectionMatrix);
            sheet.properties.SetVector(ShaderIDs.Params, new Vector4((float)settings.vignette.value, settings.distanceFade.value, settings.maximumMarchDistance.value, lodCount));
            sheet.properties.SetVector(ShaderIDs.Params2, new Vector4((float)context.width / (float)context.height, (float)size / (float)noiseTex.width, settings.thickness.value, settings.maximumIterationCount.value));

            cmd.GetTemporaryRT(ShaderIDs.Test, size, size, 0, FilterMode.Point, context.sourceFormat);
            cmd.BlitFullscreenTriangle(context.source, ShaderIDs.Test, sheet, (int)Pass.Test);

            if (context.isSceneView)
            {
                cmd.BlitFullscreenTriangle(context.source, m_Resolve, sheet, (int)Pass.Resolve);
            }
            else
            {
                CheckRT(ref m_History, size, size, FilterMode.Bilinear, false);

                if (m_ResetHistory)
                {
                    context.command.BlitFullscreenTriangle(context.source, m_History);
                    m_ResetHistory = false;
                }

                cmd.GetTemporaryRT(ShaderIDs.SSRResolveTemp, size, size, 0, FilterMode.Bilinear, context.sourceFormat);
                cmd.BlitFullscreenTriangle(context.source, ShaderIDs.SSRResolveTemp, sheet, (int)Pass.Resolve);

                sheet.properties.SetTexture(ShaderIDs.History, m_History);
                cmd.BlitFullscreenTriangle(ShaderIDs.SSRResolveTemp, m_Resolve, sheet, (int)Pass.Reproject);

                cmd.CopyTexture(m_Resolve, 0, 0, m_History, 0, 0);

                cmd.ReleaseTemporaryRT(ShaderIDs.SSRResolveTemp);
            }

            cmd.ReleaseTemporaryRT(ShaderIDs.Test);

            // Pre-cache mipmaps ids
            if (m_MipIDs == null || m_MipIDs.Length == 0)
            {
                m_MipIDs = new int[kMaxLods];

                for (int i = 0; i < kMaxLods; i++)
                {
                    m_MipIDs[i] = Shader.PropertyToID("_SSRGaussianMip" + i);
                }
            }

            var compute   = context.resources.computeShaders.gaussianDownsample;
            int kernel    = compute.FindKernel("KMain");
            var mipFormat = RuntimeUtilities.defaultHDRRenderTextureFormat;

            var last = new RenderTargetIdentifier(m_Resolve);

            for (int i = 0; i < lodCount; i++)
            {
                size >>= 1;
                Assert.IsTrue(size > 0);

                cmd.GetTemporaryRT(m_MipIDs[i], size, size, 0, FilterMode.Bilinear, mipFormat, RenderTextureReadWrite.Default, 1, true);
                cmd.SetComputeTextureParam(compute, kernel, "_Source", last);
                cmd.SetComputeTextureParam(compute, kernel, "_Result", m_MipIDs[i]);
                cmd.SetComputeVectorParam(compute, "_Size", new Vector4(size, size, 1f / size, 1f / size));
                cmd.DispatchCompute(compute, kernel, size / 8, size / 8, 1);
                cmd.CopyTexture(m_MipIDs[i], 0, 0, m_Resolve, 0, i + 1);

                last = m_MipIDs[i];
            }

            for (int i = 0; i < lodCount; i++)
            {
                cmd.ReleaseTemporaryRT(m_MipIDs[i]);
            }

            sheet.properties.SetTexture(ShaderIDs.Resolve, m_Resolve);
            cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Composite);
            cmd.EndSample("Screen-space Reflections");
        }
示例#18
0
        public override void Render(PostProcessRenderContext context)
        {
            var       sheet          = context.uberSheet;
            Matrix4x4 frustumCorners = Matrix4x4.identity;

            context.camera.depthTextureMode |= DepthTextureMode.Depth;
            sheet.EnableKeyword("FOGWITHNOISE");
            float fov    = context.camera.fieldOfView;
            float near   = context.camera.nearClipPlane;
            float aspect = context.camera.aspect;

            float   halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
            Vector3 toRight    = context.camera.transform.right * halfHeight * aspect;
            Vector3 toTop      = context.camera.transform.up * halfHeight;

            Vector3 topLeft = context.camera.transform.forward * near + toTop - toRight;
            float   scale   = topLeft.magnitude / near;

            topLeft.Normalize();
            topLeft *= scale;

            Vector3 topRight = context.camera.transform.forward * near + toRight + toTop;

            topRight.Normalize();
            topRight *= scale;

            Vector3 bottomLeft = context.camera.transform.forward * near - toTop - toRight;

            bottomLeft.Normalize();
            bottomLeft *= scale;

            Vector3 bottomRight = context.camera.transform.forward * near + toRight - toTop;

            bottomRight.Normalize();
            bottomRight *= scale;

            if (settings.inArea > settings.area)
            {
                settings.inArea = settings.area;
            }

            frustumCorners.SetRow(0, bottomLeft);
            frustumCorners.SetRow(1, bottomRight);
            frustumCorners.SetRow(2, topRight);
            frustumCorners.SetRow(3, topLeft);


            sheet.properties.SetMatrix(ShaderIDs.FrustumCornersRay, frustumCorners);

            sheet.properties.SetFloat(ShaderIDs.FogDensity, settings.fogDensity * 2);
            sheet.properties.SetColor(ShaderIDs.FogColor1, settings.fogColor);
            sheet.properties.SetFloat(ShaderIDs.FogStart, settings.fogStart + context.camera.transform.position.y + 128);
            sheet.properties.SetFloat(ShaderIDs.FogEnd, settings.fogEnd + context.camera.transform.position.y + 128);
            if (settings.noiseTexture.value != null)
            {
                sheet.properties.SetTexture(ShaderIDs.NoiseTex, settings.noiseTexture.value);
            }
            sheet.properties.SetFloat(ShaderIDs.FogXSpeed, settings.fogXSpeed);
            sheet.properties.SetFloat(ShaderIDs.FogYSpeed, settings.fogYSpeed);
            sheet.properties.SetFloat(ShaderIDs.NoiseAmount, settings.noiseAmount);
            //material.SetFloat(ShaderIDs.WeakFactor", weakFactor);
            sheet.properties.SetFloat(ShaderIDs.OutArea, settings.area * 2);
            sheet.properties.SetFloat(ShaderIDs.InArea, settings.inArea / 2);
            sheet.properties.SetFloat(ShaderIDs.CenterX, settings.centerX);
            sheet.properties.SetFloat(ShaderIDs.CenterY, settings.centerY);
        }
示例#19
0
        // 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, 24, 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, 24, 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;
        }
示例#20
0
 /// <summary>
 /// Returns <c>true</c> if the effect is currently enabled and supported.
 /// </summary>
 /// <param name="context">The current post-processing render context</param>
 /// <returns><c>true</c> if the effect is currently enabled and supported</returns>
 public override bool IsEnabledAndSupported(PostProcessRenderContext context)
 {
     return(enabled.value &&
            ((mode.value == VignetteMode.Classic && intensity.value > 0f) ||
             (mode.value == VignetteMode.Masked && opacity.value > 0f && mask.value != null)));
 }
示例#21
0
        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, 24, 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 <ChromaticAberration>(context);
            RenderEffect <Bloom>(context);
            RenderEffect <Vignette>(context);
            RenderEffect <Grain>(context);

            if (!breakBeforeColorGrading)
            {
                RenderEffect <ColorGrading>(context);
            }

            int pass = 0;

            if (isFinalPass)
            {
                uberSheet.EnableKeyword("FINALPASS");
                dithering.Render(context);

                if (context.flip && !context.isSceneView)
                {
                    pass = 1;
                }
            }

            cmd.BlitFullscreenTriangle(context.source, context.destination, uberSheet, pass);

            context.source      = context.destination;
            context.destination = finalDestination;

            if (releaseTargetAfterUse > -1)
            {
                cmd.ReleaseTemporaryRT(releaseTargetAfterUse);
            }
            if (motionBlurTarget > -1)
            {
                cmd.ReleaseTemporaryRT(motionBlurTarget);
            }
            if (depthOfFieldTarget > -1)
            {
                cmd.ReleaseTemporaryRT(motionBlurTarget);
            }
            if (context.bloomBufferNameID > -1)
            {
                cmd.ReleaseTemporaryRT(context.bloomBufferNameID);
            }

            cmd.EndSample("BuiltinStack");

            return(tempTarget);
        }
示例#22
0
        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);
            sheet.properties.SetFloat(Shader.PropertyToID("_NoNearBlur"), settings.noNearBlur);

            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;
        }
示例#23
0
        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
            var f      = settings.focalLength.value / 1000f;
            var s1     = Mathf.Max(settings.focusDistance.value, f);
            var aspect = (float)context.width / (float)context.height;
            var coeff  = f * f / (settings.aperture.value * (s1 - f) * k_FilmHeight * 2);
            var maxCoC = CalculateMaxCoCRadius(context.height);

            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
            cmd.GetTemporaryRT(ShaderIDs.CoCTex, context.width, context.height, 0, FilterMode.Bilinear, 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;
                var historyRead  = CheckHistory(++pp % 2, context.width, context.height, cocFormat);
                var historyWrite = CheckHistory(++pp % 2, context.width, context.height, cocFormat);
                m_HistoryPingPong = ++pp % 2;

                cmd.BlitFullscreenTriangle(historyRead, historyWrite, sheet, (int)Pass.CoCTemporalFilter);
                cmd.ReleaseTemporaryRT(ShaderIDs.CoCTex);
                cmd.SetGlobalTexture(ShaderIDs.CoCTex, historyWrite);
            }

            // Downsampling and prefiltering pass
            cmd.GetTemporaryRT(ShaderIDs.DepthOfFieldTex, context.width / 2, context.height / 2, 0, FilterMode.Bilinear, colorFormat);
            cmd.BlitFullscreenTriangle(context.source, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.DownsampleAndPrefilter);

            // Bokeh simulation pass
            cmd.GetTemporaryRT(ShaderIDs.DepthOfFieldTemp, context.width / 2, context.height / 2, 0, FilterMode.Bilinear, colorFormat);
            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);

            // 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;
        }
示例#24
0
 /// <summary>
 /// Returns <c>true</c> if the effect is currently enabled and supported.
 /// </summary>
 /// <param name="context">The current post-processing render context</param>
 /// <returns><c>true</c> if the effect is currently enabled and supported</returns>
 public override bool IsEnabledAndSupported(PostProcessRenderContext context)
 {
     return(enabled.value &&
            SystemInfo.graphicsShaderLevel >= 35);
 }
示例#25
0
        // HDR color pipeline is rendered to a 3D lut; it requires Texture3D & compute shaders
        // support - Desktop / Consoles / Some high-end mobiles
        // TODO: Use ShaderIDs for compute once the compatible APIs go in
        void RenderHDRPipeline3D(PostProcessRenderContext context)
        {
            // Unfortunately because AnimationCurve doesn't implement GetHashCode and we don't have
            // any reliable way to figure out if a curve data is different from another one we can't
            // skip regenerating the Lut if nothing has changed. So it has to be done on every
            // frame...
            // It's not a very expensive operation anyway (we're talking about filling a 33x33x33
            // Lut on the GPU) but every little thing helps, especially on mobile.
            {
                CheckInternalLogLut();

                // Lut setup
                var compute = context.resources.computeShaders.lut3DBaker;
                int kernel  = 0;

                switch (settings.tonemapper.value)
                {
                case Tonemapper.None: kernel = compute.FindKernel("KGenLut3D_NoTonemap");
                    break;

                case Tonemapper.Neutral: kernel = compute.FindKernel("KGenLut3D_NeutralTonemap");
                    break;

                case Tonemapper.ACES: kernel = compute.FindKernel("KGenLut3D_AcesTonemap");
                    break;

                case Tonemapper.Custom: kernel = compute.FindKernel("KGenLut3D_CustomTonemap");
                    break;
                }

                int groupSizeXY = Mathf.CeilToInt(k_Lut3DSize / 8f);
                int groupSizeZ  = Mathf.CeilToInt(k_Lut3DSize / (RuntimeUtilities.isAndroidOpenGL ? 2f : 8f));
                var cmd         = context.command;
                cmd.SetComputeTextureParam(compute, kernel, "_Output", m_InternalLogLut);
                cmd.SetComputeVectorParam(compute, "_Size", new Vector4(k_Lut3DSize, 1f / (k_Lut3DSize - 1f), 0f, 0f));

                var colorBalance = ColorUtilities.ComputeColorBalance(settings.temperature.value, settings.tint.value);
                cmd.SetComputeVectorParam(compute, "_ColorBalance", colorBalance);
                cmd.SetComputeVectorParam(compute, "_ColorFilter", settings.colorFilter.value);

                float hue = settings.hueShift.value / 360f;         // Remap to [-0.5;0.5]
                float sat = settings.saturation.value / 100f + 1f;  // Remap to [0;2]
                float con = settings.contrast.value / 100f + 1f;    // Remap to [0;2]
                cmd.SetComputeVectorParam(compute, "_HueSatCon", new Vector4(hue, sat, con, 0f));

                var channelMixerR = new Vector4(settings.mixerRedOutRedIn, settings.mixerRedOutGreenIn, settings.mixerRedOutBlueIn, 0f);
                var channelMixerG = new Vector4(settings.mixerGreenOutRedIn, settings.mixerGreenOutGreenIn, settings.mixerGreenOutBlueIn, 0f);
                var channelMixerB = new Vector4(settings.mixerBlueOutRedIn, settings.mixerBlueOutGreenIn, settings.mixerBlueOutBlueIn, 0f);
                cmd.SetComputeVectorParam(compute, "_ChannelMixerRed", channelMixerR / 100f); // Remap to [-2;2]
                cmd.SetComputeVectorParam(compute, "_ChannelMixerGreen", channelMixerG / 100f);
                cmd.SetComputeVectorParam(compute, "_ChannelMixerBlue", channelMixerB / 100f);

                var lift     = ColorUtilities.ColorToLift(settings.lift.value * 0.2f);
                var gain     = ColorUtilities.ColorToGain(settings.gain.value * 0.8f);
                var invgamma = ColorUtilities.ColorToInverseGamma(settings.gamma.value * 0.8f);
                cmd.SetComputeVectorParam(compute, "_Lift", new Vector4(lift.x, lift.y, lift.z, 0f));
                cmd.SetComputeVectorParam(compute, "_InvGamma", new Vector4(invgamma.x, invgamma.y, invgamma.z, 0f));
                cmd.SetComputeVectorParam(compute, "_Gain", new Vector4(gain.x, gain.y, gain.z, 0f));

                cmd.SetComputeTextureParam(compute, kernel, "_Curves", GetCurveTexture(true));

                if (settings.tonemapper.value == Tonemapper.Custom)
                {
                    m_HableCurve.Init(
                        settings.toneCurveToeStrength.value,
                        settings.toneCurveToeLength.value,
                        settings.toneCurveShoulderStrength.value,
                        settings.toneCurveShoulderLength.value,
                        settings.toneCurveShoulderAngle.value,
                        settings.toneCurveGamma.value
                        );

                    cmd.SetComputeVectorParam(compute, "_CustomToneCurve", m_HableCurve.uniforms.curve);
                    cmd.SetComputeVectorParam(compute, "_ToeSegmentA", m_HableCurve.uniforms.toeSegmentA);
                    cmd.SetComputeVectorParam(compute, "_ToeSegmentB", m_HableCurve.uniforms.toeSegmentB);
                    cmd.SetComputeVectorParam(compute, "_MidSegmentA", m_HableCurve.uniforms.midSegmentA);
                    cmd.SetComputeVectorParam(compute, "_MidSegmentB", m_HableCurve.uniforms.midSegmentB);
                    cmd.SetComputeVectorParam(compute, "_ShoSegmentA", m_HableCurve.uniforms.shoSegmentA);
                    cmd.SetComputeVectorParam(compute, "_ShoSegmentB", m_HableCurve.uniforms.shoSegmentB);
                }

                // Generate the lut
                context.command.BeginSample("HdrColorGradingLut3D");
                cmd.DispatchCompute(compute, kernel, groupSizeXY, groupSizeXY, groupSizeZ);
                context.command.EndSample("HdrColorGradingLut3D");
            }

            var lut       = m_InternalLogLut;
            var uberSheet = context.uberSheet;

            uberSheet.EnableKeyword("COLOR_GRADING_HDR_3D");
            uberSheet.properties.SetTexture(ShaderIDs.Lut3D, lut);
            uberSheet.properties.SetVector(ShaderIDs.Lut3D_Params, new Vector2(1f / lut.width, lut.width - 1f));
            uberSheet.properties.SetFloat(ShaderIDs.PostExposure, RuntimeUtilities.Exp2(settings.postExposure.value));

            context.logLut = lut;
        }
示例#26
0
 public virtual bool IsEnabledAndSupported(PostProcessRenderContext context)
 {
     return(enabled.value);
 }
示例#27
0
 public bool IsSupported(PostProcessRenderContext context)
 {
     return(intensity > 0f &&
            !RuntimeUtilities.scriptableRenderPipelineActive);
 }
 internal void BeginFrame(PostProcessRenderContext context)
 {
     m_Command        = context.command;
     m_PropertySheets = context.propertySheets;
     m_Resources      = context.resources;
 }
示例#29
0
        public override void Render(PostProcessRenderContext context)
        {
            var cmd = context.command;

            if (m_ResetHistory)
            {
                cmd.BlitFullscreenTriangle(context.source, context.destination);
                m_ResetHistory = false;
                return;
            }

            const float kMaxBlurRadius = 5f;
            var vectorRTFormat = RenderTextureFormat.RGHalf;
            var packedRTFormat = RenderTextureFormat.ARGB2101010.IsSupported()
                ? RenderTextureFormat.ARGB2101010
                : RenderTextureFormat.ARGB32;

            var sheet = context.propertySheets.Get(context.resources.shaders.motionBlur);
            cmd.BeginSample("MotionBlur");

            // Calculate the maximum blur radius in pixels.
            int maxBlurPixels = (int)(kMaxBlurRadius * context.height / 100);

            // Calculate the TileMax size.
            // It should be a multiple of 8 and larger than maxBlur.
            int tileSize = ((maxBlurPixels - 1) / 8 + 1) * 8;

            // Pass 1 - Velocity/depth packing
            var velocityScale = settings.shutterAngle / 360f;
            sheet.properties.SetFloat(ShaderIDs.VelocityScale, velocityScale);
            sheet.properties.SetFloat(ShaderIDs.MaxBlurRadius, maxBlurPixels);
            sheet.properties.SetFloat(ShaderIDs.RcpMaxBlurRadius, 1f / maxBlurPixels);

            int vbuffer = ShaderIDs.VelocityTex;
            CreateTemporaryRT(context, vbuffer, context.width, context.height, packedRTFormat);
            cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, vbuffer, sheet, (int)Pass.VelocitySetup);

            // Pass 2 - First TileMax filter (1/2 downsize)
            int tile2 = ShaderIDs.Tile2RT;
            CreateTemporaryRT(context, tile2, context.width / 2, context.height / 2, vectorRTFormat);
            cmd.BlitFullscreenTriangle(vbuffer, tile2, sheet, (int)Pass.TileMax1);

            // Pass 3 - Second TileMax filter (1/2 downsize)
            int tile4 = ShaderIDs.Tile4RT;
            CreateTemporaryRT(context, tile4, context.width / 4, context.height / 4, vectorRTFormat);
            cmd.BlitFullscreenTriangle(tile2, tile4, sheet, (int)Pass.TileMax2);
            cmd.ReleaseTemporaryRT(tile2);

            // Pass 4 - Third TileMax filter (1/2 downsize)
            int tile8 = ShaderIDs.Tile8RT;
            CreateTemporaryRT(context, tile8, context.width / 8, context.height / 8, vectorRTFormat);
            cmd.BlitFullscreenTriangle(tile4, tile8, sheet, (int)Pass.TileMax2);
            cmd.ReleaseTemporaryRT(tile4);

            // Pass 5 - Fourth TileMax filter (reduce to tileSize)
            var tileMaxOffs = Vector2.one * (tileSize / 8f - 1f) * -0.5f;
            sheet.properties.SetVector(ShaderIDs.TileMaxOffs, tileMaxOffs);
            sheet.properties.SetFloat(ShaderIDs.TileMaxLoop, (int)(tileSize / 8f));

            int tile = ShaderIDs.TileVRT;
            CreateTemporaryRT(context, tile, context.width / tileSize, context.height / tileSize, vectorRTFormat);
            cmd.BlitFullscreenTriangle(tile8, tile, sheet, (int)Pass.TileMaxV);
            cmd.ReleaseTemporaryRT(tile8);

            // Pass 6 - NeighborMax filter
            int neighborMax = ShaderIDs.NeighborMaxTex;
            CreateTemporaryRT(context, neighborMax, context.width / tileSize, context.height / tileSize, vectorRTFormat);
            cmd.BlitFullscreenTriangle(tile, neighborMax, sheet, (int)Pass.NeighborMax);
            cmd.ReleaseTemporaryRT(tile);

            // Pass 7 - Reconstruction pass
            sheet.properties.SetFloat(ShaderIDs.LoopCount, Mathf.Clamp(settings.sampleCount / 2, 1, 64));
            cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Reconstruction);

            cmd.ReleaseTemporaryRT(vbuffer);
            cmd.ReleaseTemporaryRT(neighborMax);
            cmd.EndSample("MotionBlur");
        }
        public override void Render(PostProcessRenderContext context)
        {
            var sheet = context.propertySheets.Get(_shader);

            context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 4);
        }