馃悕馃悕馃悕
at main 205 lines 6.4 kB view raw
1 2struct Uniforms /* buffer 0 0 */ { 3 width: u32, 4 height: u32, 5 center: vec2f, 6 p: vec2f, // -3 to 3 = 0,0 7 q: f32, // 0 to 1 = 0 8 zoom: f32, 9 iterations: u32, // hard 0 to 500 = 100 10 escape_distance: f32 // 0 to 10 = 2 11} 12 13@group(0) @binding(0) var<uniform> uniforms: Uniforms; 14@group(0) @binding(1) var output_texture: texture_storage_2d<rgba8unorm, write>; 15 16fn add12(ab: vec2<f32>) -> vec2<f32> { 17 let s = ab.x + ab.y; 18 let v = s - ab.x; 19 let r = (ab.x - (s - v)) + (ab.y - v); 20 return vec2<f32>(s, r); 21} 22 23fn split(a: f32) -> vec2<f32> { 24 let c = 4097 * a; 25 let a_b = c - a; 26 let a_h = c - a_b; 27 let a_l = a - a_h; 28 return vec2<f32>(a_h, a_l); 29} 30 31fn mul12(ab: vec2<f32>) -> vec2<f32> { 32 let x = ab.x * ab.y; 33 let a_split = split(ab.x); 34 let b_split = split(ab.y); 35 let err1 = x - (a_split.x * b_split.x); // high * high 36 let err2 = err1 - (a_split.y * b_split.x); // low * high 37 let err3 = err2 - (a_split.x * b_split.y); // high * low 38 let y = (a_split.y * b_split.y) - err3; // low * low 39 return vec2<f32>(x, y); 40} 41 42fn complex_mag_sq(z: vec2<f32>) -> f32 { 43 return z.x * z.x + z.y * z.y; 44} 45 46fn complex_mag(z: vec2<f32>) -> f32 { 47 return sqrt(complex_mag_sq(z)); 48} 49 50fn complex_angle(z: vec2<f32>) -> f32 { 51 return atan2(z.y, z.x); 52} 53 54fn complex_mul(za: vec2<f32>, zb: vec2<f32>) -> vec2<f32> { 55 return vec2<f32>( 56 za.x * zb.x - za.y * zb.y, 57 za.x * zb.y + za.y * zb.x 58 ); 59} 60 61fn pixel_to_complex(px: u32, py: u32) -> vec2<f32> { 62 let aspect = f32(uniforms.width) / f32(uniforms.height); 63 let scale = 1.0 / uniforms.zoom; 64 let half_width = f32(uniforms.width) * 0.5; 65 let half_height = f32(uniforms.height) * 0.5; 66 let x = (f32(px) - half_width) * scale * aspect / f32(uniforms.width) + uniforms.center.x; 67 let y = (f32(py) - half_height) * scale / f32(uniforms.height) + uniforms.center.y; 68 return vec2<f32>(x, y); 69} 70 71fn pixel_to_complex_alt(px: u32, py: u32) -> vec2<f32> { 72 let aspect = f32(uniforms.width) / f32(uniforms.height); 73 let scale = 4.0 / uniforms.zoom; 74 let half_width = f32(uniforms.width) * 0.5; 75 let half_height = f32(uniforms.height) * 0.5; 76 77 // map y-axis to magnitude, x-axis to angle 78 let angle = (f32(px) - half_width) * scale * aspect / f32(uniforms.width) + uniforms.center.x; 79 let mag = (f32(py) - half_height) * scale / (2.0 * f32(uniforms.height)) + uniforms.center.y; 80 81 return vec2<f32>(mag * cos(angle), mag * sin(angle)); 82} 83 84fn pixel_to_complex_inverted(px: u32, py: u32) -> vec2<f32> { 85 let aspect = f32(uniforms.width) / f32(uniforms.height); 86 let scale = 4.0 / uniforms.zoom; 87 let half_width = f32(uniforms.width) * 0.5; 88 let half_height = f32(uniforms.height) * 0.5; 89 90 let x = (f32(px) - half_width) * scale * aspect / f32(uniforms.width) + uniforms.center.x; 91 let y = (f32(py) - half_height) * scale / f32(uniforms.height) + uniforms.center.y; 92 93 let z = vec2<f32>(x, y); 94 let mag_sq = x * x + y * y; 95 96 // handle singularity at origin 97 if (mag_sq < 1e-10) { 98 return vec2<f32>(1e10, 0.0); // or whatever you want infinity to map to 99 } 100 101 return vec2<f32>(x / mag_sq, -y / mag_sq); 102} 103 104fn pixel_to_complex_inverted_d(px: u32, py: u32) -> vec2<f32> { 105 let aspect = f32(uniforms.width) / f32(uniforms.height); 106 let scale = 16.0 / uniforms.zoom; 107 let half_width = f32(uniforms.width) * 0.5; 108 let half_height = f32(uniforms.height) * 0.5; 109 110 // get position relative to center 111 let x = (f32(px) - half_width) * scale * aspect / f32(uniforms.width); 112 let y = (f32(py) - half_height) * scale / f32(uniforms.height); 113 114 let mag_sq = x * x + y * y; 115 if (mag_sq < 1e-10) { 116 return vec2<f32>(uniforms.center.x + 1e10, uniforms.center.y); 117 } 118 119 // invert then add center back 120 return vec2<f32>( 121 uniforms.center.x + x / mag_sq, 122 uniforms.center.y - y / mag_sq 123 ); 124} 125 126fn c_avg(prev: f32, val: f32, n: f32) -> f32 { 127 return prev + (val - prev) / n; 128} 129 130fn hash(seed: u32) -> u32 { 131 var x = seed; 132 x = ((x >> 16u) ^ x) * 0x45d9f3bu; 133 x = ((x >> 16u) ^ x) * 0x45d9f3bu; 134 x = (x >> 16u) ^ x; 135 return x; 136} 137 138fn pcg_hash(x: u32) -> u32 { 139 let state = x * 747796405u + 2891336453u; 140 let word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; 141 return (word >> 22u) ^ word; 142} 143 144fn random_float(seed: u32) -> f32 { 145 return f32(hash(seed)) / 4294967296.0; // 2^32 146} 147 148@compute @workgroup_size(16, 16) 149fn main(@builtin(global_invocation_id) id: vec3<u32>) { 150 let px = id.x; 151 let py = id.y; 152 153 if (px >= uniforms.width || py >= uniforms.height) { 154 return; 155 } 156 157 var nq = 1.0 - uniforms.q; 158 var c = ${pixel_mapping}(px, py) * nq + uniforms.p * uniforms.q; 159 var z = uniforms.p * nq + ${pixel_mapping}(px, py) * uniforms.q; 160 let orig_z = z; 161 let n_perturbations = 1u; 162 let escape_threshold = uniforms.escape_distance * uniforms.escape_distance; 163 164 var escaped = false; 165 var iter = 0u; 166 var cavg = f32(0.0); 167 let epsilon = 1.19e-6; 168 169 let transient_skip = u32(f32(uniforms.iterations) * f32(0.95)); 170 171 for (iter = 0u; iter < uniforms.iterations; iter = iter + 1u) { 172 let mag_sq = complex_mag_sq(z); 173 if (mag_sq > escape_threshold) { 174 escaped = true; 175 break; 176 } 177 178 z = complex_mul(z, z) + c; 179 //z = avg_abs_df_z_p; 180 } 181 182 var color: vec4<f32>; 183 if (escaped) { 184 let escape_speed = 1.0 - pow(f32(iter) / f32(uniforms.iterations), 2.0); 185 color = vec4<f32>(escape_speed, escape_speed, escape_speed, 1.0); 186 } else { 187 let final_mag = complex_mag(z); 188 let final_angle = complex_angle(z); 189 //let scaled_mag = log(final_mag); 190 //let final_x = scaled_mag * (z.x / final_mag); 191 //let final_y = scaled_mag * (z.y / final_mag); 192 //color = vec4<f32>(0.5 + 0.5 * final_x, 0.0, 0.5 + 0.5 * final_y, 1.0); 193 let scaled_mag = pow(final_mag / escape_threshold, 0.5); 194 let scaled_angle = (final_angle + 3.1415926535) / 6.283185307179586; 195 let r = max(0, 2.0 * scaled_angle - 1.0); 196 let b = max(0, 2.0 * (1.0 - scaled_angle) - 1.0); 197 color = vec4<f32>(r, scaled_mag, b, 1.0); 198 } 199 200 //color = vec4<f32>(1.0 - cavg / 10.0, 1.0 - (-cavg / 5.0), 1.0 - (-cavg / 5.0), 1.0); 201 202 textureStore(output_texture, vec2<i32>(i32(px), i32(py)), color); 203} 204 205