我正在使用 libGDX 开发音频可视化工具。
我想将音频频谱数据(包含音频样本的 FFT 的数组)传递到我从 Shadertoy 获取的着色器:https://www.shadertoy.com/view/ttfGzH .
在 GLSL 代码中,我期望一个包含数据作为纹理的制服:
均匀采样器2D 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)
最佳答案
您可以简单地使用drawPixel
方法并将数据存储在每个像素的第一个 channel 中,就像在shadertoy示例中一样(它们使用红色 channel )。
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 channel ,为每个像素使用 4 个 channel 。但是,这会使着色器变得有点复杂。
您提供的着色器示例中传递的数据不是任意的,它的精度非常有限,范围在 0 到 1 之间。如果您想提高精度,您可能需要跨多个 channel 存储浮点(尽管着色器中的 IEEE 重组可能很痛苦)或传递要缩小的整数(定点)。如果您需要 -inf 和 inf 之间的数据,您可以使用 sigmoid 和 anti sigmoig 函数,但代价是再次大幅降低精度。我相信这种技术适用于您的示例,因为它们似乎只需要 0 到 1 之间的值,并且精度并不是非常重要,因为结果是平滑的。
关于kotlin - 将音频频谱作为 libGDX 中的纹理传递给着色器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59557460/