Skip to content

Instantly share code, notes, and snippets.

@phi16
Last active August 1, 2020 07:33
Show Gist options
  • Save phi16/7d4c9dff08eb4adf96a926a621bcdaaa to your computer and use it in GitHub Desktop.
Save phi16/7d4c9dff08eb4adf96a926a621bcdaaa to your computer and use it in GitHub Desktop.
Shader "Mochi/Snow"
{
Properties
{
_Color ("Color", Color) = (0.5,0.8,1,1)
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" "LightMode"="ForwardBase" "DisableBatching"="True" }
LOD 100
Blend SrcAlpha One
ZWrite Off
Cull Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
};
appdata vert (appdata v) {
return v;
}
float rand(float2 co){
return frac(sin(dot(co.xy, float2(12.9898,78.233))) * 43758.5453);
}
struct v2f {
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldPos : TEXCOORD1;
float3 color : TEXCOORD2;
float4 projPos : TEXCOORD3;
};
float noise(float i, float t) {
float ut = floor(t), ft = frac(t);
float v0 = rand(float2(i,ut+0));
float v1 = rand(float2(i,ut+1));
return lerp(v0,v1,smoothstep(0,1,ft));
}
float4 _Color;
sampler2D _CameraDepthTexture;
[maxvertexcount(4)]
void geom (point appdata IN[1], inout TriangleStream<v2f> stream) {
int ix = IN[0].vertex.x;
v2f o;
float2 uvs[4] = { float2(-1,-1), float2(-1,1), float2(1,-1), float2(1,1) };
float2 seed = float2(ix/1000.0, 0);
float3 rep = 40;
float3 rs = float3(rand(seed+0), rand(seed+1), rand(seed+2));
float3 center = rs * rep;
float t = _Time.y;
// Fall animation
center.y -= t * rep.y / 80 + noise(seed.x+0, t/4 + rs.x) * 0.1;
center.x += noise(seed.x+1, t/2 + rs.z) * 0.1;
center.z += noise(seed.x+2, t/2 + rs.y) * 0.1;
// Move to camera position (like repetition)
center += rep / 2 - _WorldSpaceCameraPos;
center -= floor(center/rep) * rep;
center -= rep / 2 - _WorldSpaceCameraPos;
float size = 0.02 * lerp(0.5, 5, pow(rand(seed+3),4));
size *= smoothstep(1, 0.5, distance(_WorldSpaceCameraPos, center)/rep*2);
// Polygon coordinates
float3 normal = normalize(center - _WorldSpaceCameraPos);
float3 tangent = normalize(mul(transpose((float3x3)UNITY_MATRIX_V), float3(1,0,0)));
float3 binormal = normalize(cross(tangent, normal));
tangent = cross(normal, binormal);
for(int i=0;i<4;i++) {
o.worldPos = center + (uvs[i].x * binormal + uvs[i].y * tangent) * size;
o.vertex = mul(UNITY_MATRIX_VP, float4(o.worldPos, 1));
o.uv = uvs[i];
o.projPos = ComputeScreenPos(o.vertex);
o.projPos.z = - o.vertex.z;
o.color = lerp(_Color.xyz, float3(1,1,1), rand(seed+4));
stream.Append(o);
}
stream.RestartStrip();
}
float4 frag (v2f i) : SV_Target
{
float d = length(i.uv);
clip(1-d);
float3 color = i.color;
color *= lerp(float3(1,1,1), float3(0.5,0.7,1), i.uv.x); // Constant gradation
// Soft particle
float3 viewDir = normalize(i.worldPos - _WorldSpaceCameraPos);
float3 forward = normalize(mul(transpose((float3x3)UNITY_MATRIX_V), float3(0,0,-1)));
float3 eyeViewDir = viewDir / dot(viewDir, forward);
float eyeDepth = LinearEyeDepth(tex2D(_CameraDepthTexture, i.projPos.xy / i.projPos.w));
float3 collision = _WorldSpaceCameraPos + eyeViewDir * eyeDepth;
float depth = distance(collision, i.worldPos);
float alpha = smoothstep(1,0.2,d) * smoothstep(0,1,depth);
// Fade out if too near to the camera
float worldDist = distance(i.worldPos, _WorldSpaceCameraPos);
alpha *= smoothstep(0.1, 0.2, worldDist);
return float4(color, alpha);
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment