正确指定帧缓冲区并绑定均匀纹理吗?

问题描述 投票:1回答:1

是否有设置程序输出并将纹理绑定到片段着色器中的制服的序列?

我有以下代码。如果将包含“ 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); 
webgl
1个回答
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。然后最后它绑定了null,所以没有纹理绑定到单元1) 1了,然后绘制并得到看到的错误

There is no texture bound to the unit 1.

没有“正确的顺序”。只有全局webgl状态,您有责任在调用gl.draw???之前确保正确设置了该状态。您可以按照自己想要的任何方式进行操作。例如,可以让makeTexture在制作纹理时使用其他纹理单元。您还可以让makeTexture查找当前绑定的纹理,使其新的纹理,然后重新绑定旧的纹理。或者,就像您发现的那样,可以在绑定要绘制的纹理之前调用它。

就是说,您的代码确实看起来有些混乱,因为大多数WebGL应用程序绘制了很多次,因此它们通常将资源创建代码(初始化)与呈现代码(绘制)分开。创建代码创建着色器,程序,缓冲区,纹理,甚至顶点数组对象,渲染代码使用它们。

然后,渲染代码将设置绘制所需的所有状态

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,这是创建时间(您可能不会在每次绘制调用之前创建纹理)。因此,随着程序变大,您可能会在初始化/创建而不是绘制/渲染时在其他地方调用makeTexture

PS:这是一个webgl state diagram,您可以逐步查看WebGL状态更改。
© www.soinside.com 2019 - 2024. All rights reserved.