如何设置片段着色器的读取和写入纹理?
How to set the read-from and write-to textures for a fragment shader?
我是 WebGL 的新手,我试图通过阅读本教程来了解 WebGL 纹理的工作原理:WebGL Image Processing Continued。
同一个教程系列中还有另一个 example,它通过为两个输入纹理单元 0 和 1 显式设置 uniform
来使用两个纹理:
// set which texture units to render with.
gl.uniform1i(u_image0Location, 0); // texture unit 0
gl.uniform1i(u_image1Location, 1); // texture unit 1
但在第一个示例中,片段着色器使用 sampler2D u_image
作为输入纹理,所以我希望代码中应该有类似的内容:
gl.uniform1i(gl.getUniformLocation(program, "u_image"), 0);
...但我找不到它。 这是如何工作的? 只是猜测:纹理单元 0 是否用作所有 WebGL 程序中所有 2D 采样器的默认值?那么,为什么第二个例子需要gl.uniform1i(u_image0Location, 0);
?
编辑:
到目前为止,我从上面提到的教程中了解到 - 如果我错了请纠正我:
至少有两种使用纹理的方法:
- 输入纹理,我可以从中读取 -
在这里,我需要将位置传递给片段着色器(即 "u_image")
- 输出纹理,我可以写入 - 这是当前绑定的纹理(在上面提到的教程中,纹理单元 0)
我无法完全理解此示例的工作原理,因为未设置 u_image
制服,而且代码中没有任何 gl.activeTexture()
调用
编辑 2:
感谢Rabbid76 I believe I found further clarification in a comment of gman (the Author of the tutorial mentioned above) to that :
You need the framebuffers. By attaching a texture to a framebuffer and
then binding that framebuffer you're making the shader write to the
texture.
- input textures, where i can read from - here, i need to pass to the fragment shader the location (i.e. "u_image")
是的,纹理可以这样使用。
如果你想在片段着色器中使用不同的纹理,那么你必须将纹理绑定到不同的纹理单元。并且您必须将纹理单元的索引设置为纹理采样器统一变量。
纹理绑定到的纹理单元,可以通过WebGLRenderingContext.activeTexture()
设置:
var textureObj = gl.createTexture();
.....
var texUnit = 0; // texture unit 0 in this example
gl.activeTexture(gl.TEXTURE0 + texUnit);
gl.bindTexture(gl.TEXTURE_2D, textureObj);
链接程序后(linkProgram
),可以检索纹理采样器统一的位置:
u_image0Location = gl.getUniformLocation(program, "u_image");
程序成为激活程序后(useProgram
),可以设置纹理采样器统一:
gl.uniform1i(u_image0Location, texUnit);
- output textures, where i can write to - this is the texture currently bound (in the tutorial mentioned above, to the texture unit 0)
不对,完全错了。没有什么比输出纹理更好的了,而且可以肯定的是,绑定到纹理单元 0 的纹理不是输出纹理。
在片段着色器中写入 gl_FragColor
。您写入 gl_FragColor
的颜色存储在片段位置的帧缓冲区中。
如果要写入纹理,则必须通过 WebGLRenderingContext.framebufferTexture2D()
:
将纹理附加到帧缓冲区
var vp_w, vp_h; // withd and height of the viewport
var fbTexObj = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, fbTexObj );
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, vp_w, vp_h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
.....
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbTexObj, 0);
请注意,当您绑定 (gl.bindTexture
) 并指定 (gl.texImage2D
) fbTexObj
时,任何纹理单元都可以激活。
我是 WebGL 的新手,我试图通过阅读本教程来了解 WebGL 纹理的工作原理:WebGL Image Processing Continued。
同一个教程系列中还有另一个 example,它通过为两个输入纹理单元 0 和 1 显式设置 uniform
来使用两个纹理:
// set which texture units to render with.
gl.uniform1i(u_image0Location, 0); // texture unit 0
gl.uniform1i(u_image1Location, 1); // texture unit 1
但在第一个示例中,片段着色器使用 sampler2D u_image
作为输入纹理,所以我希望代码中应该有类似的内容:
gl.uniform1i(gl.getUniformLocation(program, "u_image"), 0);
...但我找不到它。 这是如何工作的? 只是猜测:纹理单元 0 是否用作所有 WebGL 程序中所有 2D 采样器的默认值?那么,为什么第二个例子需要gl.uniform1i(u_image0Location, 0);
?
编辑:
到目前为止,我从上面提到的教程中了解到 - 如果我错了请纠正我:
至少有两种使用纹理的方法:
- 输入纹理,我可以从中读取 - 在这里,我需要将位置传递给片段着色器(即 "u_image")
- 输出纹理,我可以写入 - 这是当前绑定的纹理(在上面提到的教程中,纹理单元 0)
我无法完全理解此示例的工作原理,因为未设置 u_image
制服,而且代码中没有任何 gl.activeTexture()
调用
编辑 2:
感谢Rabbid76 I believe I found further clarification in a comment of gman (the Author of the tutorial mentioned above)
You need the framebuffers. By attaching a texture to a framebuffer and then binding that framebuffer you're making the shader write to the texture.
- input textures, where i can read from - here, i need to pass to the fragment shader the location (i.e. "u_image")
是的,纹理可以这样使用。
如果你想在片段着色器中使用不同的纹理,那么你必须将纹理绑定到不同的纹理单元。并且您必须将纹理单元的索引设置为纹理采样器统一变量。
纹理绑定到的纹理单元,可以通过WebGLRenderingContext.activeTexture()
设置:
var textureObj = gl.createTexture();
.....
var texUnit = 0; // texture unit 0 in this example
gl.activeTexture(gl.TEXTURE0 + texUnit);
gl.bindTexture(gl.TEXTURE_2D, textureObj);
链接程序后(linkProgram
),可以检索纹理采样器统一的位置:
u_image0Location = gl.getUniformLocation(program, "u_image");
程序成为激活程序后(useProgram
),可以设置纹理采样器统一:
gl.uniform1i(u_image0Location, texUnit);
- output textures, where i can write to - this is the texture currently bound (in the tutorial mentioned above, to the texture unit 0)
不对,完全错了。没有什么比输出纹理更好的了,而且可以肯定的是,绑定到纹理单元 0 的纹理不是输出纹理。
在片段着色器中写入 gl_FragColor
。您写入 gl_FragColor
的颜色存储在片段位置的帧缓冲区中。
如果要写入纹理,则必须通过 WebGLRenderingContext.framebufferTexture2D()
:
var vp_w, vp_h; // withd and height of the viewport
var fbTexObj = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, fbTexObj );
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, vp_w, vp_h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
.....
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbTexObj, 0);
请注意,当您绑定 (gl.bindTexture
) 并指定 (gl.texImage2D
) fbTexObj
时,任何纹理单元都可以激活。