antvis / L7

🌎 Large-scale WebGL-powered Geospatial Data Visualization analysis engine.
https://l7.antv.antgroup.com
MIT License
3.56k stars 624 forks source link

场景内添加threejs后切换页面销毁场景,threejs报错 #2343

Open zuoyifeng opened 3 months ago

zuoyifeng commented 3 months ago

问题描述

用registerRenderService()添加threejs,加载模型,在路由离开后销毁scene.destroy();但是threejs没有被销毁,并且报错, THREE.WebGLRenderer: Context Lost.

重现链接

No response

重现步骤

No response

预期行为

不要出现THREE.WebGLRenderer: Context Lost.报错,所暂用的内存也应该清除销毁

平台

屏幕截图或视频(可选)

image

补充说明(可选)

No response

lzxue commented 3 months ago

是不是频繁创建,导致实例太多了

zuoyifeng commented 3 months ago

是不是频繁创建,导致实例太多了

没有 我就初始化页面后,切换路由离开就出现了,在切换路由离开加的销毁操作 就会有以上提示 但是肯定要有销毁,这个销毁场景方法scene.destroy();之后不需要再threejs销毁模型之类的吗? threejs是加载了模型组件的 代码如下:

    scene.registerRenderService(ThreeRender)
      const threeJSLayer = new ThreeLayer({
        enableMultiPassRenderer: false,
        zIndex: -1,
        onAddMeshes: (threeScene, layer) => {
          threeSceneNode = threeScene
          // 当前场景的中心
          const center = scene.getCenter()
          // 环境光照
          threeScene.add(new THREE.AmbientLight(0xffffff))
          const sunlight = new THREE.DirectionalLight(0xffffff, 0.25)
          sunlight.position.set(0, 80000000, 100000000)
          sunlight.matrixWorldNeedsUpdate = true
          threeScene.add(sunlight)

          // 使用 Three.js glTFLoader 加载模型
          const loader = new GLTFLoader()
          loader.load('./engine/models/build.glb', (gltf) => {
            const gltfScene = gltf.scene
            setDouble(gltfScene)
            layer.adjustMeshToMap(gltfScene)
            // 设置模型颜色透明度
            gltfScene.children.forEach((modeEl) => {
              // modeEl.material = shadermaterial;
              modeEl.material.transparent = true
              modeEl.material.opacity = 0.5
              modeEl.translateX(-530)
              modeEl.translateZ(163)
            })
            layer.setMeshScale(gltfScene, 18.95, 24, 10)

            gltfScene.rotation.y = THREE.MathUtils.degToRad(180)
            layer.setObjectLngLat(gltfScene, [center.lng + 0.05, center.lat], 0)
            // 向场景中添加模型
            threeScene.add(gltfScene)
            // 重绘图层
            // layer.render();
          })
        }
      }).animate(true)

      scene.addLayer(threeJSLayer)
zhnny commented 3 months ago

这是我的尝试:

import { Scene } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
import { ThreeLayer, ThreeRender } from '@antv/l7-three';
import * as THREE from 'three';

const scene = new Scene({
  id: 'map',
  map: new GaodeMap({
    center: [111.4453125, 32.84267363195431],
    pitch: 45,
    rotation: 30,
    zoom: 12,
    mapStyle: 'amap://styles/darkblue',
  })
});

scene.on('loaded', () => {
  scene.registerRenderService(ThreeRender);

  const threeJSLayer = new ThreeLayer({
    enableMultiPassRenderer: false,
    onAddMeshes: (threeScene, layer) => {

      // 当前场景的中心
      const center = scene.getCenter();

      // 环境光照
      threeScene.add(new THREE.AmbientLight(0xffffff, 0.2));
      const sunlight = new THREE.DirectionalLight(0xff0000, 0.8);
      layer.setObjectLngLat(sunlight, [center.lng + 0.3, center.lat + 0.08], 1000);
      sunlight.matrixWorldNeedsUpdate = true;
      threeScene.add(sunlight);

      const directionalLightHelper = new THREE.DirectionalLightHelper( sunlight, 5 );
      threeScene.add( directionalLightHelper );

      const box = createBoxGeometry();
      box.scale.set(1000, 1000, 1000);
      box.rotation.set(0, 90, 0)
      layer.setObjectLngLat(box, [center.lng - 0.05, center.lat], 0);
      threeScene.add(box);

     // ....

      // 测试
      setTimeout(()=>{
        console.log(layer.threeRenderService) // 获取Three.js的渲染器,可以对渲染器进行操作,比如销毁
        console.log(layer.scene) // 获取Three.js的Scene,可以对里面的Object进行操作,比如销毁

        layer.threeRenderService.renderer.dispose() // 关闭Three.js的渲染器(避免出现上下文丢失的问题)

        scene.destroy() // 销毁L7的Scene
      }, 4000);

    }
  }).animate(true);
  scene.addLayer(threeJSLayer);
});

经测试呢,不出现THREE.WebGLRenderer: Context Lost报错,但是有概率会出现regl的Context Lost,供参考

1772

zuoyifeng commented 3 months ago

这是我的尝试:

import { Scene } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
import { ThreeLayer, ThreeRender } from '@antv/l7-three';
import * as THREE from 'three';

const scene = new Scene({
  id: 'map',
  map: new GaodeMap({
    center: [111.4453125, 32.84267363195431],
    pitch: 45,
    rotation: 30,
    zoom: 12,
    mapStyle: 'amap://styles/darkblue',
  })
});

scene.on('loaded', () => {
  scene.registerRenderService(ThreeRender);

  const threeJSLayer = new ThreeLayer({
    enableMultiPassRenderer: false,
    onAddMeshes: (threeScene, layer) => {

      // 当前场景的中心
      const center = scene.getCenter();

      // 环境光照
      threeScene.add(new THREE.AmbientLight(0xffffff, 0.2));
      const sunlight = new THREE.DirectionalLight(0xff0000, 0.8);
      layer.setObjectLngLat(sunlight, [center.lng + 0.3, center.lat + 0.08], 1000);
      sunlight.matrixWorldNeedsUpdate = true;
      threeScene.add(sunlight);

      const directionalLightHelper = new THREE.DirectionalLightHelper( sunlight, 5 );
      threeScene.add( directionalLightHelper );

      const box = createBoxGeometry();
      box.scale.set(1000, 1000, 1000);
      box.rotation.set(0, 90, 0)
      layer.setObjectLngLat(box, [center.lng - 0.05, center.lat], 0);
      threeScene.add(box);

     // ....

      // 测试
      setTimeout(()=>{
        console.log(layer.threeRenderService) // 获取Three.js的渲染器,可以对渲染器进行操作,比如销毁
        console.log(layer.scene) // 获取Three.js的Scene,可以对里面的Object进行操作,比如销毁

        layer.threeRenderService.renderer.dispose() // 关闭Three.js的渲染器(避免出现上下文丢失的问题)

        scene.destroy() // 销毁L7的Scene
      }, 4000);

    }
  }).animate(true);
  scene.addLayer(threeJSLayer);
});

经测试呢,不出现THREE.WebGLRenderer: Context Lost报错,但是有概率会出现regl的Context Lost,供参考

1772

多谢 确实是的 是不是要考虑解决 @lzxue

lzxue commented 3 months ago

@zuoyifeng codesanbox 提供个在线demo?

zuoyifeng commented 3 months ago

@zuoyifeng codesanbox 提供个在线demo?

不会弄😅