diff --git a/HDRP/Runtime/OitRenderPass.cs b/HDRP/Runtime/OitRenderPass.cs index 7878069..e40806c 100644 --- a/HDRP/Runtime/OitRenderPass.cs +++ b/HDRP/Runtime/OitRenderPass.cs @@ -12,21 +12,22 @@ class OitRenderPass : CustomPass protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) { - orderIndependentTransparency ??= new OitLinkedList(); + orderIndependentTransparency ??= new OitLinkedList("OitRenderHDRP"); } protected override void Execute(CustomPassContext ctx) { // draw objects with UAV targets set var preRenderCmd = CommandBufferPool.Get("Order Independent Transparency Pre Render"); - preRenderCmd.Clear(); orderIndependentTransparency.PreRender(preRenderCmd); ctx.renderContext.ExecuteCommandBuffer(preRenderCmd); + preRenderCmd.Clear(); CommandBufferPool.Release(preRenderCmd); CustomPassUtils.DrawRenderers(ctx, objectLayerMask); // fullscreen blend of transparent pixel buffer - orderIndependentTransparency.Render(ctx.cmd, ctx.cameraColorBuffer, ctx.cameraColorBuffer); + var mat = orderIndependentTransparency.Render(ctx.cmd, ctx.cameraColorBuffer, ctx.cameraColorBuffer); + Blitter.BlitCameraTexture(ctx.cmd, ctx.cameraColorBuffer, ctx.cameraColorBuffer, mat, 0); } protected override void Cleanup() diff --git a/PostProcessingStackV2/Runtime/OitPostProcess.cs b/PostProcessingStackV2/Runtime/OitPostProcess.cs index a7d5f8f..c29238a 100644 --- a/PostProcessingStackV2/Runtime/OitPostProcess.cs +++ b/PostProcessingStackV2/Runtime/OitPostProcess.cs @@ -19,7 +19,7 @@ internal class OitPostProcessRenderer : PostProcessEffectRenderer<OitPostProcess public override void Init() { base.Init(); - orderIndependentTransparency ??= new OitLinkedList(); + orderIndependentTransparency ??= new OitLinkedList("OitRenderPPv2"); Camera.onPreRender += PreRender; } @@ -33,7 +33,8 @@ private void PreRender(Camera cam) public override void Render(PostProcessRenderContext context) { - orderIndependentTransparency?.Render(context.command, context.source, context.destination); + var mat = orderIndependentTransparency?.Render(context.command, context.source, context.destination); + context.command.Blit(context.source, context.destination, mat); } public override void Release() diff --git a/README.md b/README.md index 46e2e33..3bc488c 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ If in doubt try to import the sample you want to use and start from there. 1. Setup the rendering implementation for your chosen pipeline: - **High-Definition Render Pipeline:** Create a [Custom Pass volume](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@12.1/manual/Custom-Pass-Creating.html) and add `OitRenderPass` to it. - - **Universal Render Pipeline:** Add the renderer feature `Order Independent Transparency Renderer` to your Universal Renderer Asset. _Note: URP documentation only describes a [fullscreen Blit](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@15.0/manual/renderer-features/how-to-fullscreen-blit.html) which only works in Game view. If you know whether a fullscreen Blit in URP in Scene view as well as in Game view is possible, help would be very much appreciated._ + - **Universal Render Pipeline:** Add the renderer feature `Order Independent Transparency Renderer` to your Universal Renderer Asset. - **Post-Processing Stack v2:** Add the post-processing override `Order Independent Transparency` to a post-processing volume in your scene. 2. Change the material of every object that shall be rendered with order-independent transparency. They have to be rendered with a shader writing to the buffer used by the order-independent transparency implementation. Two sample shaders that you can use are included in this project: `OrderIndependentTransparency/Unlit` for all pipelines and additionally `OrderIndependentTransparency/Standard` for the built-in pipeline. diff --git a/Shaders/LinkedListRendering.hlsl b/Shaders/LinkedListRendering.hlsl index 2844463..d29acd6 100644 --- a/Shaders/LinkedListRendering.hlsl +++ b/Shaders/LinkedListRendering.hlsl @@ -1,7 +1,6 @@ #ifndef OIT_LINKED_LIST_INCLUDED #define OIT_LINKED_LIST_INCLUDED -#include "UnityShaderVariables.cginc" #include "OitUtils.hlsl" struct FragmentAndLinkBuffer_STRUCT diff --git a/Shaders/Resources/OitFullscreenRender.shader b/Shaders/Resources/OitFullscreenRender.shader deleted file mode 100644 index 91ae89e..0000000 --- a/Shaders/Resources/OitFullscreenRender.shader +++ /dev/null @@ -1,95 +0,0 @@ -Shader "Hidden/OitFullscreenRender" -{ - Properties{ - _MainTex("Main Texture", 2DArray) = "white" {} - } - SubShader { - PackageRequirements { - "com.unity.render-pipelines.high-definition" - } - Tags { "RenderPipeline" = "HighDefinitionRenderPipeline" } - Pass { - Name "HDRP Order-Independent Transparency Post Process" - ZWrite Off - ZTest Always - Blend SrcAlpha OneMinusSrcAlpha - Cull Off - - HLSLPROGRAM - #pragma fragment frag - #pragma vertex Vert - #pragma target 5.0 - #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch - #pragma require randomwrite - // #pragma enable_d3d11_debug_symbols - - #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassCommon.hlsl" - #include "../LinkedListRendering.hlsl" - - float4 frag(Varyings input, uint uSampleIndex : SV_SampleIndex) : SV_Target - { - UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); - - float4 col = float4 (0, 1, 0, 1); - float depth = LoadCameraDepth(input.positionCS.xy); - PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V); - // Load the camera color buffer at the mip 0 if we're not at the before rendering injection point - if (_CustomPassInjectionPoint != CUSTOMPASSINJECTIONPOINT_BEFORE_RENDERING) - col = float4(CustomPassSampleCameraColor(posInput.positionNDC.xy, 0), 1); - - return renderLinkedList(float4(col.r,col.g,col.b,1), input.positionCS.xy, uSampleIndex); - } - ENDHLSL - } - } - SubShader - { - Tags { "RenderPipeline" = "UniversalRenderPipeline" } - Pass { - ZTest Always - ZWrite Off - Cull Off - Blend Off - - HLSLPROGRAM - #pragma vertex vert - #pragma fragment frag - #pragma target 5.0 - #pragma require randomwrite - // #pragma enable_d3d11_debug_symbols - - #include "UnityCG.cginc" - #include "../LinkedListRendering.hlsl" - - struct appdata { - float4 vertex : POSITION; - float2 texcoord : TEXCOORD0; - }; - struct v2f { - float2 uv : TEXCOORD0; - float4 vertex : SV_POSITION; - }; - - sampler2D _MainTex; - float4 _MainTex_ST; - - v2f vert(appdata v) - { - v2f o; - o.vertex = UnityObjectToClipPos(v.vertex); - o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); - return o; - } - - //Pixel function returns a solid color for each point. - fixed4 frag(v2f i, uint uSampleIndex : SV_SampleIndex) : SV_Target - { - // Retrieve current color from background texture - float4 col = tex2D(_MainTex, i.uv); - - return renderLinkedList(col, i.vertex.xy, uSampleIndex); - } - ENDHLSL - } - } -} \ No newline at end of file diff --git a/Shaders/Resources/OitRenderHDRP.shader b/Shaders/Resources/OitRenderHDRP.shader new file mode 100644 index 0000000..c87e93f --- /dev/null +++ b/Shaders/Resources/OitRenderHDRP.shader @@ -0,0 +1,46 @@ +Shader "Hidden/OitRenderHDRP" +{ + Properties{ + _MainTex("Main Texture", 2DArray) = "white" {} + } + SubShader + { + PackageRequirements { + "com.unity.render-pipelines.high-definition" + } + Tags { "RenderPipeline" = "HDRenderPipeline" } + Pass { + Name "HDRP Order-Independent Transparency Pass" + ZTest Always + ZWrite Off + Blend Off + Cull Off + + HLSLPROGRAM + #pragma fragment frag + #pragma vertex Vert + #pragma target 5.0 + #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch + #pragma require randomwrite + // #pragma enable_d3d11_debug_symbols + + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassCommon.hlsl" + #include "../LinkedListRendering.hlsl" + + float4 frag(Varyings input, uint uSampleIndex : SV_SampleIndex) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + + float4 col = float4 (0, 1, 0, 1); + float depth = LoadCameraDepth(input.positionCS.xy); + PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V); + // Load the camera color buffer at the mip 0 if we're not at the before rendering injection point + if (_CustomPassInjectionPoint != CUSTOMPASSINJECTIONPOINT_BEFORE_RENDERING) + col = float4(CustomPassSampleCameraColor(posInput.positionNDC.xy, 0), 1); + + return renderLinkedList(col, input.positionCS.xy, uSampleIndex); + } + ENDHLSL + } + } +} \ No newline at end of file diff --git a/Shaders/Resources/OitRenderHDRP.shader.meta b/Shaders/Resources/OitRenderHDRP.shader.meta new file mode 100644 index 0000000..51b8e1e --- /dev/null +++ b/Shaders/Resources/OitRenderHDRP.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a14176a5b941edd47a10e786ce634d9e +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Shaders/Resources/OitRenderPPv2.shader b/Shaders/Resources/OitRenderPPv2.shader new file mode 100644 index 0000000..99e6e1a --- /dev/null +++ b/Shaders/Resources/OitRenderPPv2.shader @@ -0,0 +1,55 @@ +Shader "Hidden/OitRenderPPv2" +{ + Properties{ + _MainTex("Main Texture", 2DArray) = "white" {} + } + SubShader + { + Pass { + ZTest Always + ZWrite Off + Cull Off + Blend Off + + HLSLPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 5.0 + #pragma require randomwrite + // #pragma enable_d3d11_debug_symbols + + #include "UnityCG.cginc" + #include "../LinkedListRendering.hlsl" + + struct appdata { + float4 vertex : POSITION; + float2 texcoord : TEXCOORD0; + }; + struct v2f { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); + return o; + } + + //Pixel function returns a solid color for each point. + fixed4 frag(v2f i, uint uSampleIndex : SV_SampleIndex) : SV_Target + { + // Retrieve current color from background texture + float4 col = tex2D(_MainTex, i.uv); + + return renderLinkedList(col, i.vertex.xy, uSampleIndex); + } + ENDHLSL + } + } +} \ No newline at end of file diff --git a/Shaders/Resources/OitFullscreenRender.shader.meta b/Shaders/Resources/OitRenderPPv2.shader.meta similarity index 100% rename from Shaders/Resources/OitFullscreenRender.shader.meta rename to Shaders/Resources/OitRenderPPv2.shader.meta diff --git a/Shaders/Resources/OitRenderURP.shader b/Shaders/Resources/OitRenderURP.shader new file mode 100644 index 0000000..c1e29aa --- /dev/null +++ b/Shaders/Resources/OitRenderURP.shader @@ -0,0 +1,42 @@ +Shader "Hidden/OitRenderURP" +{ + SubShader + { + PackageRequirements { + "com.unity.render-pipelines.universal" + } + Tags { "RenderPipeline" = "UniversalRenderPipeline" } + Pass { + Name "URP Order-Independent Transparency Pass" + ZTest Always + ZWrite Off + Cull Off + Blend Off + + HLSLPROGRAM + #pragma vertex Vert + #pragma fragment frag + #pragma target 5.0 + #pragma require randomwrite + // #pragma enable_d3d11_debug_symbols + + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" + #include "../LinkedListRendering.hlsl" + + TEXTURE2D_X(_CameraOpaqueTexture); + SAMPLER(sampler_CameraOpaqueTexture); + + //Pixel function returns a solid color for each point. + half4 frag(Varyings input, uint uSampleIndex: SV_SampleIndex) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + // Retrieve current color from background texture + float4 col = SAMPLE_TEXTURE2D_X(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, input.texcoord); + + return renderLinkedList(col, input.positionCS.xy, uSampleIndex); + } + ENDHLSL + } + } +} \ No newline at end of file diff --git a/Shaders/Resources/OitRenderURP.shader.meta b/Shaders/Resources/OitRenderURP.shader.meta new file mode 100644 index 0000000..0c43bb2 --- /dev/null +++ b/Shaders/Resources/OitRenderURP.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6d23e2ef444cae444b9ddd1167cd8553 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Shared/OitInterface.cs b/Shared/OitInterface.cs index 4c86a00..1b741b7 100644 --- a/Shared/OitInterface.cs +++ b/Shared/OitInterface.cs @@ -1,3 +1,4 @@ +using UnityEngine; using UnityEngine.Rendering; namespace OrderIndependentTransparency @@ -5,7 +6,7 @@ namespace OrderIndependentTransparency public interface IOrderIndependentTransparency { void PreRender(CommandBuffer command); - void Render(CommandBuffer command, RenderTargetIdentifier src, RenderTargetIdentifier dest); + Material Render(CommandBuffer command, RenderTargetIdentifier src, RenderTargetIdentifier dest); void Release(); } } \ No newline at end of file diff --git a/Shared/OitLinkedList.cs b/Shared/OitLinkedList.cs index 10e2ff0..d7b8c21 100644 --- a/Shared/OitLinkedList.cs +++ b/Shared/OitLinkedList.cs @@ -17,9 +17,9 @@ public class OitLinkedList : IOrderIndependentTransparency private readonly int clearStartOffsetBufferKernel; private int dispatchGroupSizeX, dispatchGroupSizeY; - public OitLinkedList() + public OitLinkedList(string shaderName) { - linkedListMaterial = new Material(Resources.Load<Shader>("OitFullscreenRender")); + linkedListMaterial = new Material(Resources.Load<Shader>(shaderName)); fragmentLinkBufferId = Shader.PropertyToID("FLBuffer"); startOffsetBufferId = Shader.PropertyToID("StartOffsetBuffer"); @@ -44,13 +44,13 @@ public void PreRender(CommandBuffer command) command.SetRandomWriteTarget(2, startOffsetBuffer); } - public void Render(CommandBuffer command, RenderTargetIdentifier src, RenderTargetIdentifier dest) + public Material Render(CommandBuffer command, RenderTargetIdentifier src, RenderTargetIdentifier dest) { command.ClearRandomWriteTargets(); // blend linked list linkedListMaterial.SetBuffer(fragmentLinkBufferId, fragmentLinkBuffer); linkedListMaterial.SetBuffer(startOffsetBufferId, startOffsetBuffer); - command.Blit(src, dest, linkedListMaterial); + return linkedListMaterial; } public void Release() diff --git a/URP/Runtime/OitPass.cs b/URP/Runtime/OitPass.cs index 03d5aad..1437d34 100644 --- a/URP/Runtime/OitPass.cs +++ b/URP/Runtime/OitPass.cs @@ -12,26 +12,28 @@ internal class OitPass : ScriptableRenderPass public OitPass() { renderPassEvent = RenderPassEvent.BeforeRenderingTransparents; - orderIndependentTransparency = new OitLinkedList(); + orderIndependentTransparency = new OitLinkedList("OitRenderURP"); RenderPipelineManager.beginContextRendering += PreRender; } private void PreRender(ScriptableRenderContext context, List<Camera> cameras) { CommandBuffer cmd = CommandBufferPool.Get("Order Independent Transparency Pre Render"); - cmd.Clear(); orderIndependentTransparency.PreRender(cmd); context.ExecuteCommandBuffer(cmd); + cmd.Clear(); CommandBufferPool.Release(cmd); } public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { CommandBuffer cmd = CommandBufferPool.Get("Order Independent Transparency"); - cmd.Clear(); - orderIndependentTransparency.Render(cmd, renderingData.cameraData.renderer.cameraColorTarget, - renderingData.cameraData.renderer.cameraColorTarget); + var mat = orderIndependentTransparency.Render(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, + renderingData.cameraData.renderer.cameraColorTargetHandle); + Blitter.BlitCameraTexture(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, + renderingData.cameraData.renderer.cameraColorTargetHandle, mat, 0); context.ExecuteCommandBuffer(cmd); + cmd.Clear(); CommandBufferPool.Release(cmd); } diff --git a/URP/Runtime/OrderIndependentTransparencyRenderer.cs b/URP/Runtime/OrderIndependentTransparencyRenderer.cs index 38641da..f5394d1 100644 --- a/URP/Runtime/OrderIndependentTransparencyRenderer.cs +++ b/URP/Runtime/OrderIndependentTransparencyRenderer.cs @@ -1,5 +1,3 @@ -using System; -using UnityEngine; using UnityEngine.Rendering.Universal; namespace OrderIndependentTransparency.URP @@ -17,10 +15,10 @@ public override void Create() public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { - // Unity does not provide an example how to perform a fullscreen Blit that works in scene view - // Hence only Blit in Game view for now - if (renderingData.cameraData.cameraType != CameraType.Game) + if (renderingData.cameraData.isPreviewCamera) + { return; + } //Calling ConfigureInput with the ScriptableRenderPassInput.Color argument ensures that the opaque texture is available to the Render Pass oitPass.ConfigureInput(ScriptableRenderPassInput.Color); renderer.EnqueuePass(oitPass); diff --git a/package.json b/package.json index 4cf8e99..95e83a2 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "org.happy-turtle.order-independent-transparency", "version": "3.0.1", + "unity": "2021.2", "displayName": "Order-independent Transparency", "description": "This is an implementation of order-independent transparency for the Built-In Pipeline. It uses Per-Pixel Linked Lists, implemented with RWStructuredBuffers. This is a feature requiring Shader Model 5.0 with ComputeBuffers, see the Unity Manual for supported platforms.", - "unity": "2020.3", "author": { "name": "Till Davin", "email": "code@tilldavin.de"