Created
March 24, 2025 12:54
-
-
Save Myonmu/03db0062f9f202dff018182804cb170c to your computer and use it in GitHub Desktop.
URP Copy Normals
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Shader "Custom/BlitShader" | |
| { | |
| SubShader | |
| { | |
| Tags | |
| { | |
| "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" | |
| } | |
| Pass | |
| { | |
| Name "Blit" | |
| ZTest Always | |
| ZWrite[_ZWrite] | |
| Cull Off | |
| HLSLPROGRAM | |
| #pragma vertex Vert | |
| #pragma fragment frag | |
| #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" | |
| #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" | |
| TEXTURE2D(_SourceTex); | |
| SAMPLER(sampler_SourceTex); | |
| float4 frag(Varyings input) : SV_Target | |
| { | |
| UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); | |
| return SAMPLE_TEXTURE2D(_SourceTex,sampler_SourceTex, input.texcoord); | |
| } | |
| ENDHLSL | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using UnityEngine; | |
| using UnityEngine.Rendering.Universal; | |
| namespace Rendering.Dithering | |
| { | |
| public class CopyNormalsFeature: ScriptableRendererFeature | |
| { | |
| public RenderPassEvent injectionPoint = RenderPassEvent.AfterRenderingDeferredLights; | |
| public Vector2Int size= new(200,200); | |
| private CopyNormalsPass _pass ; | |
| private bool _requiresReset; | |
| public override void Create() | |
| { | |
| var copyDepthPS = Shader.Find("Custom/BlitShader"); | |
| _pass = new CopyNormalsPass(injectionPoint, copyDepthPS, size); | |
| } | |
| public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) | |
| { | |
| _pass.renderPassEvent = injectionPoint; | |
| renderer.EnqueuePass(_pass); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using UnityEngine; | |
| using UnityEngine.Rendering; | |
| using UnityEngine.Rendering.RenderGraphModule; | |
| using UnityEngine.Rendering.Universal; | |
| namespace Rendering.Dithering | |
| { | |
| public class CopyNormalsPass: ScriptableRenderPass | |
| { | |
| private readonly Material _material; | |
| private static int _shaderVarId; | |
| private RTHandle _destination; | |
| /// <summary> | |
| /// Creates a new <c>CopyDepthPass</c> instance. | |
| /// </summary> | |
| /// <param name="evt">The <c>RenderPassEvent</c> to use.</param> | |
| /// <param name="shader">The <c>Shader</c> to use for copying the depth.</param> | |
| /// <param name="customPassName">An optional custom profiling name to disambiguate multiple copy passes.</param> | |
| /// <seealso cref="RenderPassEvent"/> | |
| public CopyNormalsPass(RenderPassEvent evt, Shader shader, Vector2Int size, string customPassName = null) | |
| { | |
| profilingSampler = customPassName != null | |
| ? new ProfilingSampler(customPassName) | |
| : new ProfilingSampler(nameof(CopyNormalsPass)); | |
| _material = shader != null ? CoreUtils.CreateEngineMaterial(shader) : null; | |
| renderPassEvent = evt; | |
| _shaderVarId = Shader.PropertyToID( "_CameraNormalsTexture"); | |
| _destination = RTHandles.Alloc(size.x, size.y); | |
| } | |
| private class PassData | |
| { | |
| internal TextureHandle source; | |
| internal TextureHandle destination; | |
| internal UniversalCameraData cameraData; | |
| internal Material material; | |
| // The size of the camera target changes during the frame so we must make a copy of it here to preserve its record-time value. | |
| internal Vector2Int cameraTargetSizeCopy; | |
| } | |
| private static void ExecutePass(RasterCommandBuffer cmd, PassData passData, RTHandle source, | |
| RTHandle destination) | |
| { | |
| var mat = passData.material; | |
| if (mat == null) | |
| { | |
| Debug.LogErrorFormat( | |
| "Missing {0}. Copy Depth render pass will not execute. Check for missing reference in the renderer resources.", | |
| mat); | |
| return; | |
| } | |
| var viewportScale = source.useScaling | |
| ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) | |
| : Vector2.one; | |
| // We y-flip if | |
| // 1) we are blitting from render texture to back buffer(UV starts at bottom) and | |
| // 2) renderTexture starts UV at top | |
| var yflip = passData.cameraData.IsHandleYFlipped(source) != | |
| passData.cameraData.IsHandleYFlipped(destination); | |
| var scaleBias = yflip | |
| ? new Vector4(viewportScale.x, -viewportScale.y, 0, viewportScale.y) | |
| : new Vector4(viewportScale.x, viewportScale.y, 0, 0); | |
| cmd.SetViewport(new Rect(0, 0, passData.cameraTargetSizeCopy.x, passData.cameraTargetSizeCopy.y)); | |
| mat.SetTexture(Shader.PropertyToID("_SourceTex"), source); | |
| Blitter.BlitTexture(cmd, source, scaleBias, mat, 0); | |
| } | |
| /// <inheritdoc/> | |
| public override void OnCameraCleanup(CommandBuffer cmd) | |
| { | |
| if (cmd == null) | |
| throw new ArgumentNullException(nameof(cmd)); | |
| } | |
| /// <summary> | |
| /// Sets up the Copy Depth pass for RenderGraph execution | |
| /// </summary> | |
| /// <param name="renderGraph">The current RenderGraph used for recording and execution of a frame.</param> | |
| /// <param name="destination"><c>TextureHandle</c> of the destination it will copy to.</param> | |
| /// <param name="source"><c>TextureHandle</c> of the source it will copy from.</param> | |
| /// <param name="cameraData">Camera settings for the current frame.</param> | |
| /// <param name="bindAsCameraDepth">If this is true, the destination texture is bound as _CameraDepthTexture after the copy pass</param> | |
| /// <param name="passName">The pass name used for debug and identifying the pass.</param> | |
| public void Render(RenderGraph renderGraph, TextureHandle destination, TextureHandle source, | |
| UniversalCameraData cameraData, bool bindAsCameraDepth = false, | |
| string passName = "Copy Normals") | |
| { | |
| // TODO RENDERGRAPH: should call the equivalent of Setup() to initialise everything correctly | |
| using (var builder = | |
| renderGraph.AddRasterRenderPass<PassData>(passName, out var passData, profilingSampler)) | |
| { | |
| passData.material = _material; | |
| passData.cameraData = cameraData; | |
| passData.cameraTargetSizeCopy = new Vector2Int(cameraData.cameraTargetDescriptor.width, | |
| cameraData.cameraTargetDescriptor.height); | |
| // Writes depth as "grayscale color" output | |
| passData.destination = destination; | |
| builder.SetRenderAttachment(destination, 0); | |
| passData.source = source; | |
| builder.UseTexture(source); | |
| if (bindAsCameraDepth && destination.IsValid()) | |
| builder.SetGlobalTextureAfterPass(destination, _shaderVarId); | |
| // TODO RENDERGRAPH: culling? force culling off for testing | |
| builder.AllowPassCulling(false); | |
| builder.AllowGlobalStateModification(true); | |
| builder.SetRenderFunc((PassData data, RasterGraphContext context) => | |
| { | |
| ExecutePass(context.cmd, data, data.source, data.destination); | |
| }); | |
| } | |
| } | |
| public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) | |
| { | |
| var resourceData = frameData.Get<UniversalResourceData>(); | |
| var cameraData = frameData.Get<UniversalCameraData>(); | |
| var src = resourceData.gBuffer[2]; | |
| var dest = renderGraph.ImportTexture(_destination); | |
| Render(renderGraph, dest, src, cameraData, true); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment