我们有一个也在iPad上运行的应用程序。使用three.js r100。
它有一个“主”和几个“弹出窗口”,每个都有自己的画布,场景和渲染器。 “主要”也有场景等,总是显示。
为避免内存问题,我们在打开弹出窗口时创建所有对象,并在关闭弹出窗口时进行清理。 但是在iPad上,网络信息仍然显示关闭的弹出窗口的画布。
在打开/关闭几个弹出窗口后,我们收到有关上下文太多的错误(“此页面上的活动WebGL上下文太多,最旧的上下文将丢失。”)。 丢失的第一个上下文是“主要”场景。之后,系统尝试松开“弹出”上下文。显示第二个错误:“ WebGL:INVALID_OPERATION:lostContext:上下文已丢失”。这似乎合乎逻辑,因为我们在关闭弹出窗口时做了一个forceContextLoss()。
在弹出窗口关闭,我们:
我怀疑画布阻止清理上下文,但是也许我错过了一些事情吗? 那么,如何才能完全删除弹出窗口的上下文?
谢谢,威廉
答案 0 :(得分:0)
不确定这是否是直接答案,但是我想您也将有更好的运气
(a)使用单个上下文和剪刀测试来模拟多个画布(推荐)
或
(b)使用virtual webgl context模拟单个上下文之上的多个上下文。
您实际上只有1个上下文,而其他上下文是虚拟的
AFAIK无法强制浏览器释放上下文。即使强迫上下文丢失也不能保证摆脱WebGLRenderingContext
对象,实际上它显然不是。当您遇到上下文丢失事件时,即使还原后仍会使用相同的上下文对象。
因此,不能保证浏览器不会在创建第9个上下文(或任何限制)后立即删除最早的上下文。通常,唯一的保证是在创建新上下文时只有旧上下文会丢失。
是最近最少使用的上下文还是最早的上下文,或者上下文最少的资源还是没有更多引用的上下文取决于浏览器。确实,浏览器没有简单的方法知道要释放哪些上下文。
这里是创建和删除上下文的快速测试。在Chrome桌面上创建第17个上下文后,最早的上下文丢失了
'use strict';
/* global THREE */
function makeScene(canvas, color = 0x44aa88, timeout = 0) {
const renderer = new THREE.WebGLRenderer({canvas: canvas});
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
const material = new THREE.MeshPhongMaterial({color});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
let requestId;
function render(time) {
time *= 0.001; // convert time to seconds
cube.rotation.x = time;
cube.rotation.y = time;
renderer.render(scene, camera);
requestId = requestAnimationFrame(render);
}
requestId = requestAnimationFrame(render);
if (timeout) {
setTimeout(() => {
cancelAnimationFrame(requestId);
canvas.parentElement.removeChild(canvas);
// manually free all three objects that hold GPU resoucres
geometry.dispose();
material.dispose();
renderer.dispose();
}, timeout);
}
}
makeScene(document.querySelector('#c'));
let count = 0;
setInterval(() => {
console.log(++count);
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
makeScene(canvas, Math.random() * 0xFFFFFF | 0, 500);
}, 1000);
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/three.min.js"></script>
这里是与virtual-webgl相同的测试
'use strict';
/* global THREE */
function makeScene(canvas, color = 0x44aa88, timeout = 0) {
const renderer = new THREE.WebGLRenderer({canvas: canvas});
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
const material = new THREE.MeshPhongMaterial({color});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
let requestId;
function render(time) {
time *= 0.001; // convert time to seconds
cube.rotation.x = time;
cube.rotation.y = time;
renderer.render(scene, camera);
requestId = requestAnimationFrame(render);
}
requestId = requestAnimationFrame(render);
if (timeout) {
setTimeout(() => {
cancelAnimationFrame(requestId);
// take the canvas out of the dom
canvas.parentElement.removeChild(canvas);
// manually free all three objects that hold GPU resoures
geometry.dispose();
material.dispose();
// hold on to the context incase the rendered forgets it
const gl = renderer.context;
// dispose the rendered in case it has any GPU resources
renderer.dispose();
// dispose the virutal context
gl.dispose(); // added by virtual-webgl
}, timeout);
}
}
makeScene(document.querySelector('#c'));
let count = 0;
setInterval(() => {
console.log(++count);
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
makeScene(canvas, Math.random() * 0xFFFFFF | 0, 500);
}, 1000);
<canvas id="c"></canvas>
<script src="https://greggman.github.io/virtual-webgl/src/virtual-webgl.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/three.min.js"></script>