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 将第一个作为纹理输入。但这听起来像是渲染了两次,这并不好。
您确实想再次渲染,但您需要获取第一遍的输出并将其用作第二遍的输入纹理。
交换纹理和绘制矩形(两个三角形)很便宜,尤其是在现代可编程硬件上。
对于简单效果(使用可见图像作为输入,而不是几何或深度的效果),您:
- 像平常一样绘制场景,成为可读纹理。
- 绑定该纹理作为下一个程序的输入。
- 用你的程序和之前的输出画一个矩形。
您可以重复#2 和#3 到 运行 多种效果。这最多需要两个纹理(一个作为输入,一个作为输出,然后交换)。这适用于模糊、黑白、光晕等简单效果。
更复杂的效果可能需要额外的输入纹理(包括深度)并可能使用额外的数据。
除了 WebGL 术语之外@ssube 所说的...
在初始时间
- 您创建了一个帧缓冲区 (gl.createFramebuffer)
- 您为其附加纹理 (gl.framebufferTexture2D)。
- 如果您的场景需要深度缓冲区,您还需要将深度缓冲区附加到帧缓冲区(gl.renderbufferStorage、gl.framebufferRenderbuffer)。
在渲染时
您通过帧缓冲区将场景渲染到纹理中。
// make rendering render to framebuffer's attachments
gl.bindFramebuffer(gl.FRAMEBUFFER, yourFramebuffer);
// .. render scene ..
然后使用 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.
如何让 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 将第一个作为纹理输入。但这听起来像是渲染了两次,这并不好。
您确实想再次渲染,但您需要获取第一遍的输出并将其用作第二遍的输入纹理。
交换纹理和绘制矩形(两个三角形)很便宜,尤其是在现代可编程硬件上。
对于简单效果(使用可见图像作为输入,而不是几何或深度的效果),您:
- 像平常一样绘制场景,成为可读纹理。
- 绑定该纹理作为下一个程序的输入。
- 用你的程序和之前的输出画一个矩形。
您可以重复#2 和#3 到 运行 多种效果。这最多需要两个纹理(一个作为输入,一个作为输出,然后交换)。这适用于模糊、黑白、光晕等简单效果。
更复杂的效果可能需要额外的输入纹理(包括深度)并可能使用额外的数据。
除了 WebGL 术语之外@ssube 所说的...
在初始时间
- 您创建了一个帧缓冲区 (gl.createFramebuffer)
- 您为其附加纹理 (gl.framebufferTexture2D)。
- 如果您的场景需要深度缓冲区,您还需要将深度缓冲区附加到帧缓冲区(gl.renderbufferStorage、gl.framebufferRenderbuffer)。
在渲染时
您通过帧缓冲区将场景渲染到纹理中。
// make rendering render to framebuffer's attachments gl.bindFramebuffer(gl.FRAMEBUFFER, yourFramebuffer); // .. render scene ..
然后使用 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.