EHOT & Afterlight
Afterlight Afterlight
Привет, я тут разрабатываю движок визуализации, который реагирует на звук в реальном времени – превращает каждый бит в живую картину. Типа, как будто мы в режиме реального времени взламываем чувства. Хочешь посмотреть, что из этого можно выжать?
EHOT EHOT
Круто, я вообще фанат косяков. На чём это гоняете? WebGL, OpenGL, Vulkan? Выложи демо или кусочек кода, посмотрим, как это заставить работать как надо.
Afterlight Afterlight
Привет, Запускаю это в браузере через WebGL 2, использую Three.js для трехмерной структуры и GLSL фрагментный шейдер, реагирующий на данные FFT. Основной цикл выглядит примерно так: ```javascript // init renderer, camera, scene const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); camera.position.z = 5; // create a full‑screen quad with a shader material const geometry = new THREE.PlaneGeometry(2, 2); const material = new THREE.ShaderMaterial({ uniforms: { uTime: { value: 0 }, uFreq: { value: new Float32Array(64) } // placeholder for audio spectrum }, vertexShader: `void main(){ gl_Position = vec4(position,1.0); }`, fragmentShader: ` uniform float uTime; uniform sampler1D uFreq; void main(){ float freq = texture(uFreq, gl_FragCoord.x / 128.0).r; vec3 color = vec3(sin(uTime+freq*10.0), cos(uTime+freq*10.0), sin(uTime-freq*5.0)); gl_FragColor = vec4(color,1.0); }` }); scene.add(new THREE.Mesh(geometry, material)); // audio setup const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const analyser = audioCtx.createAnalyser(); analyser.fftSize = 128; // connect microphone or audio element navigator.mediaDevices.getUserMedia({ audio:true }).then(stream => { const source = audioCtx.createMediaStreamSource(stream); source.connect(analyser); }); const freqArray = new Uint8Array(analyser.frequencyBinCount); function animate(time){ requestAnimationFrame(animate); analyser.getByteFrequencyData(freqArray); material.uniforms.uFreq.value = freqArray; material.uniforms.uTime.value = time * 0.001; renderer.render(scene, camera); } animate(0); ``` Это основа. Подключи это к своему треку, подкрути шейдер, и у тебя будет живая, дышащая визуализация, которая отзывается на каждый удар баса. Хочешь добавить свой VU метр или взрыв частиц? Просто перемиксуй uniform’ы и код шейдера — глитчи — новый бит!
EHOT EHOT
Отличная настройка, но шейдер какой-то вялый – текстуры ищешь по gl_FragCoord.x, получится только одна линия. Попробуй лучше спектр на UV-координаты отобразить, или 2D-текстуру от анализатора подай. И не забудь, WebGL может быть придирчив к sampler1D, можно нарваться на запасной вариант. Могу быстро скинуть кусочек кода, который расширит твой uFreq в 1D-текстуру и использует линейную интерполяцию. Нужна? Только дай знать.
Afterlight Afterlight
Конечно, вот небольшое улучшение: превращает массив FFT в текстуру 2D, состоящую из одной строки, и передает её sampler2D с линейной фильтрацией: ```javascript // создаём текстуру из данных анализатора const freqTexture = new THREE.DataTexture( new Uint8Array(analyser.frequencyBinCount), // ширина = binCount, высота = 1 analyser.frequencyBinCount, 1, THREE.LuminanceFormat, THREE.UnsignedByteType ); freqTexture.needsUpdate = true; freqTexture.minFilter = THREE.LinearFilter; freqTexture.magFilter = THREE.LinearFilter; // передаём текстуру шейдеру const material = new THREE.ShaderMaterial({ uniforms: { uTime: { value: 0 }, uFreqTex: { value: freqTexture } }, vertexShader: `void main(){ gl_Position = vec4(position,1.0); }`, fragmentShader: ` uniform float uTime; uniform sampler2D uFreqTex; void main(){ // сопоставляем gl_FragCoord.x с текстурными координатами по ширине float texX = gl_FragCoord.x / 128.0; // 128 = ширина холста float freq = texture(uFreqTex, vec2(texX, 0.5)).r; vec3 color = vec3(sin(uTime+freq*10.0), cos(uTime+freq*10.0), sin(uTime-freq*5.0)); gl_FragColor = vec4(color,1.0); }` }); scene.add(new THREE.Mesh(geometry, material)); // цикл обновления: копируем данные FFT в текстуру function animate(time){ requestAnimationFrame(animate); analyser.getByteFrequencyData(freqArray); freqTexture.image.data.set(freqArray); freqTexture.needsUpdate = true; material.uniforms.uTime.value = time * 0.001; renderer.render(scene, camera); } animate(0); ``` Просто замени старый шейдер и логику работы с текстурой на это, и ты получишь плавные, интерполированные значения частоты на весь экран. Дай знать, как танцы получатся!
EHOT EHOT
Отлично подправил, но ты жестко задал ширину – 128. Если канва изменит размер, texX будет неправильным, и спектр обрежется. Передавай разрешение как uniform и рассчитывай texX = gl_FragCoord.x / resolution.x. И ещё, если нужно больше 256 ячеек, используй THREE.RGBAFormat и тип данных с большей точностью – картинка останется четкой.