Skip to content

Commit 3b57e0c

Browse files
committed
Ported "Miracle Snowflakes" (https://www.shadertoy.com/view/Xsd3zf).
1 parent ad40252 commit 3b57e0c

File tree

3 files changed

+453
-1
lines changed

3 files changed

+453
-1
lines changed

shaders/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub mod clouds;
1515
pub mod galaxy_of_universes;
1616
pub mod heart;
1717
pub mod mandelbrot_smooth;
18+
pub mod miracle_snowflakes;
1819
pub mod phantom_star;
1920
pub mod playing_marble;
2021
pub mod protean_clouds;
@@ -126,6 +127,12 @@ pub fn fs(constants: &ShaderConstants, mut frag_coord: Vec2) -> Vec4 {
126127
})
127128
.main_image(&mut color, frag_coord),
128129
14 => soft_shadow_variation::Inputs { resolution, time }.main_image(&mut color, frag_coord),
130+
15 => miracle_snowflakes::State::new(miracle_snowflakes::Inputs {
131+
resolution,
132+
time,
133+
mouse,
134+
})
135+
.main_image(&mut color, frag_coord),
129136
_ => {}
130137
}
131138
pow(color.truncate(), 2.2).extend(color.w)

shaders/src/miracle_snowflakes.rs

Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
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

Comments
 (0)