// Parameters #define CAMERA_FOCAL_LENGTH 1.5 #define VOXEL_STEP 50.0 #define SOUND #define MOUSE #define HSV2RGB_FAST // Constants #define PI 3.14159265359 #define SQRT2 1.41421356237 // PRNG // From https://www.shadertoy.com/view/4djSRW float rand (in vec2 seed) { seed = fract (seed * vec2 (5.3983, 5.4427)); seed += dot (seed.yx, seed.xy + vec2 (21.5351, 14.3137)); return fract (seed.x * seed.y * 95.4337); } // HSV to RGB vec3 hsv2rgb (in vec3 hsv) { #ifdef HSV2RGB_SAFE hsv.yz = clamp (hsv.yz, 0.0, 1.0); #endif #ifdef HSV2RGB_FAST return hsv.z * (1.0 + 0.5 * hsv.y * (cos (2.0 * PI * (hsv.x + vec3 (0.0, 2.0 / 3.0, 1.0 / 3.0))) - 1.0)); #else return hsv.z * (1.0 + hsv.y * clamp (abs (fract (hsv.x + vec3 (0.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - 3.0) - 2.0, -1.0, 0.0)); #endif } // Main function void mainImage (out vec4 fragColor, in vec2 fragCoord) { // Define the ray corresponding to this fragment vec3 ray = normalize (vec3 ((2.0 * fragCoord.xy - iResolution.xy) / iResolution.y, CAMERA_FOCAL_LENGTH)); // Get the music info #ifdef SOUND float soundBass = texture (iChannel0, vec2 (0.0)).x; float soundTreble = texture (iChannel0, vec2 (0.9, 0.0)).x; #else float soundBass = 0.6 + 0.4 * cos (iTime * 0.2); float soundTreble = 0.5 + 0.5 * cos (iTime * 1.2); #endif // Set the camera vec3 origin = vec3 (0.0, 6.0 - 3.0 * cos (iTime * 0.3), iTime * 2.0 + 700.0 * (0.5 + 0.5 * sin (iTime * 0.1))); float cameraAngle = iTime * 0.1; #ifdef MOUSE cameraAngle += 2.0 * PI * iMouse.x / iResolution.x; #endif vec3 cameraForward = vec3 (cos (cameraAngle), cos (iTime * 0.3) - 1.5, sin (cameraAngle)); vec3 cameraUp = vec3 (0.2 * cos (iTime * 0.7), 1.0, 0.0); mat3 cameraRotation; cameraRotation [2] = normalize (cameraForward); cameraRotation [0] = normalize (cross (cameraUp, cameraForward)); cameraRotation [1] = cross (cameraRotation [2], cameraRotation [0]); ray = cameraRotation * ray; // Voxel vec3 color = vec3 (0.0); vec2 voxelSign = sign (ray.xz); vec2 voxelIncrement = voxelSign / ray.xz; float voxelTimeCurrent = 0.0; vec2 voxelTimeNext = (0.5 + voxelSign * (0.5 - fract (origin.xz + 0.5))) * voxelIncrement; vec2 voxelPosition = floor (origin.xz + 0.5); float voxelHeight = 0.0; bool voxelDone = false; vec3 voxelNormal = vec3 (0.0); for (float voxelStep = 1.0; voxelStep <= VOXEL_STEP; ++voxelStep) { // Compute the height of this column voxelHeight = 2.0 * rand (voxelPosition) * smoothstep (0.2, 0.5, soundBass) * sin (soundBass * 8.0 + voxelPosition.x * voxelPosition.y) - 5.0 * (0.5 + 0.5 * cos (voxelPosition.y * 0.15)); // Check whether we hit the side of the column if (voxelDone = voxelHeight > origin.y + voxelTimeCurrent * ray.y) { break; } // Check whether we hit the top of the column float timeNext = min (voxelTimeNext.x, voxelTimeNext.y); float timeIntersect = (voxelHeight - origin.y) / ray.y; if (voxelDone = timeIntersect > voxelTimeCurrent && timeIntersect < timeNext) { voxelTimeCurrent = timeIntersect; voxelNormal = vec3 (0.0, 1.0, 0.0); break; } // Next voxel... voxelTimeCurrent = timeNext; voxelNormal.xz = step (voxelTimeNext.xy, voxelTimeNext.yx); voxelTimeNext += voxelNormal.xz * voxelIncrement; voxelPosition += voxelNormal.xz * voxelSign; } if (voxelDone) { origin += voxelTimeCurrent * ray; // Compute the local color vec3 mapping = origin; mapping.y -= voxelHeight + 0.5; mapping *= 1.0 - voxelNormal; mapping += 0.5; float id = rand (voxelPosition); color = hsv2rgb (vec3 ((iTime + floor (mapping.y)) * 0.05 + voxelPosition.x * 0.01, smoothstep (0.2, 0.4, soundBass), 0.7 + 0.3 * cos (id * iTime + PI * soundTreble))); color *= smoothstep (0.8 - 0.6 * cos (soundBass * PI), 0.1, length (fract (mapping) - 0.5)); color *= 0.5 + smoothstep (0.90, 0.95, cos (id * 100.0 + soundTreble * PI * 0.5 + iTime * 0.5)); color *= 1.0 - voxelTimeCurrent / VOXEL_STEP * SQRT2; } // Set the fragment color fragColor = vec4 (color, 1.0); }