// CC0 #define PI 3.14159265359 #define GRID_ROWS 5 #define GRID_COLS 10 vec4 evaluatePosition(float t, int idx) { float x = -8.5 + 2.0 * float(idx % GRID_COLS); // Grid in x direction float y = sin(iTime/2.0 + float(idx)/2.0) + 2.5 + 2.0 * float(idx / GRID_COLS); // Grid in y direction float z = 0.0 + sin(iTime * 0.7 + float(idx) / 5.0 * PI * 0.1) * 4.; // Sinusoidal movement in z direction return vec4(x, z, y, 0.0); // Position } vec3 evaluateColor(float t, int idx) { vec4 position = evaluatePosition(t, idx); float r = 0.7 + 0.3*sin(iTime / 4.0 + position.y); float g = 0.4 + 0.2*cos(iTime / 4.2 + position.z); float b = 0.3 + 0.2*sin(iTime / 1.0 + position.y); return vec3(r,g,b); // Color based on position } // 3D noise function (replace this with a more complex noise if desired) float hash13(vec3 p) { return fract(sin(dot(p ,vec3(12.9898,78.233,45.164)))*43758.5453); } // Sphere SDF with noise float sphereSDF(vec3 p, vec3 c, float r, float blur) { float baseDist = length(p - c) - r; float n = hash13(p * 1.5); // Scale factor affects the frequency of the noise return baseDist + n * blur * 3.2; // Amplitude of noise (focus) } float calculateBlur(float distanceToObject, float focalDistance, float apertureSize) { float focusDifference = abs(distanceToObject - focalDistance); return sqrt(focusDifference / apertureSize); } vec3 calculateNormal(vec3 p, vec4 sphereInfo, float blur) { vec2 e = vec2(0.01, 0.0); vec3 n = vec3( sphereSDF(p + e.xyy, sphereInfo.xyz, 0.4, blur) - sphereSDF(p - e.xyy, sphereInfo.xyz, 0.4, blur), sphereSDF(p + e.yxy, sphereInfo.xyz, 0.4, blur) - sphereSDF(p - e.yxy, sphereInfo.xyz, 0.4, blur), sphereSDF(p + e.yyx, sphereInfo.xyz, 0.4, blur) - sphereSDF(p - e.yyx, sphereInfo.xyz, 0.4, blur)); return normalize(n); } vec4 raymarch3(vec3 ro, vec3 rd, vec3 cameraDirection, vec3 lightDir) { vec4 accumColor = vec4(0.0); int numSpheres = 50; // Number of spheres float focalDistance = 10. + 5. * sin(iTime); // Focal distance from the camera float accumulatedDistance = 0.0; // Accumulated distance inside spheres for (int j = 0; j < numSpheres; j++) { float t = 0.0; vec4 sphereInfo = evaluatePosition(iTime, j); vec3 toObject = sphereInfo.xyz - ro; // Vector from camera to object float distanceToObject = length(toObject); // Euclidean distance to object float distanceToFocalPlane = dot(toObject, cameraDirection); // Projection onto viewing direction float blur = (distanceToFocalPlane - 10.) / 10.0; for (int i = 0; i < 100; i++) { vec3 p = ro + rd * t; float d = sphereSDF(p, sphereInfo.xyz, 0.8, blur); if (d < 0.001) { vec3 sphereColor = evaluateColor(iTime, j); float transmittance = exp(-t * 0.006); // Attenuation based on distance inside spheres accumColor.w = 1.0; vec3 normal = calculateNormal(p, sphereInfo, blur); float diffuse = max(0.0, dot(normal, lightDir)); accumColor.xyz += transmittance * sphereColor * (diffuse + .6); break; } t += d; if (t > 10.4) break; } } if (accumColor.w == 0.) return vec4(-1.0); // Background return accumColor; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0; uv *= iResolution.xy / iResolution.y; // Camera setup vec3 ro = vec3(0.0, 0.0, -9.0); vec3 target = vec3(0.0, 0.0, 5.0); // Look-at point // Mouse controls float angleY = iTime / 2.0; if(iMouse.z > 0.) { angleY = iMouse.x / iResolution.x * 2.0 * PI; } mat3 rotY = mat3( cos(angleY), 0.0, sin(angleY), 0.0, 1.0, 0.0, -sin(angleY), 0.0, cos(angleY) ); ro -= target; // Move ro relative to target ro = rotY * ro; // Rotate camera position ro += target; // Move ro back vec3 cf = normalize(target - ro); vec3 right = cross(vec3(0.0, 1.0, 0.0), cf); vec3 up = cross(cf, right); vec3 rd = cf + uv.x * right + uv.y * up; // Ray direction // For focal plane vec3 cameraDirection = normalize(target - ro); // Direction camera is facing vec3 lightDir = normalize(vec3(1., 0., 1.)); // Directional light // Raymarch vec4 color = raymarch3(ro, normalize(rd), cameraDirection, lightDir); // Check if hit anything if (color.w < 1.0) { vec3 normal = normalize(rd); // Normal from the camera direction float diffuse = max(0.0, dot(normal, lightDir)); fragColor = vec4(.4, .3, .3, 1.0) * diffuse; // Background color } else { fragColor = vec4(color.xyz, 1.0); // Sphere color with lighting } }