|  | @@ -1,44 +1,51 @@
 | 
	
		
			
				|  |  |  import * as THREE from 'three';
 | 
	
		
			
				|  |  |  import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
 | 
	
		
			
				|  |  |  // 导入轨道控制器
 | 
	
		
			
				|  |  | -import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
 | 
	
		
			
				|  |  | -import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer'
 | 
	
		
			
				|  |  | +import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
 | 
	
		
			
				|  |  | +import { CSS3DRenderer } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
 | 
	
		
			
				|  |  |  // import gsap from 'gsap';
 | 
	
		
			
				|  |  | -import ResourceTracker from '/@/utils/threejs/ResourceTracker';
 | 
	
		
			
				|  |  | -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
 | 
	
		
			
				|  |  | -import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +import ResourceTracker from '/@/utils/threejs/ResourceTracker.js';
 | 
	
		
			
				|  |  | +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
 | 
	
		
			
				|  |  | +import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
 | 
	
		
			
				|  |  | +import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
 | 
	
		
			
				|  |  | +import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader.js';
 | 
	
		
			
				|  |  | +import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
 | 
	
		
			
				|  |  | +import { setModalCenter } from '/@/utils/threejs/util';
 | 
	
		
			
				|  |  | +import Stats from 'three/examples/jsm/libs/stats.module.js';
 | 
	
		
			
				|  |  | +import { useModelStore } from '/@/store/modules/threejs';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class UseThree {
 | 
	
		
			
				|  |  | -  canvasContainer: HTMLCanvasElement;
 | 
	
		
			
				|  |  | -  CSSCanvasContainer: HTMLCanvasElement | null = null;
 | 
	
		
			
				|  |  | -  camera: THREE.PerspectiveCamera | null = null;
 | 
	
		
			
				|  |  | +  stats: Stats | null = null; // 帧
 | 
	
		
			
				|  |  | +  canvasContainer: HTMLCanvasElement | null; //canvas 容器
 | 
	
		
			
				|  |  | +  CSSCanvasContainer: HTMLCanvasElement | null = null; // css canvas 容器
 | 
	
		
			
				|  |  | +  camera: THREE.PerspectiveCamera | null = null; // 相机
 | 
	
		
			
				|  |  |    scene: THREE.Scene | null = null;
 | 
	
		
			
				|  |  |    renderer: THREE.WebGLRenderer | null = null;
 | 
	
		
			
				|  |  |    css3dRender: CSS3DRenderer | null = null;
 | 
	
		
			
				|  |  |    orbitControls: OrbitControls | null = null;
 | 
	
		
			
				|  |  | -  giftLoader: THREE.Object3D | null = null;
 | 
	
		
			
				|  |  | -  animationMixer: THREE.AnimationMixer | null = null;
 | 
	
		
			
				|  |  |    animationAction: THREE.AnimationAction | null = null;
 | 
	
		
			
				|  |  | -  clock: THREE.Clock = new THREE.Clock(); // 计时器
 | 
	
		
			
				|  |  | +  clock: THREE.Clock | null = new THREE.Clock(); // 计时器
 | 
	
		
			
				|  |  |    timeoutId: NodeJS.Timeout | null = null;
 | 
	
		
			
				|  |  | -  animationId: number = 0
 | 
	
		
			
				|  |  | -  resourceTracker:ResourceTracker | null = null
 | 
	
		
			
				|  |  | -  track: any = null
 | 
	
		
			
				|  |  | -  spriteText: THREE.Sprite | null = null
 | 
	
		
			
				|  |  | +  animationId = 0;
 | 
	
		
			
				|  |  | +  spriteText: THREE.Sprite | null = null;
 | 
	
		
			
				|  |  | +  mouse = new THREE.Vector2();
 | 
	
		
			
				|  |  | +  rayCaster: THREE.Raycaster | null = null;
 | 
	
		
			
				|  |  | +  animations: THREE.AnimationClip[] = [];
 | 
	
		
			
				|  |  | +  mixers: THREE.AnimationMixer[] = [];
 | 
	
		
			
				|  |  | +  FPS = 40;
 | 
	
		
			
				|  |  | +  timeS = 0;
 | 
	
		
			
				|  |  | +  resourceTracker: ResourceTracker | null = null;
 | 
	
		
			
				|  |  | +  track: any = null;
 | 
	
		
			
				|  |  | +  composer; //后期
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    constructor(canvasSelector, cssCanvas?) {
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.resourceTracker = new ResourceTracker()
 | 
	
		
			
				|  |  | -    this.track = this.resourceTracker.track.bind(this.resourceTracker)
 | 
	
		
			
				|  |  | -    this.animationId = 0
 | 
	
		
			
				|  |  | +    this.resourceTracker = new ResourceTracker();
 | 
	
		
			
				|  |  | +    this.track = this.resourceTracker.track.bind(this.resourceTracker);
 | 
	
		
			
				|  |  | +    this.animationId = 0;
 | 
	
		
			
				|  |  |      this.canvasContainer = document.querySelector(canvasSelector);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      //初始化
 | 
	
		
			
				|  |  |      this.init(cssCanvas);
 | 
	
		
			
				|  |  | -    this.animate();
 | 
	
		
			
				|  |  | +    // this.animate();
 | 
	
		
			
				|  |  |      window.addEventListener('resize', this.resizeRenderer.bind(this));
 | 
	
		
			
				|  |  |      // 添加滚动事件,鼠标滚动模型执行动画
 | 
	
		
			
				|  |  |      // window.addEventListener('wheel', this.wheelRenderer.bind(this));
 | 
	
	
		
			
				|  | @@ -47,31 +54,39 @@ class UseThree {
 | 
	
		
			
				|  |  |      // 初始化场景
 | 
	
		
			
				|  |  |      this.initScene();
 | 
	
		
			
				|  |  |      // 初始化环境光
 | 
	
		
			
				|  |  | -    this.initLight();
 | 
	
		
			
				|  |  | +    // this.initLight();
 | 
	
		
			
				|  |  |      // 初始化相机
 | 
	
		
			
				|  |  |      this.initCamera();
 | 
	
		
			
				|  |  |      //初始化渲染器
 | 
	
		
			
				|  |  |      this.initRenderer();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      // 初始化控制器
 | 
	
		
			
				|  |  |      this.initControles();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if(cssCanvas){
 | 
	
		
			
				|  |  | -      this.initCSSRenderer(cssCanvas)
 | 
	
		
			
				|  |  | -      // this.addTextSprite()
 | 
	
		
			
				|  |  | +    if (cssCanvas) {
 | 
	
		
			
				|  |  | +      this.initCSSRenderer(cssCanvas);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    // this.setTestPlane()
 | 
	
		
			
				|  |  | +    // this.setTestPlane();
 | 
	
		
			
				|  |  | +    this.rayCaster = this.track(new THREE.Raycaster());
 | 
	
		
			
				|  |  | +    this.createStats();
 | 
	
		
			
				|  |  | +    // this.removeSawtooth();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  createStats() {
 | 
	
		
			
				|  |  | +    this.stats = Stats();
 | 
	
		
			
				|  |  | +    this.stats?.setMode(0);
 | 
	
		
			
				|  |  | +    this.stats.domElement.style.position = 'absolute';
 | 
	
		
			
				|  |  | +    this.stats.domElement.style.left = '200px';
 | 
	
		
			
				|  |  | +    this.stats.domElement.style.top = '100px';
 | 
	
		
			
				|  |  | +    document.body.appendChild(this.stats.domElement);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    initScene() {
 | 
	
		
			
				|  |  |      this.scene = this.track(new THREE.Scene());
 | 
	
		
			
				|  |  |      // const axesHelper = new THREE.AxesHelper(100);
 | 
	
		
			
				|  |  |      // this.scene?.add(axesHelper);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      // const size = 1000;
 | 
	
		
			
				|  |  |      // const divisions = 10;
 | 
	
		
			
				|  |  | -    // const gridHelper = new THREE.GridHelper( size, divisions );
 | 
	
		
			
				|  |  | -    // this.scene?.add( gridHelper )
 | 
	
		
			
				|  |  | +    // const gridHelper = new THREE.GridHelper(size, divisions);
 | 
	
		
			
				|  |  | +    // this.scene?.add(gridHelper);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    initLight() {
 | 
	
	
		
			
				|  | @@ -81,192 +96,192 @@ class UseThree {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    initCamera() {
 | 
	
		
			
				|  |  | -    this.camera = this.track(new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 1000));
 | 
	
		
			
				|  |  | -    this.camera?.position.set(0, 0.2, 0.3);
 | 
	
		
			
				|  |  | -    // const helper = new THREE.CameraHelper( this.camera);
 | 
	
		
			
				|  |  | -    // this.scene?.add( helper );
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | +    this.camera = this.track(new THREE.PerspectiveCamera(50, this.canvasContainer.clientWidth / this.canvasContainer.clientHeight, 0.000001, 10000));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // const helper = new THREE.CameraHelper(this.camera);
 | 
	
		
			
				|  |  | +    // this.scene?.add(helper);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    initRenderer() {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.renderer = this.track(new THREE.WebGLRenderer({ antialias: true, alpha:true })) as THREE.WebGLRenderer;
 | 
	
		
			
				|  |  | +    this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true }) as THREE.WebGLRenderer;
 | 
	
		
			
				|  |  |      // 设置屏幕像素比
 | 
	
		
			
				|  |  |      this.renderer?.setPixelRatio(window.devicePixelRatio);
 | 
	
		
			
				|  |  |      // 设置渲染的尺寸
 | 
	
		
			
				|  |  | -    this.renderer?.setSize(window.innerWidth, window.innerHeight);
 | 
	
		
			
				|  |  | +    this.renderer?.setSize(this.canvasContainer.clientWidth, this.canvasContainer.clientHeight);
 | 
	
		
			
				|  |  |      // 色调映射
 | 
	
		
			
				|  |  |      this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      this.renderer.outputEncoding = THREE.sRGBEncoding;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    this.renderer.shadowMap.enabled = true
 | 
	
		
			
				|  |  | +    this.renderer.shadowMap.enabled = true;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
 | 
	
		
			
				|  |  | +    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      // 曝光程度
 | 
	
		
			
				|  |  |      this.renderer.toneMappingExposure = 1;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    this.canvasContainer.appendChild(this.renderer.domElement);
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | +    this.canvasContainer?.appendChild(this.renderer.domElement);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    initCSSRenderer(cssCanvas) {
 | 
	
		
			
				|  |  |      this.CSSCanvasContainer = document.querySelector(cssCanvas);
 | 
	
		
			
				|  |  | -    this.css3dRender = this.track(new CSS3DRenderer()) as CSS3DRenderer
 | 
	
		
			
				|  |  | -    this.css3dRender.setSize((window.innerWidth), (window.innerHeight))
 | 
	
		
			
				|  |  | -    this.CSSCanvasContainer?.appendChild(this.css3dRender.domElement)
 | 
	
		
			
				|  |  | -    this.css3dRender.render(this.scene as THREE.Scene, this.camera as THREE.PerspectiveCamera)
 | 
	
		
			
				|  |  | +    this.css3dRender = this.track(new CSS3DRenderer()) as CSS3DRenderer;
 | 
	
		
			
				|  |  | +    this.css3dRender.setSize(this.canvasContainer.clientWidth, this.canvasContainer.clientHeight);
 | 
	
		
			
				|  |  | +    this.CSSCanvasContainer?.appendChild(this.css3dRender.domElement);
 | 
	
		
			
				|  |  | +    this.css3dRender.render(this.scene as THREE.Scene, this.camera as THREE.PerspectiveCamera);
 | 
	
		
			
				|  |  |      this.orbitControls = this.track(new OrbitControls(this.camera as THREE.Camera, this.css3dRender?.domElement)) as OrbitControls;
 | 
	
		
			
				|  |  | -    this.orbitControls.update()
 | 
	
		
			
				|  |  | -    // this.orbitControls.enableZoom = false;
 | 
	
		
			
				|  |  | -    // // to disable rotation
 | 
	
		
			
				|  |  | -    // this.orbitControls.enableRotate = false;
 | 
	
		
			
				|  |  | -    // // to disable pan
 | 
	
		
			
				|  |  | -    // this.orbitControls.enablePan = false;
 | 
	
		
			
				|  |  | +    this.orbitControls.update();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    initControles() {
 | 
	
		
			
				|  |  |      this.orbitControls = this.track(new OrbitControls(this.camera as THREE.Camera, this.renderer?.domElement)) as OrbitControls;
 | 
	
		
			
				|  |  | -    this.orbitControls.update()
 | 
	
		
			
				|  |  | -    // this.orbitControls.enableZoom = false;
 | 
	
		
			
				|  |  | -    // // to disable rotation
 | 
	
		
			
				|  |  | -    // this.orbitControls.enableRotate = false;
 | 
	
		
			
				|  |  | -    // // to disable pan
 | 
	
		
			
				|  |  | -    // this.orbitControls.enablePan = false;
 | 
	
		
			
				|  |  | +    this.orbitControls.update();
 | 
	
		
			
				|  |  | +    // this.orbitControls.enableDamping = true;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  setModalCenter(group) {
 | 
	
		
			
				|  |  | -    var box3 = new THREE.Box3()
 | 
	
		
			
				|  |  | -  
 | 
	
		
			
				|  |  | -    // 计算层级模型group的包围盒
 | 
	
		
			
				|  |  | -    // 模型group是加载一个三维模型返回的对象,包含多个网格模型
 | 
	
		
			
				|  |  | -    box3.expandByObject(group)
 | 
	
		
			
				|  |  | -    // 计算一个层级模型对应包围盒的几何体中心在世界坐标中的位置
 | 
	
		
			
				|  |  | -    var center = new THREE.Vector3()
 | 
	
		
			
				|  |  | -    box3.getCenter(center)
 | 
	
		
			
				|  |  | -    // console.log('查看几何体中心坐标', center);
 | 
	
		
			
				|  |  | -    // 重新设置模型的位置,使之居中。
 | 
	
		
			
				|  |  | -    group.position.x = group.position.x - center.x
 | 
	
		
			
				|  |  | -    group.position.y = group.position.y - center.y
 | 
	
		
			
				|  |  | -    group.position.z = group.position.z - center.z
 | 
	
		
			
				|  |  | -  };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    setModel(modalName) {
 | 
	
		
			
				|  |  | -    const a = new Date().getTime() / 1000
 | 
	
		
			
				|  |  | +    const modelStore = useModelStore();
 | 
	
		
			
				|  |  |      return new Promise(async (resolve, reject) => {
 | 
	
		
			
				|  |  |        try {
 | 
	
		
			
				|  |  | -        const db =  window['CustomDB']
 | 
	
		
			
				|  |  | -        const modalArr =  await db.modal.where('modalName').equals(modalName).toArray()
 | 
	
		
			
				|  |  | -        // debugger
 | 
	
		
			
				|  |  | -        if(modalArr.length > 0) {
 | 
	
		
			
				|  |  | -          const modalValue = modalArr[0].modalVal
 | 
	
		
			
				|  |  | +        const a = new Date().getTime();
 | 
	
		
			
				|  |  | +        let modalValue = modelStore.modelArr.get(modalName);
 | 
	
		
			
				|  |  | +        if (!modalValue) {
 | 
	
		
			
				|  |  | +          const db = window['CustomDB'];
 | 
	
		
			
				|  |  | +          const modalArr = await db.modal.where('modalName').equals(modalName).toArray();
 | 
	
		
			
				|  |  | +          modalValue = modalArr[0].modalVal;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (modalValue) {
 | 
	
		
			
				|  |  | +          console.log('模型下载速度', new Date().getTime() - a);
 | 
	
		
			
				|  |  | +          const b = new Date().getTime();
 | 
	
		
			
				|  |  |            try {
 | 
	
		
			
				|  |  | -            const gltfLoader = new GLTFLoader()
 | 
	
		
			
				|  |  | -            const dracoLoader = new DRACOLoader();
 | 
	
		
			
				|  |  | -            dracoLoader.setDecoderPath( '/3D/draco/gltf/' );
 | 
	
		
			
				|  |  | -            dracoLoader.setDecoderConfig({ type: "js" }); //使用兼容性强的draco_decoder.js解码器
 | 
	
		
			
				|  |  | +            const gltfLoader = this.track(new GLTFLoader());
 | 
	
		
			
				|  |  | +            const dracoLoader = this.track(new DRACOLoader());
 | 
	
		
			
				|  |  | +            dracoLoader.setDecoderPath('/model/draco/gltf/');
 | 
	
		
			
				|  |  | +            dracoLoader.setDecoderConfig({ type: 'js' }); //使用兼容性强的draco_decoder.js解码器
 | 
	
		
			
				|  |  |              dracoLoader.preload();
 | 
	
		
			
				|  |  |              gltfLoader.setDRACOLoader(dracoLoader);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            gltfLoader.setPath('/3d/glft/')
 | 
	
		
			
				|  |  | -            gltfLoader.parse(modalValue, '/3d/glft/', (gltf) => {
 | 
	
		
			
				|  |  | -              const object = this.track(gltf.scene.children[0])
 | 
	
		
			
				|  |  | -              this.setModalCenter(object)
 | 
	
		
			
				|  |  | -              object.traverse((obj) => {
 | 
	
		
			
				|  |  | -                if (obj instanceof THREE.Mesh) {
 | 
	
		
			
				|  |  | -                  obj.material.emissiveIntensity = 1
 | 
	
		
			
				|  |  | -                  obj.material.emissiveMap = obj.material.map
 | 
	
		
			
				|  |  | -                  if(obj.name !== "buxiugangse") {
 | 
	
		
			
				|  |  | -                    obj.receiveShadow = true
 | 
	
		
			
				|  |  | +            gltfLoader.setPath('/model/glft/');
 | 
	
		
			
				|  |  | +            gltfLoader.parse(
 | 
	
		
			
				|  |  | +              modalValue,
 | 
	
		
			
				|  |  | +              '/model/glft/',
 | 
	
		
			
				|  |  | +              (gltf) => {
 | 
	
		
			
				|  |  | +                const object = this.track(gltf.scene);
 | 
	
		
			
				|  |  | +                setModalCenter(object);
 | 
	
		
			
				|  |  | +                object.traverse((obj) => {
 | 
	
		
			
				|  |  | +                  if (obj instanceof THREE.Mesh) {
 | 
	
		
			
				|  |  | +                    obj.material.emissiveIntensity = 1;
 | 
	
		
			
				|  |  | +                    obj.material.emissiveMap = obj.material.map;
 | 
	
		
			
				|  |  | +                    obj.material.blending = THREE.CustomBlending;
 | 
	
		
			
				|  |  | +                    if (obj.name !== 'buxiugangse') {
 | 
	
		
			
				|  |  | +                      obj.receiveShadow = true;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    obj.castShadow = true;
 | 
	
		
			
				|  |  |                    }
 | 
	
		
			
				|  |  | -                  obj.castShadow = true
 | 
	
		
			
				|  |  | -                  
 | 
	
		
			
				|  |  | -                  
 | 
	
		
			
				|  |  | -                } else if (obj.type === 'Object3D') {
 | 
	
		
			
				|  |  | -                  // const text3D = this.addYFText(obj)
 | 
	
		
			
				|  |  | -                  // const textCQ3D = this.addCQText(obj)
 | 
	
		
			
				|  |  | -                  // gltf.scene.add(text3D)
 | 
	
		
			
				|  |  | -                  // gltf.scene.add(textCQ3D)
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -              })
 | 
	
		
			
				|  |  | -              this.scene?.add(object);
 | 
	
		
			
				|  |  | -              console.log(object);
 | 
	
		
			
				|  |  | -              resolve(object)
 | 
	
		
			
				|  |  | -            }, (err)=> {
 | 
	
		
			
				|  |  | -              console.log(err);
 | 
	
		
			
				|  |  | -              
 | 
	
		
			
				|  |  | -            })
 | 
	
		
			
				|  |  | -  
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +                object.name = modalName;
 | 
	
		
			
				|  |  | +                this.scene?.add(object);
 | 
	
		
			
				|  |  | +                console.log('模型渲染时间', object, new Date().getTime() - b);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                resolve(gltf);
 | 
	
		
			
				|  |  | +                dracoLoader.dispose();
 | 
	
		
			
				|  |  | +              },
 | 
	
		
			
				|  |  | +              (err) => {
 | 
	
		
			
				|  |  | +                console.log(err);
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  |            } catch (error) {
 | 
	
		
			
				|  |  |              console.log(error);
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  | -        } 
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |        } catch (error) {
 | 
	
		
			
				|  |  | -        reject('加载模型出错')
 | 
	
		
			
				|  |  | +        reject('加载模型出错');
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -    })
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    setTestPlane() {
 | 
	
		
			
				|  |  | -			const plane = new THREE.Mesh(
 | 
	
		
			
				|  |  | -				new THREE.PlaneGeometry( 100, 100 ),
 | 
	
		
			
				|  |  | -				new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
 | 
	
		
			
				|  |  | -			);
 | 
	
		
			
				|  |  | -			plane.rotation.x = - Math.PI / 2;
 | 
	
		
			
				|  |  | -			plane.position.y = 0.03;
 | 
	
		
			
				|  |  | -			plane.receiveShadow = true;
 | 
	
		
			
				|  |  | -			// this.scene?.add( plane );
 | 
	
		
			
				|  |  | +    const plane = this.track(new THREE.Mesh(new THREE.PlaneGeometry(100, 100), new THREE.MeshPhongMaterial({ color: 0x999999, specular: 0x101010 })));
 | 
	
		
			
				|  |  | +    plane.rotation.x = -Math.PI / 2;
 | 
	
		
			
				|  |  | +    plane.position.y = 0.03;
 | 
	
		
			
				|  |  | +    plane.receiveShadow = true;
 | 
	
		
			
				|  |  | +    this.scene?.add(plane);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  removeSawtooth() {
 | 
	
		
			
				|  |  | +    this.composer = this.track(new EffectComposer(this.renderer as THREE.WebGLRenderer));
 | 
	
		
			
				|  |  | +    const FXAAShaderPass = this.track(new ShaderPass(FXAAShader));
 | 
	
		
			
				|  |  | +    FXAAShaderPass.uniforms['resolution'].value.set(1 / this.canvasContainer.clientWidth, 1 / this.canvasContainer.clientHeight);
 | 
	
		
			
				|  |  | +    FXAAShaderPass.renderToScreen = true;
 | 
	
		
			
				|  |  | +    this.composer.addPass(FXAAShaderPass);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    /* 自定义材质 */
 | 
	
		
			
				|  |  | -  setCustomMaterial(group){}
 | 
	
		
			
				|  |  | +  setCustomMaterial(group) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* 场景环境背景 */
 | 
	
		
			
				|  |  |    setEnvMap(hdr) {
 | 
	
		
			
				|  |  | -    // new RGBELoader().setPath('/public/3D/hdr/').load(hdr + '.jpeg', (texture) => {
 | 
	
		
			
				|  |  | +    // new RGBELoader().setPath('/public/model/hdr/').load(hdr + '.jpeg', (texture) => {
 | 
	
		
			
				|  |  |      //   debugger
 | 
	
		
			
				|  |  |      //   texture.mapping = THREE.EquirectangularReflectionMapping;
 | 
	
		
			
				|  |  |      //   (this.scene as THREE.Scene).background = texture;
 | 
	
		
			
				|  |  |      //   (this.scene as THREE.Scene).environment = texture;
 | 
	
		
			
				|  |  |      // });
 | 
	
		
			
				|  |  | -    new THREE.TextureLoader().setPath('/3D/hdr/').load(hdr + '.jpeg', (texture) => {
 | 
	
		
			
				|  |  | -      texture.mapping = THREE.EquirectangularReflectionMapping;
 | 
	
		
			
				|  |  | -      // (this.scene as THREE.Scene).background = new THREE.Color('#00000000');
 | 
	
		
			
				|  |  | -      (this.scene as THREE.Scene).environment = texture;
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | +    this.track(new THREE.TextureLoader())
 | 
	
		
			
				|  |  | +      .setPath('/model/hdr/')
 | 
	
		
			
				|  |  | +      .load(hdr + '.jpeg', (texture) => {
 | 
	
		
			
				|  |  | +        this.track(texture);
 | 
	
		
			
				|  |  | +        texture.mapping = THREE.EquirectangularReflectionMapping;
 | 
	
		
			
				|  |  | +        // (this.scene as THREE.Scene).background = texture;
 | 
	
		
			
				|  |  | +        (this.scene as THREE.Scene).environment = texture;
 | 
	
		
			
				|  |  | +      });
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    render() {
 | 
	
		
			
				|  |  | -    const delta = this.clock.getElapsedTime();
 | 
	
		
			
				|  |  | -    this.resetLookAt()
 | 
	
		
			
				|  |  | -    this.startMY()
 | 
	
		
			
				|  |  | -    this.renderer?.render(this.scene as THREE.Object3D, this.camera as THREE.Camera);
 | 
	
		
			
				|  |  | -    this.css3dRender?.render(this.scene as THREE.Scene, this.camera as THREE.PerspectiveCamera)
 | 
	
		
			
				|  |  | -    this.animationMixer?.update(delta);
 | 
	
		
			
				|  |  | +    this.camera?.updateMatrixWorld();
 | 
	
		
			
				|  |  | +    this.stats?.update();
 | 
	
		
			
				|  |  | +    this.resetLookAt();
 | 
	
		
			
				|  |  | +    this.startMY();
 | 
	
		
			
				|  |  | +    this.startAnimation();
 | 
	
		
			
				|  |  | +    this.orbitControls?.update();
 | 
	
		
			
				|  |  | +    this.composer?.render();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // this.css3dRender?.render(this.scene as THREE.Scene, this.camera as THREE.PerspectiveCamera)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* 实时物体刷新朝向 */
 | 
	
		
			
				|  |  | -  resetLookAt() {
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +  resetLookAt() {}
 | 
	
		
			
				|  |  |    /* 漫游 */
 | 
	
		
			
				|  |  |    startMY() {}
 | 
	
		
			
				|  |  | +  /* 初始动画 */
 | 
	
		
			
				|  |  | +  startAnimation() {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    animate() {
 | 
	
		
			
				|  |  | -    // this.renderer?.setAnimationLoop(this.render.bind(this));
 | 
	
		
			
				|  |  | -    if(this.animationId != -1) {
 | 
	
		
			
				|  |  | -      this.render()
 | 
	
		
			
				|  |  | -      this.animationId = requestAnimationFrame(this.animate.bind(this))
 | 
	
		
			
				|  |  | +    if (this.animationId != -1) {
 | 
	
		
			
				|  |  | +      setTimeout(() => {
 | 
	
		
			
				|  |  | +        this.animationId = requestAnimationFrame(this.animate.bind(this));
 | 
	
		
			
				|  |  | +      }, 1000 / 30);
 | 
	
		
			
				|  |  | +      this.renderer?.render(this.scene as THREE.Object3D, this.camera as THREE.Camera);
 | 
	
		
			
				|  |  | +      this.render();
 | 
	
		
			
				|  |  | +      // this.animationId = requestAnimationFrame(this.animate.bind(this));
 | 
	
		
			
				|  |  | +      // const T = this.clock.getDelta();
 | 
	
		
			
				|  |  | +      // this.timeS += T;
 | 
	
		
			
				|  |  | +      // if (this.timeS > 1 / this.FPS) {
 | 
	
		
			
				|  |  | +      //   this.render();
 | 
	
		
			
				|  |  | +      //   this.timeS = 0;
 | 
	
		
			
				|  |  | +      // }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    resizeRenderer() {
 | 
	
		
			
				|  |  |      // 更新相机比例
 | 
	
		
			
				|  |  | -    (this.camera as THREE.PerspectiveCamera).aspect = window.innerWidth / window.innerHeight;
 | 
	
		
			
				|  |  | +    (this.camera as THREE.PerspectiveCamera).aspect = this.canvasContainer.clientWidth / this.canvasContainer.clientHeight;
 | 
	
		
			
				|  |  |      // 刷新相机矩阵
 | 
	
		
			
				|  |  |      this.camera?.updateProjectionMatrix();
 | 
	
		
			
				|  |  |      // 设置场景尺寸
 | 
	
		
			
				|  |  | -    this.renderer?.setSize(window.innerWidth, window.innerHeight);
 | 
	
		
			
				|  |  | -    this.css3dRender?.setSize(window.innerWidth, window.innerHeight);
 | 
	
		
			
				|  |  | +    this.renderer?.setSize(this.canvasContainer.clientWidth, this.canvasContainer.clientHeight);
 | 
	
		
			
				|  |  | +    // this.css3dRender?.setSize(this.canvasContainer.clientWidth, this.canvasContainer.clientHeight);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    wheelRenderer(e: WheelEvent) {
 | 
	
		
			
				|  |  |      const timeScale = e.deltaY > 0 ? 1 : -1;
 | 
	
	
		
			
				|  | @@ -280,162 +295,86 @@ class UseThree {
 | 
	
		
			
				|  |  |        this.animationAction?.halt(0.5);
 | 
	
		
			
				|  |  |      }, 500);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    deleteModal() {
 | 
	
		
			
				|  |  |      try {
 | 
	
		
			
				|  |  | -      
 | 
	
		
			
				|  |  | -      this.resourceTracker && this.resourceTracker.dispose()
 | 
	
		
			
				|  |  | -      this.renderer?.dispose()
 | 
	
		
			
				|  |  | -      this.renderer?.forceContextLoss()
 | 
	
		
			
				|  |  | -      // this.renderer?.domElement = null
 | 
	
		
			
				|  |  | -      this.renderer = null
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      // this.css3dRender?.domElement = null
 | 
	
		
			
				|  |  | +      const gl = this.renderer?.domElement?.getContext('webgl');
 | 
	
		
			
				|  |  | +      gl && gl.getExtension('WEBGL_lose_context')?.loseContext();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      const gl1 = this.css3dRender?.domElement?.getContext('webgl');
 | 
	
		
			
				|  |  | +      gl1 && gl1.getExtension('WEBGL_lose_context')?.loseContext();
 | 
	
		
			
				|  |  | +      this.renderer?.forceContextLoss();
 | 
	
		
			
				|  |  | +      this.renderer?.dispose();
 | 
	
		
			
				|  |  | +      if (this.renderer) this.renderer.domElement = null;
 | 
	
		
			
				|  |  | +      this.renderer = null;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      this.resourceTracker && this.resourceTracker.dispose();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (this.canvasContainer) this.canvasContainer.innerHTML = '';
 | 
	
		
			
				|  |  | +      this.canvasContainer = null;
 | 
	
		
			
				|  |  | +      this.orbitControls = null;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        this.css3dRender = null;
 | 
	
		
			
				|  |  | +      this.camera = null;
 | 
	
		
			
				|  |  | +      this.clock = null;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        cancelAnimationFrame(this.animationId);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      const gl = this.renderer?.domElement.getContext("webgl");
 | 
	
		
			
				|  |  | -      gl && gl?.getExtension("WEBGL_lose_context")?.loseContext();
 | 
	
		
			
				|  |  | +      this.animationId = -1;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      const gl1 = this.css3dRender?.domElement.getContext("webgl");
 | 
	
		
			
				|  |  | -      gl1 && gl1?.getExtension("WEBGL_lose_context")?.loseContext();
 | 
	
		
			
				|  |  | +      this.scene = null;
 | 
	
		
			
				|  |  | +      this.mixers = [];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      this.animationId = -1
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      this.resourceTracker?.untrack(this.resourceTracker.resources)
 | 
	
		
			
				|  |  | -      // this.scene = null
 | 
	
		
			
				|  |  | -      console.log('销毁场景',this.scene);
 | 
	
		
			
				|  |  | -      
 | 
	
		
			
				|  |  | +      console.log('销毁场景', this.scene);
 | 
	
		
			
				|  |  |      } catch (error) {
 | 
	
		
			
				|  |  |        console.log(error);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    // this.scene?.children.forEach((obj:any) => {
 | 
	
		
			
				|  |  | -    //   if(obj.type === 'Group'){
 | 
	
		
			
				|  |  | -    //     obj.traverse(function(item:any) {
 | 
	
		
			
				|  |  | -    //       if (item.type === 'Mesh') {
 | 
	
		
			
				|  |  | -    //         item.geometry.dispose();
 | 
	
		
			
				|  |  | -    //         item.material.dispose();
 | 
	
		
			
				|  |  | -    //         !!item.clear&&item.clear();
 | 
	
		
			
				|  |  | -    //       }
 | 
	
		
			
				|  |  | -    //     })
 | 
	
		
			
				|  |  | -    //   }else if (obj.material) {
 | 
	
		
			
				|  |  | -    //     obj.material.dispose();
 | 
	
		
			
				|  |  | -    //   }else if (obj.geometry) {
 | 
	
		
			
				|  |  | -    //     obj.geometry.dispose();
 | 
	
		
			
				|  |  | -    //   }
 | 
	
		
			
				|  |  | -    //   this.scene?.remove(obj)
 | 
	
		
			
				|  |  | -    //   !!obj.clear??obj.clear()
 | 
	
		
			
				|  |  | -    //   obj = null;
 | 
	
		
			
				|  |  | -    // })
 | 
	
		
			
				|  |  | -    // let gl = this.renderer?.domElement.getContext("webgl");
 | 
	
		
			
				|  |  | -    // gl && gl?.getExtension("WEBGL_lose_context")?.loseContext();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // this.renderer?.forceContextLoss();
 | 
	
		
			
				|  |  | -    // this.renderer?.dispose();
 | 
	
		
			
				|  |  | -    // this.camera = null;
 | 
	
		
			
				|  |  | -    // this.orbitControls = null;
 | 
	
		
			
				|  |  | -    // this.renderer.domElement = null;
 | 
	
		
			
				|  |  | -    // this.renderer = null;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // css3dRender.domElement = null;
 | 
	
		
			
				|  |  | -    // css3dRender = null;
 | 
	
		
			
				|  |  | -    // model3D.innerHTML = '';
 | 
	
		
			
				|  |  | -    // css3D.innerHTML = '';
 | 
	
		
			
				|  |  | -    // model3D = null
 | 
	
		
			
				|  |  | -    // css3D = null
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // this.stats = null
 | 
	
		
			
				|  |  | -    // scene = null
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    THREE.Cache.clear();  
 | 
	
		
			
				|  |  | +    THREE.Cache.clear();
 | 
	
		
			
				|  |  |      console.log('3D环境已清理干净');
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  deleteModal1() {
 | 
	
		
			
				|  |  | +    this.scene?.children.forEach((obj) => {
 | 
	
		
			
				|  |  | +      if (obj.type === 'Group') {
 | 
	
		
			
				|  |  | +        obj.traverse(function (item) {
 | 
	
		
			
				|  |  | +          if (item.type === 'Mesh') {
 | 
	
		
			
				|  |  | +            item.geometry.dispose();
 | 
	
		
			
				|  |  | +            item.material.dispose();
 | 
	
		
			
				|  |  | +            !!item.clear && item.clear();
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +      } else if (obj.material) {
 | 
	
		
			
				|  |  | +        obj.material.dispose();
 | 
	
		
			
				|  |  | +      } else if (obj.geometry) {
 | 
	
		
			
				|  |  | +        obj.geometry.dispose();
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      this.scene?.remove(obj);
 | 
	
		
			
				|  |  | +      !!obj.clear ?? obj.clear();
 | 
	
		
			
				|  |  | +      obj = null;
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* 创建字体精灵 */
 | 
	
		
			
				|  |  | -  addTextSprite(message, parameters) {
 | 
	
		
			
				|  |  | -    if (parameters === undefined) parameters = {};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    var fontface = parameters.hasOwnProperty("fontface") ?
 | 
	
		
			
				|  |  | -        parameters["fontface"] : "Arial";
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 字体大小 */
 | 
	
		
			
				|  |  | -    var fontsize = parameters.hasOwnProperty("fontsize") ?
 | 
	
		
			
				|  |  | -        parameters["fontsize"] : 18;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 边框厚度 */
 | 
	
		
			
				|  |  | -    var borderThickness = parameters.hasOwnProperty("borderThickness") ?
 | 
	
		
			
				|  |  | -        parameters["borderThickness"] : 4;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 边框颜色 */
 | 
	
		
			
				|  |  | -    var borderColor = parameters.hasOwnProperty("borderColor") ?
 | 
	
		
			
				|  |  | -        parameters["borderColor"] : { r: 0, g: 0, b: 0, a: 1.0 };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 背景颜色 */
 | 
	
		
			
				|  |  | -    var backgroundColor = parameters.hasOwnProperty("backgroundColor") ?
 | 
	
		
			
				|  |  | -        parameters["backgroundColor"] : { r: 255, g: 255, b: 255, a: 1.0 };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 创建画布 */
 | 
	
		
			
				|  |  | -    var canvas = document.createElement('canvas');
 | 
	
		
			
				|  |  | -    var context = canvas.getContext('2d') as CanvasRenderingContext2D;
 | 
	
		
			
				|  |  | -    // canvas.width = 0
 | 
	
		
			
				|  |  | -    // canvas.height = 200
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 字体加粗 */
 | 
	
		
			
				|  |  | -    context.font = "Bold " + fontsize + "px " + fontface;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 获取文字的大小数据,高度取决于文字的大小 */
 | 
	
		
			
				|  |  | -    var metrics = context.measureText(message);
 | 
	
		
			
				|  |  | -    var textWidth = metrics.width;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 背景颜色 */
 | 
	
		
			
				|  |  | -    context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + ","
 | 
	
		
			
				|  |  | -        + backgroundColor.b + "," + backgroundColor.a + ")";
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 边框的颜色 */
 | 
	
		
			
				|  |  | -    context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
 | 
	
		
			
				|  |  | -        + borderColor.b + "," + borderColor.a + ")";
 | 
	
		
			
				|  |  | -    context.lineWidth = borderThickness;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 绘制圆角矩形 */
 | 
	
		
			
				|  |  | -    this.roundRect(context, borderThickness / 2, borderThickness / 2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);
 | 
	
		
			
				|  |  | -    // this.roundRect(context, borderThickness / 2, borderThickness / 2, 10000, 10000, 6);
 | 
	
		
			
				|  |  | -    /* 字体颜色 */
 | 
	
		
			
				|  |  | -    context.fillStyle = "rgba(0, 0, 0, 1.0)";
 | 
	
		
			
				|  |  | -    context.fillText(message, borderThickness, fontsize + borderThickness);
 | 
	
		
			
				|  |  | -    // context.fillRect(borderThickness / 2, borderThickness / 2, 10000, 10000)
 | 
	
		
			
				|  |  | -    /* 画布内容用于纹理贴图 */
 | 
	
		
			
				|  |  | -    var texture = new THREE.Texture(canvas);
 | 
	
		
			
				|  |  | -    texture.needsUpdate = true;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    var spriteMaterial = new THREE.SpriteMaterial({ map: texture, transparent:false });
 | 
	
		
			
				|  |  | -    var sprite = new THREE.Sprite(spriteMaterial);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* 缩放比例 */
 | 
	
		
			
				|  |  | -    sprite.scale.set(10, 5, 1);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return sprite;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* 绘制圆角矩形 */
 | 
	
		
			
				|  |  | -  roundRect(ctx, x, y, w, h, r) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    ctx.beginPath();
 | 
	
		
			
				|  |  | -    ctx.moveTo(x + r, y);
 | 
	
		
			
				|  |  | -    ctx.lineTo(x + w - r, y);
 | 
	
		
			
				|  |  | -    ctx.quadraticCurveTo(x + w, y, x + w, y + r);
 | 
	
		
			
				|  |  | -    ctx.lineTo(x + w, y + h - r);
 | 
	
		
			
				|  |  | -    ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
 | 
	
		
			
				|  |  | -    ctx.lineTo(x + r, y + h);
 | 
	
		
			
				|  |  | -    ctx.quadraticCurveTo(x, y + h, x, y + h - r);
 | 
	
		
			
				|  |  | -    ctx.lineTo(x, y + r);
 | 
	
		
			
				|  |  | -    ctx.quadraticCurveTo(x, y, x + r, y);
 | 
	
		
			
				|  |  | -    ctx.closePath();
 | 
	
		
			
				|  |  | -    ctx.fill();
 | 
	
		
			
				|  |  | -    ctx.stroke();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +    const gl = this.renderer?.domElement.getContext('webgl');
 | 
	
		
			
				|  |  | +    gl && gl.getExtension('WEBGL_lose_context')?.loseContext();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    this.renderer?.forceContextLoss();
 | 
	
		
			
				|  |  | +    this.renderer?.dispose();
 | 
	
		
			
				|  |  | +    this.camera = null;
 | 
	
		
			
				|  |  | +    this.orbitControls = null;
 | 
	
		
			
				|  |  | +    if (this.renderer) this.renderer.domElement = null;
 | 
	
		
			
				|  |  | +    this.renderer = null;
 | 
	
		
			
				|  |  | +    if (this.css3dRender) this.css3dRender.domElement = null;
 | 
	
		
			
				|  |  | +    this.css3dRender = null;
 | 
	
		
			
				|  |  | +    if (this.canvasContainer) this.canvasContainer.innerHTML = '';
 | 
	
		
			
				|  |  | +    if (this.CSSCanvasContainer) this.CSSCanvasContainer.innerHTML = '';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    !!this.scene?.clear ?? this.scene?.clear();
 | 
	
		
			
				|  |  | +    cancelAnimationFrame(this.animationId);
 | 
	
		
			
				|  |  | +    this.animationId = -1;
 | 
	
		
			
				|  |  | +    this.stats = null;
 | 
	
		
			
				|  |  | +    this.scene = null;
 | 
	
		
			
				|  |  | +    THREE.Cache.clear();
 | 
	
		
			
				|  |  | +    console.log('3D环境已清理干净');
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  export default UseThree;
 |