Анимация Специальный (2) Музыка Ритм

внешний интерфейс анимация
Анимация Специальный (2) Музыка Ритм

Два дня назад, когда Netease облачные песни, увидеть функцию, называемую звуками китов, следующие моменты в долго, как это. Это очень распространенная анимация музыкального ритма во время воспроизведения музыки, дрожание компакт-диска по кривой, чтобы оказать двойное воздействие на слуховое восприятие слушателя.

律动

Сегодня я пытаюсь использовать код для достижения [аналогичного] эффекта, взволнованные друзья могут пропустить статью и просмотреть ее напрямую.окончательный эффект. Друзья, кому это нравится, не скупитесь на лайки, комментарии и внимание, чтобы у меня было больше мотивации для создания статей по теме.

效果

(Звуковой эффект кита NetEase на самом деле эксклюзивен для виниловых VIP-клиентов.)

Резюме

Эта статья по умолчанию требует, чтобы читатели освоилиCanvasОсновное использование, если оно не знакомо со студентами, может сначаларассмотрение. Следующее содержание не будет повторять, как использоватьCanvasОсновы рисования линий.

.

.讲到随机第一反应当然是Math.random(), этот метод JS может генерировать случайные числа от 0 до 1 в среднем с вероятностью. Однако, поскольку его случайные результаты слишком дискретны, результаты двух исполнений до и после не имеют корреляции, а результаты, непосредственно используемые в видении, часто не идеальны. Например, на плоскости каждый раз, когда горизонтальная координата перемещается на один пиксель, вертикальная координата принимает случайную высоту и соединяет переднюю и заднюю координаты, затемMath.random()Результат такой.

毫无章法的线条

Очевидно, что такой случайный метод не может быть преобразован в анимацию случайной кривой.Чтобы добиться естественной анимации случайных линий при рендеринге, в этом примере используется метод, называемыйBerlin Noiseалгоритм.

Что такое Берлинский шум?

Berlin NoiseЭто очень мощный алгоритм, который часто используется для создания случайного контента, такого как волны, волнообразные материалы или текстуры в игровом поле.Berlin NoiseСуществует понятие размерности: например, одномерное изображение можно использовать для имитации нарисованных от руки линий, а двухмерное — для создания плоских эффектов, таких как пламя и туман.

Как обычный пользователь алгоритма, конкретная реализация алгоритма временно размещается. отgithubНайдите соответствующую библиотеку реализации на simplex-noise. Напишем две демки, чтобы интуитивно ощутить всю прелесть этого алгоритма.

Основное использование симплексного шума

const simplex = new SimplexNoise();
const value2d = simplex.noise2D(x, y);
const value3d = simplex.noise3D(x, y, z);
const value4d = simplex.noise4D(x, y, z, w);

Создавая конструктор экземпляра, существуют методы MOSE2D, SHOOM3D, SHOOM4D может быть вызван на экземпляр, количество и размеры соответствующих параметров, пройти два 2D, 3D, чтобы пройти три. Эти методы вернут результат алгоритма расчета, полученный интервал[-0.5, 0.5].

Или исходный пример, он изменяется на каждую абсциссу, перемещающую пиксель, а ордината изменяется в соответствии с вычисляемым параметром времени TY (каждый раз).noiseрезультат.

// noise2D 返回的结果是[-0.5, 0.5] 的区间值,后面的计算是为了让线条落在在屏幕内
this.y = this.noise.noise2D(this.ty, 0) * window.innerHeight * 0.5 + window.innerHeight * 0.5;

Обратите внимание на приведенный выше пример иMath.random()Пример,Скорость движения по оси абсцисс та же, без увеличения по оси абсцисс, и нет никакого кода, связанного с кривой Безье, естественная кривая на изображении генерируется шумом. ты сможешьCodepenИзмените код выше, чтобы увидеть эффект.

Из изображения видно, что существует определенная связь между двумя соседними случайными значениями y. Разница между двумя значениями y до и после связана с параметрами, переданными в noise2D. В приведенном выше примере он будет изменяться после каждого рендеринга.tyПараметр, который под воздействием результатов шума.

// 每次重绘之后,修改 ty
this.ty += 0.01;

Чем ближе два параметра до и после, тем меньше результирующий зазор, чем больше зазор, тем больше зазор. Вы можете изменить тест кода на CODEPEN.

this.ty += 0.001;

this.ty += 0.1;

Ось х движется с той же скоростью

также может быть сгенерирован с помощью Noise3DСлучайная анимация изображения. (Достаточно случайного изображения 2D, для анимации используется еще одно измерение)

Основной код выглядит следующим образом:

ctx.save();
const size = 800;

var imgData = ctx.createImageData(size, size);
this.tx = 0;
for (var x = 0; x < size; x++) {
  this.ty = 0;
  for (var y = 0; y < size; y++) {
    // noise 随机生成一个 alpha 值
    const alpha = (this.noise.noise3D(this.tx, this.ty, this.tz) + 0.5) * 255;
    const index = (x + y * size) * 4;
    imgData.data[index + 3] = alpha;
    this.ty += 0.01;
  }
  this.tx += 0.01;
}
ctx.putImageData(imgData, 0, 0);
ctx.restore();
this.tz += 0.01;

Приведенный выше код выполняет итерацию по каждому пикселю и вызывает метод Noise3D для генерации случайного значения альфа-канала. Передаются три параметра. Логика расчета tx и ty заключается в том, чтобы сделать два соседних пикселя ближе, а наличие tz заключается в том, чтобы каждая перерисовка производила новые изменения для создания анимации. Если tz является фиксированным значением, то изображение не изменится после его создания.

Заключение: при использовании метода шума необходимо пройти все значения измерений, введите одни и те же значения измерений, получат тот же результат. Входящие аналогичные значения измерений, то в следующий раз случайный результат и результат операций будут аналогичны последнему полученному.

заявление

Berlin Noise

первая попытка

for (let degree = 0; degree < 360; degree++) {
  const radius = (degree / 180) * Math.PI;
  const length =
    base +
    this.noise.noise2D(
      radius,
      t
    ) *
      scale;

  this.vectors.push({
    x: length * Math.cos(radius),
    y: length * Math.sin(radius),
  });
}

this.drawLine();

Здесь сгенерированная координатная позиция предназначена не для того, чтобы напрямую генерировать значения x, y точки случайным образом, а для того, чтобы сначала создать [случайную длину], а затем преобразовать длину и угол в значения координат. Однако непосредственный результат таков.

首次尝试

Поскольку радиус отправной точки и конечной точки не связан напрямую, будет очень очевидный раскол, когда он отражен в анимации.

периодический, вычислите значение синуса/косинуса каждого угла как параметр размерности шума, тогда координаты каждых двух соседних точек аналогичны, и окончательный результат аналогичен.

Измените код:

const length =
    base +
    this.noise.noise2D(
      Math.cos(radius),
      Math.sin(radius),
      t
    ) *
      scale;

В этом же примере также используется метод Noise3D.Третий параметр t будет увеличиваться каждый раз при его рендеринге.Каждый раз, когда происходит новое изменение, результаты вычисления шума разные (но похожие), таким образом формируя анимацию.

Последние из этих пунктов, чтобы строки вместе сильный ритм, сопровождаемый музыкой.

效果

С крутым рэпом, если увидишь это, не пропустиЧистая версия. Весь код можно найти в моемCodePenнашел на главной странице.

На шаг ближе

Пока что музыка не является объединением с анимацией, связь может использоваться при необходимостиAudio APIПолучите информацию о кадре музыки, отраженные на анимации в режиме реального времени.

const audioElement = document.getElementById("audio");
// 创建 audio context
const audioContext = new AudioContext();
const audioSource = audioContext.createMediaElementSource(audioElement);

// 创建解析器
const analyser = audioContext.createAnalyser();

// 关联解析器,最终输出到设备音响
audioSource.connect(analyser);
analyser.connect(audioContext.destination);

// 样本的窗口大小
analyser.fftSize = 256;

const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);

function renderFrame() {
    requestAnimationFrame(renderFrame);
    // 每个 requestAnimationFrame 回调里面更新 dataArray
    analyser.getByteFrequencyData(dataArray);
    // 音频数据
    console.log(dataArray);
}

Цитировать

Я также открыл общедоступную учетную запись WeChat, добро пожаловать, чтобы отсканировать код, чтобы следовать, и последующий контент будет продолжать обновляться в общедоступной учетной записи.