vue3 vite项目开发中,渲染threejs时,会报下面的错误
TypeError: 'get' on proxy: property 'modelViewMatrix' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '#<Matrix4>' but got '#<Matrix4>')
原因
考虑到Three.js对象的复杂性,以及Vue可能在处理这些对象时出现问题,我建议将与Three.js相关的所有对象和变量移出Vue数据对象。这样,它们就不会被Vue的响应式系统追踪。
修改前的代码
<template>
<div className="canvasGLTFBody">
<div ref='canvasGLTF' className="canvasGLTF" id="canvasGLTF"></div>
<div id="LoadingInfo" className="LoadingInfo"></div>
</div>
</template>
<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import img from './assets/lun.png';
export default {
name: 'GLTFCanvas',
data() {
return {
renderer: null,
camera: null,
width: 0,
height: 0,
scene: null,
mesh: null
}
},
mounted() {
const viewElem = document.body;
this.$nextTick(this.init);
const resizeObserver = new ResizeObserver(this.handleResize);
resizeObserver.observe(viewElem);
},
methods: {
async init() {
this.width = this.$refs.canvasGLTF.offsetWidth;
this.height = this.$refs.canvasGLTF.offsetHeight;
// Create scene, camera, renderer, controls
this.createScene();
this.createCamera();
this.createRenderer();
this.createControls();
// Load texture and start animation
await this.loadTexture();
this.animate();
this.$refs.canvasGLTF.appendChild(this.renderer.domElement);
},
createScene() {
this.scene = new THREE.Scene();
},
createCamera() {
this.camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.1, 1000);
this.camera.position.set(-0.003236905604211045, -0.5120776906761103, 0.2721449110235568);
this.scene.add(this.camera);
},
createRenderer() {
this.renderer = new THREE.WebGLRenderer({
logarithmicDepthBuffer: true,
antialias: true,
});
this.renderer.setSize(this.width, this.height);
this.renderer.shadowMap.enabled = true;
this.renderer.physicallyCorrectLights = true;
this.renderer.setClearColor(0xcccccc, 1);
this.renderer.autoClear = false;
this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
this.renderer.outputEncoding = THREE.sRGBEncoding;
this.renderer.sortObjects = true;
this.renderer.logarithmicDepthBuffer = true;
this.renderer.setPixelRatio(window.devicePixelRatio);
},
createControls() {
const controls = new OrbitControls(this.camera, this.renderer.domElement);
controls.enableDamping = true;
},
async loadTexture() {
const loader = new THREE.TextureLoader();
const texture = await loader.loadAsync(img);
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: true,
depthWrite: false,
opacity: 0.5
});
const geometry = new THREE.PlaneGeometry(1, 1);
this.mesh = new THREE.Mesh(geometry, material);
this.scene.add(this.mesh);
},
animate() {
requestAnimationFrame(this.animate);
if (this.mesh) {
this.mesh.rotation.z += 0.005;
}
this.renderer.render(this.scene, this.camera);
},
handleResize() {
this.width = this.$refs.canvasGLTF.offsetWidth;
this.height = this.$refs.canvasGLTF.offsetHeight;
this.camera.aspect = this.width / this.height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.width, this.height);
this.renderer.setPixelRatio(window.devicePixelRatio);
}
}
}
</script>
修改后的代码
<template>
<div className="canvasGLTFBody">
<div ref='canvasGLTF' className="canvasGLTF" id="canvasGLTF"></div>
<div id="LoadingInfo" className="LoadingInfo"></div>
</div>
</template>
<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import img from './assets/lun.png';
let renderer = null;
let camera = null;
let width = 0;
let height = 0;
let scene = null;
let mesh = null;
export default {
name: 'GLTFCanvas',
mounted() {
const viewElem = document.body;
this.$nextTick(this.init);
const resizeObserver = new ResizeObserver(this.handleResize);
resizeObserver.observe(viewElem);
},
methods: {
async init() {
const canvasGLTF = this.$refs.canvasGLTF;
width = canvasGLTF.offsetWidth;
height = canvasGLTF.offsetHeight;
// Create scene, camera, renderer, controls
this.createScene();
this.createCamera();
this.createRenderer();
this.createControls();
// Load texture and start animation
await this.loadTexture();
this.animate();
canvasGLTF.appendChild(renderer.domElement);
},
createScene() {
scene = new THREE.Scene();
},
createCamera() {
camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
camera.position.set(-0.003236905604211045, -0.5120776906761103, 0.2721449110235568);
scene.add(camera);
},
createRenderer() {
renderer = new THREE.WebGLRenderer({
logarithmicDepthBuffer: true,
antialias: true,
});
renderer.setSize(width, height);
renderer.shadowMap.enabled = true;
renderer.physicallyCorrectLights = true;
renderer.setClearColor(0xcccccc, 1);
renderer.autoClear = false;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.sortObjects = true;
renderer.logarithmicDepthBuffer = true;
renderer.setPixelRatio(window.devicePixelRatio);
},
createControls() {
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
},
async loadTexture() {
const loader = new THREE.TextureLoader();
const texture = await loader.loadAsync(img);
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: true,
depthWrite: false,
opacity: 0.5
});
const geometry = new THREE.PlaneGeometry(1, 1);
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
},
animate() {
requestAnimationFrame(this.animate);
if (mesh) {
mesh.rotation.z += 0.005;
}
renderer.render(scene, camera);
},
handleResize() {
const canvasGLTF = this.$refs.canvasGLTF;
width = canvasGLTF.offsetWidth;
height = canvasGLTF.offsetHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
renderer.setPixelRatio(window.devicePixelRatio);
}
}
}
</script>
以上的代码中,所有与Three.js相关的变量现在都被定义为脚本的全局变量,而不是Vue组件的数据。这样,它们就不会被Vue的响应式系统跟踪,并且可以避免可能出现的问题。