181 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C#
		
	
	
	
| //namespace UnityEngine.PostProcessing
 | |
| //{
 | |
| //    public sealed class EyeAdaptationComponent : PostProcessingComponentRenderTexture<EyeAdaptationModel>
 | |
| //    {
 | |
| //        static class Uniforms
 | |
| //        {
 | |
| //            internal static readonly int _Params               = Shader.PropertyToID("_Params");
 | |
| //            internal static readonly int _Speed                = Shader.PropertyToID("_Speed");
 | |
| //            internal static readonly int _ScaleOffsetRes       = Shader.PropertyToID("_ScaleOffsetRes");
 | |
| //            internal static readonly int _ExposureCompensation = Shader.PropertyToID("_ExposureCompensation");
 | |
| //            internal static readonly int _AutoExposure         = Shader.PropertyToID("_AutoExposure");
 | |
| //            internal static readonly int _DebugWidth           = Shader.PropertyToID("_DebugWidth");
 | |
| //        }
 | |
| 
 | |
| //        ComputeShader m_EyeCompute;
 | |
| //        ComputeBuffer m_HistogramBuffer;
 | |
| 
 | |
| //        readonly RenderTexture[] m_AutoExposurePool = new RenderTexture[2];
 | |
| //        int m_AutoExposurePingPing;
 | |
| //        RenderTexture m_CurrentAutoExposure;
 | |
| 
 | |
| //        RenderTexture m_DebugHistogram;
 | |
| 
 | |
| //        static uint[] s_EmptyHistogramBuffer;
 | |
| 
 | |
| //        bool m_FirstFrame = true;
 | |
| 
 | |
| //        // Don't forget to update 'EyeAdaptation.cginc' if you change these values !
 | |
| //        const int k_HistogramBins = 64;
 | |
| //        const int k_HistogramThreadX = 16;
 | |
| //        const int k_HistogramThreadY = 16;
 | |
| 
 | |
| //        public override bool active
 | |
| //        {
 | |
| //            get
 | |
| //            {
 | |
| //                return model.enabled
 | |
| //                       && SystemInfo.supportsComputeShaders
 | |
| //                       && !context.interrupted;
 | |
| //            }
 | |
| //        }
 | |
| 
 | |
| //        public override void OnEnable()
 | |
| //        {
 | |
| //            m_FirstFrame = true;
 | |
| //        }
 | |
| 
 | |
| //        public override void OnDisable()
 | |
| //        {
 | |
| //            foreach (var rt in m_AutoExposurePool)
 | |
| //                GraphicsUtils.Destroy(rt);
 | |
| 
 | |
| //            if (m_HistogramBuffer != null)
 | |
| //                m_HistogramBuffer.Release();
 | |
| 
 | |
| //            m_HistogramBuffer = null;
 | |
| 
 | |
| //            if (m_DebugHistogram != null)
 | |
| //                m_DebugHistogram.Release();
 | |
| 
 | |
| //            m_DebugHistogram = null;
 | |
| //        }
 | |
| 
 | |
| //        Vector4 GetHistogramScaleOffsetRes()
 | |
| //        {
 | |
| //            var settings = model.settings;
 | |
| //            float diff = settings.logMax - settings.logMin;
 | |
| //            float scale = 1f / diff;
 | |
| //            float offset = -settings.logMin * scale;
 | |
| //            return new Vector4(scale, offset, Mathf.Floor(context.width / 2f), Mathf.Floor(context.height / 2f));
 | |
| //        }
 | |
| 
 | |
| //        public Texture Prepare(RenderTexture source, Material uberMaterial)
 | |
| //        {
 | |
| //            var settings = model.settings;
 | |
| 
 | |
| //            // Setup compute
 | |
| //            if (m_EyeCompute == null)
 | |
| //                m_EyeCompute = Resources.Load<ComputeShader>("Shaders/EyeHistogram");
 | |
| 
 | |
| //            var material = context.materialFactory.Get("Hidden/Post FX/Eye Adaptation");
 | |
| 
 | |
| //            if (m_HistogramBuffer == null)
 | |
| //                m_HistogramBuffer = new ComputeBuffer(k_HistogramBins, sizeof(uint));
 | |
| 
 | |
| //            if (s_EmptyHistogramBuffer == null)
 | |
| //                s_EmptyHistogramBuffer = new uint[k_HistogramBins];
 | |
| 
 | |
| //            // Downscale the framebuffer, we don't need an absolute precision for auto exposure and it
 | |
| //            // helps making it more stable
 | |
| //            var scaleOffsetRes = GetHistogramScaleOffsetRes();
 | |
| 
 | |
| //            var rt = context.renderTextureFactory.Get((int)scaleOffsetRes.z, (int)scaleOffsetRes.w, 0, source.format);
 | |
| //            Graphics.Blit(source, rt);
 | |
| 
 | |
| //            if (m_AutoExposurePool[0] == null || !m_AutoExposurePool[0].IsCreated())
 | |
| //                m_AutoExposurePool[0] = new RenderTexture(1, 1, 0, RenderTextureFormat.RFloat);
 | |
| 
 | |
| //            if (m_AutoExposurePool[1] == null || !m_AutoExposurePool[1].IsCreated())
 | |
| //                m_AutoExposurePool[1] = new RenderTexture(1, 1, 0, RenderTextureFormat.RFloat);
 | |
| 
 | |
| //            // Clears the buffer on every frame as we use it to accumulate luminance values on each frame
 | |
| //            m_HistogramBuffer.SetData(s_EmptyHistogramBuffer);
 | |
| 
 | |
| //            // Gets a log histogram
 | |
| //            int kernel = m_EyeCompute.FindKernel("KEyeHistogram");
 | |
| //            m_EyeCompute.SetBuffer(kernel, "_Histogram", m_HistogramBuffer);
 | |
| //            m_EyeCompute.SetTexture(kernel, "_Source", rt);
 | |
| //            m_EyeCompute.SetVector("_ScaleOffsetRes", scaleOffsetRes);
 | |
| //            m_EyeCompute.Dispatch(kernel, Mathf.CeilToInt(rt.width / (float)k_HistogramThreadX), Mathf.CeilToInt(rt.height / (float)k_HistogramThreadY), 1);
 | |
| 
 | |
| //            // Cleanup
 | |
| //            context.renderTextureFactory.Release(rt);
 | |
| 
 | |
| //            // Make sure filtering values are correct to avoid apocalyptic consequences
 | |
| //            const float minDelta = 1e-2f;
 | |
| //            settings.highPercent = Mathf.Clamp(settings.highPercent, 1f + minDelta, 99f);
 | |
| //            settings.lowPercent = Mathf.Clamp(settings.lowPercent, 1f, settings.highPercent - minDelta);
 | |
| 
 | |
| //            // Compute auto exposure
 | |
| //            material.SetBuffer("_Histogram", m_HistogramBuffer); // No (int, buffer) overload for SetBuffer ?
 | |
| //            material.SetVector(Uniforms._Params, new Vector4(settings.lowPercent * 0.01f, settings.highPercent * 0.01f, settings.minLuminance, settings.maxLuminance));
 | |
| //            material.SetVector(Uniforms._Speed, new Vector2(settings.speedDown, settings.speedUp));
 | |
| //            material.SetVector(Uniforms._ScaleOffsetRes, scaleOffsetRes);
 | |
| //            material.SetFloat(Uniforms._ExposureCompensation, settings.exposureCompensation);
 | |
| 
 | |
| //            if (m_FirstFrame || !Application.isPlaying)
 | |
| //            {
 | |
| //                // 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[0];
 | |
| //                Graphics.Blit(null, m_CurrentAutoExposure, material, (int)EyeAdaptationModel.EyeAdaptationType.Fixed);
 | |
| 
 | |
| //                // Copy current exposure to the other pingpong target to avoid adapting from black
 | |
| //                Graphics.Blit(m_AutoExposurePool[0], m_AutoExposurePool[1]);
 | |
| //            }
 | |
| //            else
 | |
| //            {
 | |
| //                int pp = m_AutoExposurePingPing;
 | |
| //                var src = m_AutoExposurePool[++pp % 2];
 | |
| //                var dst = m_AutoExposurePool[++pp % 2];
 | |
| //                Graphics.Blit(src, dst, material, (int)settings.adaptationType);
 | |
| //                m_AutoExposurePingPing = ++pp % 2;
 | |
| //                m_CurrentAutoExposure = dst;
 | |
| //            }
 | |
| 
 | |
| //            // Uber setup
 | |
| //            uberMaterial.EnableKeyword("EYE_ADAPTATION");
 | |
| //            uberMaterial.SetTexture(Uniforms._AutoExposure, m_CurrentAutoExposure);
 | |
| 
 | |
| //            // Generate debug histogram
 | |
| //            if (context.profile.debugViews.IsModeActive(BuiltinDebugViewsModel.Mode.EyeAdaptation))
 | |
| //            {
 | |
| //                if (m_DebugHistogram == null || !m_DebugHistogram.IsCreated())
 | |
| //                {
 | |
| //                    m_DebugHistogram = new RenderTexture(256, 128, 0, RenderTextureFormat.ARGB32)
 | |
| //                    {
 | |
| //                        filterMode = FilterMode.Point,
 | |
| //                        wrapMode = TextureWrapMode.Clamp
 | |
| //                    };
 | |
| //                }
 | |
| 
 | |
| //                material.SetFloat(Uniforms._DebugWidth, m_DebugHistogram.width);
 | |
| //                Graphics.Blit(null, m_DebugHistogram, material, 2);
 | |
| //            }
 | |
| 
 | |
| //            m_FirstFrame = false;
 | |
| //            return m_CurrentAutoExposure;
 | |
| //        }
 | |
| 
 | |
| //        public void OnGUI()
 | |
| //        {
 | |
| //            if (m_DebugHistogram == null || !m_DebugHistogram.IsCreated())
 | |
| //                return;
 | |
| 
 | |
| //            var rect = new Rect(context.viewport.x * Screen.width + 8f, 8f, m_DebugHistogram.width, m_DebugHistogram.height);
 | |
| //            GUI.DrawTexture(rect, m_DebugHistogram);
 | |
| //        }
 | |
| //    }
 | |
| //}
 |