I'm trying to emulate older 3D games that did per-polygon clipping.
Using degenerate triangles, it works except when looking away with the camera.
Here's an animated GIF, a sphere with that material applied to it:
The green faces are what I'm expecting, triangle is completely clipped.
The red faces are obviously wrong, they're all glued to screen center.
Here's the shader in question:
Shader"PerPolygonClipping"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Distance ("Distance", Float) = 1.0
}
SubShader
{
Tags
{
"RenderType"="Opaque"
}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
fixed4 color : COLOR;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Distance;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
const float3 world_position = mul(unity_ObjectToWorld, v.vertex).xyz;
const float distance = length(world_position - _WorldSpaceCameraPos);
float difference = _Distance - distance;
if (difference < 0)
{
o.color = fixed4(1, 0, 0, 1);
}
else if (difference > 0)
{
o.color = fixed4(0, 1, 0, 1);
}
else
{
o.color = fixed4(0, 0, 1, 1);
}
// https://gamedev.net/forums/topic/421211-clip-in-vertex-shader-in-hlsl/3805467/
o.vertex *= step(0, difference);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col *= i.color;
return col;
}
ENDCG
}
}
}
Suggestions are welcome on how to fix this problem.

The issue is that you're attempting to clip triangles at a per-vertex level. Each vertex is being checked independently, and so it's possible that only one of the three vertices that make up a triangle is moved to the center of the screen, resulting in the stretching you're seeing with the red triangles. In order to solve this problem, you'll need to clip entire triangles rather than just the vertices.
The easiest way to solve this problem in a shader is by performing the clipping in a geometry shader, since the geometry shader can operate on the entire triangle at once, though it should be noted that geometry shaders are not supported in Metal, and are generally not recommended for performance reasons.
A slightly more complex solution which does not rely on a geometry shader would be to create another set of texture coordinates for your mesh, where the UVW coordinate of each vertex is the center of its connected triangle. Your vertex shader can then check this triangle center coordinate instead of the vertex position. Since it will be the same for each vertex of the triangle, the whole triangle will be clipped at once.
This is a bit annoying, since it involves generating new meshes with additional data, but it would allow you to achieve the clipping effect you're after using only vertex and fragment shaders.