Skip to content

Instantly share code, notes, and snippets.

@unitycoder
Created September 30, 2025 13:06
Show Gist options
  • Save unitycoder/bef1f441e7ce12491e6d87d8ddbe49ce to your computer and use it in GitHub Desktop.
Save unitycoder/bef1f441e7ce12491e6d87d8ddbe49ce to your computer and use it in GitHub Desktop.

Revisions

  1. unitycoder created this gist Sep 30, 2025.
    108 changes: 108 additions & 0 deletions FresnelOverlay_Add1.shader
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,108 @@
    Shader "Custom/FresnelOverlay_Add1"
    {
    Properties
    {
    [HDR]_RimColor ("Fresnel Color (HDR)", Color) = (3,3,3,1)
    _RimPower ("Fresnel Power", Range(0.1, 8)) = 3.0
    _RimStrength ("Fresnel Strength", Range(0, 10)) = 1.0
    _DoubleSided ("Double-Sided (0=Back,1=Off,2=Front)", Range(0,2)) = 2
    _DepthBias ("Depth Bias (to avoid misses)", Float) = 0.0
    }

    SubShader
    {
    Tags { "Queue"="Transparent+10" "RenderType"="Transparent" }

    // Additive overlay on top of what’s already rendered
    Blend One One
    ZWrite Off
    ZTest Equal // draw only where depth already matches (on the mesh)
    Cull Back // default: draw front faces only
    ColorMask RGB

    Pass
    {
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    #pragma target 3.0
    #pragma multi_compile_instancing

    #include "UnityCG.cginc"

    float4 _RimColor;
    float _RimPower;
    float _RimStrength;
    float _DoubleSided; // 0=Back, 1=Off (both), 2=Front
    float _DepthBias;

    struct appdata
    {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    UNITY_VERTEX_INPUT_INSTANCE_ID
    };

    struct v2f
    {
    float4 pos : SV_POSITION;
    float3 worldPos : TEXCOORD0;
    float3 worldNrm : TEXCOORD1;
    UNITY_VERTEX_INPUT_INSTANCE_ID
    UNITY_VERTEX_OUTPUT_STEREO
    };

    v2f vert (appdata v)
    {
    v2f o;
    UNITY_SETUP_INSTANCE_ID(v);
    UNITY_INITIALIZE_OUTPUT(v2f, o);
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

    float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    float3 worldNrm = UnityObjectToWorldNormal(v.normal);

    // Optional tiny depth bias to make ZTest Equal more forgiving
    float4 clip = UnityObjectToClipPos(v.vertex);
    clip.z += _DepthBias * clip.w;

    o.pos = clip;
    o.worldPos = worldPos;
    o.worldNrm = worldNrm;
    return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
    // Handle sidedness quickly
    float3 N = normalize(i.worldNrm);
    float3 V = normalize(_WorldSpaceCameraPos - i.worldPos);

    // Which faces to keep:
    // Front: dot(N,V) > 0
    // Back: dot(N,V) < 0
    // Both: no discard
    float ndotv = dot(N, V);
    if (_DoubleSided < 0.5) // Back faces only
    {
    if (ndotv > 0) discard;
    }
    else if (_DoubleSided > 1.5) // Front faces only
    {
    if (ndotv < 0) discard;
    }
    // else: both sides

    // Fresnel
    ndotv = saturate(abs(ndotv)); // abs for double-sided consistency
    float rim = pow(1.0 - ndotv, _RimPower);

    float3 color = _RimColor.rgb * (rim * _RimStrength);
    return float4(color, 1);
    }
    ENDCG
    }
    }

    Fallback Off
    }
    105 changes: 105 additions & 0 deletions FresnelOverlay_Add2.shader
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,105 @@
    Shader "Custom/FresnelOverlay_Add2"
    {
    Properties
    {
    [HDR]_RimColor ("Fresnel Color (HDR)", Color) = (3,3,3,1)
    _RimPower ("Fresnel Power", Range(0.1, 8)) = 3.0
    _RimStrength ("Fresnel Strength", Range(0, 10)) = 1.0
    [HDR]_OverlayColor ("Overlay Color (HDR, fill)", Color) = (0,0,0,0)
    _DoubleSided ("Double-Sided (0=Back,1=Both,2=Front)", Range(0,2)) = 2
    _DepthBias ("Depth Bias (to avoid misses)", Float) = 0.0
    }

    SubShader
    {
    Tags { "Queue"="Transparent+10" "RenderType"="Transparent" }

    // Additive overlay on top of what's already rendered
    Blend One One
    ZWrite Off
    ZTest Equal // only on the mesh where depth matches
    Cull Back
    ColorMask RGB

    Pass
    {
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    #pragma target 3.0
    #pragma multi_compile_instancing

    #include "UnityCG.cginc"

    float4 _RimColor;
    float _RimPower;
    float _RimStrength;
    float4 _OverlayColor;
    float _DoubleSided; // 0=Back, 1=Both, 2=Front
    float _DepthBias;

    struct appdata
    {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    UNITY_VERTEX_INPUT_INSTANCE_ID
    };

    struct v2f
    {
    float4 pos : SV_POSITION;
    float3 worldPos : TEXCOORD0;
    float3 worldNrm : TEXCOORD1;
    UNITY_VERTEX_INPUT_INSTANCE_ID
    UNITY_VERTEX_OUTPUT_STEREO
    };

    v2f vert (appdata v)
    {
    v2f o;
    UNITY_SETUP_INSTANCE_ID(v);
    UNITY_INITIALIZE_OUTPUT(v2f, o);
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

    float4 clip = UnityObjectToClipPos(v.vertex);
    clip.z += _DepthBias * clip.w; // tiny bias if needed

    o.pos = clip;
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    o.worldNrm = UnityObjectToWorldNormal(v.normal);
    return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
    float3 N = normalize(i.worldNrm);
    float3 V = normalize(_WorldSpaceCameraPos - i.worldPos);

    float ndotv = dot(N, V);

    // Sidedness gating
    if (_DoubleSided < 0.5) // back faces only
    {
    if (ndotv > 0) discard;
    }
    else if (_DoubleSided > 1.5) // front faces only
    {
    if (ndotv < 0) discard;
    }

    // Fresnel rim
    ndotv = saturate(abs(ndotv)); // abs for double-sided consistency
    float rim = pow(1.0 - ndotv, _RimPower);
    float3 rimCol = _RimColor.rgb * (rim * _RimStrength);

    // Full-surface overlay (set to black to disable)
    float3 fillCol = _OverlayColor.rgb;

    return float4(rimCol + fillCol, 1);
    }
    ENDCG
    }
    }

    Fallback Off
    }
    86 changes: 86 additions & 0 deletions PBR_FresnelRim.shader
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,86 @@
    Shader "Custom/PBR_FresnelRim"
    {
    Properties
    {
    _Color ("Base Color", Color) = (1,1,1,1)
    _MainTex ("Albedo (RGB) Alpha (A)", 2D) = "white" {}
    _Metallic ("Metallic", Range(0,1)) = 0.0
    _Glossiness ("Smoothness", Range(0,1)) = 0.5

    [NoScaleOffset]_BumpMap ("Normal Map", 2D) = "bump" {}
    _BumpScale ("Normal Scale", Range(0,2)) = 1.0

    [HDR]_RimColor ("Fresnel Edge Color (HDR)", Color) = (4,4,4,1)
    _RimPower ("Fresnel Power (falloff)", Range(0.1, 8)) = 3.0
    _RimStrength ("Fresnel Strength (intensity)", Range(0, 10)) = 1.0
    }

    SubShader
    {
    Tags { "RenderType"="Opaque" "Queue"="Geometry" }
    LOD 300

    CGPROGRAM
    #pragma surface surf Standard fullforwardshadows
    #pragma target 3.0
    #pragma multi_compile_instancing

    sampler2D _MainTex;
    fixed4 _Color;
    half _Metallic;
    half _Glossiness;

    sampler2D _BumpMap;
    half _BumpScale;

    fixed4 _RimColor;
    half _RimPower;
    half _RimStrength;

    struct Input
    {
    float2 uv_MainTex;
    float2 uv_BumpMap;
    float3 worldPos;
    float3 viewDir; // Unity provides world-space view direction
    };

    UNITY_INSTANCING_BUFFER_START(Props)
    UNITY_INSTANCING_BUFFER_END(Props)

    inline float3 UnpackNormalScaled(sampler2D nmap, float2 uv, float scale)
    {
    float3 n = UnpackNormal(tex2D(nmap, uv));
    n.xy *= scale;
    n = normalize(n);
    return n;
    }

    void surf (Input IN, inout SurfaceOutputStandard o)
    {
    fixed4 albedo = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    o.Albedo = albedo.rgb;
    o.Metallic = _Metallic;
    o.Smoothness = _Glossiness;
    o.Alpha = albedo.a;

    // Normal mapping (optional)
    float3 N = float3(0,0,1);
    if (_BumpScale > 0.0001)
    N = UnpackNormalScaled(_BumpMap, IN.uv_BumpMap, _BumpScale);
    else
    N = normalize(o.Normal);

    // Fresnel rim: pow(1 - N·V, power)
    float3 V = normalize(IN.viewDir);
    float ndotv = saturate(dot(N, V));
    float rim = pow(1.0 - ndotv, _RimPower);

    // Emission drives the glow; HDR color recommended
    o.Emission = _RimColor.rgb * rim * _RimStrength;
    }
    ENDCG
    }

    FallBack "Diffuse"
    }