// // some reference code from // https://www.shadertoy.com/view/slBSzt // https://www.shadertoy.com/view/7lBSWy // const int MAX_MARCHING_STEPS = 255; const float MIN_DIST = 0.0; const float MAX_DIST = 200.0; const float PRECISION = 0.001; const float EPSILON = 0.0005; const float PI = 3.14159265359; const float TWO_PI = (3.14159265359*2.0); mat3 rotateX(float theta) { float c = cos(theta); float s = sin(theta); return mat3( vec3(1, 0, 0), vec3(0, c, -s), vec3(0, s, c) ); } mat3 rotateY(float theta) { float c = cos(theta); float s = sin(theta); return mat3( vec3(c, 0, s), vec3(0, 1, 0), vec3(-s, 0, c) ); } mat3 rotateZ(float theta) { float c = cos(theta); float s = sin(theta); return mat3( vec3(c, -s, 0), vec3(s, c, 0), vec3(0, 0, 1) ); } float TriangleFunction(float x, float y) // output range +- y*0.5 with center at x=0 { return abs(mod(x-y*0.5,y*2.0)-y)-y*0.5; } ////////////////////////////////////////////////////// float sdCircle(vec2 p, float r) { return length(p) - r; } float sdSphere( vec3 p, float R) { return length(p)-R; } float sdBox( vec3 p, vec3 b) { vec3 q = abs(p) - b; //float d = length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0); float d = max(q.x,max(q.y,q.z)); // intersection operator return d; } // vertical Cylinder, by intersection operator float sdCylinder( vec3 p0, vec2 h) { vec3 p = p0; //vec2 d = abs(vec2(length(p.xz),p.y)) - h; //float distance = min(max(d.x,d.y),0.0) + length(max(d,0.0)); float distance = length(p.xz) - h.x; // inifinite length distance = max(max(distance, p.y-h.y), -p.y); // two intersection operator return distance; } // Spring Distance function, by float sdSpring(vec3 p, float Radius, float radius, float height, float turns ) { float pitch = height/turns; // p.xz of Spring cylinder vec2 np = normalize(p.xz)*Radius; // closest Point On Spring Cylinder vec3 pc = vec3(np.x, clamp(p.y, -height*0.5, height*0.5), np.y); // closest distance to Spring cylinder, p to pc float distanceToCylinder = distance(p, pc); // distance, pc to Spring Coil center float pcToSpring = p.y + atan(p.z, p.x)*pitch/TWO_PI; // atan() range -PI to PI float distanceToSpring = TriangleFunction(pcToSpring, pitch); // so 'close distance to Spring center for p' is length(vec2(distanceToCylinder, distanceToSpring) // we could construct springCoords with origin at Spring Coil center to calculate closest distance. vec2 springCoords = vec2(distanceToCylinder, distanceToSpring); return sdCircle(springCoords, radius); // circle shape of spings } //// SPRING + mount + Load //// float scene(vec3 p) { float dist0 = sdCylinder( p-vec3(0,2.0,0), vec2(2.5, 0.2)); float height = sin(iTime)+3.0; p.y -= 2. - height*0.5; float dist1 = sdSpring(p, 0.25, 0.05, height, 8.0) ; // Radius, radius, height, turns p.y += height*0.5; //float dist2 = sdBox( p-vec3(0,-0.5,0), vec3(0.5, 0.5, 0.5)); float dist2 = sdSphere( p-vec3(0,-0.5,0), 0.75); return min(dist2,min(dist0, dist1)); } float rayMarch(vec3 ro, vec3 rd) { float depth = MIN_DIST; float d; // distance ray has travelled for (int i = 0; i < MAX_MARCHING_STEPS; i++) { vec3 p = ro + depth * rd; d = scene(p); depth += d; if (abs(d) < PRECISION || depth > MAX_DIST) break; } return depth; } vec3 getNormal(vec3 p) { float d = scene(p); vec2 e = vec2(.001, 0); vec3 n = d - vec3( scene(p-e.xyy), scene(p-e.yxy), scene(p-e.yyx)); return normalize(n); } vec3 GetRayDir(vec2 uv, vec3 p, vec3 l, float z) { vec3 f = normalize(l-p), r = normalize(cross(vec3(0,1,0), f)), u = cross(f,r), c = f*z, i = c + uv.x*r + uv.y*u, d = normalize(i); return d; } ////////////////////////////////////////////////////////////////// void mainImage( out vec4 fragColor, in vec2 fragCoord ) { //vec2 mouse = (iMouse.xy-.5*iResolution.xy)/iResolution.y; vec2 dmouse = (iMouse.xy-abs(iMouse.zw))/iResolution.y; // delta mouse movement of drag vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y; vec3 origin = vec3(0, 0, -8); // ray origin that represents camera position vec3 dir = normalize(vec3(uv, 1)); // ray direction dir *= rotateY(dmouse.x*TWO_PI)*rotateX(-dmouse.y*PI); origin *= rotateY(dmouse.x*TWO_PI)*rotateX(-dmouse.y*PI); //vec3 dir = GetRayDir(uv, origin, vec3(0), 1.); vec3 col = texture(iChannel0, dir).rgb; float dist = rayMarch(origin, dir); // signed distance value to closest object if (dist < MAX_DIST) { // ray hit anything vec3 p = origin + dir * dist; // point discovered from ray marching vec3 normal = getNormal(p); // surface normal vec3 rflct = reflect(dir, normal); vec3 ref = texture(iChannel0, rflct).rgb; col = 1.5*ref; } col= pow(col, vec3(.4545)); // gamma correction fragColor = vec4(col, 1.0); }