| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- using System;
- using UnityEngine;
- namespace UnityStandardAssets.ImageEffects
- {
- [ExecuteInEditMode]
- [RequireComponent (typeof(Camera))]
- [AddComponentMenu ("Image Effects/Camera/Depth of Field (Lens Blur, Scatter, DX11)") ]
- public class DepthOfField : PostEffectsBase {
- public bool visualizeFocus = false;
- public float focalLength = 10.0f;
- public float focalSize = 0.05f;
- public float aperture = 0.5f;
- public Transform focalTransform = null;
- public float maxBlurSize = 2.0f;
- public bool highResolution = false;
- public enum BlurType {
- DiscBlur = 0,
- DX11 = 1,
- }
- public enum BlurSampleCount {
- Low = 0,
- Medium = 1,
- High = 2,
- }
- public BlurType blurType = BlurType.DiscBlur;
- public BlurSampleCount blurSampleCount = BlurSampleCount.High;
- public bool nearBlur = false;
- public float foregroundOverlap = 1.0f;
- public Shader dofHdrShader;
- private Material dofHdrMaterial = null;
- public Shader dx11BokehShader;
- private Material dx11bokehMaterial;
- public float dx11BokehThreshold = 0.5f;
- public float dx11SpawnHeuristic = 0.0875f;
- public Texture2D dx11BokehTexture = null;
- public float dx11BokehScale = 1.2f;
- public float dx11BokehIntensity = 2.5f;
- private float focalDistance01 = 10.0f;
- private ComputeBuffer cbDrawArgs;
- private ComputeBuffer cbPoints;
- private float internalBlurWidth = 1.0f;
- private Camera cachedCamera;
- public override bool CheckResources () {
- CheckSupport (true); // only requires depth, not HDR
- dofHdrMaterial = CheckShaderAndCreateMaterial (dofHdrShader, dofHdrMaterial);
- if (supportDX11 && blurType == BlurType.DX11) {
- dx11bokehMaterial = CheckShaderAndCreateMaterial(dx11BokehShader, dx11bokehMaterial);
- CreateComputeResources ();
- }
- if (!isSupported)
- ReportAutoDisable ();
- return isSupported;
- }
- void OnEnable () {
- cachedCamera = GetComponent<Camera>();
- cachedCamera.depthTextureMode |= DepthTextureMode.Depth;
- }
- void OnDisable () {
- ReleaseComputeResources ();
- if (dofHdrMaterial) DestroyImmediate(dofHdrMaterial);
- dofHdrMaterial = null;
- if (dx11bokehMaterial) DestroyImmediate(dx11bokehMaterial);
- dx11bokehMaterial = null;
- }
- void ReleaseComputeResources () {
- if (cbDrawArgs != null) cbDrawArgs.Release();
- cbDrawArgs = null;
- if (cbPoints != null) cbPoints.Release();
- cbPoints = null;
- }
- void CreateComputeResources () {
- if (cbDrawArgs == null)
- {
- cbDrawArgs = new ComputeBuffer (1, 16, ComputeBufferType.IndirectArguments);
- var args= new int[4];
- args[0] = 0; args[1] = 1; args[2] = 0; args[3] = 0;
- cbDrawArgs.SetData (args);
- }
- if (cbPoints == null)
- {
- cbPoints = new ComputeBuffer (90000, 12+16, ComputeBufferType.Append);
- }
- }
- float FocalDistance01 ( float worldDist) {
- return cachedCamera.WorldToViewportPoint((worldDist-cachedCamera.nearClipPlane) * cachedCamera.transform.forward + cachedCamera.transform.position).z / (cachedCamera.farClipPlane-cachedCamera.nearClipPlane);
- }
- private void WriteCoc ( RenderTexture fromTo, bool fgDilate) {
- dofHdrMaterial.SetTexture("_FgOverlap", null);
- if (nearBlur && fgDilate) {
- int rtW = fromTo.width/2;
- int rtH = fromTo.height/2;
- // capture fg coc
- RenderTexture temp2 = RenderTexture.GetTemporary (rtW, rtH, 0, fromTo.format);
- Graphics.Blit (fromTo, temp2, dofHdrMaterial, 4);
- // special blur
- float fgAdjustment = internalBlurWidth * foregroundOverlap;
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (0.0f, fgAdjustment , 0.0f, fgAdjustment));
- RenderTexture temp1 = RenderTexture.GetTemporary (rtW, rtH, 0, fromTo.format);
- Graphics.Blit (temp2, temp1, dofHdrMaterial, 2);
- RenderTexture.ReleaseTemporary(temp2);
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (fgAdjustment, 0.0f, 0.0f, fgAdjustment));
- temp2 = RenderTexture.GetTemporary (rtW, rtH, 0, fromTo.format);
- Graphics.Blit (temp1, temp2, dofHdrMaterial, 2);
- RenderTexture.ReleaseTemporary(temp1);
- // "merge up" with background COC
- dofHdrMaterial.SetTexture("_FgOverlap", temp2);
- Graphics.Blit (fromTo, fromTo, dofHdrMaterial, 13);
- RenderTexture.ReleaseTemporary(temp2);
- }
- else {
- // capture full coc in alpha channel (fromTo is not read, but bound to detect screen flip)
- Graphics.Blit (fromTo, fromTo, dofHdrMaterial, 0);
- }
- }
- void OnRenderImage (RenderTexture source, RenderTexture destination) {
- if (!CheckResources ()) {
- Graphics.Blit (source, destination);
- return;
- }
- // clamp & prepare values so they make sense
- if (aperture < 0.0f) aperture = 0.0f;
- if (maxBlurSize < 0.1f) maxBlurSize = 0.1f;
- focalSize = Mathf.Clamp(focalSize, 0.0f, 2.0f);
- internalBlurWidth = Mathf.Max(maxBlurSize, 0.0f);
- // focal & coc calculations
- focalDistance01 = (focalTransform) ? (cachedCamera.WorldToViewportPoint (focalTransform.position)).z / (cachedCamera.farClipPlane) : FocalDistance01 (focalLength);
- dofHdrMaterial.SetVector("_CurveParams", new Vector4(1.0f, focalSize, (1.0f / (1.0f - aperture) - 1.0f), focalDistance01));
- // possible render texture helpers
- RenderTexture rtLow = null;
- RenderTexture rtLow2 = null;
- RenderTexture rtSuperLow1 = null;
- RenderTexture rtSuperLow2 = null;
- float fgBlurDist = internalBlurWidth * foregroundOverlap;
- if (visualizeFocus)
- {
- //
- // 2.
- // visualize coc
- //
- //
- WriteCoc (source, true);
- Graphics.Blit (source, destination, dofHdrMaterial, 16);
- }
- else if ((blurType == BlurType.DX11) && dx11bokehMaterial)
- {
- //
- // 1.
- // optimized dx11 bokeh scatter
- //
- //
- if (highResolution) {
- internalBlurWidth = internalBlurWidth < 0.1f ? 0.1f : internalBlurWidth;
- fgBlurDist = internalBlurWidth * foregroundOverlap;
- rtLow = RenderTexture.GetTemporary (source.width, source.height, 0, source.format);
- var dest2= RenderTexture.GetTemporary (source.width, source.height, 0, source.format);
- // capture COC
- WriteCoc (source, false);
- // blur a bit so we can do a frequency check
- rtSuperLow1 = RenderTexture.GetTemporary(source.width>>1, source.height>>1, 0, source.format);
- rtSuperLow2 = RenderTexture.GetTemporary(source.width>>1, source.height>>1, 0, source.format);
- Graphics.Blit(source, rtSuperLow1, dofHdrMaterial, 15);
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (0.0f, 1.5f , 0.0f, 1.5f));
- Graphics.Blit (rtSuperLow1, rtSuperLow2, dofHdrMaterial, 19);
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (1.5f, 0.0f, 0.0f, 1.5f));
- Graphics.Blit (rtSuperLow2, rtSuperLow1, dofHdrMaterial, 19);
- // capture fg coc
- if (nearBlur)
- Graphics.Blit (source, rtSuperLow2, dofHdrMaterial, 4);
- dx11bokehMaterial.SetTexture ("_BlurredColor", rtSuperLow1);
- dx11bokehMaterial.SetFloat ("_SpawnHeuristic", dx11SpawnHeuristic);
- dx11bokehMaterial.SetVector ("_BokehParams", new Vector4(dx11BokehScale, dx11BokehIntensity, Mathf.Clamp(dx11BokehThreshold, 0.005f, 4.0f), internalBlurWidth));
- dx11bokehMaterial.SetTexture ("_FgCocMask", nearBlur ? rtSuperLow2 : null);
- // collect bokeh candidates and replace with a darker pixel
- Graphics.SetRandomWriteTarget (1, cbPoints);
- Graphics.Blit (source, rtLow, dx11bokehMaterial, 0);
- Graphics.ClearRandomWriteTargets ();
- // fg coc blur happens here (after collect!)
- if (nearBlur) {
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (0.0f, fgBlurDist , 0.0f, fgBlurDist));
- Graphics.Blit (rtSuperLow2, rtSuperLow1, dofHdrMaterial, 2);
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (fgBlurDist, 0.0f, 0.0f, fgBlurDist));
- Graphics.Blit (rtSuperLow1, rtSuperLow2, dofHdrMaterial, 2);
- // merge fg coc with bg coc
- Graphics.Blit (rtSuperLow2, rtLow, dofHdrMaterial, 3);
- }
- // NEW: LAY OUT ALPHA on destination target so we get nicer outlines for the high rez version
- Graphics.Blit (rtLow, dest2, dofHdrMaterial, 20);
- // box blur (easier to merge with bokeh buffer)
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (internalBlurWidth, 0.0f , 0.0f, internalBlurWidth));
- Graphics.Blit (rtLow, source, dofHdrMaterial, 5);
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (0.0f, internalBlurWidth, 0.0f, internalBlurWidth));
- Graphics.Blit (source, dest2, dofHdrMaterial, 21);
- // apply bokeh candidates
- Graphics.SetRenderTarget (dest2);
- ComputeBuffer.CopyCount (cbPoints, cbDrawArgs, 0);
- dx11bokehMaterial.SetBuffer ("pointBuffer", cbPoints);
- dx11bokehMaterial.SetTexture ("_MainTex", dx11BokehTexture);
- dx11bokehMaterial.SetVector ("_Screen", new Vector3(1.0f/(1.0f*source.width), 1.0f/(1.0f*source.height), internalBlurWidth));
- dx11bokehMaterial.SetPass (2);
- Graphics.DrawProceduralIndirectNow (MeshTopology.Points, cbDrawArgs, 0);
- Graphics.Blit (dest2, destination); // hackaround for DX11 high resolution flipfun (OPTIMIZEME)
- RenderTexture.ReleaseTemporary(dest2);
- RenderTexture.ReleaseTemporary(rtSuperLow1);
- RenderTexture.ReleaseTemporary(rtSuperLow2);
- }
- else {
- rtLow = RenderTexture.GetTemporary (source.width>>1, source.height>>1, 0, source.format);
- rtLow2 = RenderTexture.GetTemporary (source.width>>1, source.height>>1, 0, source.format);
- fgBlurDist = internalBlurWidth * foregroundOverlap;
- // capture COC & color in low resolution
- WriteCoc (source, false);
- source.filterMode = FilterMode.Bilinear;
- Graphics.Blit (source, rtLow, dofHdrMaterial, 6);
- // blur a bit so we can do a frequency check
- rtSuperLow1 = RenderTexture.GetTemporary(rtLow.width>>1, rtLow.height>>1, 0, rtLow.format);
- rtSuperLow2 = RenderTexture.GetTemporary(rtLow.width>>1, rtLow.height>>1, 0, rtLow.format);
- Graphics.Blit(rtLow, rtSuperLow1, dofHdrMaterial, 15);
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (0.0f, 1.5f , 0.0f, 1.5f));
- Graphics.Blit (rtSuperLow1, rtSuperLow2, dofHdrMaterial, 19);
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (1.5f, 0.0f, 0.0f, 1.5f));
- Graphics.Blit (rtSuperLow2, rtSuperLow1, dofHdrMaterial, 19);
- RenderTexture rtLow3 = null;
- if (nearBlur) {
- // capture fg coc
- rtLow3 = RenderTexture.GetTemporary (source.width>>1, source.height>>1, 0, source.format);
- Graphics.Blit (source, rtLow3, dofHdrMaterial, 4);
- }
- dx11bokehMaterial.SetTexture ("_BlurredColor", rtSuperLow1);
- dx11bokehMaterial.SetFloat ("_SpawnHeuristic", dx11SpawnHeuristic);
- dx11bokehMaterial.SetVector ("_BokehParams", new Vector4(dx11BokehScale, dx11BokehIntensity, Mathf.Clamp(dx11BokehThreshold, 0.005f, 4.0f), internalBlurWidth));
- dx11bokehMaterial.SetTexture ("_FgCocMask", rtLow3);
- // collect bokeh candidates and replace with a darker pixel
- Graphics.SetRandomWriteTarget (1, cbPoints);
- Graphics.Blit (rtLow, rtLow2, dx11bokehMaterial, 0);
- Graphics.ClearRandomWriteTargets ();
- RenderTexture.ReleaseTemporary(rtSuperLow1);
- RenderTexture.ReleaseTemporary(rtSuperLow2);
- // fg coc blur happens here (after collect!)
- if (nearBlur) {
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (0.0f, fgBlurDist , 0.0f, fgBlurDist));
- Graphics.Blit (rtLow3, rtLow, dofHdrMaterial, 2);
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (fgBlurDist, 0.0f, 0.0f, fgBlurDist));
- Graphics.Blit (rtLow, rtLow3, dofHdrMaterial, 2);
- // merge fg coc with bg coc
- Graphics.Blit (rtLow3, rtLow2, dofHdrMaterial, 3);
- }
- // box blur (easier to merge with bokeh buffer)
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (internalBlurWidth, 0.0f , 0.0f, internalBlurWidth));
- Graphics.Blit (rtLow2, rtLow, dofHdrMaterial, 5);
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (0.0f, internalBlurWidth, 0.0f, internalBlurWidth));
- Graphics.Blit (rtLow, rtLow2, dofHdrMaterial, 5);
- // apply bokeh candidates
- Graphics.SetRenderTarget (rtLow2);
- ComputeBuffer.CopyCount (cbPoints, cbDrawArgs, 0);
- dx11bokehMaterial.SetBuffer ("pointBuffer", cbPoints);
- dx11bokehMaterial.SetTexture ("_MainTex", dx11BokehTexture);
- dx11bokehMaterial.SetVector ("_Screen", new Vector3(1.0f/(1.0f*rtLow2.width), 1.0f/(1.0f*rtLow2.height), internalBlurWidth));
- dx11bokehMaterial.SetPass (1);
- Graphics.DrawProceduralIndirectNow (MeshTopology.Points, cbDrawArgs, 0);
- // upsample & combine
- dofHdrMaterial.SetTexture ("_LowRez", rtLow2);
- dofHdrMaterial.SetTexture ("_FgOverlap", rtLow3);
- dofHdrMaterial.SetVector ("_Offsets", ((1.0f*source.width)/(1.0f*rtLow2.width)) * internalBlurWidth * Vector4.one);
- Graphics.Blit (source, destination, dofHdrMaterial, 9);
- if (rtLow3) RenderTexture.ReleaseTemporary(rtLow3);
- }
- }
- else
- {
- //
- // 2.
- // poisson disc style blur in low resolution
- //
- //
- source.filterMode = FilterMode.Bilinear;
- if (highResolution) internalBlurWidth *= 2.0f;
- WriteCoc (source, true);
- rtLow = RenderTexture.GetTemporary (source.width >> 1, source.height >> 1, 0, source.format);
- rtLow2 = RenderTexture.GetTemporary (source.width >> 1, source.height >> 1, 0, source.format);
- int blurPass = (blurSampleCount == BlurSampleCount.High || blurSampleCount == BlurSampleCount.Medium) ? 17 : 11;
- if (highResolution) {
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (0.0f, internalBlurWidth, 0.025f, internalBlurWidth));
- Graphics.Blit (source, destination, dofHdrMaterial, blurPass);
- }
- else {
- dofHdrMaterial.SetVector ("_Offsets", new Vector4 (0.0f, internalBlurWidth, 0.1f, internalBlurWidth));
- // blur
- Graphics.Blit (source, rtLow, dofHdrMaterial, 6);
- Graphics.Blit (rtLow, rtLow2, dofHdrMaterial, blurPass);
- // cheaper blur in high resolution, upsample and combine
- dofHdrMaterial.SetTexture("_LowRez", rtLow2);
- dofHdrMaterial.SetTexture("_FgOverlap", null);
- dofHdrMaterial.SetVector ("_Offsets", Vector4.one * ((1.0f*source.width)/(1.0f*rtLow2.width)) * internalBlurWidth);
- Graphics.Blit (source, destination, dofHdrMaterial, blurSampleCount == BlurSampleCount.High ? 18 : 12);
- }
- }
- if (rtLow) RenderTexture.ReleaseTemporary(rtLow);
- if (rtLow2) RenderTexture.ReleaseTemporary(rtLow2);
- }
- }
- }
|