|
| 1 | +//! Ported to Rust from <https://www.shadertoy.com/view/Xsd3zf> |
| 2 | +//! |
| 3 | +//! Original comment: |
| 4 | +//! ```glsl |
| 5 | +//! /* |
| 6 | +//! // |
| 7 | +//! /* Panteleymonov Aleksandr Konstantinovich 2015 |
| 8 | +//! // |
| 9 | +//! // if i write this string my code will be 0 chars, :) */ |
| 10 | +//! */ |
| 11 | +//! ``` |
| 12 | +
|
| 13 | +use shared::*; |
| 14 | +use spirv_std::glam::{ |
| 15 | + const_vec4, vec2, vec3, vec4, Mat3, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, |
| 16 | +}; |
| 17 | + |
| 18 | +// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but |
| 19 | +// we tie #[no_std] above to the same condition, so it's fine. |
| 20 | +#[cfg(target_arch = "spirv")] |
| 21 | +use spirv_std::num_traits::Float; |
| 22 | + |
| 23 | +pub struct Inputs { |
| 24 | + pub resolution: Vec3, |
| 25 | + pub time: f32, |
| 26 | + pub mouse: Vec4, |
| 27 | +} |
| 28 | + |
| 29 | +const ITERATIONS: f32 = 15.0; |
| 30 | +const DEPTH: f32 = 0.0125; |
| 31 | +const LAYERS: f32 = 8.0; |
| 32 | +const LAYERSBLOB: i32 = 20; |
| 33 | +const STEP: f32 = 1.0; |
| 34 | +const FAR: f32 = 10000.0; |
| 35 | + |
| 36 | +pub struct State { |
| 37 | + inputs: Inputs, |
| 38 | + radius: f32, |
| 39 | + zoom: f32, |
| 40 | + |
| 41 | + light: Vec3, |
| 42 | + seed: Vec2, |
| 43 | + iteratorc: f32, |
| 44 | + powr: f32, |
| 45 | + res: f32, |
| 46 | + |
| 47 | + nray: Vec3, |
| 48 | + nray1: Vec3, |
| 49 | + nray2: Vec3, |
| 50 | + mxc: f32, |
| 51 | +} |
| 52 | + |
| 53 | +impl State { |
| 54 | + pub fn new(inputs: Inputs) -> Self { |
| 55 | + State { |
| 56 | + inputs, |
| 57 | + radius: 0.25, // radius of Snowflakes. maximum for this demo 0.25. |
| 58 | + zoom: 4.0, // use this to change details. optimal 0.1 - 4.0. |
| 59 | + light: vec3(0.0, 0.0, 1.0), |
| 60 | + seed: vec2(0.0, 0.0), |
| 61 | + iteratorc: ITERATIONS, |
| 62 | + powr: 0.0, |
| 63 | + res: 0.0, |
| 64 | + |
| 65 | + nray: Vec3::zero(), |
| 66 | + nray1: Vec3::zero(), |
| 67 | + nray2: Vec3::zero(), |
| 68 | + mxc: 1.0, |
| 69 | + } |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +const NC0: Vec4 = const_vec4!([0.0, 157.0, 113.0, 270.0]); |
| 74 | +const NC1: Vec4 = const_vec4!([1.0, 158.0, 114.0, 271.0]); |
| 75 | + |
| 76 | +fn hash4(n: Vec4) -> Vec4 { |
| 77 | + (n.sin() * 1399763.5453123).gl_fract() |
| 78 | +} |
| 79 | +fn noise2(x: Vec2) -> f32 { |
| 80 | + let p: Vec2 = x.floor(); |
| 81 | + let mut f: Vec2 = x.gl_fract(); |
| 82 | + f = f * f * (Vec2::splat(3.0) - 2.0 * f); |
| 83 | + let n: f32 = p.x + p.y * 157.0; |
| 84 | + let h: Vec4 = hash4(Vec4::splat(n) + vec4(NC0.x, NC0.y, NC1.x, NC1.y)); |
| 85 | + let s1: Vec2 = mix(h.xy(), h.zw(), f.xx()); |
| 86 | + mix(s1.x, s1.y, f.y) |
| 87 | +} |
| 88 | + |
| 89 | +fn noise222(x: Vec2, y: Vec2, z: Vec2) -> f32 { |
| 90 | + let lx: Vec4 = vec4(x.x * y.x, x.y * y.x, x.x * y.y, x.y * y.y); |
| 91 | + let p: Vec4 = lx.floor(); |
| 92 | + let mut f: Vec4 = lx.gl_fract(); |
| 93 | + f = f * f * (Vec4::splat(3.0) - 2.0 * f); |
| 94 | + let n: Vec2 = p.xz() + p.yw() * 157.0; |
| 95 | + let h: Vec4 = mix( |
| 96 | + hash4(n.xxyy() + NC0.xyxy()), |
| 97 | + hash4(n.xxyy() + NC1.xyxy()), |
| 98 | + f.xxzz(), |
| 99 | + ); |
| 100 | + mix(h.xz(), h.yw(), f.yw()).dot(z) |
| 101 | +} |
| 102 | + |
| 103 | +fn noise3(x: Vec3) -> f32 { |
| 104 | + let p: Vec3 = x.floor(); |
| 105 | + let mut f: Vec3 = x.gl_fract(); |
| 106 | + f = f * f * (Vec3::splat(3.0) - 2.0 * f); |
| 107 | + let n: f32 = p.x + p.yz().dot(vec2(157.0, 113.0)); |
| 108 | + let s1: Vec4 = mix( |
| 109 | + hash4(Vec4::splat(n) + NC0), |
| 110 | + hash4(Vec4::splat(n) + NC1), |
| 111 | + f.xxxx(), |
| 112 | + ); |
| 113 | + return mix(mix(s1.x, s1.y, f.y), mix(s1.z, s1.w, f.y), f.z); |
| 114 | +} |
| 115 | +fn noise3_2(x: Vec3) -> Vec2 { |
| 116 | + vec2(noise3(x), noise3(x + Vec3::splat(100.0))) |
| 117 | +} |
| 118 | + |
| 119 | +impl State { |
| 120 | + fn map(&self, rad: Vec2) -> f32 { |
| 121 | + let a: f32; |
| 122 | + if self.res < 0.0015 { |
| 123 | + //a = noise2(rad.xy*20.6)*0.9+noise2(rad.xy*100.6)*0.1; |
| 124 | + a = noise222(rad, vec2(20.6, 100.6), vec2(0.9, 0.1)); |
| 125 | + } else if self.res < 0.005 { |
| 126 | + //let a1: f32 = mix(noise2(rad.xy()*10.6),1.0,l); |
| 127 | + //a = texture(iChannel0,rad*0.3).x; |
| 128 | + a = noise2(rad * 20.6); |
| 129 | + //if a1<a {a=a1;} |
| 130 | + } else { |
| 131 | + a = noise2(rad * 10.3); |
| 132 | + } |
| 133 | + a - 0.5 |
| 134 | + } |
| 135 | +} |
| 136 | +impl State { |
| 137 | + fn dist_obj(&self, pos: Vec3, mut ray: Vec3, mut r: f32, seed: Vec2) -> Vec3 { |
| 138 | + let rq: f32 = r * r; |
| 139 | + let mut dist: Vec3 = ray * FAR; |
| 140 | + |
| 141 | + let norm: Vec3 = vec3(0.0, 0.0, 1.0); |
| 142 | + let invn: f32 = 1.0 / norm.dot(ray); |
| 143 | + let mut depthi: f32 = DEPTH; |
| 144 | + if invn < 0.0 { |
| 145 | + depthi = -depthi; |
| 146 | + } |
| 147 | + let mut ds: f32 = 2.0 * depthi * invn; |
| 148 | + let mut r1: Vec3 = ray * (norm.dot(pos) - depthi) * invn - pos; |
| 149 | + let op1: Vec3 = r1 + norm * depthi; |
| 150 | + let len1: f32 = op1.dot(op1); |
| 151 | + let mut r2: Vec3 = r1 + ray * ds; |
| 152 | + let op2: Vec3 = r2 - norm * depthi; |
| 153 | + let len2: f32 = op2.dot(op2); |
| 154 | + let n: Vec3 = ray.cross(norm).normalize(); |
| 155 | + let mind: f32 = pos.dot(n); |
| 156 | + let n2: Vec3 = ray.cross(n); |
| 157 | + let d: f32 = n2.dot(pos) / n2.dot(norm); |
| 158 | + let invd: f32 = 0.2 / DEPTH; |
| 159 | + |
| 160 | + if (len1 < rq || len2 < rq) || (mind.abs() < r && d <= DEPTH && d >= -DEPTH) { |
| 161 | + let _r3: Vec3 = r2; |
| 162 | + let len: f32 = len1; |
| 163 | + if len >= rq { |
| 164 | + let n3: Vec3 = norm.cross(n); |
| 165 | + let a: f32 = 1.0 / (rq - mind * mind).sqrt() * ray.dot(n3).abs(); |
| 166 | + let dt: Vec3 = ray / a; |
| 167 | + r1 = -d * norm - mind * n - dt; |
| 168 | + if len2 >= rq { |
| 169 | + r2 = -d * norm - mind * n + dt; |
| 170 | + } |
| 171 | + ds = (r2 - r1).dot(ray); |
| 172 | + } |
| 173 | + ds = (ds.abs() + 0.1) / (ITERATIONS); |
| 174 | + ds = mix(DEPTH, ds, 0.2); |
| 175 | + if ds > 0.01 { |
| 176 | + ds = 0.01; |
| 177 | + } |
| 178 | + let ir: f32 = 0.35 / r; |
| 179 | + r *= self.zoom; |
| 180 | + ray = ray * ds * 5.0; |
| 181 | + let mut m: f32 = 0.0; |
| 182 | + while m < ITERATIONS { |
| 183 | + if m >= self.iteratorc { |
| 184 | + break; |
| 185 | + } |
| 186 | + let mut l: f32 = r1.xy().length(); //r1.xy().dot(r1.xy()).sqrt(); |
| 187 | + let mut c3: Vec2 = (r1.xy() / l).abs(); |
| 188 | + if c3.x > 0.5 { |
| 189 | + c3 = (c3 * 0.5 + vec2(-c3.y, c3.x) * 0.86602540).abs(); |
| 190 | + } |
| 191 | + let g: f32 = l + c3.x * c3.x; //*1.047197551; |
| 192 | + l *= self.zoom; |
| 193 | + let mut h: f32 = l - r - 0.1; |
| 194 | + l = l.powf(self.powr) + 0.1; |
| 195 | + h = h.max(mix(self.map(c3 * l + seed), 1.0, (r1.z * invd).abs())) + g * ir - 0.245; //0.7*0.35=0.245 //*0.911890636 |
| 196 | + if (h < self.res * 20.0) || r1.z.abs() > DEPTH + 0.01 { |
| 197 | + break; |
| 198 | + } |
| 199 | + r1 += ray * h; |
| 200 | + ray *= 0.99; |
| 201 | + m += 1.0; |
| 202 | + } |
| 203 | + if r1.z.abs() < DEPTH + 0.01 { |
| 204 | + dist = r1 + pos; |
| 205 | + } |
| 206 | + } |
| 207 | + dist |
| 208 | + } |
| 209 | + |
| 210 | + fn filter_flake( |
| 211 | + &mut self, |
| 212 | + mut color: Vec4, |
| 213 | + pos: Vec3, |
| 214 | + ray: Vec3, |
| 215 | + ray1: Vec3, |
| 216 | + ray2: Vec3, |
| 217 | + ) -> Vec4 { |
| 218 | + let d: Vec3 = self.dist_obj(pos, ray, self.radius, self.seed); |
| 219 | + let n1: Vec3 = self.dist_obj(pos, ray1, self.radius, self.seed); |
| 220 | + let n2: Vec3 = self.dist_obj(pos, ray2, self.radius, self.seed); |
| 221 | + |
| 222 | + let lq: Vec3 = vec3(d.dot(d), n1.dot(n1), n2.dot(n2)); |
| 223 | + if lq.x < FAR || lq.y < FAR || lq.z < FAR { |
| 224 | + let n: Vec3 = (n1 - d).cross(n2 - d).normalize(); |
| 225 | + if lq.x < FAR && lq.y < FAR && lq.z < FAR { |
| 226 | + self.nray = n; //(self.nray+n).normalize(); |
| 227 | + //self.nray1 = (ray1+n).normalize(); |
| 228 | + //self.nray2 = (ray2+n).normalize(); |
| 229 | + } |
| 230 | + let da: f32 = n.dot(self.light).abs().powf(3.0); |
| 231 | + let mut cf: Vec3 = mix(vec3(0.0, 0.4, 1.0), color.xyz() * 10.0, n.dot(ray).abs()); |
| 232 | + cf = mix(cf, Vec3::splat(2.0), da); |
| 233 | + color = (mix( |
| 234 | + color.xyz(), |
| 235 | + cf, |
| 236 | + self.mxc * self.mxc * (0.5 + n.dot(ray).abs() * 0.5), |
| 237 | + )) |
| 238 | + .extend(color.w); |
| 239 | + } |
| 240 | + |
| 241 | + color |
| 242 | + } |
| 243 | + |
| 244 | + pub fn main_image(&mut self, frag_color: &mut Vec4, frag_coord: Vec2) { |
| 245 | + let time: f32 = self.inputs.time * 0.2; //*0.1; |
| 246 | + self.res = 1.0 / self.inputs.resolution.y; |
| 247 | + let p: Vec2 = (-self.inputs.resolution.xy() + 2.0 * frag_coord) * self.res; |
| 248 | + |
| 249 | + let mut rotate: Vec3; |
| 250 | + let mut mr: Mat3; |
| 251 | + let mut ray: Vec3; |
| 252 | + let mut ray1: Vec3; |
| 253 | + let mut ray2: Vec3; |
| 254 | + let mut pos: Vec3 = vec3(0.0, 0.0, 1.0); |
| 255 | + |
| 256 | + *frag_color = vec4(0.0, 0.0, 0.0, 0.0); |
| 257 | + self.nray = Vec3::zero(); |
| 258 | + self.nray1 = Vec3::zero(); |
| 259 | + self.nray2 = Vec3::zero(); |
| 260 | + |
| 261 | + let mut refcolor: Vec4 = Vec4::zero(); |
| 262 | + self.iteratorc = ITERATIONS - LAYERS; |
| 263 | + |
| 264 | + let mut addrot: Vec2 = Vec2::zero(); |
| 265 | + if self.inputs.mouse.z > 0.0 { |
| 266 | + addrot = (self.inputs.mouse.xy() - self.inputs.resolution.xy() * 0.5) * self.res; |
| 267 | + } |
| 268 | + |
| 269 | + let mut mxcl: f32 = 1.0; |
| 270 | + let mut addpos: Vec3 = Vec3::zero(); |
| 271 | + pos.z = 1.0; |
| 272 | + self.mxc = 1.0; |
| 273 | + self.radius = 0.25; |
| 274 | + let mzd: f32 = (self.zoom - 0.1) / LAYERS; |
| 275 | + let mut i = 0; |
| 276 | + while i < LAYERSBLOB { |
| 277 | + let p2: Vec2 = p - Vec2::splat(0.25) + Vec2::splat(0.1 * i as f32); |
| 278 | + ray = p2.extend(2.0) - self.nray * 2.0; |
| 279 | + //ray = self.nray;//*0.6; |
| 280 | + ray1 = (ray + vec3(0.0, self.res * 2.0, 0.0)).normalize(); |
| 281 | + ray2 = (ray + vec3(self.res * 2.0, 0.0, 0.0)).normalize(); |
| 282 | + ray = ray.normalize(); |
| 283 | + let mut sb: Vec2 = ray.xy() * pos.length() / pos.normalize().dot(ray) + vec2(0.0, time); |
| 284 | + self.seed = (sb + vec2(0.0, pos.z)).floor() + Vec2::splat(pos.z); |
| 285 | + let mut seedn: Vec3 = self.seed.extend(pos.z); |
| 286 | + sb = sb.floor(); |
| 287 | + if noise3(seedn) > 0.2 && i < LAYERS as i32 { |
| 288 | + self.powr = noise3(seedn * 10.0) * 1.9 + 0.1; |
| 289 | + rotate = (((Vec2::splat(0.5) - noise3_2(seedn)) * time * 5.0).sin() * 0.3 + addrot) |
| 290 | + .extend(0.0); |
| 291 | + rotate.z = (0.5 - noise3(seedn + vec3(10.0, 3.0, 1.0))) * time * 5.0; |
| 292 | + seedn.z += time * 0.5; |
| 293 | + addpos = (sb + vec2(0.25, 0.25 - time) + noise3_2(seedn) * 0.5).extend(addpos.z); |
| 294 | + let sins: Vec3 = rotate.sin(); |
| 295 | + let coss: Vec3 = rotate.cos(); |
| 296 | + mr = Mat3::from_cols( |
| 297 | + vec3(coss.x, 0.0, sins.x), |
| 298 | + vec3(0.0, 1.0, 0.0), |
| 299 | + vec3(-sins.x, 0.0, coss.x), |
| 300 | + ); |
| 301 | + mr = Mat3::from_cols( |
| 302 | + vec3(1.0, 0.0, 0.0), |
| 303 | + vec3(0.0, coss.y, sins.y), |
| 304 | + vec3(0.0, -sins.y, coss.y), |
| 305 | + ) * mr; |
| 306 | + mr = Mat3::from_cols( |
| 307 | + vec3(coss.z, sins.z, 0.0), |
| 308 | + vec3(-sins.z, coss.z, 0.0), |
| 309 | + vec3(0.0, 0.0, 1.0), |
| 310 | + ) * mr; |
| 311 | + |
| 312 | + self.light = mr.transpose() * vec3(1.0, 0.0, 1.0).normalize(); |
| 313 | + // let cc: Vec4 = self.filter_flake( |
| 314 | + // *frag_color, |
| 315 | + // mr.transpose() * (pos + addpos), |
| 316 | + // (mr.transpose() * ray + self.nray * 0.1).normalize(), |
| 317 | + // (mr.transpose() * ray1 + self.nray * 0.1).normalize(), |
| 318 | + // (mr.transpose() * ray2 + self.nray * 0.1).normalize(), |
| 319 | + // ); |
| 320 | + let mut cc: Vec4 = self.filter_flake( |
| 321 | + *frag_color, |
| 322 | + mr.transpose() * (pos + addpos), |
| 323 | + mr.transpose() * ray, |
| 324 | + mr.transpose() * ray1, |
| 325 | + mr.transpose() * ray2, |
| 326 | + ); |
| 327 | + if false { |
| 328 | + if i > 0 |
| 329 | + && self.nray.dot(self.nray) != 0.0 |
| 330 | + && self.nray1.dot(self.nray1) != 0.0 |
| 331 | + && self.nray2.dot(self.nray2) != 0.0 |
| 332 | + { |
| 333 | + refcolor = self.filter_flake( |
| 334 | + refcolor, |
| 335 | + mr.transpose() * (pos + addpos), |
| 336 | + self.nray, |
| 337 | + self.nray1, |
| 338 | + self.nray2, |
| 339 | + ); |
| 340 | + } |
| 341 | + cc += refcolor * 0.5; |
| 342 | + } |
| 343 | + *frag_color = mix(cc, *frag_color, frag_color.w.min(1.0)); |
| 344 | + } |
| 345 | + seedn = sb.extend(pos.z) + vec3(0.5, 1000.0, 300.0); |
| 346 | + if noise3(seedn * 10.0) > 0.4 { |
| 347 | + let raf: f32 = 0.3 + noise3(seedn * 100.0); |
| 348 | + addpos = |
| 349 | + (sb + vec2(0.2, 0.2 - time) + noise3_2(seedn * 100.0) * 0.6).extend(addpos.z); |
| 350 | + let mut l: f32 = (ray * ray.dot(pos + addpos) - pos - addpos).length(); |
| 351 | + l = (1.0 - l * 10.0 * raf).max(0.0); |
| 352 | + *frag_color += |
| 353 | + vec4(1.0, 1.2, 3.0, 1.0) * l.powf(5.0) * ((0.6 + raf).powf(2.0) - 0.6) * mxcl; |
| 354 | + } |
| 355 | + self.mxc -= 1.1 / LAYERS; |
| 356 | + pos.z += STEP; |
| 357 | + self.iteratorc += 2.0; |
| 358 | + mxcl -= 1.1 / LAYERSBLOB as f32; |
| 359 | + self.zoom -= mzd; |
| 360 | + i += 1; |
| 361 | + } |
| 362 | + |
| 363 | + let cr: Vec3 = mix(Vec3::zero(), vec3(0.0, 0.0, 0.4), (-0.55 + p.y) * 2.0); |
| 364 | + *frag_color = (frag_color.xyz() |
| 365 | + + mix( |
| 366 | + (cr - frag_color.xyz()) * 0.1, |
| 367 | + vec3(0.2, 0.5, 1.0), |
| 368 | + ((-p.y + 1.0) * 0.5).clamp(0.0, 1.0), |
| 369 | + )) |
| 370 | + .extend(frag_color.z); |
| 371 | + |
| 372 | + *frag_color = Vec4::one().min(*frag_color); |
| 373 | + } |
| 374 | +} |
0 commit comments