////////////////////////////////////////////////////// // MK Glow Effect // // // // Created by Michael Kremmel // // www.michaelkremmel.de // // Copyright © 2020 All rights reserved. // ////////////////////////////////////////////////////// using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using System.Linq; namespace MK.Glow { using ShaderProperties = PipelineProperties.ShaderProperties; internal sealed class Effect { internal Effect() { } ///////////////////////////////////////////////////////////////////////////////////////////// // Members ///////////////////////////////////////////////////////////////////////////////////////////// //always needed parameters - static private static MK.Glow.Resources _resources; private static readonly Vector2 _selectiveWorkflowThreshold = new Vector2(0.1f, 10); //Selective rendering objects private static readonly string _selectiveReplacementTag = "RenderType"; private static readonly string _selectiveGlowCameraObjectName = "selectiveGlowCameraObject"; private GameObject _selectiveGlowCameraObject; private UnityEngine.Camera _selectiveGlowCamera; //Renderbuffers private CommandBuffer _commandBuffer; private RenderTarget _selectiveRenderTarget; private MipBuffer _bloomDownsampleBuffer, _bloomUpsampleBuffer; private RenderTarget _sourceFrameBuffer, _destinationFrameBuffer; private RenderTarget sourceFrameBuffer { get { return _settings.GetWorkflow() == Workflow.Selective && _debugView != DebugView.None ? _selectiveRenderTarget : _sourceFrameBuffer; } } //Runtime needed private Keyword[] _shaderKeywords = new Keyword[] { new Keyword("_MK_BLOOM", false), new Keyword("_MK_LENS_SURFACE", false), new Keyword("_MK_LENS_FLARE", false), new Keyword("_MK_GLARE_1", false), new Keyword("_MK_DEBUG_RAW_BLOOM", false), new Keyword("_MK_DEBUG_RAW_LENS_FLARE", false), new Keyword("_MK_DEBUG_RAW_GLARE", false), new Keyword("_MK_DEBUG_BLOOM", false), //No Keyword will be set new Keyword("_MK_DEBUG_LENS_FLARE", false), new Keyword("_MK_DEBUG_GLARE", false), new Keyword("_MK_DEBUG_COMPOSITE", false), new Keyword("_MK_LEGACY_BLIT", false), new Keyword("_MK_RENDER_PRIORITY_QUALITY", false), new Keyword("_MK_NATURAL", false), new Keyword("_MK_GLARE_2", false), new Keyword("_MK_GLARE_3", false), new Keyword("_MK_GLARE_4", false), new Keyword("", false), new Keyword("_MK_RENDER_PRIORITY_BALANCED", false) }; //Used features private bool _useLensSurface; //Lists private List _renderTargetsBundle; private List _renderKeywordsBundle; //Rendering dependent private ICameraData _cameraData; private int _bloomIterations, _minIterations, _currentRenderIndex; internal int currentRenderIndex { get { return _currentRenderIndex; }} private float bloomUpsampleSpread, _lensFlareUpsampleSpread, _glareScatteringMult; private RenderTextureFormat _renderTextureFormat; internal RenderTextureFormat renderTextureFormat { get{ return _renderTextureFormat; } } private RenderContext[] _sourceContext, _renderContext; private RenderContext _selectiveRenderContext; private UnityEngine.Camera _renderingCamera; private RenderPipeline _renderPipeline; private DebugView _debugView; //Materials private Material _renderMaterialNoGeometry; internal Material renderMaterialNoGeometry { get { return _renderMaterialNoGeometry; } } //Settings private ISettings _settings; ///////////////////////////////////////////////////////////////////////////////////////////// // Unity MonoBehavior Messages ///////////////////////////////////////////////////////////////////////////////////////////// internal void Enable(RenderPipeline renderPipeline) { _resources = MK.Glow.Resources.LoadResourcesAsset(); _renderTextureFormat = Compatibility.CheckSupportedRenderTextureFormat(); _renderPipeline = renderPipeline; _sourceContext = new RenderContext[1]{new RenderContext()}; _renderContext = new RenderContext[PipelineProperties.renderBufferSize]; for(int i = 0; i < PipelineProperties.renderBufferSize; i++) _renderContext[i] = new RenderContext(); _selectiveRenderContext = new RenderContext(); _renderMaterialNoGeometry = new Material(_resources.sm35Shader) { hideFlags = HideFlags.HideAndDontSave }; _renderTargetsBundle = new List(); _renderKeywordsBundle = new List(); //create buffers _bloomDownsampleBuffer = new MipBuffer(PipelineProperties.CommandBufferProperties.bloomDownsampleBuffer, _renderPipeline); _bloomUpsampleBuffer = new MipBuffer(PipelineProperties.CommandBufferProperties.bloomUpsampleBuffer, _renderPipeline); } internal void Disable() { _currentRenderIndex = 0; _renderTargetsBundle.Clear(); _renderKeywordsBundle.Clear(); PipelineExtensions.Destroy(_selectiveGlowCamera); PipelineExtensions.Destroy(_selectiveGlowCameraObject); PipelineExtensions.Destroy(_renderMaterialNoGeometry); MK.Glow.Resources.UnLoadResourcesAsset(_resources); } ///////////////////////////////////////////////////////////////////////////////////////////// // RenderBuffers ///////////////////////////////////////////////////////////////////////////////////////////// /// /// Prepare Scattering parameters fora given Scattering value /// /// /// /// /// private void PrepareScattering(float Scattering, float scale, ref int iterations, ref float spread) { /* float lit = Mathf.Log(scale, 2f) + Mathf.Min(Scattering, 10f) - 10f; int litF = Mathf.FloorToInt(lit); iterations = Mathf.Clamp(litF, 1, 15); spread = 0.5f + lit - litF; */ float scaledIterations = scale + Mathf.Clamp(Scattering, 1f, 10.0f) - 10.0f; iterations = Mathf.Max(Mathf.FloorToInt(scaledIterations), 1); spread = scaledIterations > 1 ? 0.5f + scaledIterations - iterations : 0.5f; } /// /// Create renderbuffers /// private void UpdateRenderBuffers() { RenderDimension renderDimension = new RenderDimension((int)((float)_cameraData.GetCameraWidth()), (int)((float)_cameraData.GetCameraHeight())); _sourceContext[0].UpdateRenderContext(_cameraData, _renderTextureFormat, 0, renderDimension); _sourceContext[0].SinglePassStereoAdjustWidth(_cameraData.GetStereoEnabled()); Vector2 anamorphic = new Vector2(_settings.GetAnamorphicRatio() < 0 ? -_settings.GetAnamorphicRatio() : 0f, _settings.GetAnamorphicRatio() > 0 ? _settings.GetAnamorphicRatio() : 0f); renderDimension = new RenderDimension(Mathf.CeilToInt(_sourceContext[0].width / (2f - anamorphic.x)), Mathf.CeilToInt(_sourceContext[0].height / (2f - anamorphic.y))); float sizeScale = Mathf.Log(Mathf.FloorToInt(Mathf.Max(renderDimension.width, renderDimension.height)), 2.0f); //float sizeScale = Mathf.FloorToInt(Mathf.Max(renderDimension.width, renderDimension.height)); PrepareScattering(_settings.GetBloomScattering(), sizeScale, ref _bloomIterations, ref bloomUpsampleSpread); _minIterations = _bloomIterations; _cameraData.UpdateMipRenderContext(_renderContext, renderDimension, _minIterations + 1, _renderTextureFormat, 0); } ///////////////////////////////////////////////////////////////////////////////////////////// // Selective glow setup ///////////////////////////////////////////////////////////////////////////////////////////// /// /// selective replacement shader rendering camera for the glow /// private GameObject selectiveGlowCameraObject { get { if(!_selectiveGlowCameraObject) { _selectiveGlowCameraObject = new GameObject(_selectiveGlowCameraObjectName); _selectiveGlowCameraObject.AddComponent(); _selectiveGlowCameraObject.hideFlags = HideFlags.HideAndDontSave; } return _selectiveGlowCameraObject; } } /// /// selective replacement shader rendering camera forthe glow /// private UnityEngine.Camera selectiveGlowCamera { get { if(_selectiveGlowCamera == null) { _selectiveGlowCamera = selectiveGlowCameraObject.GetComponent(); _selectiveGlowCamera.hideFlags = HideFlags.HideAndDontSave; _selectiveGlowCamera.enabled = false; } return _selectiveGlowCamera; } } /// /// Prepare replacement rendering camera forthe selective glow /// private void SetupSelectiveGlowCamera() { selectiveGlowCamera.CopyFrom(_renderingCamera); selectiveGlowCamera.targetTexture = _selectiveRenderTarget.renderTexture; selectiveGlowCamera.clearFlags = CameraClearFlags.SolidColor; selectiveGlowCamera.rect = new Rect(0,0, 1,1); selectiveGlowCamera.backgroundColor = new Color(0, 0, 0, 1); selectiveGlowCamera.cullingMask = _settings.GetSelectiveRenderLayerMask(); selectiveGlowCamera.renderingPath = RenderingPath.VertexLit; } ///////////////////////////////////////////////////////////////////////////////////////////// // CommandBuffer creation ///////////////////////////////////////////////////////////////////////////////////////////// /// /// Enable or disable all supported / unsupported shaders based on the platform /// private void CheckFeatureSupport() { //Check iflens surface is set if(_settings.GetAllowLensSurface()) _useLensSurface = true; else _useLensSurface = false; //If any debug view without depending feature is enabled fallback to default rendering /* if(_debugView != DebugView.None) { if(!_useLensFlare && (_debugView == DebugView.LensFlare || _debugView == DebugView.RawLensFlare) || !_useGlare &&(_debugView == DebugView.Glare || _debugView == DebugView.RawGlare)) _debugView = DebugView.None; } */ } private void BeginProfileSample(string text) { if(_renderPipeline == RenderPipeline.SRP) _commandBuffer.BeginSample(text); else UnityEngine.Profiling.Profiler.BeginSample(text); } private void EndProfileSample(string text) { if(_renderPipeline == RenderPipeline.SRP) _commandBuffer.EndSample(text); else UnityEngine.Profiling.Profiler.EndSample(); } /// /// Renders the effect from source into destination buffer /// /// /// internal void Build(RenderTarget source, RenderTarget destination, ISettings settings, CommandBuffer cmd, ICameraData cameraData, UnityEngine.Camera renderingCamera) { _commandBuffer = cmd; _settings = settings; _renderingCamera = renderingCamera; _cameraData = cameraData; _debugView = settings.GetDebugView(); BeginProfileSample(PipelineProperties.CommandBufferProperties.samplePrepare); CheckFeatureSupport(); _sourceFrameBuffer = source; _destinationFrameBuffer = destination; UpdateRenderBuffers(); EndProfileSample(PipelineProperties.CommandBufferProperties.samplePrepare); //Prepare for selective glow if(_settings.GetWorkflow() == Workflow.Selective) { BeginProfileSample(PipelineProperties.CommandBufferProperties.sampleReplacement); _selectiveRenderContext.UpdateRenderContext(_cameraData, _renderTextureFormat, 16, _sourceContext[0].renderDimension); //The allowVerticallyFlip flag seems to break sometimes orientation of the rendered glow map, therefore force the old way. _selectiveRenderTarget.renderTexture = RenderTexture.GetTemporary((int)((float)_cameraData.GetCameraWidth()) / 2, (int)((float)_cameraData.GetCameraHeight()) / 2, 16, _renderTextureFormat, RenderTextureReadWrite.Default, 1);//PipelineExtensions.GetTemporary(_selectiveRenderContext, _renderTextureFormat); SetupSelectiveGlowCamera(); selectiveGlowCamera.RenderWithShader(_resources.selectiveRenderShader, _selectiveReplacementTag); EndProfileSample(PipelineProperties.CommandBufferProperties.sampleReplacement); } BeginProfileSample(PipelineProperties.CommandBufferProperties.sampleSetup); UpdateConstantBuffers(); EndProfileSample(PipelineProperties.CommandBufferProperties.sampleSetup); PreSample(); Downsample(); Upsample(); Composite(); } /// /// Update the profile based on the user input /// private void UpdateConstantBuffers() { //Common SetFloat(PipelineProperties.ShaderProperties.singlePassStereoScale, PipelineProperties.singlePassStereoDoubleWideEnabled ? 2 : 1); Matrix4x4 viewMatrix = _renderingCamera.worldToCameraMatrix; Shader.SetGlobalMatrix(ShaderProperties.viewMatrix.id, viewMatrix); //Bloom SetFloat(PipelineProperties.ShaderProperties.bloomIntensity, ConvertGammaValue(_settings.GetBloomIntensity()), true); SetFloat(PipelineProperties.ShaderProperties.bloomSpread, bloomUpsampleSpread); SetFloat(PipelineProperties.ShaderProperties.bloomSpread, bloomUpsampleSpread, true); SetVector(PipelineProperties.ShaderProperties.bloomThreshold, _settings.GetWorkflow() == Workflow.Selective ? _selectiveWorkflowThreshold : new Vector2(ConvertGammaValue(_settings.GetBloomThreshold().minValue), ConvertGammaValue(_settings.GetBloomThreshold().maxValue)), _debugView == DebugView.RawBloom ? true : false); //LensSurface if(_useLensSurface) { SetFloat(PipelineProperties.ShaderProperties.lensSurfaceDirtIntensity, ConvertGammaValue(_settings.GetLensSurfaceDirtIntensity()), true); SetFloat(PipelineProperties.ShaderProperties.lensSurfaceDiffractionIntensity, ConvertGammaValue(_settings.GetLensSurfaceDiffractionIntensity()), true); float dirtRatio = (float)(_settings.GetLensSurfaceDirtTexture() ? _settings.GetLensSurfaceDirtTexture().width : _resources.lensSurfaceDirtTextureDefault.width) / (float)(_settings.GetLensSurfaceDirtTexture() ? _settings.GetLensSurfaceDirtTexture().height : _resources.lensSurfaceDirtTextureDefault.height); float dsRatio = _cameraData.GetAspect() / dirtRatio; float sdRatio = dirtRatio / _cameraData.GetAspect(); SetVector(PipelineProperties.ShaderProperties.lensSurfaceDirtTexST, dirtRatio > _cameraData.GetAspect() ? new Vector4(dsRatio, 1, (1f - dsRatio) * 0.5f, 0) : new Vector4(1, sdRatio, 0, (1f - sdRatio) * 0.5f), true); } } ///////////////////////////////////////////////////////////////////////////////////////////// // Commandbuffer helpers ///////////////////////////////////////////////////////////////////////////////////////////// /// /// Set a specific keyword for the pixelshader /// /// /// private void SetKeyword(MaterialKeywords keyword, bool enable) { //For now disable check if a keyword is already set //to make sure the cmd is always correctly setuped //if(_shaderKeywords[(int)keyword].enabled != enable) { if(_renderPipeline == RenderPipeline.SRP) _commandBuffer.SetKeyword(_shaderKeywords[(int)keyword].name, enable); else PipelineExtensions.SetKeyword(_shaderKeywords[(int)keyword].name, enable); _shaderKeywords[(int)keyword].enabled = enable; } } /// /// Convert an angle (degree) to a Vector2 direction /// /// private Vector2 AngleToDirection(float angleDegree) { return new Vector2(Mathf.Sin(angleDegree * Mathf.Deg2Rad), Mathf.Cos(angleDegree * Mathf.Deg2Rad)); } /// /// get a threshold value based on current color space /// private float ConvertGammaValue(float gammaSpacedValue) { if(QualitySettings.activeColorSpace == ColorSpace.Linear) { return Mathf.GammaToLinearSpace(gammaSpacedValue); } else return gammaSpacedValue; } /// /// get a threshold value based on current color space /// private Vector4 ConvertGammaValue(Vector4 gammaSpacedVector) { if(QualitySettings.activeColorSpace == ColorSpace.Linear) { gammaSpacedVector.x = ConvertGammaValue(gammaSpacedVector.x); gammaSpacedVector.y = ConvertGammaValue(gammaSpacedVector.y); gammaSpacedVector.z = ConvertGammaValue(gammaSpacedVector.z); gammaSpacedVector.w = ConvertGammaValue(gammaSpacedVector.w); return gammaSpacedVector; } else return gammaSpacedVector; } /// /// Update the renderindex (pass) forthe next Draw /// /// private void UpdateRenderIndex(int v) { _currentRenderIndex = v; } /// /// Auto set a float value on the renderpipeline /// /// /// private void SetFloat(ShaderProperties.DefaultProperty property, float value, bool forcePixelShader = false) { if(_renderPipeline == RenderPipeline.SRP) _commandBuffer.SetGlobalFloat(property.id, value); else Shader.SetGlobalFloat(property.id, value); } /// /// Auto set a vector value on the renderpipeline /// /// /// private void SetVector(ShaderProperties.DefaultProperty property, Vector4 value, bool forcePixelShader = false) { if(_renderPipeline == RenderPipeline.SRP) _commandBuffer.SetGlobalVector(property.id, value); else Shader.SetGlobalVector(property.id, value); } /// /// Auto set a vector value on the renderpipeline /// /// /// private void SetVector(ShaderProperties.DefaultProperty property, Vector3 value, bool forcePixelShader = false) { if(_renderPipeline == RenderPipeline.SRP) _commandBuffer.SetGlobalVector(property.id, value); else Shader.SetGlobalVector(property.id, value); } /// /// Auto set a vector value on the renderpipeline /// /// /// private void SetVector(ShaderProperties.DefaultProperty property, Vector2 value, bool forcePixelShader = false) { if(_renderPipeline == RenderPipeline.SRP) _commandBuffer.SetGlobalVector(property.id, value); else Shader.SetGlobalVector(property.id, value); } /// /// Auto set a texture on the renderpipeline, /// /// /// /// private void SetTexture(ShaderProperties.DefaultProperty property, RenderTarget rt, bool forcePixelShader = false) { if(_renderPipeline == RenderPipeline.SRP) _commandBuffer.SetGlobalTexture(property.id, rt.renderTargetIdentifier); else Shader.SetGlobalTexture(property.id, rt.renderTexture); } private void SetTexture(ShaderProperties.DefaultProperty property, Texture tex, bool forcePixelShader = false) { if(_renderPipeline == RenderPipeline.SRP) _commandBuffer.SetGlobalTexture(property.id, tex); else Shader.SetGlobalTexture(property.id, tex); } /// /// Setup for the next draw command /// /// /// /// private void PrepareDraw(int variant, RenderDimension renderDimension) { UpdateRenderIndex(variant); DisableRenderKeywords(); foreach(MaterialKeywords kw in _renderKeywordsBundle) SetKeyword(kw, true); _renderKeywordsBundle.Clear(); } /// /// Draw into a destination framebuffer based on shadertype /// Always prepare for drawing using the PrepareDraw command /// /// private void Draw(RenderDimension dimension) { if(_renderPipeline == RenderPipeline.SRP) { _commandBuffer.Draw(_renderTargetsBundle, _renderMaterialNoGeometry, _currentRenderIndex, new Rect(0, 0, dimension.width, dimension.height)); } else { PipelineExtensions.Draw(_renderTargetsBundle, _renderMaterialNoGeometry, _currentRenderIndex); } _renderTargetsBundle.Clear(); } ///////////////////////////////////////////////////////////////////////////////////////////// // Sampling ///////////////////////////////////////////////////////////////////////////////////////////// /// /// Disable render Keywords /// private void DisableRenderKeywords() { SetKeyword(MaterialKeywords.Bloom, false); SetKeyword(MaterialKeywords.LensSurface, false); } /// /// Disable debug Keywords /// private void DisableDebugKeywords() { SetKeyword(MaterialKeywords.DebugRawBloom, false); SetKeyword(MaterialKeywords.DebugBloom, false); SetKeyword(MaterialKeywords.DebugComposite, false); } /// /// Pre sample the glow map /// private void PreSample() { BeginProfileSample(PipelineProperties.CommandBufferProperties.samplePreSample); _bloomDownsampleBuffer.CreateTemporary(_renderContext, 0, _commandBuffer, _renderTextureFormat, _renderPipeline); _renderKeywordsBundle.Add(MaterialKeywords.Bloom); _renderTargetsBundle.Add(_bloomDownsampleBuffer.renderTargets[0]); PrepareDraw ( (int)ShaderRenderPass.Presample, _renderContext[0].renderDimension ); if(_settings.GetWorkflow() == Workflow.Selective) SetTexture(PipelineProperties.ShaderProperties.sourceTex, _selectiveRenderTarget.renderTexture); else SetTexture(PipelineProperties.ShaderProperties.sourceTex, sourceFrameBuffer); Draw(_renderContext[0].renderDimension); if(_settings.GetWorkflow() == Workflow.Selective) RenderTexture.ReleaseTemporary(_selectiveRenderTarget.renderTexture); EndProfileSample(PipelineProperties.CommandBufferProperties.samplePreSample); } /// /// Downsample the glow map /// private void Downsample() { BeginProfileSample(PipelineProperties.CommandBufferProperties.sampleDownsample); bool enableBloom; for(int i = 0; i < _minIterations; i++) { enableBloom = i < _bloomIterations; if(enableBloom) { _bloomDownsampleBuffer.CreateTemporary(_renderContext, i + 1, _commandBuffer, _renderTextureFormat, _renderPipeline); _renderKeywordsBundle.Add(MaterialKeywords.Bloom); _renderTargetsBundle.Add(_bloomDownsampleBuffer.renderTargets[i + 1]); } PrepareDraw ( (int)ShaderRenderPass.Downsample, _renderContext[i + 1].renderDimension ); if(enableBloom) { SetTexture(PipelineProperties.ShaderProperties.bloomTex, _bloomDownsampleBuffer.renderTargets[i]); } Draw(_renderContext[i + 1].renderDimension); } EndProfileSample(PipelineProperties.CommandBufferProperties.sampleDownsample); } /// /// Upsample the glow map /// private void Upsample() { BeginProfileSample(PipelineProperties.CommandBufferProperties.sampleUpsample); bool enableBloom; for(int i = _minIterations; i > 0; i--) { enableBloom = i <= _bloomIterations; if(enableBloom) { _bloomUpsampleBuffer.CreateTemporary(_renderContext, i - 1, _commandBuffer, _renderTextureFormat, _renderPipeline); _renderKeywordsBundle.Add(MaterialKeywords.Bloom); _renderTargetsBundle.Add(_bloomUpsampleBuffer.renderTargets[i - 1]); } PrepareDraw ( (int)ShaderRenderPass.Upsample, _renderContext[i - 1].renderDimension ); if(enableBloom) { SetTexture(PipelineProperties.ShaderProperties.higherMipBloomTex, _bloomDownsampleBuffer.renderTargets[i - 1]); SetTexture(PipelineProperties.ShaderProperties.bloomTex, (i >= _bloomIterations) ? _bloomDownsampleBuffer.renderTargets[i] : _bloomUpsampleBuffer.renderTargets[i]); } Draw(_renderContext[i - 1].renderDimension); if(enableBloom) { if(i >= _bloomIterations) _bloomDownsampleBuffer.ClearTemporary(_commandBuffer, i, _renderPipeline); else { _bloomDownsampleBuffer.ClearTemporary(_commandBuffer, i, _renderPipeline); _bloomUpsampleBuffer.ClearTemporary(_commandBuffer, i, _renderPipeline); } } } _bloomDownsampleBuffer.ClearTemporary(_commandBuffer, 0, _renderPipeline); EndProfileSample(PipelineProperties.CommandBufferProperties.sampleUpsample); } /// /// Precomposite of the glow map /// private void Composite() { BeginProfileSample(PipelineProperties.CommandBufferProperties.sampleComposite); int renderpass; switch(_debugView) { case DebugView.RawBloom: _renderKeywordsBundle.Add(MaterialKeywords.DebugRawBloom); renderpass = (int)ShaderRenderPass.Debug; break; case DebugView.Bloom: _renderKeywordsBundle.Add(MaterialKeywords.DebugBloom); renderpass = (int)ShaderRenderPass.Debug; break; case DebugView.Composite: if(_useLensSurface) { _renderKeywordsBundle.Add(MaterialKeywords.LensSurface); } _renderKeywordsBundle.Add(MaterialKeywords.DebugComposite); renderpass = (int)ShaderRenderPass.Debug; break; default: if(_useLensSurface) { _renderKeywordsBundle.Add(MaterialKeywords.LensSurface); } renderpass = (int)ShaderRenderPass.Composite; break; } PrepareDraw ( renderpass, _sourceContext[0].renderDimension ); if(_settings.GetWorkflow() == Workflow.Selective && (_debugView == DebugView.RawBloom)) SetTexture(PipelineProperties.ShaderProperties.sourceTex, sourceFrameBuffer.renderTexture, true); else { SetTexture(PipelineProperties.ShaderProperties.sourceTex, sourceFrameBuffer, true); SetTexture(PipelineProperties.ShaderProperties.bloomTex, _bloomUpsampleBuffer.renderTargets[0], true); } if(_useLensSurface) { SetTexture(PipelineProperties.ShaderProperties.lensSurfaceDirtTex, _settings.GetLensSurfaceDirtTexture() ? _settings.GetLensSurfaceDirtTexture() : _resources.lensSurfaceDirtTextureDefault, true); SetTexture(PipelineProperties.ShaderProperties.lensSurfaceDiffractionTex, _settings.GetLensSurfaceDiffractionTexture() ? _settings.GetLensSurfaceDiffractionTexture() : _resources.lensSurfaceDiffractionTextureDefault, true); } //Dont draw when using legacy render pipeline if(_renderPipeline == RenderPipeline.SRP) { _renderTargetsBundle.Add(_destinationFrameBuffer); Draw(_sourceContext[0].renderDimension); AfterCompositeCleanup(); } else { PipelineExtensions.SetKeyword(_shaderKeywords[(int)MaterialKeywords.LegacyBlit].name, true); _renderTargetsBundle.Clear(); } EndProfileSample(PipelineProperties.CommandBufferProperties.sampleComposite); } /// /// This cleans up the final render step /// internal void AfterCompositeCleanup() { _bloomUpsampleBuffer.ClearTemporary(_commandBuffer, 0, _renderPipeline); DisableDebugKeywords(); DisableRenderKeywords(); if(_renderPipeline == RenderPipeline.Legacy) PipelineExtensions.SetKeyword(_shaderKeywords[(int)MaterialKeywords.LegacyBlit].name, false); } ///////////////////////////////////////////////////////////////////////////////////////////// // Enum / structs used for rendering ///////////////////////////////////////////////////////////////////////////////////////////// /// /// /// Rendering passes for shaders /// internal enum ShaderRenderPass { Copy = 0, Presample = 1, Downsample = 2, Upsample = 3, Composite = 4, Debug = 5 } /// /// Material keywords represented in the keyword holder /// internal enum MaterialKeywords { Bloom = 0, LensSurface = 1, DebugRawBloom = 4, DebugBloom = 7, DebugComposite = 10, LegacyBlit = 11 } /// /// Keyword represented as with state /// internal struct Keyword { internal string name; internal bool enabled; internal Keyword(string name, bool enabled) { this.name = name; this.enabled = enabled; } } } }