webgl - Right order to specifying framebuffer and binding uniform textures?
问题描述
Is there a sequence to setting the output of a program and binding textures to uniforms in the fragment shader?
I have the following code. If I place the lines containing "attachFrameBuffer
" after the last "g.uniform1i()
" call, I get the error:
There is no texture bound to the unit 1.
But if I leave them where they are then everything is fine. This worries me that there is more initialization that I probably have missed.
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);
and the code for 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);
code for attachFrameBuffer():
frameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
解决方案
纹理绑定到“纹理单元”。纹理单元是全局状态。你可以想象他们是这样的
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。然后你绘制并得到你看到的错误
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 状态图,您可以单步查看 WebGL 状态变化。
推荐阅读
- struct - SwiftUI: How to loop through the various structs with various codes, using ForEach?
- java - 如何在 Zerocode 的 json 文件中写入 json 响应
- android - 为什么我在 android studio 中安装 HAXM 时遇到问题?
- python - 数据覆盖的 Matplotlib 误差线
- java - 使用 Stream API 比较 2 个集合中的对象、查找相等对象和更改对象属性的最佳方法是什么
- javascript - toLocaleDateString 未定义如何解决?
- solr - Solr:传递变量以使用 POST 更新字段
- javascript - React JSX vs function 在焦点处理上有区别吗?
- c - 读取二进制文件并将其存储到 c 中的 struct
- java - Java Apache poi 4.1.2 比较单元类型