Skip to content

Instantly share code, notes, and snippets.

@andybak
Last active November 17, 2019 12:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andybak/3743ce0f15cabc0331dce136e0db4168 to your computer and use it in GitHub Desktop.
Save andybak/3743ce0f15cabc0331dce136e0db4168 to your computer and use it in GitHub Desktop.
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class DepthNormalsFeature : ScriptableRendererFeature
{
private DepthNormalsPass depthNormalsPass;
RenderTargetHandle m_DepthNormalsTexture;
public override void Create()
{
if (depthNormalsPass == null)
depthNormalsPass =
new DepthNormalsPass(RenderPassEvent.BeforeRenderingPrepasses, RenderQueueRange.opaque, -1);
m_DepthNormalsTexture.Init("_CameraDepthNormalsTexture");
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
depthNormalsPass.Setup(renderingData.cameraData.cameraTargetDescriptor, m_DepthNormalsTexture);
renderer.EnqueuePass(depthNormalsPass);
}
void OnValidate()
{
depthNormalsPass?.SetLayerMask(-1);
}
}
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class DepthNormalsPass : ScriptableRenderPass
{
int kDepthBufferBits = 32;
private RenderTargetHandle depthAttachmentHandle { get; set; }
internal RenderTextureDescriptor descriptor { get; private set; }
private FilteringSettings m_FilteringSettings;
string m_ProfilerTag = "DepthNormals Prepass";
ShaderTagId m_ShaderTagId = new ShaderTagId("DepthOnly");
private Material depthNormalsMaterial = null;
public DepthNormalsPass(RenderPassEvent evt, RenderQueueRange renderQueueRange, LayerMask layerMask)
{
m_FilteringSettings = new FilteringSettings(renderQueueRange, layerMask);
renderPassEvent = evt;
}
public void Setup(RenderTextureDescriptor baseDescriptor, RenderTargetHandle depthAttachmentHandle)
{
this.depthAttachmentHandle = depthAttachmentHandle;
baseDescriptor.colorFormat = RenderTextureFormat.ARGB32;
baseDescriptor.depthBufferBits = kDepthBufferBits;
descriptor = baseDescriptor;
depthNormalsMaterial =
CoreUtils.CreateEngineMaterial("Hidden/Internal-DepthNormalsTexture");
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
cmd.GetTemporaryRT(depthAttachmentHandle.id, descriptor, FilterMode.Point);
ConfigureTarget(depthAttachmentHandle.Identifier());
ConfigureClear(ClearFlag.All, Color.black);
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);
using (new ProfilingSample(cmd, m_ProfilerTag))
{
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
var drawSettings = CreateDrawingSettings(m_ShaderTagId, ref renderingData, sortFlags);
drawSettings.perObjectData = PerObjectData.None;
ref CameraData cameraData = ref renderingData.cameraData;
Camera camera = cameraData.camera;
if (cameraData.isStereoEnabled)
context.StartMultiEye(camera);
drawSettings.overrideMaterial = depthNormalsMaterial;
context.DrawRenderers(renderingData.cullResults, ref drawSettings,
ref m_FilteringSettings);
cmd.SetGlobalTexture("_CameraDepthNormalsTexture", depthAttachmentHandle.id);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public void SetLayerMask(LayerMask mask)
{
m_FilteringSettings.layerMask = mask;
}
public override void FrameCleanup(CommandBuffer cmd)
{
if (cmd == null)
throw new ArgumentNullException("cmd");
if (depthAttachmentHandle != RenderTargetHandle.CameraTarget)
{
cmd.ReleaseTemporaryRT(depthAttachmentHandle.id);
depthAttachmentHandle = RenderTargetHandle.CameraTarget;
}
}
}
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Graphing;
namespace UnityEditor.ShaderGraph
{
[Title("Custom", "Input", "Texture", "_CameraDepthNormalsTexture")]
class DepthNormalsTextureNode : AbstractMaterialNode
{
public const int OutputSlotId = 0;
const string kOutputSlotName = "Out";
private string inputTexture;
public DepthNormalsTextureNode()
{
name = "_CameraDepthNormalsTexture";
inputTexture = "_CameraDepthNormalsTexture";
UpdateNodeAfterDeserialization();
}
public sealed override void UpdateNodeAfterDeserialization()
{
AddSlot(new Texture2DMaterialSlot(OutputSlotId, kOutputSlotName, kOutputSlotName, SlotType.Output));
RemoveSlotsNameNotMatching(new[] {OutputSlotId});
}
public override void CollectShaderProperties(PropertyCollector properties, GenerationMode generationMode)
{
properties.AddShaderProperty(new TextureShaderProperty
{
displayName = "Main Texture",
overrideReferenceName = GetVariableNameForSlot(OutputSlotId),
generatePropertyBlock = false
});
}
public override void CollectPreviewMaterialProperties(List<PreviewProperty> properties)
{
properties.Add(new PreviewProperty(PropertyType.Texture2D)
{
name = GetVariableNameForSlot(OutputSlotId),
textureValue = Shader.GetGlobalTexture(inputTexture)
});
}
public override string GetVariableNameForSlot(int slotId)
{
return slotId == OutputSlotId ? inputTexture : base.GetVariableNameForSlot(slotId);
}
}
}
float3 DecodeViewNormalStereo( 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;
}
float3 DecodeNormal( float4 enc)
{
return DecodeViewNormalStereo (enc);
}
void Outline_float(float4 ScreenPos, float Scale, float DepthThreshold, float NormalThreshold, float2 Texel, Texture2D DepthNormalsTexture, Texture2D DepthTexture, SamplerState Sampler, out float Out)
{
float halfScaleFloor = floor(Scale * 0.5);
float halfScaleCeil = ceil(Scale * 0.5);
float2 bottomLeftUV = ScreenPos.xy - float2(Texel.x, Texel.y) * halfScaleFloor;
float2 topRightUV = ScreenPos.xy + float2(Texel.x, Texel.y) * halfScaleCeil;
float2 bottomRightUV = ScreenPos.xy + float2(Texel.x * halfScaleCeil, -Texel.y * halfScaleFloor);
float2 topLeftUV = ScreenPos.xy + float2(-Texel.x * halfScaleFloor, Texel.y * halfScaleCeil);
// Depth from DepthTexture
float depth0 =SAMPLE_TEXTURE2D(DepthTexture, Sampler, bottomLeftUV).r;
float depth1 =SAMPLE_TEXTURE2D(DepthTexture, Sampler, topRightUV).r;
float depth2 =SAMPLE_TEXTURE2D(DepthTexture, Sampler, bottomRightUV).r;
float depth3 =SAMPLE_TEXTURE2D(DepthTexture, Sampler, bottomLeftUV).r;
float depthFiniteDifference0 = depth1 - depth0;
float depthFiniteDifference1 = depth3 - depth2;
float edgeDepth = sqrt(pow(depthFiniteDifference0, 2) + pow(depthFiniteDifference1, 2)) * 100;
float newDepthThreshold = DepthThreshold * depth0;
edgeDepth = edgeDepth > newDepthThreshold ? 1 : 0;
// Normals extracted from DepthNormalsTexture
float3 normal0 = DecodeNormal(SAMPLE_TEXTURE2D(DepthNormalsTexture, Sampler, bottomLeftUV));
float3 normal1 = DecodeNormal(SAMPLE_TEXTURE2D(DepthNormalsTexture, Sampler, topRightUV));
float3 normal2 = DecodeNormal(SAMPLE_TEXTURE2D(DepthNormalsTexture, Sampler, bottomRightUV));
float3 normal3 = DecodeNormal(SAMPLE_TEXTURE2D(DepthNormalsTexture, Sampler, topLeftUV));
float3 normalFiniteDifference0 = normal1 - normal0;
float3 normalFiniteDifference1 = normal3 - normal2;
float edgeNormal = sqrt(dot(normalFiniteDifference0, normalFiniteDifference0) + dot(normalFiniteDifference1, normalFiniteDifference1));
edgeNormal = edgeNormal > NormalThreshold ? 1 : 0;
// Combined
float edge = max(edgeDepth, edgeNormal);
Out = edge;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment