Skip to content

Instantly share code, notes, and snippets.

@michaelybecker
Last active November 11, 2019 21:41
Show Gist options
  • Save michaelybecker/ff366a836b0407ef27d7daa554829687 to your computer and use it in GitHub Desktop.
Save michaelybecker/ff366a836b0407ef27d7daa554829687 to your computer and use it in GitHub Desktop.
Raymarched shadertoy clouds in Unity (SPI ready)
Shader "Custom/Raymarcher4"
{
// based on MichaelPohoreski's no-noise texture variation of iq's brilliant https://www.shadertoy.com/view/XslGRr
// code is a mess. Reader beware.
// wanted to put it out there as a quick & dirty example of raymarching in Unity, since info is scarce.
// of particular note: SPI macros for instancing on stereoscopic devices, and the rewritten camera logic (no more rays-through-uvs, we're in "real" camera land now!)
// hope this is useful!
Properties
{
}
SubShader
{
Tags { "Queue" = "Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
struct appdata
{
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
float2 uv : TEXCOORD0;
};
struct v2f
{
float3 wPos : float3;
float4 v: float4;
float4 pos : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO
};
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_INSTANCING_BUFFER_END(Props)
v2f vert(appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_OUTPUT(v2f, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.pos = UnityObjectToClipPos(v.vertex);
o.v = v.vertex;
o.wPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
float iqhash(float n)
{
return frac(sin(n) * 43758.5453);
}
float noise(float3 x)
{
float3 p = floor(x);
float3 f = frac(x);
f = f * f * (3.0 - 2.0 * f);
float n = p.x + p.y * 57.0 + 113.0 * p.z;
return lerp(lerp(lerp(iqhash(n + 0.0), iqhash(n + 1.0), f.x),
lerp(iqhash(n + 57.0), iqhash(n + 58.0), f.x), f.y),
lerp(lerp(iqhash(n + 113.0), iqhash(n + 114.0), f.x),
lerp(iqhash(n + 170.0), iqhash(n + 171.0), f.x), f.y), f.z);
}
//change: factor in headpose
float map5(in float3 p, in float3 ro)
{
float3 q = p - float3(0.0, 0.1, 1.0) * _Time.y / 3;
float f;
f = 0.50000 * noise(q); q = q * 2.02;
f += 0.25000 * noise(q); q = q * 2.03;
f += 0.12500 * noise(q); q = q * 2.01;
f += 0.06250 * noise(q); q = q * 2.02;
f += 0.03125 * noise(q);
return saturate(1.5 - p.y - 2.0 + 1.75 * f + ro.y - .9);
}
float map4(in float3 p, in float3 ro)
{
float3 q = p - float3(0.0, 0.1, 1.0) * _Time.y;
float f;
f = 0.50000 * noise(q); q = q * 2.02;
f += 0.25000 * noise(q); q = q * 2.03;
f += 0.12500 * noise(q); q = q * 2.01;
f += 0.06250 * noise(q);
return saturate(1.5 - p.y - 2.0 + 1.75 * f + ro.y - .7);
}
float map3(in float3 p, in float3 ro)
{
float3 q = p - float3(0.0, 0.1, 1.0) * _Time.y;
float f;
f = 0.50000 * noise(q); q = q * 2.02;
f += 0.25000 * noise(q); q = q * 2.03;
f += 0.12500 * noise(q);
return saturate(1.5 - p.y - 2.0 + 1.75 * f + ro.y - .7);
}
float map2(in float3 p, in float3 ro)
{
float3 q = p - float3(0.0, 0.1, 1.0) * _Time.y;
float f;
f = 0.50000 * noise(q); q = q * 2.02;
f += 0.25000 * noise(q);
return saturate(1.5 - p.y - 2.0 + 1.75 * f + ro.y - .7);
}
float4 integrate(in float4 sum, in float dif, in float den, in float3 bgcol, in float t)
{
// lighting
float3 lin = float3(0.65, 0.7, 0.75) * 1.4 + float3(1.0, 0.6, 0.3) * dif;
float4 col = float4(lerp(float3(1.0, 0.95, 0.8), float3(0.25, 0.3, 0.35), den), den);
//col.xyz *= lin;
col.xyz *= lin;
col.xyz = lerp(col.xyz, bgcol, 1.0 - exp(-.0001 * t * t));
// front to back blending
col.a *= 0.4;
col.rgb *= col.a;
return sum + col * (1.0 - sum.a);
}
#define MARCH(STEPS,MAPLOD, ro) for(int i=0; i<STEPS; i++) { float3 pos = ro + t*rd; if( sum.a > 0.99 ) break; float den = MAPLOD( pos, ro ); if( den>0.01 ) { float dif = saturate((den - MAPLOD(pos+0.3*_WorldSpaceLightPos0.xyz,ro))/0.6); sum = integrate( sum, dif, den, bgcol, t ); } t += max(4.05,0.02*t); }
float4 raymarch(in float3 ro, in float3 rd, in float3 bgcol)
{
float4 sum = float4(0.0,0.0,0.0,0.0);
float t = 0.0;//0.05*texelFetch( iChannel0, px&255, 0 ).x;
MARCH(5, map5, ro);
//MARCH(30, map4, ro);
//MARCH(30, map3, ro);
//MARCH(30, map2, ro);
return saturate(sum);
}
float4 render(in float3 ro, in float3 rd)
{
// background sky
float sun = saturate(dot(_WorldSpaceLightPos0.xyz, rd));
//float3 col = float3(0.6, 0.71, 0.75) - rd.y * 0.2 * float3(1.0, 0.5, 1.0) + 0.15 * 0.5;
float3 col = float3(.0, .0, .0);
//col += 0.2 * float3(1.0, .6, 0.1) * pow(sun, 8.0);
// clouds
float4 res = raymarch(ro, rd, col);
col = col * (1.0 - res.w) + res.xyz;
// sun glare
col += 0.2 * float3(1.0, 0.4, 0.2) * pow(sun, 3.0);
if (col.x < .2)
{
//discard;
}
else {
//col *= 2;
}
return float4(col, 1.0);
}
float opScale(float3 p, float s)
{
//return MandelBulb(p / s, 17) * s;
}
fixed4 frag(v2f i) : SV_Target
{
float4 objectOrigin = mul(unity_ObjectToWorld, float4(0.0,0.0,0.0,1.0));
float3 viewDirection = normalize(i.wPos - _WorldSpaceCameraPos);
float3 worldPosition = i.wPos;
float3 ro = _WorldSpaceCameraPos;
float3 rd = viewDirection;
//float curDistance = 5. - distance(objectOrigin.xyz, i.v);
fixed4 r = render(ro, rd);
return fixed4(r.xyz,1.);
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment