ThreeJS组件在VueJS 2中工作,但在3中不工作

编程入门 行业动态 更新时间:2024-10-24 06:35:44
本文介绍了ThreeJS组件在VueJS 2中工作,但在3中不工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在将我的应用程序升级到VueJS 3。我读到你可以保留相同的组件。但我现在在控制台中有一个错误,尽管我没有更改任何东西。以下是我的组件:

<template> <v-container> <div @click="onClick" @mousemove="onMouseMove" id="menu3D" style="background-color: transparent; position: fixed; left: 20px; width:15%; height:100%;"> </div> <v-row class="text-center"> <v-col class="mb-5" cols="12" > <h2 class="headline font-weight-bold mb-3"> Accueil </h2> <v-row justify="center"> <p> Client: {{ JSON.stringify(client)}} </p> <p> Mouse: {{ JSON.stringify(mouse)}} </p> <p> Container: {{ JSON.stringify(container)}} </p> </v-row> </v-col> </v-row> </v-container> </template> <script> import * as Three from 'three'; export default { name: 'Accueil', mounted() { this.init(); }, methods: { init() { this.createScene(); this.createCamera(); this.userData.formes.forEach((x) => this.createShape(x)); this.addSpotlight(16777215); this.addAmbientLight(); this.animate(); window.addEventListener('resize', this.onResize); }, onResize() { const container = document.getElementById('menu3D'); this.renderer.setSize(container.clientWidth, container.clientHeight); this.camera.aspect = container.clientWidth / container.clientHeight; this.camera.updateProjectionMatrix(); }, createScene() { this.renderer = new Three.WebGLRenderer({ antialias: true, alpha: true, }); const container = document.getElementById('menu3D'); this.renderer.setSize(container.clientWidth, container.clientHeight); this.renderer.setPixelRatio(window.devicePixelRatio); this.renderer.setClearColor(0xffffff, 0); container.appendChild(this.renderer.domElement); }, createCamera() { const container = document.getElementById('menu3D'); this.camera = new Three.PerspectiveCamera(50, container.clientWidth / container.clientHeight, 0.01, 1000); this.camera.position.set(0, 5, 20); this.camera.zoom = 1; }, createShape(shape) { const material = new Three.MeshStandardMaterial({ color: '#0000ff', roughness: 1, metalness: 0.5, emissive: 0, depthFunc: 3, depthTest: true, depthWrite: true, stencilWrite: false, stencilWriteMask: 255, stencilFunc: 519, stencilRef: 0, stencilFuncMask: 255, stencilFail: 7680, stencilZFail: 7680, stencilZPass: 7680, }); switch (shape.nom) { case 'Box': { this.geometry = new Three.BoxBufferGeometry(1.8, 1.8, 1.8); break; } case 'Sphere': { this.geometry = new Three.SphereBufferGeometry(1, 8, 6, 0, 6.283185, 0, 3.141593); break; } case 'Dodecahedron': { this.geometry = new Three.DodecahedronBufferGeometry(1.2, 0); break; } case 'Icosahedron': { this.geometry = new Three.IcosahedronBufferGeometry(1.5, 0); break; } default: { return false; } } this.mesh = new Three.Mesh(this.geometry, material); this.mesh.name = shape.nom; this.mesh.userData = shape.userData; this.mesh.receiveShadow = true; this.mesh.castShadow = true; this.mesh.position.set(0, shape.userData.position.y, 0); this.scene.add(this.mesh); return true; }, addSpotlight(color) { const light = new Three.SpotLight(color, 2, 1000); light.position.set(0, 0, 30); this.scene.add(light); }, addAmbientLight() { const light = new Three.AmbientLight('#fff', 0.5); this.scene.add(light); }, verifForme(e) { const t = this; const elt = t.scene.getObjectByName(e); t.intersects = t.raycaster.intersectObject(elt); if (t.intersects.length !== 0) { // s'il ne figure pas dans le tableau, on le met en premier if (t.userData.souris.indexOf(e) < 0) { t.userData.souris.unshift(e); console.log(`${t.userData.souris[0]} survolé!`); } if (t.userData.souris[0] === e) { const obj = t.intersects[0].object; obj.material.color.set(`#${elt.userData.couleurs[1]}`); obj.scale.set(obj.scale.x < 1.4 ? obj.scale.x + t.VITESSE_ZOOM : obj.scale.x, obj.scale.y < 1.4 ? obj.scale.y + t.VITESSE_ZOOM : obj.scale.y, obj.scale.z < 1.4 ? obj.scale.z + t.VITESSE_ZOOM : obj.scale.z); obj.rotation.y += t.VITESSE_ROTATION / t.RALENTISSEMENT; t.replacer(obj, obj.userData.position.y + obj.userData.decalage); } else { t.retrecir(e, elt); } } else { if (t.userData.souris.indexOf(e) >= 0) { t.userData.souris = t.userData.souris.filter((forme) => forme !== e); } t.retrecir(e, elt); } }, onClick(event) { event.preventDefault(); if (this.userData.souris.length > 0) { console.log(`${this.userData.souris[0]} cliqué!`); } else { console.log('clic dans le vide!'); } }, onMouseMove(event) { const container = document.getElementById('menu3D'); this.mouse.x = (event.offsetX / container.clientWidth) * 2 - 1; this.mouse.y = -(event.offsetY / container.clientHeight) * 2 + 1; this.client.clientX = event.clientX; this.client.clientY = event.clientY; this.container.width = container.clientWidth; this.container.height = container.clientHeight; // console.log(JSON.stringify(this.mouse)) }, replacer(e, py) { // la ligne suivante est pour éviter les tremblements if (Math.abs(e.position.y - py) < 0.05) { return true; } let rhesus = 10 * this.VITESSE_DEPLACEMENT; if (this.userData.souris[0] !== e.name) { rhesus *= 3; } // console.log(e.name+': '+this.userData.souris[0]+' - '+rhesus) if (e.position.y > py) { rhesus = -1; } e.position.set(0, Math.trunc(10 * e.position.y + rhesus) / 10, 0); return true; }, retrecir(n, e) { // on vérifie si le truc cliqué est dessus let dec = 0; const elt = this; if ((elt.userData.souris.length > 0) && (elt.userData.formes.map((x) => x.nom).indexOf(n) < elt.userData.formes.map((x) => x.nom).indexOf(elt.userData.souris[0]))) { dec = Math.trunc(10 * e.parent.getObjectByName(elt.userData.souris[0]).userData.decalage * 2.1) / 10; } e.material.color.set(`#${e.userData.couleurs[0]}`); e.rotation.y += elt.VITESSE_ROTATION; e.scale.set(e.scale.x > 1 ? e.scale.x - elt.VITESSE_ZOOM : e.scale.x, e.scale.y > 1 ? e.scale.y - elt.VITESSE_ZOOM : e.scale.y, e.scale.z > 1 ? e.scale.z - elt.VITESSE_ZOOM : e.scale.z); const newY = e.userData.position.y + dec; if (e.position.y !== newY) { elt.replacer(e, newY); } }, animate() { const elt = this; requestAnimationFrame(this.animate); this.raycaster.setFromCamera(this.mouse, this.camera); this.userData.formes.map((x) => x.nom).forEach((x) => elt.verifForme(x)); if (this.userData.souris.length > 0) { document.body.style.cursor = 'pointer'; } else { document.body.style.cursor = 'default'; } this.camera.updateProjectionMatrix(); this.renderer.render(this.scene, this.camera); }, }, data: () => ({ container: { height: 0, width: 0 }, client: { clientX: 0, clientY: 0 }, scene: new Three.Scene(), camera: null, renderer: Three.WebGLRenderer, mesh: new Three.Mesh(), factor: 0, mouse: new Three.Vector2(1, 1), raycaster: new Three.Raycaster(), intersects: [], VITESSE_ROTATION: 0.05, VITESSE_DEPLACEMENT: 0.1, VITESSE_ZOOM: 0.05, RALENTISSEMENT: 3, userData: { souris: [], formes: [ { nom: 'Box', userData: { position: { x: 0, y: 7.8, z: 0, }, couleurs: [ 'aaaaaa', '095256', ], decalage: 0.5, }, }, { nom: 'Icosahedron', userData: { position: { x: 0, y: 5.5, z: 0, }, couleurs: [ 'aaaaaa', '087F8C', ], decalage: 0.5, }, }, { nom: 'Dodecahedron', userData: { position: { x: 0, y: 3.1, z: 0, }, couleurs: [ 'aaaaaa', '5AAA95', ], decalage: 0.4, }, }, { nom: 'Sphere', userData: { position: { x: 0, y: 1, z: 0, }, couleurs: [ 'aaaaaa', '86A873', ], decalage: 0.2, }, }, ], }, }), }; </script>

以下是我在VueJS 3的控制台中遇到的错误:

three.module.js?5a89:24471 Uncaught 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 '[object Object]') at renderObject (three.module.js?5a89:24471) at renderObjects (three.module.js?5a89:24458) at Proxy.WebGLRenderer.render (three.module.js?5a89:24258) at animate (HelloWorld.vue?fdab:192)

如果有任何人有线索,请提前感谢...

推荐答案它适用于VUE 2

它在Vue 2上运行良好的原因在于Vue 2使用了基于Object.definePropertyAPI的不同反应系统。

Three.jsa lot使用相同的API向其数据结构添加一些不可写和不可配置的属性

当将具有此类属性的对象传递给Vue时(例如,通过在data中声明它),Vue只是跳过了此类属性,导致存储值/对象是非反应性的(因为Vue在呈现组件模板时无法检测属性访问)

Vue 3代理

Vue 3正在使用基于ES6proxies的新反应系统。

这是一个非常新的问题,即使已经投入了大量的精力来开发和测试它,随着人们开始迁移,这样的问题也会出现(我完全同意@Serg-Vue 3仍然是新的,除非您有技能和时间生活在边缘&您应该在从Vue 2迁移之前等待一段时间)

这个新的反应性系统不能很好地处理对象上的不可写不可配置属性-您可以在this sandbox

中找到最小的可重现示例
  • 我知道这是个错误,is reported发送到Vue@Next Repo
  • 沙箱使用合成API,但这并不重要,因为使用reactive()与在data()函数中声明变量相同(Vue会自动为您完成)
  • 解决方法

    如前所述,问题出在反应系统上。我不是Three.js方面的专家,但据我所知,将这三个数据结构放到Vue反应系统中没有多大意义-所有反应的要点都是检测数据更改并在需要时重新呈现模板。Three有自己的渲染系统,通常使用单个<canvas>HTML元素,因此在三个数据结构更改时触发Vue重新渲染是没有意义的...

    有多种方式可以选择退出Vue Reactive:

  • 在对象上使用Object.freeze()。在这种情况下不是很有用,但很高兴知道
  • 不要在data()中声明变量并在created()/mounted()钩子中赋值(示例如下)。如果需要在多个方法中访问它们,可以将它们赋值到组件本身(this),如果不需要它们,可以将它们作为局部变量(const/let)
  • 使用组合API时,不要对三个数据结构使用reactive()
  • 注意:即使他们承认这是一个错误,修复它的唯一方法是让它持有的属性和对象保持非反应性(不在该对象周围放置代理),因此结果将与完全退出反应性相同。但使用此解决方法也可以让您的应用程序运行更快、占用内存更少,因为所有的反应都是not really that cheap

    示例-创建非反应性组件属性

    export default { data() { return { }; }, mounted() { this.init(); }, methods: { init() { this.scene = new THREE.Scene(); this.camera = new THREE.OrthographicCamera(...); this.renderer = new THREE.WebGLRenderer({ ... }) this.geometry = new THREE.PlaneBufferGeometry( ); const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); this.plane = new THREE.Mesh(this.geometry, material); this.scene.add(this.plane); this.renderer.render(this.scene, this.camera); }, }

    更多推荐

    ThreeJS组件在VueJS 2中工作,但在3中不工作

    本文发布于:2023-10-29 07:58:33,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1539148.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:工作   但在   中不   组件   ThreeJS

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!