Got an error when trying to add mesh to scene using "this" in Vue3

Hi everyone

I recently try to learn how to implement threeJS with Vue3 but face to a problem when trying to add mesh to a scene by declaring the scene and the mesh as data.

Here is the code of my actual project :

  data() {
      return {
        scene: null,
        camera: null,
        renderer: null,
        plane: null,
        aspect: {}
      }
    },
    mounted() {
      this.aspect = {
        ref: this.$refs.aspect,
        data: this.$refs.aspect.getBoundingClientRect()
      }
      this.init()
    },

methods: {
    init() {
      this.scene = new THREE.Scene()

      this.camera = new THREE.OrthographicCamera(
        window.innerWidth / -2,
        window.innerWidth / 2,
        window.innerHeight / 2,
        window.innerHeight / -2,
        1,
        1000
      )

      this.camera.position.z = 1

      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true,
        canvas: this.$refs.canvas
      })

      this.renderer.setSize(window.innerWidth, window.innerHeight)

      const geometry = new THREE.PlaneBufferGeometry(
        this.aspect.data.width,
        this.aspect.data.height,
        5
      )

      const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })

      this.plane = new THREE.Mesh(geometry, material)

      this.scene.add(this.plane)

      this.renderer.render(this.scene, this.camera)
  }
}

By doing that I get the following error :

Uncaught (in promise) 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]')

But if I declare the mesh and the scene like that, it works :

......
const scene = new THREE.Scene()
......
const plane = new THREE.Mesh(geometry, material)
......
scene.add(plane)

For a cleaner explanation here is the reproduction link :sweat_smile:
https://codesandbox.io/s/thirsty-mirzakhani-p8tdj?file=/src/App.vue

If someone could help me on this problem, it would be very cool !

Thank you in advance !

It works if you are able to define the threejs variables in a component scoped variable instead of defining them in Vue’s reactive data properties.

Vue does some neat tricks with properties defined in data to allow for the reactive behaviour which I suspect breaks something with the threejs object references.

1 Like

Thank you very much @amitlzkpa !
I’ll keep this in mind for my future projects

Really appreciate it :wink:

1 Like

I’m running into the same issue. Can you post your solution?

Hello @nebur

For the moment, the only solution is to declare your three global variables (like scene, mesh, etc…) outer of the export default.

Not the best solution because you lose the reactivity.
If you want your app reactive you can do a trick like so :

let theScene

export default {
  data() {
    return {
      scene: null
    }
  },
  mounted() {
    theScene = new THREE.Scene()
    this.scene = theScene
  }
}

I haven’t tested this solution but normaly it should work.

2 Likes

这种情况,是您在安装vue时使用选择了vue3.0及以上版本,vue3.0以后 表示已经放弃使用了 Object.defineProperty ,而选择了使用更快的原生 Proxy !!,所以您需要
import { toRaw } from ‘@vue/reactivity’;//第一种获取target值的方式,通过vue中的响应式对象可使用toRaw()方法获取原始对象;通过toRaw方法获取相应变量就好了

2 Likes

this looks dangerous to me. we did this once, and vues reactivity system eventually proxies the entire system including the dom because it climbs through the accessor nodes: node > parent > … > renderer > domElement > parent > … > document.body which is the biggest performance impact you can possibly have since three updates 60 times per second, triggering thousands of unintentional proxies. you can’t make three “reactive” by proxying its internals, you should drive it with reactive props instead.

maybe you can try use trois. https://github.com/troisjs/trois

黄总优秀👍知其然,知其所以然