【问题标题】:Pass audio spectrum to a shader as texture in libGDX将音频频谱作为 libGDX 中的纹理传递给着色器
【发布时间】:2020-01-02 01:28:14
【问题描述】:

我正在使用 libGDX 开发音频可视化工具。

我想将音频频谱数据(包含音频样本的 FFT 的数组)传递给我从 Shadertoy 获取的着色器:https://www.shadertoy.com/view/ttfGzH

在 GLSL 代码中,我希望制服包含作为纹理的数据:

uniform sampler2D iChannel0;

问题是我不知道如何将任意数组作为纹理传递给 libGDX 中的着色器。

我已经在 SO 和 libGDX 的论坛中进行了搜索,但我的问题没有令人满意的答案。

这是我的 Kotlin 代码(显然不起作用 xD):

val p = Pixmap(512, 1, Pixmap.Format.Alpha)
val t = Texture(p)
val map = p.pixels
map.putFloat(....) // fill the map with FFT data
[...]
t.bind(0)
shader.setUniformi("iChannel0", 0)

【问题讨论】:

  • 如果在将数据加载到Pixmap 后创建Texture 会怎样?
  • @Genhis 没什么兄弟 :(
  • 你应该在设置制服之前调用 shader.begin()。

标签: kotlin libgdx glsl shader


【解决方案1】:

您可以简单地使用 drawPixel 方法并将数据存储在每个像素的第一个通道中,就像在 shadertoy 示例中一样(它们使用红色通道)。

float[] fftData = // your data

Color tmpColor = new Color();
Pixmap pixmap = new Pixmap(fftData.length, 1, Pixmap.Format.RGBA8888);
for(int i = 0; i < fftData.length i++)
{
    tmpColor.set(fftData[i], 0, 0, 0); // using only 1 channel per pixel
    pixmap.drawPixel(i, 0, Color.rgba8888(tmpColor));
}
// then create your texture and bind it to the shader

为了提高效率并减少 4 倍的内存(根据着色器可能还需要更少的样本),您可以通过将数据拆分到 r、g、b 和 a 通道​​来使用每个像素 4 个通道。但是,这会使着色器复杂一点。

在您提供的着色器示例中传递的这些数据不是任意的,它的精度非常有限,范围在 0 和 1 之间。如果您想提高精度,您可能希望跨多个通道存储浮点数(尽管着色器中的 IEEE 重组可能很痛苦)或传递一个整数以按比例缩小(固定点)。如果你需要 -inf 和 inf 之间的数据,你可以使用 sigmoid 和 anti sigmoig 函数,代价是再次大大降低精度。我相信这种技术适用于您的示例,因为它们似乎只需要 0 到 1 之间的值,并且精度并不是非常重要,因为结果是平滑的。

【讨论】:

  • 由于这是一个实时更新的 FFT,我认为您只想创建一次纹理和像素图,并在每次更新数据时使用texture.draw(pixmap, 0, 0) 应用像素图更改。
猜你喜欢
  • 2016-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-20
  • 1970-01-01
  • 2017-12-27
  • 1970-01-01
相关资源
最近更新 更多