Skip to content

Instantly share code, notes, and snippets.

@andybak
Created November 8, 2017 00:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andybak/d5d76528348514dffd9547a2cd438944 to your computer and use it in GitHub Desktop.
Save andybak/d5d76528348514dffd9547a2cd438944 to your computer and use it in GitHub Desktop.
Shader "AAA Raymarching iq" {
Subshader {
Pass {
Cull off
CGPROGRAM
#pragma vertex vertex_shader
#pragma fragment pixel_shader
#pragma target 3.0
#define AA 0
float sdPlane(float3 p) {
return p.y;
}
float sdSphere(float3 p, float s) {
return length(p)-s;
}
float sdBox(float3 p, float3 b) {
float3 d = abs(p) - b;
return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}
float sdEllipsoid(in float3 p, in float3 r) {
return (length(p/r) - 1.0) * min(min(r.x,r.y),r.z);
}
float udRoundBox(float3 p, float3 b, float r) {
return length(max(abs(p)-b,0.0))-r;
}
float sdTorus(float3 p, float2 t) {
return length(float2(length(p.xz)-t.x,p.y))-t.y;
}
float sdHexPrism(float3 p, float2 h) {
float3 q = abs(p);
#if 0
return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);
#else
float d1 = q.z-h.y;
float d2 = max((q.x*0.866025+q.y*0.5),q.y)-h.x;
return length(max(float2(d1,d2),0.0)) + min(max(d1,d2), 0.);
#endif
}
float sdCapsule(float3 p, float3 a, float3 b, float r) {
float3 pa = p-a, ba = b-a;
float h = clamp(dot(pa,ba)/dot(ba,ba), 0.0, 1.0);
return length(pa - ba*h) - r;
}
float sdEquilateralTriangle(in float2 p) {
const float k = sqrt(3.0);
p.x = abs(p.x) - 1.0;
p.y = p.y + 1.0/k;
if(p.x + k*p.y > 0.0) p = float2(p.x - k*p.y, -k*p.x - p.y)/2.0;
p.x += 2.0 - 2.0*clamp((p.x+2.0)/2.0, 0.0, 1.0);
return -length(p)*sign(p.y);
}
float sdTriPrism(float3 p, float2 h) {
float3 q = abs(p);
float d1 = q.z-h.y;
#if 1
// distance bound
float d2 = max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5;
#else
// correct distance
h.x *= 0.866025;
float d2 = sdEquilateralTriangle(p.xy/h.x)*h.x;
#endif
return length(max(float2(d1,d2),0.0)) + min(max(d1,d2), 0.);
}
float sdCylinder(float3 p, float2 h) {
float2 d = abs(float2(length(p.xz),p.y)) - h;
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
float sdCone(in float3 p, in float3 c) {
float2 q = float2(length(p.xz), p.y);
float d1 = -q.y-c.z;
float d2 = max(dot(q,c.xy), q.y);
return length(max(float2(d1,d2),0.0)) + min(max(d1,d2), 0.);
}
float sdConeSection(in float3 p, in float h, in float r1, in float r2) {
float d1 = -p.y - h;
float q = p.y - h;
float si = 0.5*(r1-r2)/h;
float d2 = max(sqrt(dot(p.xz,p.xz)*(1.0-si*si)) + q*si - r2, q);
return length(max(float2(d1,d2),0.0)) + min(max(d1,d2), 0.);
}
float sdPryamid4(float3 p, float3 h) { // h = { cos a, sin a, height }
// Tetrahedron = Octahedron - Cube
float box = sdBox(p - float3(0, -2.0*h.z, 0), float3(2.0*h.z, 2.0*h.z, 2.0*h.z));
float d = 0.0;
d = max(d, abs(dot(p, float3(-h.x, h.y, 0))));
d = max(d, abs(dot(p, float3(h.x, h.y, 0))));
d = max(d, abs(dot(p, float3(0, h.y, h.x))));
d = max(d, abs(dot(p, float3(0, h.y,-h.x))));
float octa = d - h.z;
return max(-box,octa); // Subtraction
}
float length2(float2 p) {
return sqrt(p.x*p.x + p.y*p.y);
}
float length6(float2 p) {
p = p*p*p; p = p*p;
return pow(p.x + p.y, 1.0/6.0);
}
float length8(float2 p) {
p = p*p; p = p*p; p = p*p;
return pow(p.x + p.y, 1.0/8.0);
}
float sdTorus82(float3 p, float2 t) {
float2 q = float2(length2(p.xz)-t.x,p.y);
return length8(q)-t.y;
}
float sdTorus88(float3 p, float2 t) {
float2 q = float2(length8(p.xz)-t.x,p.y);
return length8(q)-t.y;
}
float sdCylinder6(float3 p, float2 h) {
return max(length6(p.xz)-h.x, abs(p.y)-h.y);
}
float opS(float d1, float d2) {
return max(-d2,d1);
}
float2 opU(float2 d1, float2 d2) {
return (d1.x<d2.x) ? d1 : d2;
}
float3 opRep(float3 p, float3 c) {
return fmod(p,c)-0.5*c;
}
float3 opTwist(float3 p) {
float c = cos(10.0*p.y+10.0);
float s = sin(10.0*p.y+10.0);
//float2x2 m = float2x2(c,-s,s,c);
//return float3(m*p.xz, p.y);
float4 m = float4(c,-s,s,c);
return float3(m*p.xz, p.y);
}
//------------------------------------------------------------------
float2 map(in float3 pos) {
float2 res = opU(float2(sdPlane(pos), 1.0), float2(sdSphere(pos-float3(0.0,0.25, 0.0), 0.25), 46.9));
res = opU(res, float2(sdBox(pos-float3(1.0,0.25, 0.0), float3(0.25,0.25,0.25)), 3.0));
res = opU(res, float2(udRoundBox(pos-float3(1.0,0.25, 1.0), float3(0.15,0.15,0.15), 0.1), 41.0));
res = opU(res, float2(sdTorus(pos-float3(0.0,0.25, 1.0), float2(0.20,0.05)), 25.0));
res = opU(res, float2(sdCapsule(pos,float3(-1.3,0.10,-0.1), float3(-0.8,0.50,0.2), 0.1 ), 31.9));
res = opU(res, float2(sdTriPrism(pos-float3(-1.0,0.25,-1.0), float2(0.25,0.05)),43.5));
res = opU(res, float2(sdCylinder(pos-float3(1.0,0.30,-1.0), float2(0.1,0.2)), 8.0));
res = opU(res, float2(sdCone(pos-float3(0.0,0.50,-1.0), float3(0.8,0.6,0.3)), 55.0));
res = opU(res, float2(sdTorus82(pos-float3(0.0,0.25, 2.0), float2(0.20,0.05)),50.0));
res = opU(res, float2(sdTorus88(pos-float3(-1.0,0.25, 2.0), float2(0.20,0.05)),43.0));
res = opU(res, float2(sdCylinder6(pos-float3(1.0,0.30, 2.0), float2(0.1,0.2)), 12.0));
res = opU(res, float2(sdHexPrism(pos-float3(-1.0,0.20, 1.0), float2(0.25,0.05)),17.0));
res = opU(res, float2(sdPryamid4(pos-float3(-1.0,0.15,-2.0), float3(0.8,0.6,0.25)),37.0));
res = opU(res, float2(opS(udRoundBox(pos-float3(-2.0,0.2, 1.0), float3(0.15,0.15,0.15),0.05), sdSphere(pos-float3(-2.0,0.2, 1.0), 0.25)), 13.0));
//res = opU(res, float2(opS(sdTorus82(pos-float3(-2.0,0.2, 0.0), float2(0.20,0.1)), sdCylinder(opRep(float3(atan(pos.x+2.0,pos.z)/6.2831, pos.y, 0.02+0.5*length(pos-float3(-2.0,0.2, 0.0))), float3(0.05,1.0,0.05)), float2(0.02,0.6))), 51.0));
res = opU(res, float2(0.5*sdSphere(pos-float3(-2.0,0.25,-1.0), 0.2) + 0.03*sin(50.0*pos.x)*sin(50.0*pos.y)*sin(50.0*pos.z), 65.0));
res = opU(res, float2(0.5*sdTorus(opTwist(pos-float3(-2.0,0.25, 2.0)),float2(0.20,0.05)), 46.7));
res = opU(res, float2(sdConeSection(pos-float3(0.0,0.35,-2.0), 0.15, 0.2, 0.1), 13.67));
res = opU(res, float2(sdEllipsoid(pos-float3(1.0,0.35,-2.0), float3(0.15, 0.2, 0.05)), 43.17));
return res;
}
float2 castRay(in float3 ro, in float3 rd) {
float tmin = 1.0;
float tmax = 20.0;
#if 1
// bounding volume
float tp1 = (0.0-ro.y)/rd.y;
if(tp1>0.0) tmax = min(tmax, tp1);
float tp2 = (1.6-ro.y)/rd.y;
if(tp2>0.0) {
if(ro.y>1.6) {
tmin = max(tmin, tp2);
} else {
tmax = min(tmax, tp2);
}
}
#endif
float t = tmin;
float m = -1.0;
for(int i=0; i<64; i++) {
float precis = 0.0005*t;
float2 res = map(ro+rd*t);
if(res.x<precis || t>tmax) break;
t += res.x;
m = res.y;
}
if(t>tmax) m=-1.0;
return float2(t, m);
}
float softshadow(in float3 ro, in float3 rd, in float mint, in float tmax) {
float res = 1.0;
float t = mint;
for(int i=0; i<16; i++) {
float h = map(ro + rd*t).x;
res = min(res, 8.0*h/t);
t += clamp(h, 0.02, 0.10);
if(h<0.001 || t>tmax) break;
}
return clamp(res, 0.0, 1.0);
}
float3 calcNormal(in float3 pos) {
float2 e = float2(1.0,-1.0)*0.5773*0.0005;
return normalize(e.xyy*map(pos + e.xyy).x +
e.yyx*map(pos + e.yyx).x +
e.yxy*map(pos + e.yxy).x +
e.xxx*map(pos + e.xxx).x);
/*
float3 eps = float3(0.0005, 0.0, 0.0);
float3 nor = float3(
map(pos+eps.xyy).x - map(pos-eps.xyy).x,
map(pos+eps.yxy).x - map(pos-eps.yxy).x,
map(pos+eps.yyx).x - map(pos-eps.yyx).x);
return normalize(nor);
*/
}
float calcAO(in float3 pos, in float3 nor) {
float occ = 0.0;
float sca = 1.0;
for(int i=0; i<5; i++)
{
float hr = 0.01 + 0.12*float(i)/4.0;
float3 aopos = nor * hr + pos;
float dd = map(aopos).x;
occ += -(dd-hr)*sca;
sca *= 0.95;
}
return clamp(1.0 - 3.0*occ, 0.0, 1.0);
}
float3 render(in float3 ro, in float3 rd) {
float3 col = float3(0.7, 0.9, 1.0) +rd.y*0.8;
float2 res = castRay(ro,rd);
float t = res.x;
float m = res.y;
if(m>-0.5) {
float3 pos = ro + t*rd;
float3 nor = calcNormal(pos);
float3 ref = reflect(rd, nor);
// material
col = 0.45 + 0.35*sin(float3(0.05,0.08,0.10)*(m-1.0));
if(m<1.5) {
float f = fmod(floor(5.0*pos.z) + floor(5.0*pos.x), 2.0);
col = 0.3 + 0.1*f*float3(1.0,1.0,1.0);
}
// lighitng
float occ = calcAO(pos, nor);
float3 lig = normalize(float3(-0.4, 0.7, -0.6));
float amb = clamp(0.5+0.5*nor.y, 0.0, 1.0);
float dif = clamp(dot(nor, lig), 0.0, 1.0);
float bac = clamp(dot(nor, normalize(float3(-lig.x,0.0,-lig.z))), 0.0, 1.0)*clamp(1.0-pos.y,0.0,1.0);
float dom = smoothstep(-0.1, 0.1, ref.y);
float fre = pow(clamp(1.0+dot(nor,rd),0.0,1.0), 2.0);
float spe = pow(clamp(dot(ref, lig), 0.0, 1.0),16.0);
dif *= softshadow(pos, lig, 0.02, 2.5);
dom *= softshadow(pos, ref, 0.02, 2.5);
float3 lin = float3(0.0,0.0,0.0);
lin += 1.30*dif*float3(1.00,0.80,0.55);
lin += 2.00*spe*float3(1.00,0.90,0.70)*dif;
lin += 0.40*amb*float3(0.40,0.60,1.00)*occ;
lin += 0.50*dom*float3(0.40,0.60,1.00)*occ;
lin += 0.50*bac*float3(0.25,0.25,0.25)*occ;
lin += 0.25*fre*float3(1.00,1.00,1.00)*occ;
col = col*lin;
col = lerp(col, float3(0.8,0.9,1.0), 1.0-exp(-0.0002*t*t*t));
}
return float3(clamp(col,0.0,1.0));
}
float3x3 setCamera(in float3 ro, in float3 ta, float cr) {
float3 cw = normalize(ta-ro);
float3 cp = float3(sin(cr), cos(cr),0.0);
float3 cu = normalize(cross(cw,cp));
float3 cv = normalize(cross(cu,cw));
return float3x3(cu, cv, cw);
}
//float3 scene(float3 ro, float3 mo) {
float3 scene(float3 ro, float3 rd) {
float3 tot = float3(0.0, 0.0, 0.0);
//#if AA>1
// for(int m=0; m<AA; m++)
// for(int n=0; n<AA; n++) {
// // pixel coordinates
// float2 o = float2(float(m),float(n)) / float(AA) - 0.5;
// float2 p = (-_ScreenParams.xy + 2.0*(fragCoord+o))/_ScreenParams.y;
//#else
// float2 p = (-_ScreenParams.xy + 2.0*fragCoord)/_ScreenParams.y;
//#endif
// camera
float3 ta = float3(-0.5, -0.4, 0.5);
// camera-to-world transformation
float3x3 ca = setCamera(ro, ta, 0.0);
// ray direction
////float3 rd = ca * normalize(float3(p.xy, 2.0));
// render
float3 col = render(ro, rd);
// gamma
col = pow(col, float3(0.4545,0.4545,0.4545));
tot += col;
//#if AA>1
// }
// tot /= float(AA*AA);
//#endif
return float4(tot, 1.0);
}
struct custom_type {
float4 screen_vertex:SV_POSITION;
float3 world_vertex:TEXCOORD1;
};
custom_type vertex_shader(float4 vertex:POSITION) {
custom_type vs;
vs.screen_vertex = UnityObjectToClipPos(vertex);
vs.world_vertex = mul(unity_ObjectToWorld, vertex);
return vs;
}
float4 pixel_shader(custom_type ps):SV_TARGET {
float3 worldPosition = ps.world_vertex;
float3 viewDirection = normalize(ps.world_vertex - _WorldSpaceCameraPos.xyz);
return float4(scene(worldPosition, viewDirection), 1.0);
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment