tawasuyu

tawasuyu/brahman

Rust 582TOML 222Markdown 83JSON 198635 Definitions

⎇ 52acaabcf42e81de31acf884f80c607fe8b829fe crates/modules/gioser/gioser-shaders/src/lib.rs Rust · 204 lines · 6.5 KB History Who touched what raw

gioser 52acaabcf · sergio ·

1//! Fuentes GLSL ES 3.00 para GioSer.
2//!
3//! Cada `const &str` es un shader completo, listo para pasar a
4//! `gl.shaderSource()`. No dependemos de ningún backend; el cliente
5//! decide cómo compilarlos. Convención: precision `highp float`,
6//! atributo `a_pos`, varying `v_*`, uniforms `u_*`.
7
8#![no_std]
9
10/// Vertex shader para quads en clip-space `[-1, 1]²`.
11pub const VS_FULLSCREEN: &str = "#version 300 es
12precision highp float;
13in vec2 a_pos;
14out vec2 v_clip;
15out vec2 v_uv;
16void main() {
17    v_clip = a_pos;
18    v_uv = a_pos * 0.5 + 0.5;
19    gl_Position = vec4(a_pos, 0.0, 1.0);
20}
21";
22
23/// Fragment del fondo cósmico: FBM en 3 capas + estrellas + viñeta.
24/// Uniforms esperados: `u_resolution`, `u_time`, `u_parallax`,
25/// `u_void`, `u_nebula_a`, `u_nebula_b`, `u_stardust`.
26pub const FS_COSMOS: &str = "#version 300 es
27precision highp float;
28in vec2 v_clip;
29in vec2 v_uv;
30out vec4 fragColor;
31uniform vec2  u_resolution;
32uniform float u_time;
33uniform vec2  u_parallax;
34uniform vec3  u_void;
35uniform vec3  u_nebula_a;
36uniform vec3  u_nebula_b;
37uniform vec3  u_stardust;
38
39float hash21(vec2 p) {
40    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
41}
42float vnoise(vec2 p) {
43    vec2 i = floor(p);
44    vec2 f = fract(p);
45    f = f * f * (3.0 - 2.0 * f);
46    float a = hash21(i);
47    float b = hash21(i + vec2(1.0, 0.0));
48    float c = hash21(i + vec2(0.0, 1.0));
49    float d = hash21(i + vec2(1.0, 1.0));
50    return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
51}
52float fbm(vec2 p) {
53    float v = 0.0;
54    float a = 0.55;
55    for (int i = 0; i < 5; i++) {
56        v += a * vnoise(p);
57        p *= 2.07;
58        a *= 0.55;
59    }
60    return v;
61}
62void main() {
63    float aspect = u_resolution.x / max(u_resolution.y, 1.0);
64    vec2 uv = v_clip;
65    uv.x *= aspect;
66
67    vec2 d1 = vec2( u_time * 0.010,  u_time * 0.004) + u_parallax * 0.08;
68    vec2 d2 = vec2(-u_time * 0.016,  u_time * 0.011) + u_parallax * 0.18;
69    vec2 d3 = vec2( u_time * 0.024, -u_time * 0.019) + u_parallax * 0.34;
70
71    float n1 = fbm(uv * 0.9 + d1);
72    float n2 = fbm(uv * 2.1 + d2);
73    float n3 = fbm(uv * 4.5 + d3);
74
75    vec3 color = u_void;
76    color = mix(color, u_nebula_a, pow(n1, 1.6) * 0.70);
77    color = mix(color, u_nebula_b, pow(n2, 2.0) * 0.55);
78    color += u_nebula_a * pow(n3, 3.2) * 0.22;
79
80    float r = length(v_clip);
81    color *= 1.0 - smoothstep(0.55, 1.35, r) * 0.85;
82
83    // Estrellas brillantes (pocas, titilan).
84    vec2 sgrid = uv * 90.0;
85    vec2 sid = floor(sgrid);
86    float sh = hash21(sid);
87    float twinkle = 0.4 + 0.6 * sin(u_time * 1.7 + sh * 28.0);
88    float starMask = smoothstep(0.997, 0.9985, sh);
89    color += u_stardust * starMask * twinkle * 0.95;
90
91    // Polvo (muchas, débiles).
92    vec2 dgrid = uv * 220.0;
93    float dh = hash21(floor(dgrid));
94    float dustMask = smoothstep(0.985, 0.992, dh);
95    color += u_stardust * dustMask * 0.25;
96
97    fragColor = vec4(color, 1.0);
98}
99";
100
101/// Vertex de la chacana: aplica MVP y pasa la posición de mundo al fragment.
102pub const VS_CHACANA: &str = "#version 300 es
103precision highp float;
104in vec2 a_pos;
105out vec2 v_world;
106uniform mat4 u_mvp;
107void main() {
108    v_world = a_pos;
109    gl_Position = u_mvp * vec4(a_pos, 0.0, 1.0);
110}
111";
112
113/// Fragment de la chacana: SDF de la cruz escalonada + glow + aro + sol pulsante.
114/// Uniforms: `u_time`, `u_thickness`, `u_arm_extent`,
115/// `u_line_color`, `u_rim_color`, `u_sun_color`, `u_sun_pulse`.
116pub const FS_CHACANA: &str = "#version 300 es
117precision highp float;
118in vec2 v_world;
119out vec4 fragColor;
120uniform float u_time;
121uniform float u_thickness;
122uniform float u_arm_extent;
123uniform vec3  u_line_color;
124uniform vec3  u_rim_color;
125uniform vec3  u_sun_color;
126uniform float u_sun_pulse;
127
128float sdBox(vec2 p, vec2 b) {
129    vec2 d = abs(p) - b;
130    return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
131}
132float sdChacana(vec2 p, float s, float L) {
133    float s2 = s * 2.0;
134    float halfArm = max((L - s2) * 0.5, 0.0);
135    float armOff  = s2 + halfArm;
136    float d = sdBox(p, vec2(s, s));
137    d = min(d, sdBox(p - vec2(0.0,  1.5 * s), vec2(s2, 0.5 * s)));
138    d = min(d, sdBox(p - vec2(0.0, -1.5 * s), vec2(s2, 0.5 * s)));
139    d = min(d, sdBox(p - vec2( 1.5 * s, 0.0), vec2(0.5 * s, s2)));
140    d = min(d, sdBox(p - vec2(-1.5 * s, 0.0), vec2(0.5 * s, s2)));
141    d = min(d, sdBox(p - vec2(0.0,  armOff), vec2(s, halfArm)));
142    d = min(d, sdBox(p - vec2(0.0, -armOff), vec2(s, halfArm)));
143    d = min(d, sdBox(p - vec2( armOff, 0.0), vec2(halfArm, s)));
144    d = min(d, sdBox(p - vec2(-armOff, 0.0), vec2(halfArm, s)));
145    return d;
146}
147
148void main() {
149    vec2 p = v_world;
150    float d = sdChacana(p, u_thickness, u_arm_extent);
151
152    // Línea: gaussiana alrededor del borde.
153    float lineW = 0.013;
154    float line = exp(-(d * d) / (2.0 * lineW * lineW));
155
156    // Glow exterior cae más suave.
157    float glow = exp(-max(d, 0.0) * 7.5) * 0.55;
158
159    // Fill interior tenue (ligera niebla cyan dentro).
160    float fill = smoothstep(0.0, -0.025, d);
161
162    // Aro exterior: gran círculo que envuelve la chacana.
163    float ringR = u_arm_extent * 1.18;
164    float ringD = abs(length(p) - ringR);
165    float ringW = 0.008;
166    float ring = exp(-(ringD * ringD) / (2.0 * ringW * ringW)) * 0.75;
167
168    // Rayos sutiles (12 divisiones del círculo, como husillos del calendario).
169    float ang = atan(p.y, p.x);
170    float rays = pow(abs(cos(ang * 6.0)), 80.0)
171               * smoothstep(u_arm_extent * 1.05, ringR * 0.97, length(p))
172               * (0.18 + 0.10 * sin(u_time * 0.6));
173
174    // Sol central: gauss tight + corona suave + pulso.
175    float sunR = u_thickness * 0.55;
176    float sunDist = length(p);
177    float sun = exp(-(sunDist * sunDist) / (2.0 * sunR * sunR));
178    float corR = sunR * 4.5;
179    float corona = exp(-(sunDist * sunDist) / (2.0 * corR * corR)) * 0.45;
180    float sunMix = sun + corona * (0.75 + 0.25 * u_sun_pulse);
181
182    vec3 col = vec3(0.0);
183    col += u_line_color * line * 1.45;
184    col += u_rim_color  * glow * 1.05;
185    col += u_line_color * ring * 0.95;
186    col += u_rim_color  * rays * 1.40;
187    col += u_sun_color  * sunMix * 1.35;
188    col += vec3(0.04, 0.06, 0.12) * fill * 0.55;
189
190    float alpha = clamp(line * 1.2 + glow + ring + rays + sunMix + fill * 0.5, 0.0, 1.0);
191    fragColor = vec4(col, alpha);
192}
193";
194
195/// Geometría del quad fullscreen: dos triángulos en clip-space.
196pub const FULLSCREEN_QUAD: [f32; 12] = [
197    -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0,
198];
199
200/// Quad ligeramente mayor que la chacana para no recortar el glow ni el aro.
201pub fn chacana_quad(arm_extent: f32) -> [f32; 12] {
202    let e = arm_extent * 1.45;
203    [-e, -e, e, -e, e, e, -e, -e, e, e, -e, e]
204}