Feature: visualization selector
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { VisualizerInterface } from './VisualizerInterface.js';
|
||||
|
||||
const fragmentShader = `
|
||||
uniform float u_time;
|
||||
uniform float u_beat;
|
||||
uniform float u_opacity;
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec3 u_colors[16];
|
||||
uniform int u_colorCount;
|
||||
uniform float u_seed;
|
||||
varying vec2 vUv;
|
||||
|
||||
vec3 hsv2rgb(vec3 c) {
|
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
float ledCountX = u_resolution.x;
|
||||
float ledCountY = u_resolution.y;
|
||||
|
||||
vec2 gridUV = vec2(vUv.x * ledCountX, vUv.y * ledCountY);
|
||||
|
||||
vec2 gridDeriv = fwidth(gridUV);
|
||||
float gridDensity = max(gridDeriv.x, gridDeriv.y);
|
||||
float blurFactor = smoothstep(0.3, 0.8, gridDensity);
|
||||
|
||||
vec2 cell = fract(gridUV);
|
||||
vec2 uv = mix((floor(gridUV) + 0.5) / vec2(ledCountX, ledCountY), vUv, blurFactor);
|
||||
|
||||
float dist = distance(cell, vec2(0.5));
|
||||
float edgeSoftness = clamp(gridDensity * 1.5, 0.0, 0.5);
|
||||
float mask = 1.0 - smoothstep(0.35 - edgeSoftness, 0.45 + edgeSoftness, dist);
|
||||
mask = mix(mask, 1.0, blurFactor);
|
||||
|
||||
float d = length(uv - 0.5);
|
||||
float angle = atan(uv.y - 0.5, uv.x - 0.5);
|
||||
|
||||
float wave = sin(d * 20.0 - u_time * 2.0 + u_seed);
|
||||
float beatWave = sin(angle * 5.0 + u_time + u_seed * 0.1) * u_beat;
|
||||
|
||||
float hue = fract(u_time * 0.1 + d * 0.2 + u_seed * 0.01);
|
||||
float val = 0.5 + 0.5 * sin(wave + beatWave);
|
||||
|
||||
vec3 finalColor;
|
||||
if (u_colorCount > 0) {
|
||||
float indexFloat = hue * float(u_colorCount);
|
||||
int index = int(mod(indexFloat, float(u_colorCount)));
|
||||
vec3 c = vec3(0.0);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == index) {
|
||||
c = u_colors[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
finalColor = c * val;
|
||||
} else {
|
||||
finalColor = hsv2rgb(vec3(hue, 0.8, val));
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(finalColor, mask * u_opacity);
|
||||
}
|
||||
`;
|
||||
|
||||
export class ClassicVisualizer extends VisualizerInterface {
|
||||
getName() {
|
||||
return "Classic Wave";
|
||||
}
|
||||
|
||||
getFragmentShader() {
|
||||
return fragmentShader;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { VisualizerInterface } from './VisualizerInterface.js';
|
||||
|
||||
const fragmentShader = `
|
||||
uniform float u_time;
|
||||
uniform float u_beat;
|
||||
uniform float u_opacity;
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec3 u_colors[16];
|
||||
uniform int u_colorCount;
|
||||
uniform float u_seed;
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
float ledCountX = u_resolution.x;
|
||||
float ledCountY = u_resolution.y;
|
||||
|
||||
vec2 gridUV = vec2(vUv.x * ledCountX, vUv.y * ledCountY);
|
||||
|
||||
vec2 gridDeriv = fwidth(gridUV);
|
||||
float gridDensity = max(gridDeriv.x, gridDeriv.y);
|
||||
float blurFactor = smoothstep(0.3, 0.8, gridDensity);
|
||||
|
||||
vec2 cell = fract(gridUV);
|
||||
vec2 uv = mix((floor(gridUV) + 0.5) / vec2(ledCountX, ledCountY), vUv, blurFactor);
|
||||
|
||||
float dist = distance(cell, vec2(0.5));
|
||||
float edgeSoftness = clamp(gridDensity * 1.5, 0.0, 0.5);
|
||||
float mask = 1.0 - smoothstep(0.35 - edgeSoftness, 0.45 + edgeSoftness, dist);
|
||||
mask = mix(mask, 1.0, blurFactor);
|
||||
|
||||
vec2 p = (uv - 0.5) * 2.0;
|
||||
float r = length(p);
|
||||
float a = atan(p.y, p.x);
|
||||
|
||||
float t = u_time * 0.5 + u_seed;
|
||||
|
||||
float noise = sin(p.x * 10.0 + t) * cos(p.y * 10.0 - t) * 0.5 + 0.5;
|
||||
float nebula = sin(r * 15.0 - t * 2.0 + noise * 5.0) * 0.5 + 0.5;
|
||||
|
||||
vec3 color1 = vec3(0.1, 0.0, 0.3);
|
||||
vec3 color2 = vec3(0.8, 0.2, 0.5);
|
||||
|
||||
if (u_colorCount >= 2) {
|
||||
color1 = u_colors[0];
|
||||
color2 = u_colors[1];
|
||||
}
|
||||
|
||||
vec3 finalColor = mix(color1, color2, nebula);
|
||||
|
||||
// Add some pulsing highlights based on beat
|
||||
float ring = smoothstep(0.4, 0.5, abs(fract(r * 2.0 - t * 4.0) - 0.5));
|
||||
finalColor += color2 * ring * u_beat * 0.5;
|
||||
|
||||
// Edge glow
|
||||
float edge = 1.0 - smoothstep(0.3, 0.5, r);
|
||||
finalColor += color1 * edge * (0.2 + u_beat * 0.3);
|
||||
|
||||
finalColor *= (0.4 + u_beat * 0.6);
|
||||
|
||||
gl_FragColor = vec4(finalColor, mask * u_opacity);
|
||||
}
|
||||
`;
|
||||
|
||||
export class NebulaVisualizer extends VisualizerInterface {
|
||||
getName() {
|
||||
return "Deep Nebula";
|
||||
}
|
||||
|
||||
getFragmentShader() {
|
||||
return fragmentShader;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export class VisualizerInterface {
|
||||
getName() {
|
||||
return "Generic Visualizer";
|
||||
}
|
||||
|
||||
getFragmentShader() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ClassicVisualizer } from './ClassicVisualizer.js';
|
||||
import { NebulaVisualizer } from './NebulaVisualizer.js';
|
||||
|
||||
export const visualizerLibrary = [
|
||||
new ClassicVisualizer(),
|
||||
new NebulaVisualizer(),
|
||||
];
|
||||
|
||||
export default visualizerLibrary;
|
||||
Reference in New Issue
Block a user