engine icon indicating copy to clipboard operation
engine copied to clipboard

频繁加载和销毁gltf,存在内存泄漏

Open xujie-phper opened this issue 5 months ago • 0 comments

代码示例

`import React, { useEffect, useState, useRef } from 'react'; import { Button } from 'antd-mobile'; import { WebGLEngine, Scene, Entity, Camera, DirectLight, Vector3, AssetType, GLTFResource, Animator, } from '@galacean/engine'; import { LitePhysics } from '@galacean/engine-physics-lite'; import { registerIncludes } from '@galacean/engine-toolkit'; import { ShaderLab } from '@galacean/engine-shader-lab'; import { OrbitControl } from '@galacean/engine-toolkit'; import './styles.less';

export default () => { const canvasRef = useRef<HTMLCanvasElement>(null); const engineRef = useRef<WebGLEngine | null>(null); const sceneRef = useRef<Scene | null>(null); const rootEntityRef = useRef<Entity | null>(null); const modelEntityRef = useRef<Entity | null>(null); const animatorRef = useRef<Animator | null>(null); const requestRef = useRef<number | null>(null);

const [isLoading, setIsLoading] = useState(false);

// 初始化引擎 const initEngine = async () => { if (!canvasRef.current) return;

try {
  registerIncludes();
  const shaderLab = new ShaderLab();

  const engine = await WebGLEngine.create({
    canvas: 'canvas',
    physics: new LitePhysics(),
    shaderLab,
    graphicDeviceOptions: {
      preserveDrawingBuffer: false,
    },
  });

  engine.canvas.resizeByClientSize();

  // 创建场景
  const scene = engine.sceneManager.activeScene;

  // 创建根实体
  const rootEntity = scene.createRootEntity();

  // 创建相机
  const cameraEntity = rootEntity.createChild('camera');
  const camera = cameraEntity.addComponent(Camera);
  cameraEntity.addComponent(OrbitControl);

  cameraEntity.transform.setPosition(0, 0, 2);

  // 创建光源
  const lightEntity = rootEntity.createChild('directLight');
  const light = lightEntity.addComponent(DirectLight);
  lightEntity.transform.setPosition(1, 1, 1);
  lightEntity.transform.lookAt(new Vector3(0, 0, 0));
  light.intensity = 1.0;

  // 设置场景背景
  scene.background.solidColor.set(0.5, 0.5, 0.5, 1);

  engineRef.current = engine;
  sceneRef.current = scene;
  rootEntityRef.current = rootEntity;

  await loadModel(
    'https://mdn.alipayobjects.com/chain_myent/uri/file/as/mynftmerchant/202508141045460216.gltf',
  );

  engine.run();

  // 窗口大小变化处理
  const handleResize = () => {
    engine.canvas.resizeByClientSize();
  };
  window.addEventListener('resize', handleResize);

  return () => {
    window.removeEventListener('resize', handleResize);
  };
} catch (err) {
  console.error('初始化引擎失败:', err);
}

};

// 加载模型 const loadModel = async (modelUrl: string) => { if (!engineRef.current || !sceneRef.current) return;

setIsLoading(true);
const requestId = ++requestRef.current;

try {
  console.log('开始加载模型:', modelUrl);

  // 清除之前的模型
  if (modelEntityRef.current) {
    modelEntityRef.current.destroy();
    modelEntityRef.current = null;
    animatorRef.current = null;
  }

  // 加载GLTF资源
  const gltfResource = await engineRef.current.resourceManager.load<GLTFResource>({
    url: modelUrl,
    type: AssetType.GLTF,
    timeout: 20000,
  });

  //竟态检查
  if (requestId !== requestRef.current) {
    const gltfRoot = gltfResource.instantiateSceneRoot();
    gltfRoot?.destroy();
    return;
  }

  console.log('模型加载成功:', gltfResource);

  // 创建模型实体
  const modelEntity = rootEntityRef.current!.createChild('model');
  const gltfRoot = gltfResource.instantiateSceneRoot();

  // 将GLTF根节点添加到场景中
  modelEntity.addChild(gltfRoot);

  console.log(rootEntityRef.current, '===rootEntityRef.current');

  modelEntityRef.current = modelEntity;
} catch (err) {
  console.error('加载模型失败:', err);
} finally {
  setIsLoading(false);
}

};

// 随机更换模型,MODEL_CONFIGS就是模型列表 const changeRandomModel = () => { const randomIndex = Math.floor(Math.random() * MODEL_CONFIGS.length); const newModelUrl = MODEL_CONFIGS[randomIndex].url;

console.log('切换到新模型:', newModelUrl);
loadModel(newModelUrl);

};

useEffect(() => { initEngine();

return () => {
  if (engineRef.current) {
    engineRef.current.destroy();
  }
};

}, []);

return ( <div className="url-test-container"> <canvas id="canvas" ref={canvasRef} className="galacean-canvas" style={{ width: '100vw', height: '100vw' }} />

  <Button color="primary" onClick={changeRandomModel}>
    随机更换模型
  </Button>
</div>

); };`

内存表现

与机型,设备无关,通用行为

Image

引擎版本

1.3.19

xujie-phper avatar Sep 22 '25 06:09 xujie-phper