Hey Thanks for you quick reply
have added the Despose()
done a little testing and
RenderingUtils.ReAllocateIfNeeded(ref temporaryColorTexture, opaqueDescriptor, FilterMode.Point)
does the job of creating the RTHandle and I tested the blit without the material
Blit(cmd, source, temporaryColorTexture); // , outlineMaterial, 0)
Blit(cmd, temporaryColorTexture, source);
and it is back to just showing the normal shading
from this it may be possible to conclude that the material is not working in the blit (not sure if it should just be pink?) and I really have no idea how to do this stuff. not sure where to go next really…
this is the shader
EdgeSelective.shader
Shader "EdgeSelective"
{
Properties
{
_depthSensitivity("DepthSensitivity", Range(0.0, 1.0)) = 0.0
_normalsSensitivity("NormalsSensitivity", Range(0.0, 10.0)) = 0.0
_colorSensitivity("ColorSensitivity", Range(0.0, 10.0)) = 0.0
_edgeColor("edgeColor", Color) = (1, 1, 1, 1)
_outlineThickness("EdgeThickness", Range(0.0, 4.0)) = 1.0
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
LOD 100
ZTest Always
Pass
{
Name "Unlit"
ZTest Always
ZWrite Off
Cull Off
HLSLPROGRAM
// Required to compile gles 2.0 with standard srp library
#pragma prefer_hlslcc gles
#pragma exclude_renderers d3d11_9x
#pragma shader_feature ALL_EDGES
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/Shaders/UnlitInput.hlsl"
#include "EdgeSelective.hlsl"
float _depthSensitivity;
float _normalsSensitivity;
float _colorSensitivity;
float _maskSensitivity;
float _backfaceSensitivity;
float _outlineThickness;
half4 _edgeColor;
half4 _backfaceEdgeColor;
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings vert(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
output.vertex = vertexInput.positionCS;
output.uv = input.uv;
return output;
}
half4 frag(Varyings input) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(input);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.uv;
half4 _out;
Outline_float(uv, _outlineThickness, _depthSensitivity, _normalsSensitivity, _colorSensitivity, _edgeColor, _out);
return _out;
}
ENDHLSL
}
}
FallBack "Hidden/Universal Render Pipeline/FallbackError"
}
and this is the include
EdgeSelective.hlsl
TEXTURE2D(_CameraColorTexture);
SAMPLER(sampler_CameraColorTexture);
float4 _CameraColorTexture_TexelSize;
TEXTURE2D(_CameraDepthNormalsTexture);
SAMPLER(sampler_CameraDepthNormalsTexture);
float3 DecodeNormal(float4 enc)
{
float kScale = 1.7777;
float3 nn = enc.xyz*float3(2*kScale,2*kScale,0) + float3(-kScale,-kScale,1);
float g = 2.0 / dot(nn.xyz,nn.xyz);
float3 n;
n.xy = g*nn.xy;
n.z = g-1;
return n;
}
inline float DecodeFloatRG(float2 enc)
{
float2 kDecodeDot = float2(1.0, 1 / 255.0);
return dot(enc, kDecodeDot);
}
inline float3 DecodeViewNormal(float4 enc4)
{
float kScale = 1.7777;
float3 nn = enc4.xyz*float3(2 * kScale, 2 * kScale, 0) + float3(-kScale, -kScale, 1);
float g = 2.0 / dot(nn.xyz, nn.xyz);
float3 n;
n.xy = g * nn.xy;
n.z = g - 1;
return n;
}
void DecodeDepthNormal(float4 enc, out float depth, out float3 normal)
{
depth = DecodeFloatRG(enc.zw);
normal = DecodeViewNormal(enc);
}
void Outline_float(float2 UV, float OutlineThickness,
float DepthSensitivity, float NormalsSensitivity, float ColorSensitivity, half4 OutlineColor,
out half4 Out)
{
float halfScaleFloor = floor(OutlineThickness * 0.5);
float halfScaleCeil = ceil(OutlineThickness * 0.5);
float2 Texel = (1.0) / float2(_CameraColorTexture_TexelSize.z, _CameraColorTexture_TexelSize.w);
float2 uvSamples[4];
float depthSamples[4] ;
float3 normalSamples[4], colorSamples[4];
uvSamples[0] = UV - float2(Texel.x, Texel.y) * halfScaleFloor;
uvSamples[1] = UV + float2(Texel.x, Texel.y) * halfScaleCeil;
uvSamples[2] = UV + float2(Texel.x * halfScaleCeil, -Texel.y * halfScaleFloor);
uvSamples[3] = UV + float2(-Texel.x * halfScaleFloor, Texel.y * halfScaleCeil);
for(int i = 0; i < 4 ; i++)
{
float4 samples = SAMPLE_TEXTURE2D(_CameraDepthNormalsTexture, sampler_CameraDepthNormalsTexture, uvSamples[i]);//
DecodeDepthNormal(samples, depthSamples[i], normalSamples[i]);//
colorSamples[i] = SAMPLE_TEXTURE2D(_CameraColorTexture, sampler_CameraColorTexture, uvSamples[i]).xyz;
}
// Depth
float depthFiniteDifference0 = depthSamples[1] - depthSamples[0];
float depthFiniteDifference1 = depthSamples[3] - depthSamples[2];
float edgeDepth = sqrt(pow(depthFiniteDifference0, 2) + pow(depthFiniteDifference1, 2)) * 100;
float depthThreshold = (1/DepthSensitivity) * depthSamples[0];
edgeDepth = edgeDepth > depthThreshold ? 1 : 0;
// Normals
float3 normalFiniteDifference0 = normalSamples[1] - normalSamples[0];
float3 normalFiniteDifference1 = normalSamples[3] - normalSamples[2];
float edgeNormal = sqrt(dot(normalFiniteDifference0, normalFiniteDifference0) + dot(normalFiniteDifference1, normalFiniteDifference1));
edgeNormal = edgeNormal > (1/NormalsSensitivity) ? 1 : 0;
// Color
float3 colorFiniteDifference0 = colorSamples[1] - colorSamples[0];
float3 colorFiniteDifference1 = colorSamples[3] - colorSamples[2];
float edgeColor = sqrt(dot(colorFiniteDifference0, colorFiniteDifference0) + dot(colorFiniteDifference1, colorFiniteDifference1));
edgeColor = edgeColor > (1/ColorSensitivity) ? 1 : 0;
float edge = max(edgeDepth, max(edgeNormal, edgeColor));
half4 original = SAMPLE_TEXTURE2D(_CameraColorTexture, sampler_CameraColorTexture, uvSamples[0]);
Out = ((1 - edge) * original) + (edge * lerp(original, OutlineColor, OutlineColor.a));
}
here is the depth normal render that is now working just in case some clever dev feels kind enough to try and get it all working
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections.Generic;
using UnityEngine.Rendering.Universal;
public class DepthNormalsFeature : ScriptableRendererFeature
{
class DepthNormalsPass : ScriptableRenderPass
{
Material depthNormalsMaterial = null;
FilteringSettings m_FilteringSettings;
readonly int renderTargetId;
readonly List<ShaderTagId> shaderTagIds = new List<ShaderTagId>();
RTHandle rtIdentifier = null;
//RenderTargetIdentifier renderTargetIdentifier;
// RTHandle rtIdentifier;
public DepthNormalsPass(RenderQueueRange renderQueueRange, int targetId, int layerMask, Material material)
{
renderTargetId = targetId;
m_FilteringSettings = new FilteringSettings(renderQueueRange, -1, (uint)(1 << layerMask ));
depthNormalsMaterial = material;
shaderTagIds.Add(new ShaderTagId("UniversalForward"));
shaderTagIds.Add(new ShaderTagId("UniversalForwardOnly"));
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
RenderTextureDescriptor descriptor = renderingData.cameraData.cameraTargetDescriptor;
descriptor.depthBufferBits = 24;
descriptor.colorFormat = RenderTextureFormat.ARGB32;
cmd.GetTemporaryRT(renderTargetId, descriptor, FilterMode.Point);
// renderTargetIdentifier = new RenderTargetIdentifier(renderTargetId);
rtIdentifier = null;
ConfigureTarget(rtIdentifier, renderingData.cameraData.renderer.cameraDepthTargetHandle );
ConfigureClear(ClearFlag.All, Color.black);
}
// Here you can implement the rendering logic.
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
DrawingSettings drawSettings = CreateDrawingSettings(shaderTagIds, ref renderingData, SortingCriteria.None);
drawSettings.overrideMaterial = depthNormalsMaterial;
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, new ProfilingSampler("DepthNormals Prepass")))
{
RendererListParams rendererListParams = new RendererListParams(renderingData.cullResults, drawSettings, m_FilteringSettings);
RendererList rendererList = context.CreateRendererList(ref rendererListParams);
cmd.DrawRendererList(rendererList);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
/// Cleanup any allocated resources that were created during the execution of this render pass.
public override void OnCameraCleanup(CommandBuffer cmd)
{
cmd.ReleaseTemporaryRT(renderTargetId);
}
public void Dispose()
{
rtIdentifier?.Release();
}
}
DepthNormalsPass depthNormalsPass;
Material depthNormalsMaterial;
[Range(0, 5)]
[SerializeField] int RenderlayerMask;
public override void Create()
{
int renderTargetId = Shader.PropertyToID("_CameraDepthNormalsTexture");
depthNormalsMaterial = CoreUtils.CreateEngineMaterial("Hidden/Internal-DepthNormalsTexture");
depthNormalsPass = new DepthNormalsPass(RenderQueueRange.all, renderTargetId, RenderlayerMask, depthNormalsMaterial );
depthNormalsPass.renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
RenderingLayerOutline.ID = RenderlayerMask;
}
// Here you can inject one or multiple render passes in the renderer.
// This method is called when setting up the renderer once per-camera.
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
renderer.EnqueuePass(depthNormalsPass);
}
}