我正在尝试在WebGL中实现选择。我有很多对象(大约500个),我希望每个对象都可以被选中。为了做到这一点,我做了一个循环,为每个对象分配一个独特的颜色(参见挑选原则):
for (var i = 0, len = objects.length; i < len; i++) {
framecolors[count++] = i % 256 / 256; //Red
framecolors[count++] = Math.floor(i/256) / 256; //Green
framecolors[count++] = Math.floor(i/(256*256)) / 256; //Blue
}
然后在经典缓冲区中使用 framecolors
来检查每个对象是否具有不同的红色阴影。有效。
现在,我想使用我的对象的原始颜色,以及背景中带有红色阴影的帧缓冲。我经历过一些代码,我有点困惑。
这是我到目前为止所尝试的内容。
挑选前调用的函数:
//Creates texture
colorTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 400, 400, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
//Creates framebuffer
fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0);
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
gl.enable(gl.DEPTH_TEST);
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.clear(gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, vertexPositionBuffer.numItems);
之后调用的函数:
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
gl.drawArrays(gl.POINTS, 0, vertexPositionBuffer.numItems);
你可能已经明白了,我对帧缓冲器不太满意,即使我读了很多关于它们的内容,我也不知道它们是如何工作的。我不知道如何将framecolors
链接到帧缓冲区。有办法吗?
谢谢, R上。
答案 0 :(得分:2)
帧缓冲是附件的集合(渲染缓冲区和/或纹理)。它的工作方式就像没有帧缓冲区的渲染一样。 (实际上浏览器在内部使用帧缓冲来实现WebGL的画布)
在你的情况下,你错过了一些东西。您很可能需要附加深度缓冲区,否则在渲染场景时,您将无法获得zBuffering,并且错误的对象将出现在前面。
// create renderbuffer
depthBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
// allocate renderbuffer
gl.renderbufferStorage(
gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
// attach renderebuffer
gl.framebufferRenderbuffer(
gl.FRAMEBUFFER,
gl.DEPTH_ATTACHMENT,
gl.RENDERBUFFER,
depthBuffer);
一般情况下,您还应检查您的帧缓冲区是否有效。附上所有附件后,请致电gl.checkFramebufferStatus
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
alert("this combination of attachments does not work");
return;
}
由于各种原因,帧缓冲区可能不完整。最常见的是附件大小不同或GPU不支持附件组合。注意:在WebGL中,某些组合需要工作,但是您可能以后可能会更改代码以使用不同的格式,因此检查可能仍然是个好主意。
每当切换帧缓冲区时,您还需要通过调用gl.viewport
来设置视口。
gl.bindFramebuffer(gl.FRAMEBUFFER, someFramebuffer);
gl.viewport(0, 0, someFramebufferWidth, someFramebufferHeight);
包括在将内容设置回画布时将其放回原型
gl.bindFramebuffer(gl.FRAMEBUFFER, null); // render to canvas
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
最后,上面的代码中存在一个错误,即您只清除了调用gl.clear
的帧缓冲区的深度缓冲区。你想打电话
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
由于您将在以后阅读颜色,否则将遗留旧颜色。
最后,我想你知道这一点。你找出哪个像素对应于鼠标点击并调用
var colorPicked = new Uint8Array(4);
gl.readPixels(pickX, pickY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, colorPicked);
请注意,当您致电gl.readPixels
时,您的帧缓冲区必须与gl.bindFramebuffer
绑定,否则gl.readPixels
将从画布中读取。
答案 1 :(得分:1)
非常感谢gman。只是为了完成你的答案,关于如何将framecolors
与我的帧缓冲区一起使用,这很简单。在着色器中,我添加了一个专用于framebuffer颜色的变量:
if (!offscreen) {
gl_FragColor = normalColors;
}
else {
gl_FragColor = frameColors;
}
现在,在通过readPixels()
函数确定我选择了哪个对象之前,我使用以下命令切换回帧缓冲区:
function renderFrame() {
gl.bindFramebuffer(gl.FRAMEBUFFER, fb); //fb = framebuffer
gl.uniform1i(shaderProgram.uOffscreen, true); //uOffscreen = uniform boolean in shader
draw(); //function called to draw objects (contains gl.clear and gl.viewport)
}
同样,我在调用函数后切换回通常的缓冲区。
单击鼠标时,我试图显示帧缓冲区而不是通常的缓冲区。我遇到了麻烦,但如果我找到它,我会稍后发布解决方案。
编辑:解决方案:只需删除与帧缓冲区关联的深度缓冲区(渲染缓冲区)。然后按照WebGL display framebuffer?
中的说明显示缓冲区