WebGL / Three.js - 在移动相机时,由纹理着色的粒子不规则地闪烁

时间:2014-12-11 03:05:23

标签: javascript three.js webgl

这是一个jsfiddle我把它放在一起,展示了粒子问题"闪烁"在使用纹理着色并且相机移动时。

更新:粒子上不应出现动画或移动。如果在视口上单击并拖动并且粒子闪烁或根本不会改变颜色,那么您将看到问题。这是我在mac OS 10.9和Windows 7上使用firefox和chrome测试过的问题。

粒子不会以任何方式重叠或裁剪。如果使用常规着色器对粒子进行动画处理,则不会发生闪烁。只有在使用纹理对粒子进行着色时(在本例中使用THREE.WebGLRenderTarget),才会出现闪烁现象。这样做是为了捕获先前的帧并将它们存储在缓冲区中(然后可以以更高级的方式使用,而不是在jsfiddle示例中显示)。

实际上,片段着色器可能会错误地抓取邻居像素,而不是它的目标,但我不确定 - 这并没有多大意义,因为目标坐标只在init()上生成,并且在此之后不会发生变化。

每个粒子的目标像素坐标作为顶点属性传递给片段着色器1-1不变(作为变化但没有变化的值)。

uniform sampler2D colorMap; // The texture being used to color each particle
varying float v_geoX; // x,y coordinates passed as varyings
varying float v_geoY;

void main() {
    // Normally pulling the correct color, but this seems to get confused during camera movement.
    gl_FragColor = texture2D(colorMap, vec2(v_geoX, v_geoY));
}

如果没有闪烁,任何人都有关于如何做到这一点的想法?当我将这种技术应用于更大更快的动画时,问题似乎变得更糟。它到目前为止我检查过的所有浏览器上都会发生。

1 个答案:

答案 0 :(得分:1)

问题是你指向纹素之间的边缘。

这些行

   geoX.push(tx / imageSize);
   geoY.push(1.0 - ty / imageSize); // flip y

计算纹素之间的精确边缘。我的意思是说imageSize是4个纹素,让我们说txty0转到3

你的纹理坐标是这样的

   0    0.25  0.5   0.75       <- texture coords you're computing
   |     |     |     |     
   V     V     V     V     
   +-----+-----+-----+-----+
   |     |     |     |     |
   |     |     |     |     |   <- texels
   +-----+-----+-----+-----+

但你想要的纹理坐标是这样的

     0.125 0.375 0.625 0.875   
      |     |     |     |   
      V     V     V     V  
   +-----+-----+-----+-----+
   |     |     |     |     |
   |     |     |     |     |   <- texels
   +-----+-----+-----+-----+

最简单的解决方法是添加1/2个纹素

   geoX.push(tx / imageSize       + 0.5 / imageSize);
   geoY.push(1.0 - ty / imageSize + 0.5 / imageSize); // flip y

问题在于你的数学直接指向纹素,舍入错误使它选择一个纹素或另一个。选择纹素的中心将解决这个问题。如果图像在相邻纹素之间没有那么多对比,那么你可能没有注意到。