WebGL:使用FBO的粒子引擎,如何正确地从纹理中编写和采样粒子位置?

时间:2013-06-03 19:26:36

标签: glsl webgl

我怀疑我没有正确地将粒子位置渲染到我的FBO,或者在渲染时正确地对这些位置进行采样,尽管这可能不是我的代码的实际问题,不可否认。

我在这里有一个完整的jsfiddle http://jsfiddle.net/p5mdv/53/

代码的简要概述:

初始化:

  1. 在x,y,z

  2. 中创建一个随机粒子位置数组
  3. 创建纹理采样位置数组(例如,对于2个粒子,第一个粒子为0,0,下一个为0.5,0)

  4. 创建一个帧缓冲对象和两个粒子位置纹理(一个用于输入,一个用于输出)

  5. 创建全屏四(-1,-1到1,1)

  6. 粒子模拟:

    1. 使用粒子程序渲染全屏四边形(绑定帧缓冲区,将视口设置为我的粒子位置纹理的尺寸,绑定输入纹理,并从-1,-1到1,1绘制四边形) )。输入和输出纹理每帧交换。

    2. 粒子片段着色器在当前片段位置(gl_FragCoord.xy)对粒子纹理进行采样,进行一些修改,并写出修改后的位置

    3. 粒子渲染:

      1. 使用纹理采样位置的顶点缓冲区进行绘制

      2. 顶点着色器使用采样位置对粒子位置纹理进行采样,然后使用视图投影矩阵对其进行变换

      3. 使用精灵纹理(gl.POINTS)

      4. 绘制粒子

        问题:

        1. 我是否在粒子模拟步骤中正确设置了FBO的视口?即我正确渲染全屏四核吗?

          // 6 2D corners = 12 vertices 
          var vertexBuffer = new Float32Array(12);
          
          // -1,-1 to 1,1 screen quad
          vertexBuffer[0] = -1;
          vertexBuffer[1] = -1;
          
          vertexBuffer[2] = -1;
          vertexBuffer[3] = 1;
          
          vertexBuffer[4] = 1;
          vertexBuffer[5] = 1;
          
          vertexBuffer[6] = -1;
          vertexBuffer[7] = -1;
          
          vertexBuffer[8] = 1;
          vertexBuffer[9] = 1;
          
          vertexBuffer[10] = 1;
          vertexBuffer[11] = -1;
          
          // Create GL buffers with this data
          g.particleSystem.vertexObject = gl.createBuffer();
          gl.bindBuffer(gl.ARRAY_BUFFER, g.particleSystem.vertexObject);
          gl.bufferData(gl.ARRAY_BUFFER, vertexBuffer, gl.STATIC_DRAW);
          
          ...
          
          gl.viewport(0, 0, 
                  g.particleSystem.particleFBO.width,
                  g.particleSystem.particleFBO.height);
          
          ...
          
          // Set the quad as vertex buffer
          gl.bindBuffer(gl.ARRAY_BUFFER, g.screenQuad.vertexObject);
          gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
          
          // Draw!
          gl.drawArrays(gl.TRIANGLES, 0, 6);
          
        2. 我是否正确设置纹理坐标以对粒子位置进行采样?

          for(var i=0; i<numParticles; i++)
          {
              // Coordinates of particle within texture (normalized)
              var texCoordX = Math.floor(i % texSize.width) / texSize.width;
              var texCoordY = Math.floor(i / texSize.width) / texSize.height;
          
              particleIndices[ pclIdx     ] = texCoordX;
              particleIndices[ pclIdx + 1 ] = texCoordY;
              particleIndices[ pclIdx + 2 ] = 1; // not used in shader
          }
          
        3. 相关着色器:

          粒子模拟片段着色器:

          precision mediump float;
          
          uniform sampler2D mParticleTex;
          
          void main()
          {
              // Current pixel is the particle's position on the texture
              vec2 particleSampleCoords = gl_FragCoord.xy;
              vec4 particlePos = texture2D(mParticleTex, particleSampleCoords);
          
              // Move the particle up
              particlePos.y += 0.1;
              if(particlePos.y > 2.0)
              {
                  // Reset
                  particlePos.y = -2.0;
              }
          
              // Write particle out to texture
              gl_FragColor = particlePos;
          }
          

          粒子渲染顶点着色器:

          attribute vec4 vPosition;
          
          uniform mat4 u_modelViewProjMatrix;
          
          uniform sampler2D mParticleTex;
          
          void main()
          {
              vec2 particleSampleCoords = vPosition.xy;
              vec4 particlePos = texture2D(mParticleTex, particleSampleCoords);
              gl_Position = u_modelViewProjMatrix * particlePos;
              gl_PointSize = 10.0;
          }
          

          让我知道是否有更好的方法来调试这个,如果没有别的。我正在使用webgl-debug查找gl错误并将我可以记录到控制台。

2 个答案:

答案 0 :(得分:1)

你的四边形背离视图所以我尝试添加gl.disable(gl.CULL_FACE),仍然没有结果。

然后我注意到,在使用画布调整窗口面板的大小时,它实际上显示了一个黑色的方形粒子。所以渲染循环似乎并不好。

如果查看控制台日志,它无法加载粒子图像,并且它还说FBO大小为512x1,这是不好的。

某些函数声明不存在,如getTexSize。 (?!)

代码需要整理和分组,如果您已经在使用它,请务必检查控制台。

希望这有点帮助。

答案 1 :(得分:0)

发现问题。

gl_FragCoord是从[0,0]到[screenwidth,screenheight],我错误地认为它是从[0,0]到[1,1]。

我必须传递着色器变量的宽度和高度,然后在从纹理采样之前对样本坐标进行标准化。