Spaces:
Running
Running
Download aries/src/gl.js from Ethscriptions/POLS: direct link, hf CLI and curl.
- Browser
- Download file 5.15 kB
-
https://huggingface.co/spaces/Ethscriptions/POLS/resolve/main/aries/src/gl.js
- Command line
-
hf download hf://spaces/Ethscriptions/POLS/aries/src/gl.js
-
curl -L -o gl.js https://huggingface.co/spaces/Ethscriptions/POLS/resolve/main/aries/src/gl.js
5.15 kB
| // ♈ 白羊座 —— WebGL2 背景:域扭曲分形噪声星云 + 上升的火焰流 + 程序化星点 | |
| // 不支持 WebGL2 时返回 null,由调用方降级到 Canvas 渐变。 | |
| const VERT = `#version 300 es | |
| in vec2 p; out vec2 uv; | |
| void main(){ uv = p * .5 + .5; gl_Position = vec4(p, 0., 1.); }`; | |
| const FRAG = `#version 300 es | |
| precision highp float; | |
| in vec2 uv; out vec4 o; | |
| uniform vec2 res; uniform float t; | |
| uniform vec3 a0, a1, a2, b0, b1, b2; // 两套调色板(深/中/亮) | |
| uniform float mixk, heat, stars, bright; | |
| float h21(vec2 p){ p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } | |
| float vnoise(vec2 p){ | |
| vec2 i = floor(p), f = fract(p); vec2 u = f * f * (3. - 2. * f); | |
| return mix(mix(h21(i), h21(i + vec2(1,0)), u.x), mix(h21(i + vec2(0,1)), h21(i + vec2(1,1)), u.x), u.y); | |
| } | |
| float fbm(vec2 p){ float v = 0., a = .5; mat2 m = mat2(1.6, 1.2, -1.2, 1.6); for (int k = 0; k < 5; k++){ v += a * vnoise(p); p = m * p; a *= .5; } return v; } | |
| void main(){ | |
| vec2 q = (uv - .5) * vec2(res.x / res.y, 1.); | |
| float asp = res.x / res.y; | |
| // 域扭曲星云 | |
| vec2 w = q * 1.6; | |
| vec2 d1 = vec2(fbm(w + vec2(0., t * .02)), fbm(w + vec2(5.2, 1.3) - t * .015)); | |
| float n = fbm(w + 2.2 * d1 + vec2(t * .01, 0.)); | |
| // 向上流动的火焰丝 | |
| vec2 fq = vec2(q.x * 2.2, q.y * 1.4 - t * .12); | |
| float flame = fbm(fq + fbm(fq * 1.7 + t * .05)); | |
| flame = smoothstep(.45, 1., flame) * smoothstep(.75, -.6, q.y) * heat; | |
| vec3 c0 = mix(a0, b0, mixk), c1 = mix(a1, b1, mixk), c2 = mix(a2, b2, mixk); | |
| vec3 col = mix(c0, c1, smoothstep(.25, .75, n)); | |
| col = mix(col, c2, smoothstep(.62, .95, n) * .85); | |
| col += c2 * flame * 1.1; | |
| // 中心体积光 | |
| float glow = exp(-dot(q * vec2(.8, 1.1), q * vec2(.8, 1.1)) * 2.2); | |
| col += c1 * glow * .35 * bright; | |
| // 程序化星点(三层) | |
| float s = 0.; | |
| for (int L = 0; L < 3; L++){ | |
| float sc = 90. + float(L) * 70.; | |
| vec2 g = (uv * vec2(asp, 1.) + float(L) * 7.13 + vec2(t * .002 * float(L + 1), 0.)) * sc; | |
| vec2 id = floor(g), f = fract(g) - .5; | |
| float r = h21(id); | |
| if (r > .965){ | |
| vec2 o2 = vec2(h21(id + 3.1), h21(id + 7.7)) - .5; | |
| float dd = length(f - o2 * .6); | |
| float tw = .6 + .4 * sin(t * (1.5 + r * 4.) + r * 50.); | |
| s += smoothstep(.09, 0., dd) * tw * (1.3 - float(L) * .3); | |
| } | |
| } | |
| col += vec3(1., .95, .88) * s * stars; | |
| // 暗角 + 胶片颗粒 | |
| float vig = smoothstep(1.25, .25, length(q * vec2(.9, 1.15))); | |
| col *= mix(.35, 1., vig); | |
| col += (h21(uv * res + fract(t)) - .5) * .025; | |
| col = 1. - exp(-col * 1.25); // 柔和色调映射 | |
| o = vec4(col, 1.); | |
| }`; | |
| // 场景色调(深 / 中 / 亮) | |
| export const TONES = { | |
| ember: [[.06, .01, .02], [.55, .10, .05], [1.0, .62, .22]], | |
| dawn: [[.05, .03, .10], [.48, .16, .26], [1.0, .74, .42]], | |
| night: [[.01, .02, .07], [.12, .12, .34], [.55, .62, 1.0]], | |
| sea: [[.00, .03, .08], [.04, .24, .40], [.55, .90, 1.0]], | |
| grove: [[.01, .04, .03], [.06, .26, .16], [.95, .80, .38]], | |
| royal: [[.05, .01, .07], [.38, .06, .22], [1.0, .78, .38]], | |
| }; | |
| export function createSky() { | |
| const cv = document.createElement('canvas'); | |
| const gl = cv.getContext('webgl2', { preserveDrawingBuffer: true, antialias: false, premultipliedAlpha: false }); | |
| if (!gl) return null; | |
| const sh = (type, src) => { const s = gl.createShader(type); gl.shaderSource(s, src); gl.compileShader(s); | |
| if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(s)); return s; }; | |
| const prog = gl.createProgram(); | |
| gl.attachShader(prog, sh(gl.VERTEX_SHADER, VERT)); gl.attachShader(prog, sh(gl.FRAGMENT_SHADER, FRAG)); gl.linkProgram(prog); | |
| if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) throw new Error(gl.getProgramInfoLog(prog)); | |
| gl.useProgram(prog); | |
| const buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf); | |
| gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW); | |
| const loc = gl.getAttribLocation(prog, 'p'); gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0); | |
| const U = {}; for (const n of ['res', 't', 'a0', 'a1', 'a2', 'b0', 'b1', 'b2', 'mixk', 'heat', 'stars', 'bright']) U[n] = gl.getUniformLocation(prog, n); | |
| return { | |
| canvas: cv, | |
| // scale:背景以较低分辨率渲染再放大(星云本身很柔和) | |
| render(t, W, H, from, to, k, opt = {}) { | |
| const sc = opt.scale ?? .5; | |
| const w = Math.max(64, Math.round(W * sc)), h = Math.max(64, Math.round(H * sc)); | |
| if (cv.width !== w || cv.height !== h) { cv.width = w; cv.height = h; } | |
| gl.viewport(0, 0, w, h); | |
| gl.uniform2f(U.res, w, h); gl.uniform1f(U.t, t); | |
| const A = TONES[from] || TONES.ember, B = TONES[to] || A; | |
| gl.uniform3fv(U.a0, A[0]); gl.uniform3fv(U.a1, A[1]); gl.uniform3fv(U.a2, A[2]); | |
| gl.uniform3fv(U.b0, B[0]); gl.uniform3fv(U.b1, B[1]); gl.uniform3fv(U.b2, B[2]); | |
| gl.uniform1f(U.mixk, k); gl.uniform1f(U.heat, opt.heat ?? .6); gl.uniform1f(U.stars, opt.stars ?? 1); gl.uniform1f(U.bright, opt.bright ?? 1); | |
| gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); | |
| return cv; | |
| }, | |
| }; | |
| } | |