Three.js 第一次渲染网格时出现性能问题 - 预加载选项?

发布于 2025-01-10 04:42:07 字数 1712 浏览 0 评论 0原文

我有一个包含 100 个 BoxGeometries 的项目,每个都有自己的图像(大约 10kb)。我注意到首次渲染框时移动设备上出现性能问题和跳帧,我想消除这些问题。

目前,我首先加载所有图像,并创建纹理,然后添加框:

let loader = new THREE.TextureLoader()

for(let img of assets) {

    loader.load(img.url, texture => {

        textures[img.name] = texture 
        assets.splice(assets.indexOf(img),1)
        if(!assets.length) {
            addBoxes()
        }

    })

}

然后我在网格中放置 100 个框,这里有一些伪代码来说明:

textures.forEach((texture,i) => {

    let box = new THREE.Mesh(
        new THREE.BoxGeometry(1, .04, 1),
        [
          blackMaterial,
          blackMaterial,
          new THREE.MeshBasicMaterial({
                map: Controller.textures[boxMaterial.postID]
            }),
          blackMaterial,
          blackMaterial,
          blackMaterial
          ]
    )

    box.position.x = (i % 10 - 5)
    box.position.z = (Math.floor(i / 10) - 5)

    scene.add( box )

})

requestAnimationFrame( step )

我有一个 THREE.OrthographicCamera,可以围绕这些框进行平移和缩放盒子。我注意到,当它们第一次出现时,它们会导致内存激增,但一旦看到所有盒子,净堆就会急剧下降,性能变得平稳,并且帧速率不会下降。

请注意,6 秒后内存突然变平,这是所有框都被看到一次的情况:

请注意,6 秒后内存突然变平,这是所有盒子都被看过一次的情况

为了解决这个问题,我已经尝试过盒子上的 frustrumCulled 参数:

box.frustumCulled = false

这在某些方面解决了问题。加载后,性能从一开始就非常流畅,内存问题也消失了。然而,我似乎没有办法检测所有网格是否已加载,因此初始加载很慢并且我有一个介绍动画,并且早期交互是锯齿状的并且性能密集,因为它们开始得太早。

我知道用急切加载方式加载所有盒子会导致更长的加载时间,这对于这个项目来说很好,可以避免通过延迟加载出现内存问题。然而,我还有什么其他选择呢?也许 box.frustumCulled 不是正确的方法。

有没有办法让事件侦听器监听此类加载活动?理想情况下,我会使用预加载器正确加载所有盒子,就好像它们曾经被见过一样,当系统准备就绪时,我可以触发 init 方法。

I have a project with 100 BoxGeometries, each with their own image inside (around 10kb). I have noticed performance problems and frames skipping on mobile devices when boxes are first rendered, which I'd like to eliminate.

At the moment I load up all images first, and create textures, before adding the boxes:

let loader = new THREE.TextureLoader()

for(let img of assets) {

    loader.load(img.url, texture => {

        textures[img.name] = texture 
        assets.splice(assets.indexOf(img),1)
        if(!assets.length) {
            addBoxes()
        }

    })

}

I then lay out 100 boxes in a grid, here's some pseudo-code to illustrate:

textures.forEach((texture,i) => {

    let box = new THREE.Mesh(
        new THREE.BoxGeometry(1, .04, 1),
        [
          blackMaterial,
          blackMaterial,
          new THREE.MeshBasicMaterial({
                map: Controller.textures[boxMaterial.postID]
            }),
          blackMaterial,
          blackMaterial,
          blackMaterial
          ]
    )

    box.position.x = (i % 10 - 5)
    box.position.z = (Math.floor(i / 10) - 5)

    scene.add( box )

})

requestAnimationFrame( step )

I have a THREE.OrthographicCamera that can pan and zoom around these boxes. I have noticed that when they first come into view, they cause memory to spike, but once all boxes have been seen, the net heap falls down drastically, and performance becomes smooth and no frame rates are dropped.

Please note that after 6 seconds memory suddenly flattens out, this is once all boxes have been seen once:

Please note that after 6 seconds memory suddenly flattens out, this is once all boxes have been seen once

To combat this, I have attempted the frustrumCulled parameter on the boxes:

box.frustumCulled = false

This solves the issue in some ways. Once loaded, performance is extremely smooth from the start and the memory issues are gone. However, I do not seem to have a way to detect once all the meshes are loaded, so initial load is slow and an intro animation I have, and early interactions are jagged and performance intensive as they are starting too early.

I understand that loading all boxes with eager loading will cause a larger load time, and this would be fine for this project, to avoid the memory issues through lazyloading. However, what other options do I have? Perhaps box.frustumCulled isn't the right approach.

And is there a way to have event listeners on such loading activity? Ideally I would load all boxes proper, as if they had been seen once, with a preloader, and when the system was ready, I could fire an init method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

源来凯始玺欢你 2025-01-17 04:42:07

一些想法:

1. 共享几何图形

您正在使用所有立方体,因此它们可以共享其几何图形定义。即使您希望它们具有不同的尺寸,您也可以稍后对网格应用缩放变换。

let boxGeo = new THREE.BoxGeometry(1, .04, 1)
textures.forEach((texture,i) => {
    let box = new THREE.Mesh(
        boxGeo,
        [
          blackMaterial,
          blackMaterial,
          new THREE.MeshBasicMaterial({
                map: Controller.textures[boxMaterial.postID]
            }),
          blackMaterial,
          blackMaterial,
          blackMaterial
          ]
    )

现在,您的程序只需将一个几何定义上传到 GPU,而不需要为每个纹理创建多个几何定义。

2. 在纹理之前渲染

这是在黑暗中拍摄的,但请尝试使用透明材质预先创建立方体,然后再应用纹理。我的想法是,预先上传几何图形会节省初始渲染的时间。

3. 实例

我不太了解 Three.js 如何处理实例材质,但您也许可以使用 InstancedMesh 创建立方体并提高整体渲染性能。

A few ideas:

1. Share geometry

You're using all cubes, so they can share their geometry definition. Even if you want them to be different sizes, you can apply a scaling transformation to the mesh later.

let boxGeo = new THREE.BoxGeometry(1, .04, 1)
textures.forEach((texture,i) => {
    let box = new THREE.Mesh(
        boxGeo,
        [
          blackMaterial,
          blackMaterial,
          new THREE.MeshBasicMaterial({
                map: Controller.textures[boxMaterial.postID]
            }),
          blackMaterial,
          blackMaterial,
          blackMaterial
          ]
    )

Now, your program only needs to upload one geometry definition to the GPU rather than however many you created for each texture.

2. Render before textures

This is a shot in the dark, but try creating your cubes up-front, with a transparent material, and apply your textures later. My thought is that getting the upload of the geometry out of the way up front will shave some time off your initial render.

3. Instances

I'm not up-to-date on how three.js handles instanced materials, but you might be able to use InstancedMesh to create your cubes and increase even your overall rendering performance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文