public void OnRenderImage(RenderTexture source, RenderTexture destination) { if (material == null) { Graphics.Blit(source, destination); return; } if (m_HasInformationFromPreviousFrame) { m_HasInformationFromPreviousFrame = (m_PreviousDepthBuffer != null) && (source.width == m_PreviousDepthBuffer.width) && (source.height == m_PreviousDepthBuffer.height); } bool doTemporalFilterThisFrame = m_HasInformationFromPreviousFrame && settings.advancedSettings.temporalFilterStrength > 0.0; m_HasInformationFromPreviousFrame = false; // Not using deferred shading? Just blit source to destination. if (Camera.current.actualRenderingPath != RenderingPath.DeferredShading) { Graphics.Blit(source, destination); return; } var rtW = source.width; var rtH = source.height; // RGB: Normals, A: Roughness. // Has the nice benefit of allowing us to control the filtering mode as well. RenderTexture bilateralKeyTexture = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.ARGB32); bilateralKeyTexture.filterMode = FilterMode.Point; Graphics.Blit(source, bilateralKeyTexture, material, (int)PassIndex.BilateralKeyPack); material.SetTexture("_NormalAndRoughnessTexture", bilateralKeyTexture); float sWidth = source.width; float sHeight = source.height; Vector2 sourceToTempUV = new Vector2(sWidth / rtW, sHeight / rtH); int downsampleAmount = (settings.advancedSettings.resolution == SSRResolution.FullResolution) ? 1 : 2; rtW = rtW / downsampleAmount; rtH = rtH / downsampleAmount; material.SetVector("_SourceToTempUV", new Vector4(sourceToTempUV.x, sourceToTempUV.y, 1.0f / sourceToTempUV.x, 1.0f / sourceToTempUV.y)); Matrix4x4 P = GetComponent <Camera>().projectionMatrix; Vector4 projInfo = new Vector4 ((-2.0f / (sWidth * P[0])), (-2.0f / (sHeight * P[5])), ((1.0f - P[2]) / P[0]), ((1.0f + P[6]) / P[5])); /** The height in pixels of a 1m object if viewed from 1m away. */ float pixelsPerMeterAtOneMeter = sWidth / (-2.0f * (float)(Math.Tan(GetComponent <Camera>().fieldOfView / 180.0 * Math.PI * 0.5))); material.SetFloat("_PixelsPerMeterAtOneMeter", pixelsPerMeterAtOneMeter); float sx = sWidth / 2.0f; float sy = sHeight / 2.0f; Matrix4x4 warpToScreenSpaceMatrix = new Matrix4x4(); warpToScreenSpaceMatrix.SetRow(0, new Vector4(sx, 0.0f, 0.0f, sx)); warpToScreenSpaceMatrix.SetRow(1, new Vector4(0.0f, sy, 0.0f, sy)); warpToScreenSpaceMatrix.SetRow(2, new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); warpToScreenSpaceMatrix.SetRow(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); Matrix4x4 projectToPixelMatrix = warpToScreenSpaceMatrix * P; material.SetVector("_ScreenSize", new Vector2(sWidth, sHeight)); material.SetVector("_ReflectionBufferSize", new Vector2(rtW, rtH)); Vector2 invScreenSize = new Vector2((float)(1.0 / sWidth), (float)(1.0 / sHeight)); Matrix4x4 worldToCameraMatrix = GetComponent <Camera>().worldToCameraMatrix; Matrix4x4 cameraToWorldMatrix = GetComponent <Camera>().worldToCameraMatrix.inverse; material.SetVector("_InvScreenSize", invScreenSize); material.SetVector("_ProjInfo", projInfo); // used for unprojection material.SetMatrix("_ProjectToPixelMatrix", projectToPixelMatrix); material.SetMatrix("_WorldToCameraMatrix", worldToCameraMatrix); material.SetMatrix("_CameraToWorldMatrix", cameraToWorldMatrix); material.SetInt("_EnableRefine", settings.advancedSettings.reduceBanding ? 1 : 0); material.SetInt("_AdditiveReflection", settings.basicSettings.additiveReflection ? 1 : 0); material.SetInt("_ImproveCorners", settings.advancedSettings.improveCorners ? 1 : 0); material.SetFloat("_ScreenEdgeFading", settings.basicSettings.screenEdgeFading); material.SetFloat("_MipBias", mipBias); material.SetInt("_UseOcclusion", useOcclusion ? 1 : 0); material.SetInt("_BilateralUpsampling", settings.advancedSettings.bilateralUpsample ? 1 : 0); material.SetInt("_FallbackToSky", fallbackToSky ? 1 : 0); material.SetInt("_TreatBackfaceHitAsMiss", settings.advancedSettings.treatBackfaceHitAsMiss ? 1 : 0); material.SetInt("_AllowBackwardsRays", settings.advancedSettings.allowBackwardsRays ? 1 : 0); material.SetInt("_TraceEverywhere", settings.advancedSettings.traceEverywhere ? 1 : 0); float z_f = GetComponent <Camera>().farClipPlane; float z_n = GetComponent <Camera>().nearClipPlane; Vector3 cameraClipInfo = (float.IsPositiveInfinity(z_f)) ? new Vector3(z_n, -1.0f, 1.0f) : new Vector3(z_n * z_f, z_n - z_f, z_f); material.SetVector("_CameraClipInfo", cameraClipInfo); material.SetFloat("_MaxRayTraceDistance", settings.basicSettings.maxDistance); material.SetFloat("_FadeDistance", settings.basicSettings.fadeDistance); material.SetFloat("_LayerThickness", settings.reflectionSettings.widthModifier); const int maxMip = 5; RenderTexture[] reflectionBuffers; RenderTextureFormat intermediateFormat = settings.basicSettings.enableHDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32; reflectionBuffers = new RenderTexture[maxMip]; for (int i = 0; i < maxMip; ++i) { if (fullResolutionFiltering) { reflectionBuffers[i] = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, intermediateFormat); } else { reflectionBuffers[i] = m_RTU.GetTemporaryRenderTexture(rtW >> i, rtH >> i, 0, intermediateFormat); } // We explicitly interpolate during bilateral upsampling. reflectionBuffers[i].filterMode = settings.advancedSettings.bilateralUpsample ? FilterMode.Point : FilterMode.Bilinear; } material.SetInt("_EnableSSR", 1); material.SetInt("_DebugMode", (int)settings.debugSettings.debugMode); material.SetInt("_TraceBehindObjects", settings.advancedSettings.traceBehindObjects ? 1 : 0); material.SetInt("_MaxSteps", settings.reflectionSettings.maxSteps); RenderTexture rayHitTexture = m_RTU.GetTemporaryRenderTexture(rtW, rtH); // We have 5 passes for different step sizes int tracePass = Mathf.Clamp(settings.reflectionSettings.rayStepSize, 0, 4); Graphics.Blit(source, rayHitTexture, material, tracePass); material.SetTexture("_HitPointTexture", rayHitTexture); // Resolve the hitpoints into the mirror reflection buffer Graphics.Blit(source, reflectionBuffers[0], material, (int)PassIndex.HitPointToReflections); material.SetTexture("_ReflectionTexture0", reflectionBuffers[0]); material.SetInt("_FullResolutionFiltering", fullResolutionFiltering ? 1 : 0); material.SetFloat("_MaxRoughness", 1.0f - settings.reflectionSettings.smoothFallbackThreshold); material.SetFloat("_RoughnessFalloffRange", settings.reflectionSettings.smoothFallbackDistance); material.SetFloat("_SSRMultiplier", settings.basicSettings.reflectionMultiplier); RenderTexture[] edgeTextures = new RenderTexture[maxMip]; if (settings.advancedSettings.bilateralUpsample && useEdgeDetector) { edgeTextures[0] = m_RTU.GetTemporaryRenderTexture(rtW, rtH); Graphics.Blit(source, edgeTextures[0], material, (int)PassIndex.EdgeGeneration); for (int i = 1; i < maxMip; ++i) { edgeTextures[i] = m_RTU.GetTemporaryRenderTexture(rtW >> i, rtH >> i); material.SetInt("_LastMip", i - 1); Graphics.Blit(edgeTextures[i - 1], edgeTextures[i], material, (int)PassIndex.MinMipGeneration); } } if (settings.advancedSettings.highQualitySharpReflections) { RenderTexture filteredReflections = m_RTU.GetTemporaryRenderTexture(reflectionBuffers[0].width, reflectionBuffers[0].height, 0, reflectionBuffers[0].format); filteredReflections.filterMode = reflectionBuffers[0].filterMode; reflectionBuffers[0].filterMode = FilterMode.Bilinear; Graphics.Blit(reflectionBuffers[0], filteredReflections, material, (int)PassIndex.PoissonBlur); // Replace the unfiltered buffer with the newly filtered one. m_RTU.ReleaseTemporaryRenderTexture(reflectionBuffers[0]); reflectionBuffers[0] = filteredReflections; material.SetTexture("_ReflectionTexture0", reflectionBuffers[0]); } // Generate the blurred low-resolution buffers for (int i = 1; i < maxMip; ++i) { RenderTexture inputTex = reflectionBuffers[i - 1]; RenderTexture hBlur; if (fullResolutionFiltering) { hBlur = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, intermediateFormat); } else { int lowMip = i; hBlur = m_RTU.GetTemporaryRenderTexture(rtW >> lowMip, rtH >> (i - 1), 0, intermediateFormat); } for (int j = 0; j < (fullResolutionFiltering ? (i * i) : 1); ++j) { // Currently we blur at the resolution of the previous mip level, we could save bandwidth by blurring directly to the lower resolution. material.SetVector("_Axis", new Vector4(1.0f, 0.0f, 0.0f, 0.0f)); material.SetFloat("_CurrentMipLevel", i - 1.0f); Graphics.Blit(inputTex, hBlur, material, (int)PassIndex.Blur); material.SetVector("_Axis", new Vector4(0.0f, 1.0f, 0.0f, 0.0f)); inputTex = reflectionBuffers[i]; Graphics.Blit(hBlur, inputTex, material, (int)PassIndex.Blur); } material.SetTexture("_ReflectionTexture" + i, reflectionBuffers[i]); m_RTU.ReleaseTemporaryRenderTexture(hBlur); } if (settings.advancedSettings.bilateralUpsample && useEdgeDetector) { for (int i = 0; i < maxMip; ++i) { material.SetTexture("_EdgeTexture" + i, edgeTextures[i]); } } material.SetInt("_UseEdgeDetector", useEdgeDetector ? 1 : 0); RenderTexture averageRayDistanceBuffer = m_RTU.GetTemporaryRenderTexture(source.width, source.height, 0, RenderTextureFormat.RHalf); if (computeAverageRayDistance) { Graphics.Blit(source, averageRayDistanceBuffer, material, (int)PassIndex.AverageRayDistanceGeneration); } material.SetInt("_UseAverageRayDistance", computeAverageRayDistance ? 1 : 0); material.SetTexture("_AverageRayDistanceBuffer", averageRayDistanceBuffer); bool resolveDiffersFromTraceRes = (settings.advancedSettings.resolution == SSRResolution.HalfTraceFullResolve); RenderTexture finalReflectionBuffer = m_RTU.GetTemporaryRenderTexture(resolveDiffersFromTraceRes ? source.width : rtW, resolveDiffersFromTraceRes ? source.height : rtH, 0, intermediateFormat); material.SetFloat("_FresnelFade", settings.reflectionSettings.fresnelFade); material.SetFloat("_FresnelFadePower", settings.reflectionSettings.fresnelFadePower); material.SetFloat("_DistanceBlur", settings.reflectionSettings.distanceBlur); material.SetInt("_HalfResolution", (settings.advancedSettings.resolution != SSRResolution.FullResolution) ? 1 : 0); material.SetInt("_HighlightSuppression", settings.advancedSettings.highlightSuppression ? 1 : 0); Graphics.Blit(reflectionBuffers[0], finalReflectionBuffer, material, (int)PassIndex.CompositeSSR); material.SetTexture("_FinalReflectionTexture", finalReflectionBuffer); RenderTexture temporallyFilteredBuffer = m_RTU.GetTemporaryRenderTexture(resolveDiffersFromTraceRes ? source.width : rtW, resolveDiffersFromTraceRes ? source.height : rtH, 0, intermediateFormat); if (doTemporalFilterThisFrame) { material.SetInt("_UseTemporalConfidence", settings.advancedSettings.useTemporalConfidence ? 1 : 0); material.SetFloat("_TemporalAlpha", settings.advancedSettings.temporalFilterStrength); material.SetMatrix("_CurrentCameraToPreviousCamera", m_PreviousWorldToCameraMatrix * cameraToWorldMatrix); material.SetTexture("_PreviousReflectionTexture", m_PreviousReflectionBuffer); material.SetTexture("_PreviousCSZBuffer", m_PreviousDepthBuffer); Graphics.Blit(source, temporallyFilteredBuffer, material, (int)PassIndex.TemporalFilter); material.SetTexture("_FinalReflectionTexture", temporallyFilteredBuffer); } if (settings.advancedSettings.temporalFilterStrength > 0.0) { m_PreviousWorldToCameraMatrix = worldToCameraMatrix; PreparePreviousBuffers(source.width, source.height); Graphics.Blit(source, m_PreviousDepthBuffer, material, (int)PassIndex.BlitDepthAsCSZ); Graphics.Blit(rayHitTexture, m_PreviousHitBuffer); Graphics.Blit(doTemporalFilterThisFrame ? temporallyFilteredBuffer : finalReflectionBuffer, m_PreviousReflectionBuffer); m_HasInformationFromPreviousFrame = true; } Graphics.Blit(source, destination, material, (int)PassIndex.CompositeFinal); m_RTU.ReleaseAllTemporaryRenderTextures(); }
private void DoDepthOfField(RenderTexture source, RenderTexture destination) { m_CurrentQualitySettings = QualitySettings.presetQualitySettings[(int)settings.filteringQuality]; float radiusAdjustement = source.height / 720f; float textureBokehScale = radiusAdjustement; float textureBokehMaxRadius = Mathf.Max(focus.nearBlurRadius, focus.farBlurRadius) * textureBokehScale * 0.75f; float nearBlurRadius = focus.nearBlurRadius * radiusAdjustement; float farBlurRadius = focus.farBlurRadius * radiusAdjustement; float maxBlurRadius = Mathf.Max(nearBlurRadius, farBlurRadius); switch (settings.apertureShape) { case ApertureShape.Hexagonal: maxBlurRadius *= 1.2f; break; case ApertureShape.Octogonal: maxBlurRadius *= 1.15f; break; } if (maxBlurRadius < 0.5f) { Graphics.Blit(source, destination); return; } // Quarter resolution int rtW = source.width / 2; int rtH = source.height / 2; var blurrinessCoe = new Vector4(nearBlurRadius * 0.5f, farBlurRadius * 0.5f, 0f, 0f); var colorAndCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH); var colorAndCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH); // Downsample to Color + COC buffer Vector4 cocParam; Vector4 cocCoe; ComputeCocParameters(out cocParam, out cocCoe); filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam); filmicDepthOfFieldMaterial.SetVector("_BlurCoe", cocCoe); Graphics.Blit(source, colorAndCoc2, filmicDepthOfFieldMaterial, (int)Passes.CaptureCocExplicit); var src = colorAndCoc2; var dst = colorAndCoc; // Collect texture bokeh candidates and replace with a darker pixel if (shouldPerformBokeh) { // Blur a bit so we can do a frequency check var blurred = m_RTU.GetTemporaryRenderTexture(rtW, rtH); Graphics.Blit(src, blurred, filmicDepthOfFieldMaterial, (int)Passes.BoxBlur); filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0f, 1.5f, 0f, 1.5f)); Graphics.Blit(blurred, dst, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted); filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(1.5f, 0f, 0f, 1.5f)); Graphics.Blit(dst, blurred, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted); // Collect texture bokeh candidates and replace with a darker pixel textureBokehMaterial.SetTexture("_BlurredColor", blurred); textureBokehMaterial.SetFloat("_SpawnHeuristic", bokehTexture.spawnHeuristic); textureBokehMaterial.SetVector("_BokehParams", new Vector4(bokehTexture.scale * textureBokehScale, bokehTexture.intensity, bokehTexture.threshold, textureBokehMaxRadius)); Graphics.SetRandomWriteTarget(1, computeBufferPoints); Graphics.Blit(src, dst, textureBokehMaterial, (int)BokehTexturesPasses.Collect); Graphics.ClearRandomWriteTargets(); SwapRenderTexture(ref src, ref dst); m_RTU.ReleaseTemporaryRenderTexture(blurred); } filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam); filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); // Dilate near blur factor RenderTexture blurredFgCoc = null; if (m_CurrentQualitySettings.dilateNearBlur) { var blurredFgCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); blurredFgCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0f, nearBlurRadius * 0.75f, 0f, 0f)); Graphics.Blit(src, blurredFgCoc2, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCocFromColor); filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(nearBlurRadius * 0.75f, 0f, 0f, 0f)); Graphics.Blit(blurredFgCoc2, blurredFgCoc, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCoc); m_RTU.ReleaseTemporaryRenderTexture(blurredFgCoc2); blurredFgCoc.filterMode = FilterMode.Point; } // Blur downsampled color to fill the gap between samples if (m_CurrentQualitySettings.prefilterBlur) { Graphics.Blit(src, dst, filmicDepthOfFieldMaterial, (int)Passes.CocPrefilter); SwapRenderTexture(ref src, ref dst); } // Apply blur : Circle / Hexagonal or Octagonal (blur will create bokeh if bright pixel where not removed by "m_UseBokehTexture") switch (settings.apertureShape) { case ApertureShape.Circular: DoCircularBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); break; case ApertureShape.Hexagonal: DoHexagonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); break; case ApertureShape.Octogonal: DoOctogonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); break; } // Smooth result switch (m_CurrentQualitySettings.medianFilter) { case FilterQuality.Normal: { medianFilterMaterial.SetVector("_Offsets", new Vector4(1f, 0f, 0f, 0f)); Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3); SwapRenderTexture(ref src, ref dst); medianFilterMaterial.SetVector("_Offsets", new Vector4(0f, 1f, 0f, 0f)); Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3); SwapRenderTexture(ref src, ref dst); break; } case FilterQuality.High: { Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3X3); SwapRenderTexture(ref src, ref dst); break; } } // Merge to full resolution (with boost) + upsampling (linear or bicubic) filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); filmicDepthOfFieldMaterial.SetVector("_Convolved_TexelSize", new Vector4(src.width, src.height, 1f / src.width, 1f / src.height)); filmicDepthOfFieldMaterial.SetTexture("_SecondTex", src); int mergePass = (int)Passes.MergeExplicit; // Apply texture bokeh if (shouldPerformBokeh) { var tmp = m_RTU.GetTemporaryRenderTexture(source.height, source.width, 0, source.format); Graphics.Blit(source, tmp, filmicDepthOfFieldMaterial, mergePass); Graphics.SetRenderTarget(tmp); ComputeBuffer.CopyCount(computeBufferPoints, computeBufferDrawArgs, 0); textureBokehMaterial.SetBuffer("pointBuffer", computeBufferPoints); textureBokehMaterial.SetTexture("_MainTex", bokehTexture.texture); textureBokehMaterial.SetVector("_Screen", new Vector3(1f / (1f * source.width), 1f / (1f * source.height), textureBokehMaxRadius)); textureBokehMaterial.SetPass((int)BokehTexturesPasses.Apply); Graphics.DrawProceduralIndirect(MeshTopology.Points, computeBufferDrawArgs, 0); Graphics.Blit(tmp, destination); // Hackaround for DX11 flipfun (OPTIMIZEME) } else { Graphics.Blit(source, destination, filmicDepthOfFieldMaterial, mergePass); } }