是否存在设置程序输出并将纹理绑定到片段着色器中的制服的顺序?
我有以下代码。如果将包含“ attachFrameBuffer
”的行放在最后一个“ g.uniform1i()
”调用之后,则会出现错误:
There is no texture bound to the unit 1.
但是,如果我把它们留在原处,那一切都很好。令我担心的是,我可能错过了更多的初始化操作。
gl.useProgram(program);
// Create and bind a framebuffer
var outputTexture = this.makeTexture(gl.FLOAT, null);
this.attachFrameBuffer(outputTexture);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, aTexture);
gl.uniform1i(AHandle, 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, bTexture);
gl.uniform1i(BHandle, 1);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
和makeTexture的代码:
texture = gl.createTexture();
// Bind the texture so the following methods effect this texture.
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// Pixel format and data for the texture
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, type, data);
// Unbind the texture.
gl.bindTexture(gl.TEXTURE_2D, null);
attachFrameBuffer()的代码:
frameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
答案 0 :(得分:3)
纹理绑定到“纹理单位”。纹理单位是全局状态。你可以想象他们像这样
glState = {
activeTextureUnit: 0,
textureUnits: [
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, },
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, },
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, },
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, },
...
... up to gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) ....
]
};
当您致电gl.activeTexture(textureUnit)
时,WebGL内部发生的事情实际上是有效的
gl.activeTexture = function(textureUnit) {
// convert texture unit to 0 to N index
glState.activeTextureUnit = textureUnit - gl.TEXTURE0;
};
实际上,当您致电gl.bindTexture
时会发生什么
gl.bindTexture = function(target, texture) {
glState.textureUnits[glState.activeTextureUnit][target] = texture;
};
统一采样器间接引用纹理单位。您可以给它们指定要从中获取纹理的纹理单位的索引。
因此,在您的情况下,此代码
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, aTexture);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, bTexture);
有效地使glState
glState = {
activeTextureUnit: 1, // because the last call to activeTexture was gl.TEXTURE1
textureUnits: [
{ TEXTURE_2D: aTexture, TEXTURE_CUBE_MAP: null, }, // <=- aTexture bound
{ TEXTURE_2D: bTexture, TEXTURE_CUBE_MAP: null, }, // <=- bTexture bound
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, },
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, },
...
... up to gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) ....
]
};
如果您致电
// Create and bind a framebuffer
var outputTexture = this.makeTexture(gl.FLOAT, null);
this.attachFrameBuffer(outputTexture);
然后,makeTexture
将不同的纹理绑定到单元1(因为对activeTexture
的最后一次调用将activeTextureUnit
设置为1。然后最后,它绑定了{{1} },因此不再有纹理绑定到单元1,然后绘制并得到看到的错误
null
没有“正确的顺序”。只有全局的webgl状态,您有责任在调用There is no texture bound to the unit 1.
之前确保正确设置了该状态。您可以按照自己想要的任何方式进行操作。例如,可以让makeTexture在制作纹理时使用其他纹理单元。您还可以让makeTexture查找当前的绑定纹理,使其成为新纹理,然后重新绑定旧纹理。或者,就像您发现的那样,可以在绑定用于绘制的纹理之前调用它。
也就是说,您的代码确实有些混乱,因为大多数WebGL应用程序绘制多次,因此它们通常将资源创建代码(初始化)与渲染代码(绘制)分开。创建代码创建着色器,程序,缓冲区,纹理,甚至顶点数组对象,渲染代码使用它们。
然后,渲染代码将设置绘制所需的所有状态
gl.draw???
但是您发布的代码for each thing to draw
useProgram
bind buffers and set attributes (or use vertex array object)
bind textures to texture units
set uniforms for program
draw
跟在我的useProgram
之后,这是创建时间(您不可能在每次绘制调用之前都创建纹理)。因此,随着程序变大,您可能会在初始化/创建而不是绘制/渲染时调用makeTexture