WebGL - 连续应用多个程序

WebGL - apply several programs successively

如何让 WebGl 连续应用多个程序,例如

在这个例子中,很容易将所有这些放在一个着色器中,但我希望能够将它们分开以便更大着色器的可重用性。

到目前为止,我有类似的东西

gl = canvas.getContext("webgl");
gl.viewport(0, 0, canvas.width, canvas.height);

fragmentShader = attachShader(fragmentShaderCode, gl, gl.FRAGMENT_SHADER);
vertexShader = attachShader(vertexShaderCode, gl, gl.VERTEX_SHADER);

program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);

gl.useProgram(program);

// attach textures and variables

gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);

而且我不确定如何添加第二遍以有效地从第一遍获取输入。我最好的猜测是使用第二个 canvas 将第一个作为纹理输入。但这听起来像是渲染了两次,这并不好。

您确实想再次渲染,但您需要获取第一遍的输出并将其用作第二遍的输入纹理。

交换纹理和绘制矩形(两个三角形)很便宜,尤其是在现代可编程硬件上。

对于简单效果(使用可见图像作为输入,而不是几何或深度的效果),您:

  1. 像平常一样绘制场景,成为可读纹理。
  2. 绑定该纹理作为下一个程序的输入。
  3. 用你的程序和之前的输出画一个矩形。

您可以重复#2 和#3 到 运行 多种效果。这最多需要两个纹理(一个作为输入,一个作为输出,然后交换)。这适用于模糊、黑白、光晕等简单效果。

更复杂的效果可能需要额外的输入纹理(包括深度)并可能使用额外的数据。

除了 WebGL 术语之外@ssube 所说的...

在初始时间

  1. 您创建了一个帧缓冲区 (gl.createFramebuffer)
  2. 您为其附加纹理 (gl.framebufferTexture2D)。
  3. 如果您的场景需要深度缓冲区,您还需要将深度缓冲区附加到帧缓冲区(gl.renderbufferStorage、gl.framebufferRenderbuffer)。

在渲染时

  1. 您通过帧缓冲区将场景渲染到纹理中。

    // make rendering render to framebuffer's attachments
    gl.bindFramebuffer(gl.FRAMEBUFFER, yourFramebuffer);
    
    // .. render scene ..
    
  2. 然后使用 post 处理着色器

    将帧缓冲区的纹理渲染到 canvas
    // make rendering render to canvas
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    
    // .. render framebuffer's texture to canvas with post processing shader..
    

正如@ssube 所说,要应用多个 post 处理效果,您可以创建带有附加纹理的帧缓冲区。您将场景渲染到第一个帧缓冲区纹理,然后使用第一个 post 处理效果将该纹理渲染到第二个纹理中,现在您可以使用下一个 post 将第二个纹理渲染回第一个纹理处理效果。最后一个 post 处理效果呈现给 canvas.

For an example of applying multiple effects see this