【问题标题】:Three.js - stop rendering scene when not visible / out of viewportThree.js - 在不可见/超出视口时停止渲染场景
【发布时间】:2020-10-13 00:50:09
【问题描述】:

我正在制作一个使用大量 js 和动画的网站,第一部分是全屏 three.js 场景,它随着鼠标移动而移动。场景本身很好,但即使我没有查看 three.js webgl 画布并且它正在产生性能问题,而其他动画在网站上发生的速度较低。

当场景不在视口中时,我需要完全停止渲染场景,这会极大地增加 pewrformacne。

这里是渲染函数:

const render = () => {
    requestAnimationFrame(render);


    camera.position.x += (mouseX - camera.position.x) * 0.05;
    camera.position.y += (mouseY * -1 - camera.position.y) * 0.05;
    camera.lookAt(scene.position);

    const t = Date.now() * 0.001;
    const rx = Math.sin(t * 0.6) * 0.5;
    const ry = Math.sin(t * 0.3) * 0.5;
    const rz = Math.sin(t * 0.2) * 0.5;
    group.rotation.x = rx;
    group.rotation.y = ry;
    group.rotation.z = rz;
    textMesh.rotation.x = rx;
    textMesh.rotation.y = ry;
    textMesh.rotation.z = rx; // :) 

    renderer.render(scene, camera);
};
render();

这是我尝试添加以停止渲染的内容(在此处的另一个线程上找到了此内容,但无法使其正常工作)

var stopRendering = (af) => {
    cancelAnimationFrame(af);
    isRendering = false;
};

window.addEventListener('scroll', () => {
    let scrollPosition = document.body.scrollTop;

    //element is almost about to be visible, time to start rendering
    if (scrollPosition >= ("#canvas-wrapper")-50) {
        if (everythingIsLoaded && !isRendering) {
            render();
            console.log('render has been started');
        } else {
            //wait until everythingIsLoaded is true
        }
    //element is not visible, stop rendering
    } else {
        //need to stop rendering here!
        if (render) {
            stopRendering(render);
            console.log('render has been halted');
        }
    }
});

Here is full codepen

另一件事是,但这不应该是一个问题,我正在使用locomotive scroll library 进行滚动和视口可见性检测,而这个库正在劫持滚动,所以基本的“滚动”不起作用。

暂停渲染的主要目标是大幅提升性能。

WORKING SOLUTION HERE以防有人发现这个问题。

【问题讨论】:

    标签: javascript canvas three.js


    【解决方案1】:

    您可以使用IntersectionObserver 来获取元素在屏幕上/屏幕外的事件。

    const statusElem = document.querySelector('.status');
    
    const onScreen = new Set();
    const intersectionObserver = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          onScreen.add(entry.target);
        } else {
          onScreen.delete(entry.target);
        }
      });
      statusElem.textContent = onScreen.size
        ? `on screen: ${[...onScreen].map(e => e.textContent).join(', ')}`
        : 'none';
    });
    
    document.querySelectorAll('.test').forEach(elem => {
      intersectionObserver.observe(elem);
    });
    body {
      font-size: xx-large;
    }
    .test {
      padding: 3em;
      background: orange;
    }
    .status {
      position: fixed;
      background: rgba(0,0,0,0.8);
      color: white;
      padding: 1em;
      font-size: medium;
      top: 0;
      left: 0;
    }
    <div class="test">a</div>
    <p>Lorem ipsum dolor sit amet, quaestio principes ea eos. Feugait ocurreret mea ea. Wisi altera intellegebat vix an, sed iuvaret tincidunt adipiscing ea, at debet iudico labores eum. Mucius adversarium vix no, nec amet contentiones ea. Sea noluisse mandamus referrentur cu. Facilisis similique quo eu, pri alii noluisse efficiantur in.
    </p>
    <div class="test">b</div>
    <p>
    Sea cu vidit neglegentur, te pro maluisset accusamus, ad est diceret iudicabit. Honestatis referrentur no vim, per no putant prompta antiopam. Est singulis vituperata no, adhuc nonumy consectetuer quo cu, quas primis at mel. No doming fabulas admodum est. Cu usu ornatus principes constituam, sint petentium at quo.
    </p>
    <div class="test">c</div>
    <div class="status"></div>

    然后您可以使用它来开始/停止渲染这些元素

    【讨论】:

    • 非常感谢!一切正常。我还成功实现了渲染的停止和开始,这是最终的工作代码笔,以防有人发现这个问题,因为我在谷歌上搜索了很长时间并找到了很好的解决方案:codepen.io/najkenko/pen/eYzpJmN
    • @gnam 在该代码中发现了 wierdes 错误,也许您可​​以帮助我,因为您已经在这里了。我不知道为什么会这样,但这正在发生。 - 当我重新加载那支笔时,向下滑动停止/开始渲染工作 - 但是,当我第一次在画布上移动鼠标然后向下滚动以停止渲染时,停止渲染根本不起作用,我必须再次点击运行
    • 另外奇怪的是,当我第一次滚动以停止渲染然后向上滚动重新启动它时,我可以在画布上移动鼠标并停止/启动它应该像它应该的那样工作,它只是在我做的第一件事是在画布上移动鼠标,似乎是一些层次结构问题,试图修复它但失败了
    • 您笔中的代码正在向观察者添加&lt;div class="test"&gt;。您想将画布添加到观察者。例如intersectionObserver.observe(renderer.domElement)
    • 问题在其他地方,即使我像这里codepen.io/najkenko/pen/ZEObKvv 那样将该类添加到画布包装器中,它仍然具有相同的奇怪行为。当我在移动鼠标之前向下滚动时,停止和重新启动工作,但是当我第一次移动鼠标然后滚动出视图时,停止和重新启动不起作用:/
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多