我们用于WebGL渲染缓冲区存储的纹理是否需要具有二次幂的维度?
我正在追逐客户在此设置中报告的FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
Windows 7 Enterprise 32位 Firefox版本:33 视频卡:Intel Q45 / Q43 Express芯片组驱动程序版本8.13.10.2413
到目前为止,我不知道为什么会这样,所以猜测它可能与NPOT纹理有关。
这是我的渲染缓冲区实现,它还没有两个纹理:
SceneJS._webgl.RenderBuffer = function (cfg) {
/**
* True as soon as this buffer is allocated and ready to go
* @type {boolean}
*/
this.allocated = false;
this.canvas = cfg.canvas;
this.gl = cfg.canvas.gl;
this.buf = null;
this.bound = false;
};
/**
* Called after WebGL context is restored.
*/
SceneJS._webgl.RenderBuffer.prototype.webglRestored = function (_gl) {
this.gl = _gl;
this.buf = null;
};
/**
* Binds this buffer
*/
SceneJS._webgl.RenderBuffer.prototype.bind = function () {
this._touch();
if (this.bound) {
return;
}
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.buf.framebuf);
this.bound = true;
};
SceneJS._webgl.RenderBuffer.prototype._touch = function () {
var width = this.canvas.canvas.width;
var height = this.canvas.canvas.height;
if (this.buf) { // Currently have a buffer
if (this.buf.width == width && this.buf.height == height) { // Canvas size unchanged, buffer still good
return;
} else { // Buffer needs reallocation for new canvas size
this.gl.deleteTexture(this.buf.texture);
this.gl.deleteFramebuffer(this.buf.framebuf);
this.gl.deleteRenderbuffer(this.buf.renderbuf);
}
}
this.buf = {
framebuf: this.gl.createFramebuffer(),
renderbuf: this.gl.createRenderbuffer(),
texture: this.gl.createTexture(),
width: width,
height: height
};
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.buf.framebuf);
this.gl.bindTexture(this.gl.TEXTURE_2D, this.buf.texture);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
try {
// Do it the way the spec requires
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, null);
} catch (exception) {
// Workaround for what appears to be a Minefield bug.
var textureStorage = new WebGLUnsignedByteArray(width * height * 3);
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, textureStorage);
}
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.buf.renderbuf);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, width, height);
this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this.buf.texture, 0);
this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.buf.renderbuf);
this.gl.bindTexture(this.gl.TEXTURE_2D, null);
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);
// Verify framebuffer is OK
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.buf.framebuf);
if (!this.gl.isFramebuffer(this.buf.framebuf)) {
throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Invalid framebuffer");
}
var status = this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);
switch (status) {
case this.gl.FRAMEBUFFER_COMPLETE:
break;
case this.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
case this.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
case this.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
case this.gl.FRAMEBUFFER_UNSUPPORTED:
throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");
default:
throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: " + status);
}
this.bound = false;
};
/**
* Clears this renderbuffer
*/
SceneJS._webgl.RenderBuffer.prototype.clear = function () {
if (!this.bound) {
throw "Render buffer not bound";
}
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
this.gl.disable(this.gl.BLEND);
};
/**
* Reads buffer pixel at given coordinates
*/
SceneJS._webgl.RenderBuffer.prototype.read = function (pickX, pickY) {
var x = pickX;
var y = this.canvas.canvas.height - pickY;
var pix = new Uint8Array(4);
this.gl.readPixels(x, y, 1, 1, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pix);
return pix;
};
/**
* Unbinds this renderbuffer
*/
SceneJS._webgl.RenderBuffer.prototype.unbind = function () {
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);
this.bound = false;
};
/** Returns the texture
*/
SceneJS._webgl.RenderBuffer.prototype.getTexture = function () {
var self = this;
return {
bind: function (unit) {
if (self.buf && self.buf.texture) {
self.gl.activeTexture(self.gl["TEXTURE" + unit]);
self.gl.bindTexture(self.gl.TEXTURE_2D, self.buf.texture);
return true;
}
return false;
},
unbind: function (unit) {
if (self.buf && self.buf.texture) {
self.gl.activeTexture(self.gl["TEXTURE" + unit]);
self.gl.bindTexture(self.gl.TEXTURE_2D, null);
}
}
};
};
/** Destroys this buffer
*/
SceneJS._webgl.RenderBuffer.prototype.destroy = function () {
if (this.buf) {
this.gl.deleteTexture(this.buf.texture);
this.gl.deleteFramebuffer(this.buf.framebuf);
this.gl.deleteRenderbuffer(this.buf.renderbuf);
this.buf = null;
this.bound = false;
}
};
答案 0 :(得分:0)
据我所知(我不使用WebGL),WebGL规范委托这些FBO相关调用的OpenGL ES 2.0规范。每个组件8位的RGBA不是ES 2.0中作为渲染目标支持的格式。许多设备都支持它(使用OES_rgb8_rgba8扩展名做广告),但它不是标准的一部分。
您用作COLOR_ATTACHMENT0
的纹理是具有8位分量的RGBA:
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0,
this.gl.RGBA, this.gl.UNSIGNED_BYTE, textureStorage);
尝试将其指定为RGB565,颜色可渲染:
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0,
this.gl.RGB, this.gl.UNSIGNED_SHORT_5_6_5, textureStorage);
如果您需要纹理中的alpha分量,RGBA4444或RGB5_A1是您唯一的便携式选项:
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0,
this.gl.RGBA, this.gl.UNSIGNED_SHORT_4_4_4_4, textureStorage);
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0,
this.gl.RGBA, this.gl.UNSIGNED_SHORT_5_5_5_1, textureStorage);
规范实际上看起来有些矛盾。在" WebGL和OpenGL ES 2.0之间的差异",它说:
以下帧缓冲对象附件的组合,当所有附件都是帧缓冲附件完成,非零且具有相同的宽度和高度时,必须导致帧缓冲完成帧缓冲:
COLOR_ATTACHMENT0 = RGBA / UNSIGNED_BYTE纹理
乍看之下表明支持RGBA/UNSIGNED_BYTE
。但是,条件是"当所有附件都是帧缓冲附件完成时,根据ES 2.0规范,具有此格式的附件不附件完整。并且在WebGL规范中没有覆盖什么"附件完成"装置