是否可以在着色器中访问预设的纹理单元?
Is it possible to access pre-set textureunits within a shader?
TL;DR: 我已经激活纹理并将其绑定到纹理单元 1-4,现在我希望在着色器中使用它们而不使用程序特定的统一位置。是否可以使用“全局”纹理单元从纹理中读取数据?
我很难理解如何在 webgl 中访问纹理。在 this tutorial on textures 中,它说“纹理单元是纹理引用的全局数组。”,这听起来不错。我使用
绑定了我的纹理
gl.activeTexture(gl.TEXTURE1 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);
其中 i
是新创建的纹理的索引,tex
是纹理本身。
但它没有给出如何使用此全局引用访问着色器中的纹理的示例。在 this tutorial from the same page it does give an example of how to access the textures from within a shader, but only when using an uniform position (much like how an attribute is accessed), which requires a program (and thus, removing the global aspect, in a way, since it's dependent on the program to be accessed). In this preceding tutorial 中,完全跳过了有关如何实际设置纹理“u_texture”的任何细节。
简而言之,我有两个程序,如果可能的话,我希望在这两个程序中全局使用纹理,而不必在每个程序上都使用 getUniformLocation。看到纹理单元的承诺,我以为我可以使用它们,但我不知道如何实际做类似
的事情
sampler2D textureUnit2;
在着色器中。这可能吗?我是否将 textureUnits 的实现与使用它们的实用性混淆了?
非常感谢!
I wish to use textures globally in both of them without having to getUniformLocation on each program, if it's possible to do so
不可能这样做。
纹理单元是全局的。你可以把它想象成 JavaScript
中的一个全局数组
const textureUnits = [
{ TEXTURE_2D: someTexture, }, // unit 0
{ TEXTURE_2D: someOtherTexture, }, // unit 1
{ TEXTURE_2D: yetAnotherTexture, }, // unit 2
...
];
您可以通过先调用 gl.activeTexture
然后调用 gl.bindTexture
将纹理绑定到纹理单元。示例:
const unit = 2;
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, yetAnotherTexture);
yetAnotherTexture
现在绑定到纹理单元 2
另外还有着色器程序。要访问纹理,请在着色器中声明 uniform sampler2d someName;
。
uniform sampler2D foobar;
将其视为纹理单元的索引。然后你需要设置索引(告诉着色器程序使用哪个全局纹理单元)
const foobarLocation = gl.getUniformLocation(someProgram, "foobar");
...
// tell the program to use the texture on unit 2
const indexOfTextureUnit = 2;
gl.uniform1i(foobarLocation, indexOfTextureUnit);
纹理单元本身是全局的。每个项目的制服都是独一无二的。您需要设置它们以告诉它们您希望该制服参考哪个纹理单元。制服默认为 0,因此如果您希望它们引用纹理单元 0,则无需设置它们,但对于任何其他纹理单元,您需要设置它们。
想象一下 GLSL 的 texture2D
函数是用 JavaScript 编写的。它会像
function texture2d(sampler, texcoord) {
const texture = textureUnits[sampler].TEXTURE_2D;
return getColorFromTextureAtTexcoord(texture, texcoord);
}
如果我这样做了
uniform sampler2D foobar;
varying vec2 v_texcoord;
void main() {
gl_FragColor = texture2D(foobar, v_texcoord);
}
然后我将foobar
制服设置为2
const foobarLocation = gl.getUniformLocation(someProgram, "foobar");
...
// tell the program to use the texture on unit 2
const indexOfTextureUnit = 2;
gl.uniform1i(foobarLocation, indexOfTextureUnit);
它将引用索引 2 处的全局纹理单元。
注意:您问题中的这段代码
gl.activeTexture(gl.TEXTURE1 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);
好像不对。它应该使用 TEXTURE0
作为基础,而不是 TEXTURE1
gl.activeTexture(gl.TEXTURE0 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);
This diagram 可能有助于可视化其工作原理
上面你可以看到着色器程序(金色)有两个制服decal
和diffuse
。
decal
设置为 3,因此它引用纹理单元 3。纹理单元 3 绑定到 decalTexture
(F 的图像)
diffuse
设置为 6,因此它引用纹理单元 6。纹理单元 3 绑定到 diffuseTexture
(4x4 棋盘)
请注意,纹理单元 0 也绑定到 decalTexture
,但着色器程序未引用纹理单元 0,因此至少出于绘制像素的目的,换句话说,执行着色器程序、纹理单元0 未被使用。
TL;DR: 我已经激活纹理并将其绑定到纹理单元 1-4,现在我希望在着色器中使用它们而不使用程序特定的统一位置。是否可以使用“全局”纹理单元从纹理中读取数据?
我很难理解如何在 webgl 中访问纹理。在 this tutorial on textures 中,它说“纹理单元是纹理引用的全局数组。”,这听起来不错。我使用
绑定了我的纹理gl.activeTexture(gl.TEXTURE1 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);
其中 i
是新创建的纹理的索引,tex
是纹理本身。
但它没有给出如何使用此全局引用访问着色器中的纹理的示例。在 this tutorial from the same page it does give an example of how to access the textures from within a shader, but only when using an uniform position (much like how an attribute is accessed), which requires a program (and thus, removing the global aspect, in a way, since it's dependent on the program to be accessed). In this preceding tutorial 中,完全跳过了有关如何实际设置纹理“u_texture”的任何细节。
简而言之,我有两个程序,如果可能的话,我希望在这两个程序中全局使用纹理,而不必在每个程序上都使用 getUniformLocation。看到纹理单元的承诺,我以为我可以使用它们,但我不知道如何实际做类似
的事情sampler2D textureUnit2;
在着色器中。这可能吗?我是否将 textureUnits 的实现与使用它们的实用性混淆了?
非常感谢!
I wish to use textures globally in both of them without having to getUniformLocation on each program, if it's possible to do so
不可能这样做。
纹理单元是全局的。你可以把它想象成 JavaScript
中的一个全局数组const textureUnits = [
{ TEXTURE_2D: someTexture, }, // unit 0
{ TEXTURE_2D: someOtherTexture, }, // unit 1
{ TEXTURE_2D: yetAnotherTexture, }, // unit 2
...
];
您可以通过先调用 gl.activeTexture
然后调用 gl.bindTexture
将纹理绑定到纹理单元。示例:
const unit = 2;
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, yetAnotherTexture);
yetAnotherTexture
现在绑定到纹理单元 2
另外还有着色器程序。要访问纹理,请在着色器中声明 uniform sampler2d someName;
。
uniform sampler2D foobar;
将其视为纹理单元的索引。然后你需要设置索引(告诉着色器程序使用哪个全局纹理单元)
const foobarLocation = gl.getUniformLocation(someProgram, "foobar");
...
// tell the program to use the texture on unit 2
const indexOfTextureUnit = 2;
gl.uniform1i(foobarLocation, indexOfTextureUnit);
纹理单元本身是全局的。每个项目的制服都是独一无二的。您需要设置它们以告诉它们您希望该制服参考哪个纹理单元。制服默认为 0,因此如果您希望它们引用纹理单元 0,则无需设置它们,但对于任何其他纹理单元,您需要设置它们。
想象一下 GLSL 的 texture2D
函数是用 JavaScript 编写的。它会像
function texture2d(sampler, texcoord) {
const texture = textureUnits[sampler].TEXTURE_2D;
return getColorFromTextureAtTexcoord(texture, texcoord);
}
如果我这样做了
uniform sampler2D foobar;
varying vec2 v_texcoord;
void main() {
gl_FragColor = texture2D(foobar, v_texcoord);
}
然后我将foobar
制服设置为2
const foobarLocation = gl.getUniformLocation(someProgram, "foobar");
...
// tell the program to use the texture on unit 2
const indexOfTextureUnit = 2;
gl.uniform1i(foobarLocation, indexOfTextureUnit);
它将引用索引 2 处的全局纹理单元。
注意:您问题中的这段代码
gl.activeTexture(gl.TEXTURE1 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);
好像不对。它应该使用 TEXTURE0
作为基础,而不是 TEXTURE1
gl.activeTexture(gl.TEXTURE0 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);
This diagram 可能有助于可视化其工作原理
上面你可以看到着色器程序(金色)有两个制服decal
和diffuse
。
decal
设置为 3,因此它引用纹理单元 3。纹理单元 3 绑定到decalTexture
(F 的图像)diffuse
设置为 6,因此它引用纹理单元 6。纹理单元 3 绑定到diffuseTexture
(4x4 棋盘)
请注意,纹理单元 0 也绑定到 decalTexture
,但着色器程序未引用纹理单元 0,因此至少出于绘制像素的目的,换句话说,执行着色器程序、纹理单元0 未被使用。