You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Phaser3 麦克风输入Shader实现音频可视化遇阻求助

解决Phaser 3中麦克风音频数据传入Shader的问题

核心问题在于你需要将Uint8Array格式的音频数据转换为Phaser Shader可识别的纹理对象,而非直接传递数组。以下是具体实现步骤:


1. 创建可更新的Canvas纹理

在场景的create方法中,先创建一个与音频数组长度匹配的Canvas纹理(这里是1024x1,对应1024个音频样本):

create() {
  this.shader = this.add.shader('simplesound', 400, 300, 800, 600);

  // 创建1024x1的Canvas纹理,用于承载音频数据
  this.audioTexture = this.textures.createCanvas('audioTexture', 1024, 1);
  this.audioCtx = this.audioTexture.getContext();
  
  // 初始化纹理(避免初始黑帧)
  const initData = new Uint8Array(1024 * 4); // RGBA格式,每个像素4字节
  this.audioCtx.putImageData(new ImageData(new Uint8ClampedArray(initData), 1024, 1), 0, 0);
  this.audioTexture.refresh();

  const GKey = this.input.keyboard.addKey('G');
  GKey.on('down', () => {
    setupAudioContext((array) => {
      // 后续更新纹理逻辑写在这里
    });
  });
}

2. 在音频回调中更新纹理数据

每次获取到麦克风的Uint8Array数据后,将其写入Canvas纹理的R通道(其他通道固定为255保证不透明),然后刷新纹理并传递给Shader:

GKey.on('down', () => {
  setupAudioContext((array) => {
    const imageData = this.audioCtx.getImageData(0, 0, 1024, 1);
    const data = imageData.data;

    // 将Uint8Array音频值写入纹理的R通道
    for (let i = 0; i < array.length; i++) {
      data[i * 4] = array[i];     // R通道存储音频样本(0-255)
      data[i * 4 + 1] = 255;      // G通道固定
      data[i * 4 + 2] = 255;      // B通道固定
      data[i * 4 + 3] = 255;      // Alpha通道不透明
    }

    // 更新纹理并传递给Shader的iChannel0
    this.audioCtx.putImageData(imageData, 0, 0);
    this.audioTexture.refresh();
    this.shader.setChannel0(this.audioTexture);
  });
});

3. 调整Shader采样逻辑

由于纹理是1024x1的一维纹理,需要修改Shader中的采样方式,用uv.x对应音频样本的索引,同时将纹理值从0-255范围转换为0-1的归一化值:

#ifdef GL_ES
precision highp float;
#endif

precision mediump float;
uniform vec2 resolution;
uniform sampler2D iChannel0;

varying vec2 fragCoord;

void main() {
  vec2 uv = fragCoord.xy / resolution.xy;
  
  // 采样1024x1纹理:x轴对应音频样本索引,y轴取纹理中间位置
  float audioValue = texture2D(iChannel0, vec2(uv.x, 0.5)).r / 255.0;

  // 可视化逻辑:绘制随音频变化的水平线
  float y = abs(uv.y - audioValue);
  float intensity = smoothstep(0.0, 0.02, y);

  gl_FragColor = vec4(1.0 - intensity, 0.2, 0.2, 1.0); // 红色波形
}

关键注意事项

  • 确保纹理尺寸与音频数组长度完全一致(这里都是1024),否则采样会出现错位。
  • 使用setChannel0时必须传递Phaser的Texture对象,而非原始Canvas或数组。
  • Shader中要将纹理的8位值转换为0-1的归一化值,否则计算会超出范围。

内容的提问来源于stack exchange,提问作者rikas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:15:42