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

Glsl WebGL:使用FBO的粒子引擎,如何从纹理正确写入和采样粒子位置?,glsl,webgl,Glsl,Webgl,我怀疑我没有正确地将粒子位置渲染到FBO,或者在渲染时没有正确地对这些位置进行采样,尽管无可否认,这可能不是我的代码的实际问题 我这里有一个完整的jsfiddle: 代码的简要概述: 初始化: 在x、y、z方向创建一个随机粒子位置数组 创建纹理采样位置阵列(例如,对于2个粒子,第一个粒子位于0,0,下一个位于0.5,0) 创建一个帧缓冲区对象和两个粒子位置纹理(一个用于输入,一个用于输出) 创建一个全屏四元组(-1,-1到1,1) 粒子模拟: 使用粒子程序渲染全屏四边形(绑定帧缓冲区,将视口设置

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

我这里有一个完整的jsfiddle

代码的简要概述:

初始化:

  • 在x、y、z方向创建一个随机粒子位置数组

  • 创建纹理采样位置阵列(例如,对于2个粒子,第一个粒子位于0,0,下一个位于0.5,0)

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

  • 创建一个全屏四元组(-1,-1到1,1)

  • 粒子模拟:

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

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

  • 粒子渲染:

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

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

  • 使用精灵纹理(gl点)绘制粒子

  • 问题:

  • 我是否在粒子模拟步骤中正确设置了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);
    
  • 我是否正确设置纹理坐标以采样粒子位置

    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
    }
    
    粒子渲染顶点着色器:

    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错误,并将我所能做的记录到控制台。

    您的四元菜单面朝远离视图,因此我尝试添加gl.disable(gl.CULL_FACE),但仍然没有结果

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

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

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

    代码需要整理和分组,如果您已经在使用console,请始终检查它

    希望这有点帮助。

    发现了问题

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


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

    谢谢!我没意识到那辆四轮车走错了方向。渲染粒子为黑色的原因是粒子精灵图像未实际加载,因此这是意料之中的。FBO应该是512x1,因为有512个粒子,为什么这样不好?getTexSize在顶部声明,它选择一个纹理大小,使得像素数==粒子数(因此为512x1)。
    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;
    }