////////////////////////////////////////////////////// // MK Glow Extensions // // // // Created by Michael Kremmel // // www.michaelkremmel.de // // Copyright © 2021 All rights reserved. // ////////////////////////////////////////////////////// using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; namespace MK.Glow { using ShaderProperties = PipelineProperties.ShaderProperties; internal static class PipelineExtensions { private static Mesh _screenMesh; private static Mesh screenMesh { get { if(_screenMesh == null) { _screenMesh = new Mesh { name = "MKGlowScreenMesh" }; _screenMesh.SetVertices(new List { new Vector3(-1f, -1f, 0f), new Vector3( 3f, -1f, 0f), new Vector3(-1f, 3f, 0f) }); _screenMesh.SetIndices(new[] { 0, 1, 2 }, MeshTopology.Triangles, 0, false); _screenMesh.UploadMeshData(false); } return _screenMesh; } } public static void Destroy(UnityEngine.Object obj) { if (obj != null) { #if UNITY_EDITOR if (Application.isPlaying) UnityEngine.Object.Destroy(obj); else UnityEngine.Object.DestroyImmediate(obj); #else UnityEngine.Object.Destroy(obj); #endif } } /// /// Enable or disable a specific Shader keyword /// /// /// /// internal static void SetKeyword(this CommandBuffer cmd, string keyword, bool enable) { if(enable) cmd.EnableShaderKeyword(keyword); else cmd.DisableShaderKeyword(keyword); } internal static void SetKeyword(string keyword, bool enable) { if(enable) Shader.EnableKeyword(keyword); else Shader.DisableKeyword(keyword); } /// /// Draw the currently setuped render context with its targets /// /// /// /// /// /// internal static void Draw(this CommandBuffer cmd, List destinations, Material material, bool useGeometryShader, int pass, Rect viewport) { cmd.SetRenderTargetContext(destinations); cmd.SetViewport(viewport); if(useGeometryShader) { cmd.DrawProcedural(Matrix4x4.identity, material, pass, MeshTopology.Points, 1); } else { cmd.DrawMesh(screenMesh, Matrix4x4.identity, material, 0, pass); } } internal static void Draw(List destinations, Material material, bool useGeometryShader, int pass) { RenderTargetContext.SetRenderTargetContext(destinations); if(useGeometryShader) { material.SetPass(pass); #if UNITY_2019_1_OR_NEWER Graphics.DrawProceduralNow(MeshTopology.Points, 1); #else Graphics.DrawProcedural(MeshTopology.Points, 1); #endif } else { /* GL.Clear(true, true, Color.clear); GL.PushMatrix(); GL.LoadOrtho(); material.SetPass(pass); GL.Begin(GL.TRIANGLE_STRIP); GL.Vertex3(-1.0f, -1.0f, 0.1f); GL.Vertex3(3.0f, -1.0f, 0.1f); GL.Vertex3(-1.0f, 3.0f, 0.1f); GL.End(); GL.PopMatrix(); */ material.SetPass(pass); Graphics.DrawMeshNow(screenMesh, Vector3.zero, Quaternion.identity); } } /// /// Compute the currently setuped render context with its targets /// /// /// /// /// internal static void Draw(this CommandBuffer cmd, List destinations, ComputeShader computeShader, int kernelIndex, RenderDimension computeThreadGroups) { //cmd.SetRenderTargetContext(destinations); cmd.DispatchCompute(computeShader, kernelIndex, computeThreadGroups.width, computeThreadGroups.height, 1); } internal static void Draw(List destinations, ComputeShader computeShader, int kernelIndex, RenderDimension computeThreadGroups) { //RenderTargetContext.SetRenderTargetContext(destinations); computeShader.Dispatch(kernelIndex, computeThreadGroups.width, computeThreadGroups.height, 1); } /// /// Scaling size correctly, need if single pass stereo is enabled /// /// /// /// /// private static int SinglePassStereoDownscale(bool cameraIsStereo, int size, int scale) { //using single pass stereo can introduce some Texeloffset which makes the rendering occur on the wrong place //This happens because the samples are build on base of different mip levels //single pass stereo TexelSize needs to be adjusted in the shader too #if UNITY_2017_1_OR_NEWER return cameraIsStereo && PipelineProperties.singlePassStereoDoubleWideEnabled && ((size / 2) % 2 > 0) ? 1 + size / scale : size / scale; #else return size / scale; #endif } /// /// Update a mip based render context array /// /// /// /// /// /// /// /// internal static void UpdateMipRenderContext(this ICameraData cameraData, RenderContext[] renderContexts, RenderDimension rawDimension, int levels, RenderTextureFormat format, int depthBufferBits, bool enableRandomWrite) { for(int i = 0; i < levels; i++) { renderContexts[i].UpdateRenderContext(cameraData, format, depthBufferBits, enableRandomWrite, rawDimension); rawDimension.width = Mathf.Max(SinglePassStereoDownscale(cameraData.GetStereoEnabled(), rawDimension.width, 2), 1); rawDimension.height = Mathf.Max(rawDimension.height / 2, 1); } } /// /// Get a temporary render texture /// /// /// /// internal static RenderTexture GetTemporary(RenderContext renderContext, RenderTextureFormat format) { #if UNITY_2017_1_OR_NEWER return RenderTexture.GetTemporary(renderContext.descriptor); #else RenderTexture renderTexture = RenderTexture.GetTemporary(renderContext.width, renderContext.height, 16, format, RenderTextureReadWrite.Default, 1); //renderTexture.enableRandomWrite = renderContext.enableRandomWrite; return renderTexture; #endif } } }