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



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

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

代码概述:

初始化:

  1. 创建一个随机粒子在x,y,z位置的数组

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

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

  4. 创建一个全屏四边形(-1,-1到1,1)

粒子模拟:

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

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

粒子呈现:

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

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

  3. 使用精灵纹理(gl.POINTS)绘制粒子

问题:

  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
    }
    

相关的着色器:

粒子模拟片段着色器:

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错误并记录我可以到控制台的内容。

您的quad正面对着远离视图,所以我尝试添加gl.disable(gl.CULL_FACE),仍然没有结果。

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

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

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

代码需要排序和分组,如果你已经在使用控制台,一定要检查它。

找到问题了

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

我必须传入宽度和高度的着色器变量,然后在从纹理采样之前规范化样本坐标。

最新更新