using System; using UnityEngine.Rendering; using UnityEngine.Experimental.Rendering; using System.Collections.Generic; namespace UnityEngine.Rendering.HighDefinition { /// /// A set of custom pass utility function to help you build your effects /// public static class CustomPassUtils { /// /// Fullscreen scale and bias values, it is the default for functions that have scale and bias overloads. /// /// x: scaleX, y: scaleY, z: biasX, w: biasY public static Vector4 fullScreenScaleBias = new Vector4(1, 1, 0, 0); static ShaderTagId[] litForwardTags = { HDShaderPassNames.s_ForwardOnlyName, HDShaderPassNames.s_ForwardName, HDShaderPassNames.s_SRPDefaultUnlitName }; static ShaderTagId[] depthTags = { HDShaderPassNames.s_DepthForwardOnlyName, HDShaderPassNames.s_DepthOnlyName }; static ProfilingSampler downSampleSampler = new ProfilingSampler("DownSample"); static ProfilingSampler verticalBlurSampler = new ProfilingSampler("Vertical Blur"); static ProfilingSampler horizontalBlurSampler = new ProfilingSampler("Horizontal Blur"); static ProfilingSampler gaussianblurSampler = new ProfilingSampler("Gaussian Blur"); static ProfilingSampler copySampler = new ProfilingSampler("Copy"); static ProfilingSampler renderFromCameraSampler = new ProfilingSampler("Render From Camera"); static ProfilingSampler renderDepthFromCameraSampler = new ProfilingSampler("Render Depth"); static ProfilingSampler renderNormalFromCameraSampler = new ProfilingSampler("Render Normal"); static ProfilingSampler renderTangentFromCameraSampler = new ProfilingSampler("Render Tangent"); static MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock(); static Material customPassUtilsMaterial; static Material customPassRenderersUtilsMaterial; static Dictionary gaussianWeightsCache = new Dictionary(); static int downSamplePassIndex; static int verticalBlurPassIndex; static int horizontalBlurPassIndex; static int copyPassIndex; static int depthToColorPassIndex; static int depthPassIndex; static int normalToColorPassIndex; static int tangentToColorPassIndex; internal static void Initialize() { customPassUtilsMaterial = CoreUtils.CreateEngineMaterial(HDRenderPipeline.defaultAsset.renderPipelineResources.shaders.customPassUtils); downSamplePassIndex = customPassUtilsMaterial.FindPass("Downsample"); verticalBlurPassIndex = customPassUtilsMaterial.FindPass("VerticalBlur"); horizontalBlurPassIndex = customPassUtilsMaterial.FindPass("HorizontalBlur"); copyPassIndex = customPassUtilsMaterial.FindPass("Copy"); customPassRenderersUtilsMaterial = CoreUtils.CreateEngineMaterial(HDRenderPipeline.defaultAsset.renderPipelineResources.shaders.customPassRenderersUtils); depthToColorPassIndex = customPassRenderersUtilsMaterial.FindPass("DepthToColorPass"); depthPassIndex = customPassRenderersUtilsMaterial.FindPass("DepthPass"); normalToColorPassIndex = customPassRenderersUtilsMaterial.FindPass("NormalToColorPass"); tangentToColorPassIndex = customPassRenderersUtilsMaterial.FindPass("TangentToColorPass"); } /// /// Convert the source buffer to an half resolution buffer and output it to the destination buffer. /// /// Custom Pass Context. /// Source to use for the downsample /// Destination buffer of the downsample /// Source mip level to sample from. /// Destination mip level to write to. public static void DownSample(in CustomPassContext ctx, RTHandle source, RTHandle destination, int sourceMip = 0, int destMip = 0) => DownSample(ctx, source, destination, fullScreenScaleBias, fullScreenScaleBias, sourceMip, destMip); /// /// Convert the source buffer to an half resolution buffer and output it to the destination buffer. /// /// Custom Pass Context. /// Source to use for the downsample /// Destination buffer of the downsample /// Scale and bias to apply when sampling the source buffer /// Scale and bias to apply when writing into the destination buffer. It's scale is relative to the destination buffer, so if you want an half res downsampling into a fullres buffer you need to specify a scale of 0.5;0,5. If your buffer is already half res Then 1;1 scale works. /// Source mip level to sample from. /// Destination mip level to write to. public static void DownSample(in CustomPassContext ctx, RTHandle source, RTHandle destination, Vector4 sourceScaleBias, Vector4 destScaleBias, int sourceMip = 0, int destMip = 0) { // Check if the texture provided is at least half of the size of source. if (destination.rt.width < source.rt.width / 2 || destination.rt.height < source.rt.height / 2) Debug.LogError("Destination for DownSample is too small, it needs to be at least half as big as source."); if (source.rt.antiAliasing > 1 || destination.rt.antiAliasing > 1) Debug.LogError($"DownSample is not supported with MSAA buffers"); using (new ProfilingScope(ctx.cmd, downSampleSampler)) { SetRenderTargetWithScaleBias(ctx, propertyBlock, destination, destScaleBias, ClearFlag.None, destMip); propertyBlock.SetTexture(HDShaderIDs._Source, source); propertyBlock.SetVector(HDShaderIDs._SourceScaleBias, sourceScaleBias); SetSourceSize(propertyBlock, source); ctx.cmd.DrawProcedural(Matrix4x4.identity, customPassUtilsMaterial, downSamplePassIndex, MeshTopology.Quads, 4, 1, propertyBlock); } } // Do we provide an upsample function ? /// /// Copy an RTHandle content to another /// /// Custom Pass Context. /// Source to use for the copy /// Destination buffer of the copy /// Source mip level to sample from. /// Destination mip level to write to. public static void Copy(in CustomPassContext ctx, RTHandle source, RTHandle destination, int sourceMip = 0, int destMip = 0) => Copy(ctx, source, destination, fullScreenScaleBias, fullScreenScaleBias, sourceMip, destMip); /// /// Copy a region of an RTHandle to another /// /// Custom Pass Context. /// Source to use for the copy /// Destination buffer of the copy /// Scale and bias to apply when sampling the source buffer /// Scale and bias to apply when writing into the destination buffer. /// Source mip level to sample from. /// Destination mip level to write to. public static void Copy(in CustomPassContext ctx, RTHandle source, RTHandle destination, Vector4 sourceScaleBias, Vector4 destScaleBias, int sourceMip = 0, int destMip = 0) { if (source == destination) Debug.LogError("Can't copy the buffer. Source has to be different from the destination."); if (source.rt.antiAliasing > 1 || destination.rt.antiAliasing > 1) Debug.LogError($"Copy is not supported with MSAA buffers"); using (new ProfilingScope(ctx.cmd, copySampler)) { SetRenderTargetWithScaleBias(ctx, propertyBlock, destination, destScaleBias, ClearFlag.None, destMip); propertyBlock.SetTexture(HDShaderIDs._Source, source); propertyBlock.SetVector(HDShaderIDs._SourceScaleBias, sourceScaleBias); SetSourceSize(propertyBlock, source); ctx.cmd.DrawProcedural(Matrix4x4.identity, customPassUtilsMaterial, copyPassIndex, MeshTopology.Quads, 4, 1, propertyBlock); } } /// /// Vertical gaussian blur pass /// /// Custom Pass Context. /// Source to use for the gaussian blur. /// Destination buffer of the gaussian blur. /// Number of samples to use for the gaussian blur. A high number will impact performances. /// Radius in pixel of the gaussian blur. /// Source mip level to sample from. /// Destination mip level to write to. public static void VerticalGaussianBlur(in CustomPassContext ctx, RTHandle source, RTHandle destination, int sampleCount = 8, float radius = 5, int sourceMip = 0, int destMip = 0) => VerticalGaussianBlur(ctx, source, destination, fullScreenScaleBias, fullScreenScaleBias, sampleCount, radius, sourceMip, destMip); /// /// Vertical gaussian blur pass /// /// Custom Pass Context. /// Source to use for the gaussian blur. /// Destination buffer of the gaussian blur. /// Scale and bias to apply when sampling the source buffer /// Scale and bias to apply when writing into the destination buffer. /// Number of samples to use for the gaussian blur. A high number will impact performances. /// Radius in pixel of the gaussian blur. /// Source mip level to sample from. /// Destination mip level to write to. public static void VerticalGaussianBlur(in CustomPassContext ctx, RTHandle source, RTHandle destination, Vector4 sourceScaleBias, Vector4 destScaleBias, int sampleCount = 8, float radius = 5, int sourceMip = 0, int destMip = 0) { if (source == destination) Debug.LogError("Can't blur the buffer. Source has to be different from the destination."); if (source.rt.antiAliasing > 1 || destination.rt.antiAliasing > 1) Debug.LogError($"GaussianBlur is not supported with MSAA buffers"); using (new ProfilingScope(ctx.cmd, verticalBlurSampler)) { SetRenderTargetWithScaleBias(ctx, propertyBlock, destination, destScaleBias, ClearFlag.None, destMip); propertyBlock.SetTexture(HDShaderIDs._Source, source); propertyBlock.SetVector(HDShaderIDs._SourceScaleBias, sourceScaleBias); propertyBlock.SetBuffer(HDShaderIDs._GaussianWeights, GetGaussianWeights(sampleCount)); propertyBlock.SetFloat(HDShaderIDs._SampleCount, sampleCount); propertyBlock.SetFloat(HDShaderIDs._Radius, radius); SetSourceSize(propertyBlock, source); ctx.cmd.DrawProcedural(Matrix4x4.identity, customPassUtilsMaterial, verticalBlurPassIndex, MeshTopology.Quads, 4, 1, propertyBlock); } } /// /// Horizontal gaussian blur pass. /// /// Custom Pass Context. /// Source to use for the gaussian blur. /// Destination buffer of the gaussian blur. /// Number of samples to use for the gaussian blur. A high number will impact performances. /// Radius in pixel of the gaussian blur. /// Source mip level to sample from. /// Destination mip level to write to. public static void HorizontalGaussianBlur(in CustomPassContext ctx, RTHandle source, RTHandle destination, int sampleCount = 8, float radius = 5, int sourceMip = 0, int destMip = 0) => HorizontalGaussianBlur(ctx, source, destination, fullScreenScaleBias, fullScreenScaleBias, sampleCount, radius, sourceMip, destMip); /// /// Horizontal gaussian blur pass. /// /// Custom Pass Context. /// Source to use for the gaussian blur. /// Destination buffer of the gaussian blur. /// Scale and bias to apply when sampling the source buffer. /// Scale and bias to apply when writing into the destination buffer. /// Number of samples to use for the gaussian blur. A high number will impact performances. /// Radius in pixel of the gaussian blur. /// Source mip level to sample from. /// Destination mip level to write to. public static void HorizontalGaussianBlur(in CustomPassContext ctx, RTHandle source, RTHandle destination, Vector4 sourceScaleBias, Vector4 destScaleBias, int sampleCount = 8, float radius = 5, int sourceMip = 0, int destMip = 0) { if (source == destination) Debug.LogError("Can't blur the buffer. Source has to be different from the destination."); if (source.rt.antiAliasing > 1 || destination.rt.antiAliasing > 1) Debug.LogError($"GaussianBlur is not supported with MSAA buffers"); using (new ProfilingScope(ctx.cmd, horizontalBlurSampler)) { SetRenderTargetWithScaleBias(ctx, propertyBlock, destination, destScaleBias, ClearFlag.None, destMip); propertyBlock.SetTexture(HDShaderIDs._Source, source); propertyBlock.SetVector(HDShaderIDs._SourceScaleBias, sourceScaleBias); propertyBlock.SetBuffer(HDShaderIDs._GaussianWeights, GetGaussianWeights(sampleCount)); propertyBlock.SetFloat(HDShaderIDs._SampleCount, sampleCount); propertyBlock.SetFloat(HDShaderIDs._Radius, radius); SetSourceSize(propertyBlock, source); ctx.cmd.DrawProcedural(Matrix4x4.identity, customPassUtilsMaterial, horizontalBlurPassIndex, MeshTopology.Quads, 4, 1, propertyBlock); } } /// /// Gaussian Blur pass. /// /// Custom Pass Context. /// Source to use for the gaussian blur. /// Destination buffer of the gaussian blur. /// Temporary render target to provide used internally to swap the result between blur passes. Can be half res if downsample is true. /// Number of samples to use for the gaussian blur. A high number will impact performances. /// Radius in pixel of the gaussian blur. /// Source mip level to sample from. /// Destination mip level to write to. /// If true, will execute a downsample pass before the blur. It increases the performances of the blur. public static void GaussianBlur(in CustomPassContext ctx, RTHandle source, RTHandle destination, RTHandle tempTarget, int sampleCount = 9, float radius = 5, int sourceMip = 0, int destMip = 0, bool downSample = true) => GaussianBlur(ctx, source, destination, tempTarget, fullScreenScaleBias, fullScreenScaleBias, sampleCount, radius, sourceMip, destMip, downSample); /// /// Gaussian Blur pass. /// /// Custom Pass Context. /// Source to use for the gaussian blur. /// Destination buffer of the gaussian blur. /// Temporary render target to provide used internally to swap the result between blur passes. Can be half res if downsample is true. /// Scale and bias to apply when sampling the source buffer. /// Scale and bias to apply when writing into the destination buffer. /// Number of samples to use for the gaussian blur. A high number will impact performances. /// Radius in pixel of the gaussian blur. /// Source mip level to sample from. /// Destination mip level to write to. /// If true, will execute a downsample pass before the blur. It increases the performances of the blur. public static void GaussianBlur(in CustomPassContext ctx, RTHandle source, RTHandle destination, RTHandle tempTarget, Vector4 sourceScaleBias, Vector4 destScaleBias, int sampleCount = 9, float radius = 5, int sourceMip = 0, int destMip = 0, bool downSample = true) { if (source == tempTarget || destination == tempTarget) Debug.LogError("Can't blur the buffer. tempTarget has to be different from both source or destination."); if (tempTarget.scaleFactor.x != tempTarget.scaleFactor.y || (tempTarget.scaleFactor.x != 0.5f && tempTarget.scaleFactor.x != 1.0f)) Debug.LogError($"Can't blur the buffer. Only a scaleFactor of 0.5 or 1.0 is supported on tempTarget. Current scaleFactor: {tempTarget.scaleFactor}"); if (source.rt.antiAliasing > 1 || destination.rt.antiAliasing > 1 || tempTarget.rt.antiAliasing > 1) Debug.LogError($"GaussianBlur is not supported with MSAA buffers"); // Gaussian blur doesn't like even numbers if (sampleCount % 2 == 0) sampleCount++; using (new ProfilingScope(ctx.cmd, gaussianblurSampler)) { if (downSample) { // Downsample to half res in mip 0 of temp target (in case temp target doesn't have any mipmap we use 0) DownSample(ctx, source, tempTarget, sourceScaleBias, destScaleBias, sourceMip, 0); // Vertical blur VerticalGaussianBlur(ctx, tempTarget, destination, sourceScaleBias, destScaleBias, sampleCount, radius, 0, destMip); // Instead of allocating a new buffer on the fly, we copy the data. // We will be able to allocate it when rendergraph lands Copy(ctx, destination, tempTarget, sourceScaleBias, destScaleBias, 0, destMip); // Horizontal blur and upsample HorizontalGaussianBlur(ctx, tempTarget, destination, sourceScaleBias, destScaleBias, sampleCount, radius, sourceMip, destMip); } else { // Vertical blur VerticalGaussianBlur(ctx, source, tempTarget, sourceScaleBias, destScaleBias, sampleCount, radius, sourceMip, destMip); // Horizontal blur and upsample HorizontalGaussianBlur(ctx, tempTarget, destination, sourceScaleBias, destScaleBias, sampleCount, radius, sourceMip, destMip); } } } /// /// Simpler version of ScriptableRenderContext.DrawRenderers to draw HDRP materials. /// /// Custom Pass Context. /// LayerMask to filter the objects to render. /// Render Queue to filter the type of objects you want to render. /// Optional material that will be used to render the objects. /// Pass index to use for the override material. /// The render states to override when rendering the objects. public static void DrawRenderers(in CustomPassContext ctx, LayerMask layerMask, CustomPass.RenderQueueType renderQueueFilter = CustomPass.RenderQueueType.All, Material overrideMaterial = null, int overrideMaterialIndex = 0, RenderStateBlock overrideRenderState = default(RenderStateBlock), SortingCriteria sorting = SortingCriteria.CommonOpaque) { PerObjectData renderConfig = ctx.hdCamera.frameSettings.IsEnabled(FrameSettingsField.Shadowmask) ? HDUtils.k_RendererConfigurationBakedLightingWithShadowMask : HDUtils.k_RendererConfigurationBakedLighting; var result = new RendererListDesc(litForwardTags, ctx.cullingResults, ctx.hdCamera.camera) { rendererConfiguration = renderConfig, renderQueueRange = GetRenderQueueRangeFromRenderQueueType(renderQueueFilter), sortingCriteria = sorting, overrideMaterial = overrideMaterial, overrideMaterialPassIndex = overrideMaterialIndex, excludeObjectMotionVectors = false, layerMask = layerMask, stateBlock = overrideRenderState, }; CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, RendererList.Create(result)); } /// /// Generate gaussian weights for a given number of samples /// /// number of weights you want to generate /// a GPU compute buffer containing the weights internal static ComputeBuffer GetGaussianWeights(int weightCount) { float[] weights; ComputeBuffer gpuWeights; if (gaussianWeightsCache.TryGetValue(weightCount, out gpuWeights)) return gpuWeights; weights = new float[weightCount]; float integrationBound = 3; float p = -integrationBound; float c = 0; float step = (1.0f / (float)weightCount) * integrationBound * 2; for (int i = 0; i < weightCount; i++) { float w = (Gaussian(p) / (float)weightCount) * integrationBound * 2; weights[i] = w; p += step; c += w; } // Gaussian function float Gaussian(float x, float sigma = 1) { float a = 1.0f / Mathf.Sqrt(2 * Mathf.PI * sigma * sigma); float b = Mathf.Exp(-(x * x) / (2 * sigma * sigma)); return a * b; } gpuWeights = new ComputeBuffer(weights.Length, sizeof(float)); gpuWeights.SetData(weights); gaussianWeightsCache[weightCount] = gpuWeights; return gpuWeights; } /// /// Convert a Custom Pass render queue type to a RenderQueueRange that can be used in DrawRenderers /// /// The type of render queue /// The converted render queue range public static RenderQueueRange GetRenderQueueRangeFromRenderQueueType(CustomPass.RenderQueueType type) { switch (type) { case CustomPass.RenderQueueType.OpaqueNoAlphaTest: return HDRenderQueue.k_RenderQueue_OpaqueNoAlphaTest; case CustomPass.RenderQueueType.OpaqueAlphaTest: return HDRenderQueue.k_RenderQueue_OpaqueAlphaTest; case CustomPass.RenderQueueType.AllOpaque: return HDRenderQueue.k_RenderQueue_AllOpaque; case CustomPass.RenderQueueType.AfterPostProcessOpaque: return HDRenderQueue.k_RenderQueue_AfterPostProcessOpaque; case CustomPass.RenderQueueType.PreRefraction: return HDRenderQueue.k_RenderQueue_PreRefraction; case CustomPass.RenderQueueType.Transparent: return HDRenderQueue.k_RenderQueue_Transparent; case CustomPass.RenderQueueType.LowTransparent: return HDRenderQueue.k_RenderQueue_LowTransparent; case CustomPass.RenderQueueType.AllTransparent: return HDRenderQueue.k_RenderQueue_AllTransparent; case CustomPass.RenderQueueType.AllTransparentWithLowRes: return HDRenderQueue.k_RenderQueue_AllTransparentWithLowRes; case CustomPass.RenderQueueType.AfterPostProcessTransparent: return HDRenderQueue.k_RenderQueue_AfterPostProcessTransparent; case CustomPass.RenderQueueType.All: default: return HDRenderQueue.k_RenderQueue_All; } } /// /// Disable the single-pass rendering (use in XR) /// public struct DisableSinglePassRendering : IDisposable { CustomPassContext m_Context; /// /// Disable the single-pass rendering (use in XR) /// /// Custom Pass Context. public DisableSinglePassRendering(in CustomPassContext ctx) { m_Context = ctx; if (ctx.hdCamera.xr.enabled) m_Context.hdCamera.xr.StopSinglePass(ctx.cmd); } /// /// Re-enable the single-pass rendering if it was enabled /// void IDisposable.Dispose() { if (m_Context.hdCamera.xr.enabled) m_Context.hdCamera.xr.StartSinglePass(m_Context.cmd); } } /// /// Render a list of objects from another camera point of view. /// /// Custom Pass Context. /// The camera from where you want the objects to be rendered. /// LayerMask to filter the objects to render. /// Render Queue to filter the type of objects you want to render. /// Optional material that will be used to render the objects. /// Pass index to use for the override material. /// The render states to override when rendering the objects. public static void RenderFromCamera(in CustomPassContext ctx, Camera view, LayerMask layerMask, CustomPass.RenderQueueType renderQueueFilter = CustomPass.RenderQueueType.All, Material overrideMaterial = null, int overrideMaterialIndex = 0, RenderStateBlock overrideRenderState = default(RenderStateBlock)) => RenderFromCamera(ctx, view, null, null, ClearFlag.None, layerMask, renderQueueFilter, overrideMaterial, overrideMaterialIndex, overrideRenderState); /// /// Render a list of objects from another camera point of view. /// /// Custom Pass Context. /// The camera from where you want the objects to be rendered. /// The render target that will be bound to the color buffer before rendering /// The render target that will be bound to the depth buffer before rendering /// The type of clear to do before binding the render targets. /// LayerMask to filter the objects to render. /// Render Queue to filter the type of objects you want to render. /// Optional material that will be used to render the objects. /// Pass index to use for the override material. /// The render states to override when rendering the objects. public static void RenderFromCamera(in CustomPassContext ctx, Camera view, RTHandle targetColor, RTHandle targetDepth, ClearFlag clearFlag, LayerMask layerMask, CustomPass.RenderQueueType renderQueueFilter = CustomPass.RenderQueueType.All, Material overrideMaterial = null, int overrideMaterialIndex = 0, RenderStateBlock overrideRenderState = default(RenderStateBlock)) { if (targetColor != null && targetDepth != null) CoreUtils.SetRenderTarget(ctx.cmd, targetColor, targetDepth, clearFlag); else if (targetColor != null) CoreUtils.SetRenderTarget(ctx.cmd, targetColor, clearFlag); else if (targetDepth != null) CoreUtils.SetRenderTarget(ctx.cmd, targetDepth, clearFlag); using (new DisableSinglePassRendering(ctx)) { using (new HDRenderPipeline.OverrideCameraRendering(ctx.cmd, view)) { using (new ProfilingScope(ctx.cmd, renderFromCameraSampler)) DrawRenderers(ctx, layerMask, renderQueueFilter, overrideMaterial, overrideMaterialIndex, overrideRenderState); } } } /// /// Render eye space depth of objects from the view point of a camera into the color buffer. /// /// Custom Pass Context. /// The camera from where you want the objects to be rendered. /// LayerMask to filter the objects to render. /// Render Queue to filter the type of objects you want to render. /// The render states to override when rendering the objects. public static void RenderDepthFromCamera(in CustomPassContext ctx, Camera view, LayerMask layerMask, CustomPass.RenderQueueType renderQueueFilter = CustomPass.RenderQueueType.All, RenderStateBlock overrideRenderState = default(RenderStateBlock)) => RenderDepthFromCamera(ctx, view, null, null, ClearFlag.None, layerMask, renderQueueFilter, overrideRenderState); /// /// Render eye space depth of objects from the view point of a camera into the color and depth buffers. /// /// Custom Pass Context. /// The camera from where you want the objects to be rendered. /// The render target that will be bound to the color buffer before rendering /// The render target that will be bound to the depth buffer before rendering /// The type of clear to do before binding the render targets. /// LayerMask to filter the objects to render. /// Render Queue to filter the type of objects you want to render. /// The render states to override when rendering the objects. public static void RenderDepthFromCamera(in CustomPassContext ctx, Camera view, RTHandle targetColor, RTHandle targetDepth, ClearFlag clearFlag, LayerMask layerMask, CustomPass.RenderQueueType renderQueueFilter = CustomPass.RenderQueueType.All, RenderStateBlock overrideRenderState = default(RenderStateBlock)) { using (new ProfilingScope(ctx.cmd, renderDepthFromCameraSampler)) { if (targetColor == null && targetDepth != null) RenderFromCamera(ctx, view, targetColor, targetDepth, clearFlag, layerMask, renderQueueFilter, customPassRenderersUtilsMaterial, depthPassIndex, overrideRenderState); else RenderFromCamera(ctx, view, targetColor, targetDepth, clearFlag, layerMask, renderQueueFilter, customPassRenderersUtilsMaterial, depthToColorPassIndex, overrideRenderState); } } /// /// Render world space normal of objects from the view point of a camera into the color buffer. /// /// Custom Pass Context. /// The camera from where you want the objects to be rendered. /// LayerMask to filter the objects to render. /// Render Queue to filter the type of objects you want to render. /// The render states to override when rendering the objects. public static void RenderNormalFromCamera(in CustomPassContext ctx, Camera view, LayerMask layerMask, CustomPass.RenderQueueType renderQueueFilter = CustomPass.RenderQueueType.All, RenderStateBlock overrideRenderState = default(RenderStateBlock)) => RenderNormalFromCamera(ctx, view, null, null, ClearFlag.None, layerMask, renderQueueFilter, overrideRenderState); /// /// Render world space normal of objects from the view point of a camera into the color buffer. /// /// Custom Pass Context. /// The camera from where you want the objects to be rendered. /// The render target that will be bound to the color buffer before rendering /// The render target that will be bound to the depth buffer before rendering /// The type of clear to do before binding the render targets. /// LayerMask to filter the objects to render. /// Render Queue to filter the type of objects you want to render. /// The render states to override when rendering the objects. public static void RenderNormalFromCamera(in CustomPassContext ctx, Camera view, RTHandle targetColor, RTHandle targetDepth, ClearFlag clearFlag, LayerMask layerMask, CustomPass.RenderQueueType renderQueueFilter = CustomPass.RenderQueueType.All, RenderStateBlock overrideRenderState = default(RenderStateBlock)) { using (new ProfilingScope(ctx.cmd, renderNormalFromCameraSampler)) RenderFromCamera(ctx, view, targetColor, targetDepth, clearFlag, layerMask, renderQueueFilter, customPassRenderersUtilsMaterial, normalToColorPassIndex, overrideRenderState); } /// /// Render world space tangent of objects from the view point of a camera into the color buffer. /// /// Custom Pass Context. /// The camera from where you want the objects to be rendered. /// LayerMask to filter the objects to render. /// Render Queue to filter the type of objects you want to render. /// The render states to override when rendering the objects. public static void RenderTangentFromCamera(in CustomPassContext ctx, Camera view, LayerMask layerMask, CustomPass.RenderQueueType renderQueueFilter = CustomPass.RenderQueueType.All, RenderStateBlock overrideRenderState = default(RenderStateBlock)) => RenderTangentFromCamera(ctx, view, null, null, ClearFlag.None, layerMask, renderQueueFilter, overrideRenderState); /// /// Render world space tangent of objects from the view point of a camera into the color buffer /// /// Custom Pass Context. /// The camera from where you want the objects to be rendered. /// The render target that will be bound to the color buffer before rendering /// The render target that will be bound to the depth buffer before rendering /// The type of clear to do before binding the render targets. /// LayerMask to filter the objects to render. /// Render Queue to filter the type of objects you want to render. /// The render states to override when rendering the objects. public static void RenderTangentFromCamera(in CustomPassContext ctx, Camera view, RTHandle targetColor, RTHandle targetDepth, ClearFlag clearFlag, LayerMask layerMask, CustomPass.RenderQueueType renderQueueFilter = CustomPass.RenderQueueType.All, RenderStateBlock overrideRenderState = default(RenderStateBlock)) { using (new ProfilingScope(ctx.cmd, renderTangentFromCameraSampler)) RenderFromCamera(ctx, view, targetColor, targetDepth, clearFlag, layerMask, renderQueueFilter, customPassRenderersUtilsMaterial, tangentToColorPassIndex, overrideRenderState); } // TODO when rendergraph is available: a PostProcess pass which does the copy with a temp target internal static void Cleanup() { foreach (var gaussianWeights in gaussianWeightsCache) gaussianWeights.Value.Release(); gaussianWeightsCache.Clear(); } internal static void SetRenderTargetWithScaleBias(in CustomPassContext ctx, MaterialPropertyBlock block, RTHandle destination, Vector4 destScaleBias, ClearFlag clearFlag, int miplevel) { // viewport with RT handle scale and scale factor: Rect viewport = new Rect(); if (destination.useScaling) viewport.size = destination.GetScaledSize(destination.rtHandleProperties.currentViewportSize); else viewport.size = new Vector2Int(destination.rt.width, destination.rt.height); Vector2 destSize = viewport.size; viewport.position = new Vector2(viewport.size.x * destScaleBias.z, viewport.size.y * destScaleBias.w); viewport.size *= new Vector2(destScaleBias.x, destScaleBias.y); CoreUtils.SetRenderTarget(ctx.cmd, destination, clearFlag, Color.black, miplevel); ctx.cmd.SetViewport(viewport); block.SetVector(HDShaderIDs._ViewPortSize, new Vector4(destSize.x, destSize.y, 1.0f / destSize.x, 1.0f / destSize.y)); block.SetVector(HDShaderIDs._ViewportScaleBias, new Vector4(1.0f / destScaleBias.x, 1.0f / destScaleBias.y, destScaleBias.z, destScaleBias.w)); } static void SetSourceSize(MaterialPropertyBlock block, RTHandle source) { Vector2 sourceSize = source.GetScaledSize(source.rtHandleProperties.currentViewportSize); block.SetVector(HDShaderIDs._SourceSize, new Vector4(sourceSize.x, sourceSize.y, 1.0f / sourceSize.x, 1.0f / sourceSize.y)); block.SetVector(HDShaderIDs._SourceScaleFactor, new Vector4(source.scaleFactor.x, source.scaleFactor.y, 1.0f / source.scaleFactor.x, 1.0f / source.scaleFactor.y)); } } }