一、实现目标
是实现2个场景的定时切换,由于是用在大屏系统,需要浏览器一直能正常运行,不能运行一段时间卡死
二、遇到的问题
首先遇到的是发现切换几次场景GPU越来越高,然后就慢慢卡死,并且随着运行时间越来越长,cpu也越来越高,最终浏览器崩溃
三、解决方法
由于使用的是vue,在组件销毁之前,把场景中的物体销毁,定时器清空,定时器、场景、控制器、渲染器等都赋值为null ,便于垃圾回收,切换场景的时候定时器设置的时间不能太短,不能及时回收释放内存,最后浏览器崩溃。发现加载的图片纹理是比较影响GPU的,一定要把物体的 geometry 和 material 销毁,下面是立方体的销毁的例子,6个面的材质都要销毁
clearCache(obj){ let mesh = obj mesh.geometry.dispose() mesh.material[0].dispose() mesh.material[1].dispose() mesh.material[2].dispose() mesh.material[3].dispose() mesh.material[4].dispose() mesh.material[5].dispose() },
beforeDestroy() { console.log("leave scene") this.clearCache(this.cube) this.cube = null window.removeEventListener("click",this.clickHandle,false) cancelAnimationFrame(this.myReq); clearInterval(this.timer); this.timer = null this.scene = null; this.camera = null; this.labelRenderer = null; this.controls = null; this.renderer.dispose(); this.renderer.forceContextLoss(); this.renderer.context = null; this.renderer.domElement = null; this.renderer = null; },
场景切换的代码,定时器要设置长一些,最少一分钟,因为每个场景都有定时器,并且使用了 cancelAnimationFrame 比较耗性能,切换场景的时候不是立即垃圾回收,定时器时间太短的话,还没有回收,又有新的场景需要耗性能
mounted() { // this.currentView = ()=> import("./scene1.vue") this.currentView = scene2; let scenes = [scene1, scene2]; let i = 0; let changeSceneTimer = null; let that = this; function autoChangeScene() { console.log(i); if(changeSceneTimer){ clearTimeout(changeSceneTimer); changeSceneTimer=null } changeSceneTimer = setTimeout(() => { i++; if ((i == scenes.length)) { i = 0; } that.currentView = scenes[i]; that.currentLiIndex = i; autoChangeScene(); }, 100000); } autoChangeScene() },
场景的主要代码
<div ref="container" id="container"></div>
<template> <div class="wrap"> <div ref="container" id="container"></div> <div class="label" style="display:none" id="test-Wrap"> <div><span class="text-Num">测试</span>bar</div> </div> </div> </template> <script> import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; import {CSS3DRenderer,CSS3DObject} from "three/examples/jsm/renderers/CSS3DRenderer.js"; import { objectEach } from 'highcharts'; export default { name: "ThreeTest", data() { return { state:1, preloadIimgs:[] }; }, mounted() { this.preloadImgs() this.getData(); this.timer = null; this.myReq = null; this.container; this.scene; this.camera; this.renderer; this.labelRenderer; this.controls; this.initScene(); this.initCamera(); this.initRender(); this.initModel(); this.initControls(); this.animate(); window.onresize = this.onWindowResize; window.addEventListener("click",this.clickHandle,false) }, methods: { preloadImgs(){ let imgsArr = ["/static/lng/right1.jpg","/static/lng/left1.jpg","/static/lng/top1.jpg","/static/lng/bottom1.jpg","/static/lng/front1.jpg","/static/lng/bottom1.jpg"] for(let i=0;i<imgsArr.length;i++){ let img = new Image() img.src = imgsArr[i] this.preloadIimgs.push(img) console.log(this.preloadIimgs) // img.onload = function(){ // cube.material[i].map.image = img // cube.material[i].map.needsUpdate = true // } } }, clickHandle(){ this.state = this.state ==0 ? 1:0 }, selectScene(){ let sceneWrap = document.getElementById("sceneWrap") if(sceneWrap.style.display == "none"){ sceneWrap.style.display = "flex" }else{ sceneWrap.style.display = "none" } }, getData() { // 循环获取数据 clearTimeout(this.timer); var element = document.getElementById("enter_text_Num"); if (element) { element.innerHTML = Math.round(Math.random() * (70 - 60) + 60); } this.timer = setTimeout(this.getData, 2000); }, initScene() { this.scene = new THREE.Scene(); }, initCamera() { this.container = document.getElementById("container"); this.camera = new THREE.PerspectiveCamera( 70, this.container.clientWidth / this.container.clientHeight, 1, 1000 ); console.log(this.camera); this.camera.position.z = 1; //z设置小写会使图像变形小 }, initRender: function () { this.renderer = new THREE.WebGLRenderer({ antialias: true }); this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); this.container.appendChild(this.renderer.domElement); this.labelRenderer = new CSS3DRenderer(); this.labelRenderer.setSize( this.container.clientWidth, this.container.clientHeight ); this.labelRenderer.domElement.style.position = "absolute"; this.labelRenderer.domElement.style.top = 0; this.container.appendChild(this.labelRenderer.domElement); console.log(this.labelRenderer); }, initLight() { this.scene.add(new THREE.AmbientLight(0xffffff)); this.light = new THREE.DirectionalLight(0xffffff); //light.position.set(1,1,1); this.light.position.set(0, 0, 50); this.scene.add(this.light); }, initModel() { var texture1 = new THREE.TextureLoader().load("/static/posxx.jpg"); console.log(texture1); var texture2 = new THREE.TextureLoader().load("/static/negxx.jpg"); var texture3 = new THREE.TextureLoader().load("/static/posyy.jpg"); var texture4 = new THREE.TextureLoader().load("/static/negyy.jpg"); var texture5 = new THREE.TextureLoader().load("/static/tiaoyaxiang.jpg"); //前面与后面的图片反着放 // var texture5 = new THREE.TextureLoader().load("/static/lng/front1.jpg"); //前面与后面的图片反着放 var texture6 = new THREE.TextureLoader().load("/static/negzz.jpg"); var materialArr = [ //纹理对象赋值给6个材质对象 new THREE.MeshBasicMaterial({ map: texture1 }), new THREE.MeshBasicMaterial({ map: texture2 }), new THREE.MeshBasicMaterial({ map: texture3 }), new THREE.MeshBasicMaterial({ map: texture4 }), new THREE.MeshBasicMaterial({ map: texture5 }), new THREE.MeshBasicMaterial({ map: texture6 }), ]; var boxGeometry = new THREE.BoxGeometry(200, 200, 200, 100, 100, 100); boxGeometry.scale(1, 1, -1); this.cube = new THREE.Mesh(boxGeometry, materialArr); console.log(this.cube); this.scene.add(this.cube); //获取随机数 function getRandomNum(elementId, max, min) { var element = document.getElementById(elementId); element.innerHTML = Math.round(Math.random() * (max - min) + min); } // 测试text let testElement = document.getElementById("test-Wrap") testElement.style.display = "block" let testLabel = new CSS3DObject(testElement) testLabel.position.set(-150,-150, -380) this.scene.add(testLabel) var that = this var labelClickHandle = function(){ let imgsArr = ["/static/lng/right1.jpg","/static/lng/left1.jpg","/static/lng/top1.jpg","/static/lng/bottom1.jpg","/static/lng/front1.jpg","/static/lng/bottom1.jpg"] for(let i=0;i<imgsArr.length;i++){ // console.log(this) // cube.material[i].map.image = that.preloadIimgs[i] // cube.material[i].map.needsUpdate = true let img = new Image() img.src = imgsArr[i] img.onload = function(){ cube.material[i].map.image = img cube.material[i].map.needsUpdate = true } } // let img = new Image() // img.src = "/static/lng/right1.jpg" // img.onload = function(){ // cube.material[0].map.image = img // cube.material[0].map.needsUpdate = true // } } // 进口压力: var enterPressure = 0; var enterPressureDiv = document.createElement("div"); enterPressureDiv.className = "label"; enterPressureDiv.innerHTML = "<div class='pressure'>进口压力:<span class='text_Num' id='enter_text_Num'>" + enterPressure + "</span> kpa</div>"; let enterPressureLabel = new CSS3DObject(enterPressureDiv); enterPressureLabel.position.set(-150, -50, -380); // enterPressureLabel.scale.set(0.5,0.5,0.5) this.scene.add(enterPressureLabel); enterPressureDiv.onclick = labelClickHandle }, initControls() { //controls = new THREE.OrbitControls( camera, renderer.domElement ); this.controls = new OrbitControls( this.camera, this.labelRenderer.domElement ); // 如果使用animate方法时,将此函数删除 //controls.addEventListener( 'change', render ); // 使动画循环使用时阻尼或自转 意思是否有惯性 this.controls.enableDamping = false; //动态阻尼系数 就是鼠标拖拽旋转灵敏度 //controls.dampingFactor = 0.25; //是否可以缩放 this.controls.enableZoom = false; //是否自动旋转 this.controls.autoRotate = false; //设置相机距离原点的最远距离 this.controls.minDistance = 1; //设置相机距离原点的最远距离 this.controls.maxDistance = 10; //是否开启右键拖拽 this.controls.enablePan = false; }, render() { this.renderer.render(this.scene, this.camera); this.labelRenderer.render(this.scene, this.camera); }, clearCache(obj){ let mesh = obj mesh.geometry.dispose() mesh.material[0].dispose() mesh.material[1].dispose() mesh.material[2].dispose() mesh.material[3].dispose() mesh.material[4].dispose() mesh.material[5].dispose() }, onWindowResize() { this.camera.aspect = window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.render(); this.renderer.setSize(window.innerWidth, window.innerHeight); this.labelRenderer.setSize(window.innerWidth, window.innerHeight); }, animate() { // this.clearCache(this.cube) cancelAnimationFrame(this.myReq); this.render(); if(this.state == 1) { this.scene.rotation.y += 0.001 } this.myReq = requestAnimationFrame(this.animate); }, }, beforeDestroy() { console.log("leave scene") this.clearCache(this.cube) // this.cube.dispose() this.cube = null window.removeEventListener("click",this.clickHandle,false) cancelAnimationFrame(this.myReq); clearInterval(this.timer); this.timer = null this.scene = null; // this.scene.remove() this.camera = null; // this.renderer = null; this.labelRenderer = null; this.controls = null; this.renderer.dispose(); this.renderer.forceContextLoss(); this.renderer.context = null; this.renderer.domElement = null; this.renderer = null; }, watch: {}, filters: {}, }; </script> <style scoped> </style>
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句