一、实现目标
是实现2个场景的定时切换,由于是用在大屏系统,需要浏览器一直能正常运行,不能运行一段时间卡死
二、遇到的问题
首先遇到的是发现切换几次场景GPU越来越高,然后就慢慢卡死,并且随着运行时间越来越长,cpu也越来越高,最终浏览器崩溃
三、解决方法
由于使用的是vue,在组件销毁之前,把场景中的物体销毁,定时器清空,定时器、场景、控制器、渲染器等都赋值为null ,便于垃圾回收,切换场景的时候定时器设置的时间不能太短,不能及时回收释放内存,最后浏览器崩溃。发现加载的图片纹理是比较影响GPU的,一定要把物体的 geometry 和 material 销毁,下面是立方体的销毁的例子,6个面的材质都要销毁
代码语言:javascript复制 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()
},
代码语言:javascript复制 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 比较耗性能,切换场景的时候不是立即垃圾回收,定时器时间太短的话,还没有回收,又有新的场景需要耗性能
代码语言:javascript复制 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()
},
场景的主要代码
代码语言:javascript复制 <div ref="container" id="container"></div>
代码语言:javascript复制<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>