Shader "CrispyPin/Nut" { Properties { [Header(Raymarcher Properties)] _MaxSteps ("Max steps", Int) = 128 _MaxDist ("Max distance", Float) = 128 _SurfDist ("Surface distance threshold", Range(0.0001, 0.05)) = 0.001 } SubShader { Tags { "RenderType"="Opaque" } Cull Front LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #define PLAYER_COUNT 4 float4 _PlayerRightHandPositions[PLAYER_COUNT]; float4 _PlayerLeftHandPositions[PLAYER_COUNT]; int _MaxSteps; float _MaxDist; float _SurfDist; #define MAX_STEPS _MaxSteps #define MAX_DIST _MaxDist #define SURF_DIST _SurfDist #define REFLECTIONS 3 #define SCENE_FN main #define LIGHT_FN lighting // #define SEPARATE_MATERIAL_AND_DIST_FUNCTIONS // #define SCENE_FN separate_mat // #define DISTANCE_FN separate_dist // #define STEP_MULTIPLIER 0.1 #define SCENE_SCALE 0.7 // #define DISABLE_DEPTH // #define DISCARD_ON_MISS #define LIMIT_DEPTH_TO_MESH // #define USE_WORLD_SPACE #include "lib/libgarbage.cginc" float3 checkers(float3 p, float3 a, float3 b, float2 size) { float2 q = p.xz / size; q = int2(abs(q) + 0.5); int s = ((q.x + q.y) % 2); return s * a + (1 - s) * b; } float3 floor(float3 p) { return lerp(0.15, checkers(p - 1, 0.10, 0.18, .2), smoothstep(16, 0, length(p)) ); } SurfacePoint mRoundedHex(float3 p, float girth, float height) { SurfacePoint d; d = qRound(mHexPrism(p, girth, height), 0.01); float rounding = 3; d = qIntersect(d, mSphere(p - float3(0, -rounding + height, 0), rounding), 0.01); d = qIntersect(d, mSphere(p + float3(0, -rounding + height, 0), rounding), 0.01); return d; } SurfacePoint main(float3 p) { float girth = 0.3; float height = 0.1; float inner_radius = 0.18; float thread = 0.013; float3 thread_box = float3(thread, thread, UNITY_PI/4); SurfacePoint d; float3 rp = rotY(p, _Time.y); rp = rotX(rp, _Time.x); // nut d = mRoundedHex(rp, girth, height); d = qSub(d, mInfCylinder(rp, float3(0, 0, inner_radius)), 0.02); d = qSub(d, mHelixSquare(rp - float3(0, -1, 0), inner_radius, thread_box, thread/2), 0.003); // bolt SurfacePoint bolt_thread = mInfCylinder(rp, float3(0, 0, inner_radius + 0.3)); bolt_thread = qSub(bolt_thread, mInfCylinder(rp, float3(0, 0, inner_radius)), 0.02); bolt_thread = qSub(bolt_thread, mHelixSquare(rp - float3(0, -1, 0), inner_radius, thread_box, thread/2), 0.03); // d = qUnion(d, bolt_thread); float h = sin(_Time.y) * 0.15 + 0.2; float3 bp = rotY(rp, sin(_Time.y) * UNITY_PI * 4); bp.y -= h; SurfacePoint bolt = qSub(mCylinder(bp, inner_radius+thread*2, 0.2), bolt_thread); bolt = qUnion(bolt, mRoundedHex(bp - float3(0, 0.13, 0), girth, height)); // Material metal1 = mat(float3(0.5, 0.3, 0.1), 1); // Material metal2 = mat(float3(0.3, 0.3, 0.5), 1); Material metal1 = mat(0.3, 1); Material metal2 = mat(0.3, 1); d.mat = metal1; bolt.mat = metal2; // cube // float3 cp = rotX(bp - float3(0, -0.32, 0), _Time.w * 5); // bolt = qUnion(bolt, mBox(cp, 0.1, mat(float3(0,1,1))),.1); d = qUnion(d, bolt); // d = qUnion(d, mSphere(p - float3(0,0,.3), 0.15, mat(1,0,0.5)), 0.1); // floor // d = qUnion(d, mPlaneY(p, -0.5, mat(floor_col, 0)), 0.01); // d = qIntersect(d, mPlaneY(-p, 0.6, mat(floor_col, 0)), 0.01); d = qUnion(d, mBox(p - float3(0, -0.5 / SCENE_SCALE, 0), float3(6, 0.05, 6), mat(floor(p), 0))); [unroll] for (int i = 0; i < PLAYER_COUNT; i++) { // float visible = (float)(length(_PlayerRightHandPositions[i]) > 0); // float visible = step(0.01, length(_PlayerRightHandPositions[i])); [flatten] if (length(_PlayerRightHandPositions[i]) > 0.01) { float rad = 0.1; float3 hand_r = mul(unity_WorldToObject, float4(_PlayerRightHandPositions[i].xyz, 1)).xyz / SCENE_SCALE; d = qUnion(d, mSphere(p - hand_r, rad, mat(0.1, sin(_Time.y)*0.5 +0.5, 1)), 0.2); float3 hand_l = mul(unity_WorldToObject, float4(_PlayerLeftHandPositions[i].xyz, 1)).xyz / SCENE_SCALE; d = qUnion(d, mSphere(p - hand_l, rad, mat(float3(1, 0, 0.1), 0.5)), 0.2); } } // d = qUnion(d, mSphere(p - float3(0, -0.5, 1), 0.4)); return d; } float3 lighting(Ray ray) { float3 sun_dir = normalize(float3(4, 2, 1)); if (ray.missed) { if (ray.dir.y >= 0) { return lRenderSky(ray.dir, sun_dir); } else { float3 cam = ray.start; cam.y += 0.5 / SCENE_SCALE; float3 dir = ray.dir; float3 surface_pos = float3 ( cam.x - cam.y / (dir.y / dir.x), 0, cam.z - cam.y / (dir.y / dir.z) ); float col = 1; col = floor(surface_pos); return col * (lSky(float3(0,1,0)) + lSun(float3(0,1,0), sun_dir)); } } float3 light = lSun(ray.normal, sun_dir) * lShadow(ray.hit_pos + ray.normal * SURF_DIST, sun_dir, 50) + lSky(ray.normal); return light * ray.mat.col; } ENDCG } } }