通过纹理将浮点数组传递给片段着色器

时间:2018-03-20 11:25:47

标签: glsl webgl pixi.js

我试图通过纹理将一个浮点数组(在我的例子中是一个音频波)传递给片段着色器。它有效但我得到一些不完美的东西,好像从1px高度纹理读取的值不可靠。

enter image description here

条形宽度和金额的许多组合会发生这种情况。

我从纹理中获取值:

precision mediump float;
...
uniform sampler2D uDisp;
...
void main(){
  ...
  float columnWidth = availableWidth / barsCount;
  float barIndex = floor((coord.x-paddingH)/columnWidth);
  float textureX = min( 1.0, (barIndex+1.0)/barsCount );
  float barValue = texture2D(uDisp, vec2(textureX, 0.0)).r;
  ...

如果不使用纹理中的值而使用其他东西,那么问题似乎就不存在了。

barValue = barIndex*0.1;

enter image description here

知道可能是什么问题吗?为此目的使用纹理是个坏主意吗? 我使用Pixi.JS作为WebGL框架,因此我无法访问低级API。

对于数据和许多条形的渐变纹理,问题变得非常明显。

enter image description here

更新:看起来这个问题与textureX值的一致性有关。 尝试使用barIndex/(barsCount-1.0)等不同的公式可以减少噪音。将其包裹在min上肯定会增加更多噪音。

2 个答案:

答案 0 :(得分:1)

原来问题不在于从纹理中读取值,而是在绘图中。我没有使用IF,而是切换到步骤,问题就消失了。

vec2 topLeft = vec2(
  paddingH + (barIndex*columnWidth) + ((columnWidth-barWidthInPixels)*0.5),
  top
);
vec2 bottomRight = vec2(
  topLeft.x + barWidthInPixels,
  bottom
);
vec2 tl = step(topLeft, coord);
vec2 br = 1.0-step(bottomRight, coord);
float blend = tl.x * tl.y * br.x * br.y;

我想通过IF对浮点数进行比较在着色器中并不十分可靠。

答案 1 :(得分:0)

通常mediump不足以用于任何非平凡纹理的纹理坐标,因此尽可能使用highp。这在一些较旧的GPU上始终不可用,因此根据平台,这可能无法解决您的问题。

如果您知道您正在进行1:1映射,那么也使用GL_NEAREST而不是GL_LINEAR,因为量化效果更可能隐藏一些精确的副作用。

鉴于你可能知道列和条的数量,你可以预先计算CPU上的一些值(例如预计算1/columns并以fp32精度传递它)。传递0到1之间的小值总是要更好地保持浮点精度,而不是传递大值然后分割。