有没有一种方法可以使WebGL在离屏渲染,而不需要将webgl画布附加到DOM上?

8

我以为这会是一个很容易找到答案的问题,但结果却非常难以捉摸。基本上,我正在尝试使用WebGL来完成一些图像处理和生成任务的繁重工作,并且希望它可以离屏渲染。理想情况下,我希望WebGL可以将场景渲染到一个framebuffer中,然后我就可以使用gl.readPixels()从中读取数据,或者将其渲染到webgl画布中,以便我可以将其用作context.drawImage()的源。问题在于,我不想显示webgl画布本身,我只想将其中的一部分复制到一个可见画布中,我有一个常规的“2d”上下文。到目前为止,我似乎无法在没有以下初始化的情况下使其正常工作,这对我来说看起来像是一个丑陋的hack:

glCanvas = document.createElement('canvas');
glCanvas.width = 256;
glCanvas.height = 256;
document.body.appendChild(glCanvas); // seems necessary, but why?
glCanvas.style.visibility = 'hidden'; // ugh, is this the only way?

目前,我使用gl.createFramebuffer()创建一个framebuffer,并使用单个gl.drawArrays()调用呈现场景,然后使用gl.readPixels()将结果输出到ImageData。在与DOM相关联的glCanvas上,它按计划正常工作。但是,如果我省略上面的最后两行代码,即我附加glCanvas并隐藏它时,当我尝试从我已呈现的framebuffer中读取像素时,我没有得到任何图像。

我不理解为什么即使不渲染到它,glCanvas也需要附加到DOM上。我认为呈现到framebuffer完全发生在显卡上,缓冲区将持续存在以供我用作纹理。WebGL是否只有在至少有一个webgl-context canvas附加到DOM时才会呈现?或者我错过了其他的一些细节吗?谢谢!


1
这可能会有所帮助,虽然不是完全成熟的:https://developer.mozilla.org/zh-CN/docs/Web/API/OffscreenCanvas - user1693593
@K3N 我看到了这个,它似乎很有前途,但正如你所说,还没有准备好用于主流。它似乎只在Firefox中实现,并且只是供开发人员通过about:config设置提前访问。 - Adam Smith
@Blindman67 谢谢您的澄清。这确实令人失望,考虑到现在 WebGL 的广泛使用,有点令人惊讶。我希望它能继续得到支持,尽管我已经放弃了获得 WebCL 的梦想 :-( - Adam Smith
由于其多平台本质,网络在相当长一段时间内将被削减到可以实现的程度。Valkan是新的3D开放标准,因此请祈祷WebGL不会被遗忘,或者回到当MS设定标准并且IE4-5叱咤风云的辉煌时代。任何人都可以为浏览器使用DX12吗?DirectX始终拥有最好的游戏玩具。 - Blindman67
@Blindman67所说的“十年前的黑客技巧,可以在最基本的系统上运行”,这正是为什么ES2被选择用于Web的原因。它可以在任何地方运行... - pleup
显示剩余5条评论
2个回答

9

您不必将画布添加到DOM中即可使用WebGL。在WebGL一致性测试中有很多测试可以在不向DOM添加画布的情况下运行。

var gl = document.createElement("canvas").getContext("webgl");
gl.clearColor(1,0,1,1); // purple;
gl.clear(gl.COLOR_BUFFER_BIT);

// draw in 2d canvas
var ctx = document.querySelector("#c2d").getContext("2d");
ctx.drawImage(gl.canvas, 10, 20, 30, 40);
<canvas id="c2d"></canvas>

也许您应该发布更多的代码。可能还有其他错误。

更新

很快也会推出OffscreenCanvas API。截至2017年11月15日,它已在Firefox和Chrome中通过标志可用。它允许在Web Worker中使用WebGL。

更新2

从Chrome 69开始,OffscreenCanvas已无需标志即可使用。


1
我找到了这个错误。我们网站的所有页面都导入了一个实用脚本,其中包含一些样板内容。其中之一是尝试智能调整页面上的大小。我愚蠢地将我的离屏画布上下文命名为“gl”,与网站其他页面上可见的WebGL画布相同。我没有注意到调整大小的脚本会执行以下操作:var width = gl.canvas.clientWidth; var height = gl.canvas.clientHeight; if (gl.canvas.width !== width || gl.canvas.height !== height) { gl.canvas.width = width; gl.canvas.height = height; } 所以,是的,0像素乘以0像素,哎呀! - Adam Smith
仅仅重命名保存着未连接的WebGL画布引用的变量就解决了这个问题。实际上,常见代码包含的不止这一点,还假设存在一个“gl”变量。教训是:要知道你正在导入什么,即使它是旧代码,先于你而且在大型网站的其他任何地方都没有已知问题。 - Adam Smith
如果我想在具有WebGL上下文(而不是2D上下文)的画布上绘制,怎么办?这可行吗? - Questionnaire
另外请注意,我知道OffScreenCanvas API的存在,但Safari不支持它,而我的解决方案需要Safari支持。 - Questionnaire
那个例子在上面的答案中。 - gman

0

看起来你想使用 OffScreenCanvas。

你可以在这里了解更多。

你应该像这样做:

const offscreen = document.querySelector('canvas').transferControlToOffscreen();
const worker = new Worker('myworkerurl.js');
worker.postMessage({canvas: offscreen}, [offscreen]);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接