Your solution is not quite correct. You have to compare the depth from the depth map with the depth of the currently rendered polygon.
Shader:
Shader "Unlit/Splatoon"
{
Properties
{
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Cull Off
ZTest Always
ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//#pragma enable_d3d11_debug_symbols
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD1; // using the lightmap uv's since those are non-overlapping
};
struct v2f
{
float4 viewPos : POSITION1;
float4 clipPos : POSITION2;
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float4x4 _MV;
float4x4 _MVP;
texture2D _CameraDepthTexture;
float2 _LineStart;
float2 _LineEnd;
float _LineThickness;
// Finds the t on the segment [a, b] which is closest to an arbitrary point c.
float GetClosestPointOnSegment(float2 a, float2 b, float2 c)
{
// Explanation: Realtime Collision Detection chapter 5.1.2 page 127
float2 ab = b - a;
float2 ac = c - a;
// t = ac.dot(ab) / ab.dot(ab)
// If c projects outside the [a, b] interval on the a side; clamp to a
float numer = dot(ac, ab);
if (numer <= 0)
return 0.0;
// If c projects outside the [a, b] interval on the b side; clamp to b
float denom = dot(ab, ab); // always nonnegative
if (numer >= denom)
return 1.0;
// c projects inside the [a, b] interval
return numer / denom;
}
float GetDistanceToSegment(float2 a, float2 b, float2 c)
{
float t = GetClosestPointOnSegment(a, b, c);
float2 p = lerp(a, b, t);
return distance(p, c);
}
v2f vert (appdata v)
{
v2f o;
o.viewPos = mul(_MV, v.vertex);
o.clipPos = mul(_MVP, v.vertex);
o.uv = v.uv;
float4 uv = float4(0, 0, 0, 1);
uv.xy = (v.uv.xy * 2 - 1) * float2(1, _ProjectionParams.x);
o.vertex = uv;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
// Check if current texel maps to a pixel on the screen that's behind the camera
float viewDepth = -i.viewPos.z; // Camera looks down the negative z axis
float nearPlaneDistance = _ProjectionParams.y;
if (viewDepth < nearPlaneDistance)
return float4(1, 1, 1, 1);
// Check if current texel maps to a pixel on the screen that failed the depth test
float2 ndcPos = i.clipPos.xy / i.clipPos.w;
float2 screenPos = (ndcPos + 1.0) * 0.5 * _ScreenParams.xy; // upside down
float depth = LinearEyeDepth(_CameraDepthTexture[int2(screenPos + 0.5f)].x);
if (abs(depth - viewDepth) > 0.1)
return float4(1, 1, 1, 1);
// Calculate distance to the line
// Note: Origin of screen coordinates is at the bottom left
screenPos = (ndcPos + 1.0) * 0.5 * _ScreenParams.xy;
float distance = GetDistanceToSegment(_LineStart, _LineEnd, screenPos);
// Convert distance to line color
float t = abs(distance) / _LineThickness;
t = smoothstep(0, 1, t);
t = smoothstep(0, 1, t);
return float4(t, t, t, 1);
}
ENDCG
}
}
}
Script:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UIElements;
public class RenderScript : MonoBehaviour
{
public RenderTexture RenderTexture;
public float LineThickness = 10.0f;
private Material _material;
private Camera _camera;
private CommandBuffer _buffer;
private Renderer _renderer;
private Vector2 _lineStart;
private Vector2 _lineEnd;
private static int _mvpId = Shader.PropertyToID("_MVP");
private static int _mvId = Shader.PropertyToID("_MV");
private static int _lineStartId = Shader.PropertyToID("_LineStart");
private static int _lineEndId = Shader.PropertyToID("_LineEnd");
private static int _lineThicknessId = Shader.PropertyToID("_LineThickness");
public void Awake()
{
Shader shader = Shader.Find("Unlit/Splatoon");
if (shader == null)
{
enabled = false;
return;
}
_buffer = new CommandBuffer();
_buffer.name = "Splatoon";
_material = new Material(shader);
}
public void Start()
{
_renderer = GetComponent<Renderer>();
_camera = Camera.main;
if (_renderer == null || _camera == null || RenderTexture == null)
{
enabled = false;
return;
}
_buffer.SetRenderTarget(RenderTexture);
_buffer.ClearRenderTarget(false, true, Color.white);
_buffer.DrawRenderer(_renderer, _material);
_camera.AddCommandBuffer(CameraEvent.AfterDepthTexture, _buffer);
_lineStart = new Vector2(0.0f, 0.0f);
_lineEnd = new Vector2(Screen.width, Screen.height);
}
public void OnDestroy()
{
if (_camera != null)
_camera.RemoveCommandBuffer(CameraEvent.AfterDepthTexture, _buffer);
if (_buffer != null)
_buffer.Release();
if (_material != null)
Destroy(_material);
}
void Update()
{
// origin is at the bottom left!
if (Input.GetMouseButtonDown(0))
{
_lineStart = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
}
if (Input.GetMouseButtonDown(1))
{
_lineEnd = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
}
Matrix4x4 modelViewMatrix = _camera.worldToCameraMatrix * transform.localToWorldMatrix;
Matrix4x4 modelViewProjectionMatrix = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, false) * modelViewMatrix;
_material.SetMatrix(_mvpId, modelViewProjectionMatrix);
_material.SetMatrix(_mvId, modelViewMatrix);
_material.SetVector(_lineStartId, _lineStart);
_material.SetVector(_lineEndId, _lineEnd);
_material.SetFloat(_lineThicknessId, LineThickness);
}
}
Game view and scene view:
UV-Space
I’ve attached the project.
9269880–1297824–Splatoon.zip (123 KB)