#version 100 precision mediump float; uniform float u_time; uniform vec2 u_resolution; // Constants #define PI 3.14159265359 #define G 9.81 #define L1 1.0 #define L2 1.0 #define M1 1.0 #define M2 1.0 #define DT 0.05 #define ITERATIONS 100 void main() { // Map pixel to initial angles (-PI to PI) vec2 uv = (gl_FragCoord.xy / u_resolution.xy) * 2.0 - 1.0; float t1 = uv.x * PI; float t2 = uv.y * PI; // Initial velocities float v1 = 0.0; float v2 = 0.0; // Previous angles for Verlet or just simple Euler/RK4 // Using semi-implicit Euler for stability/simplicity in shader float flip_time = -1.0; // Animate gravity to make it breathe? Or length? float g = G + sin(u_time * 0.5) * 2.0; for (int i = 0; i < ITERATIONS; i++) { float num1 = -g * (2.0 * M1 + M2) * sin(t1); float num2 = -M2 * g * sin(t1 - 2.0 * t2); float num3 = -2.0 * sin(t1 - t2) * M2; float num4 = v2 * v2 * L2 + v1 * v1 * L1 * cos(t1 - t2); float den = L1 * (2.0 * M1 + M2 - M2 * cos(2.0 * t1 - 2.0 * t2)); float a1 = (num1 + num2 + num3 * num4) / den; num1 = 2.0 * sin(t1 - t2); num2 = (v1 * v1 * L1 * (M1 + M2)); num3 = g * (M1 + M2) * cos(t1); num4 = v2 * v2 * L2 * M2 * cos(t1 - t2); den = L2 * (2.0 * M1 + M2 - M2 * cos(2.0 * t1 - 2.0 * t2)); float a2 = (num1 * (num2 + num3 + num4)) / den; v1 += a1 * DT; v2 += a2 * DT; t1 += v1 * DT; t2 += v2 * DT; // Dampening? No, chaotic system usually conservative (or we want to see chaos) // Check for flip (crossing PI) if (abs(t1) > PI || abs(t2) > PI) { flip_time = float(i) / float(ITERATIONS); break; } } vec3 col = vec3(0.0); if (flip_time > 0.0) { // Did flip col = vec3(0.2 + 0.8 * flip_time, 0.5 * flip_time, 1.0 - flip_time); } else { // Did not flip (stableish) col = vec3(0.1, 0.1, 0.2); } gl_FragColor = vec4(col, 1.0); }