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

Three.js performance issue on first render of mesh - preload options?

我有一个包含 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 秒后内存突然变平,这是一次看到所有框后:

为了解决这个问题,我在盒子上尝试了 frustrumCulled 参数:

box.frustumCulled = false

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

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

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

一些想法:

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。在纹理之前渲染

这是在黑暗中拍摄的,但请尝试使用透明 material 创建立方体 up-front,然后再应用纹理。我的想法是,预先完成几何体的上传将节省您的初始渲染时间。

3。实例

我不是 up-to-date 了解 three.js 如何处理实例化 material,但您可以使用 InstancedMesh 创建多维数据集,甚至增加您的整体渲染性能。