Skip to content

Instantly share code, notes, and snippets.

@jbltx
Last active December 22, 2024 06:27
Show Gist options
  • Select an option

  • Save jbltx/22367b46f1d43b4e7ba682fbcf072278 to your computer and use it in GitHub Desktop.

Select an option

Save jbltx/22367b46f1d43b4e7ba682fbcf072278 to your computer and use it in GitHub Desktop.
Clipping plane (cross-section) Unity shader
Shader "Unlit/ClippedObject"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
}
SubShader
{
// The shader is semi-transparent
Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True" }
LOD 100
CGINCLUDE
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 worldPos : TEXCOORD2;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _Color;
float4 _Plane;
v2f vert (appdata v)
{
v2f o;
o.worldPos = mul(UNITY_MATRIX_M, v.vertex);
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float distance = dot(i.worldPos, _Plane.xyz);
distance = distance + _Plane.w;
clip(-distance);
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
col *= _Color;
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
// The first pass will write only in the
// stencil buffer the value 2 for the clipped
// object. Only front faces are rendered to get the difference
// for back faces. All depth and color buffer related stuff are discarded.
Pass
{
Cull Back
ZTest Always
ZWrite Off
Blend Zero One
Stencil {
Ref 2
Comp Always
Pass Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
ENDCG
}
// The second pass will write only in the stencil buffer
// the value 1 for pixels with a current value of 0. Since
// we have previously written value 2 for front faces, the only
// remaining pixels available will be the clipping plane part, where
// the back faces are visible (if any).
// All depth and color buffer related stuff are discarded.
Pass {
Cull Front
ZTest Always
ZWrite Off
Blend Zero One
Stencil {
Ref 0
Comp Equal
Pass IncrSat
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
ENDCG
}
// The last pass for the clipped object is actually the real render pass.
// Only visible front faces with a pixel value in stencil buffer equals to 2
// will be rendered. A traditional blending operation for semi-transparency
// is used.
// NOTE : Actually this pass also uses the fragment shader with the clipping
// function, but it is useless as the clipped part of the object has a value
// of 0 in the stencil buffer and won't be rendered anyway. I was too lazy to
// copy/paste the fragment shader...
Pass
{
Stencil {
Ref 2
Comp Equal
}
Blend SrcAlpha OneMinusSrcAlpha
Cull Back
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
ENDCG
}
}
}
using UnityEngine;
[ExecuteInEditMode]
public class ClippingPlane : MonoBehaviour
{
public Material mat; // <--- Put the clipped object shader's material here !
Plane m_plane;
Vector4 m_planeVector;
private void Start()
{
m_plane = new Plane(transform.up, transform.position);
m_planeVector = new Vector4(m_plane.normal.x, m_plane.normal.y, m_plane.normal.z, m_plane.distance);
}
void Update()
{
m_plane.SetNormalAndPosition(transform.up, transform.position);
m_planeVector.x = m_plane.normal.x;
m_planeVector.y = m_plane.normal.y;
m_planeVector.z = m_plane.normal.z;
m_planeVector.w = m_plane.distance;
mat.SetVector("_Plane", m_planeVector);
}
}
Shader "Unlit/Plane"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
}
SubShader
{
// The shader is semi-transparent.
Tags { "RenderType"="Transparent" "Queue"="Transparent+1" "IgnoreProjector"="True" }
LOD 100
// The clipping plane uses only an usual single render pass.
// The only modification is the Stencil buffer test : only
// pixels with a current value of 1 (back faces of the other object at the clip section)
// will be rendered. A custom blending is also added for semi-transparency.
// A little hack on the vertex position is made to scale up the plane (don't need
// to do that in the Editor).
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
Stencil {
Ref 1
Comp Equal
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _Color;
v2f vert (appdata v)
{
v2f o;
v.vertex.xyz *= 10000.;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
col *= _Color;
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
@MuhammadFaizanKhan

Copy link
Copy Markdown

where to put these two shaders and script?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment