1

I tried to render three js canvas within vue set up. But due to Vue's statemanagement pattern, it could be done only when I set the canvas related variables outside of vue state management.

I saw an example which achieved this within vue state environment but in this case, DOM element had to be created within vue not in html/template.

  1. Is there a way that I could create three canvas in vue not using variables outside of vue (it means use let scene, not this.scene)?

or

  1. using vue state management but not using

    document.body.appendChild(this.renderer.domElement);
    

rather using

this.renderer=new THREE.WebGLRenderer({canvas:this.canvas})

Thank you

My Vue code is as below.

<template>
    <div>
        <canvas id="myCanvas"></canvas>
    </div>
</template>

<script>
import * as THREE from 'three'



export default {
data(){
    return{
        canvas:null,
        pointArr:[],
        scene:null,
        camera:null,
        renderer:null,
        cube:null

    }
},
computed:{

},
methods:{

init(){
this.scene =new THREE.Scene();
this.canvas=document.querySelector('#myCanvas');
this.canvas.width=innerWidth;
this.canvas.height=innerHeight;

this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
this.renderer=new THREE.WebGLRenderer({canvas:this.canvas})
this.renderer.setSize( window.innerWidth, window.innerHeight );

var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );

this.cube= new THREE.Mesh( geometry, material );
this.camera.position.z = 5
this.scene.add(this.cube);


},

animate(){
    requestAnimationFrame( this.animate );
    this.cube.rotation.x += 0.1;
    this.cube.rotation.y += 0.1;
    this.renderer.render(this.scene, this.camera);
}

},

mounted(){


this.init()
this.animate();
// window.addEventListener()
},
created(){



},

unmounted(){
//window.removeEvenetListener()
}




}
</script>

This part keeps throwing an error

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

enter image description here

3
  • 1
    Can you post your code where you tried this? Question is not clear without additional code. Commented May 27, 2021 at 19:53
  • @ChaseDeAnda I just attached the code and the screen shot. Thank you! Commented May 27, 2021 at 20:01
  • I currently use vue3 with pinia and Three.js while using vue3's reactivity features - although a tiny bit overkill to keep the canvas, scene, camera and renderer inside vue's ref system, i did it anyway lol The canvas, scene, camera, renderer, controls are all vue composable singletons that can be passed around between vue pages and components - if ya'll still have a need for this lmk and ill post an answer for ya Commented Nov 10, 2022 at 6:48

4 Answers 4

1

2024 update for installing three js in vue 3 since this post comes up first for this question:

npm i three @types/three

<head>

<link rel="preload"href="/static/mypic.jpg"as="image"crossOrigin="anonymous" 
import { Scene } from 'three/src/scenes/Scene.js';
import { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera.js';
import { WebGLRenderer } from 'three/src/renderers/WebGLRenderer.js';
import { PlaneGeometry } from 'three/src/geometries/PlaneGeometry.js';
import { TextureLoader } from 'three/src/loaders/TextureLoader.js';

const canvas = ref(null);
onMounted(() => {
    const scene = new Scene();
    const camera = new PerspectiveCamera();
    camera.position.set(0, 0, 1);
    const renderer = new WebGLRenderer({ canvas: canvas.value });
    renderer.render(scene, camera);
    canvas.value = renderer;

    const geometry = new PlaneGeometry(82, 88);
    var texture = new TextureLoader().load(
        "/static/mypic.jpg");
    const material = new MeshBasicMaterial({
        map: texture
    });

    const plane = new Mesh(geometry, material);
    plane.position.set(0, 0, -100);
    scene.add(plane);
}

<canvas class="absolute p-0 m-0 -z-10" ref="canvas" />
Sign up to request clarification or add additional context in comments.

Comments

0

Thanks for the error screenshot. It seems like you will not be able to use state variables to store your values.

This is because Vue actually converts your state variables to observables for reactivity to work. Three.js is complaining that the variable you assigned has changed it's value from # to [object Object] which shows that once you assigned it to a class variable, Vue changed its value and now it is no longer usable by Three.js.

That is why all the other examples you've seen are defining it outside of the Vue component.

Comments

0

I think Chase is right to the point, in the link below you can find a workaround to the problem (that implies taking ThreeJS variables outside of the Vue reactivity system). This problem seems related to Vue3 only, apparently for some reason it did work with Vue2.

Check here: ThreeJS component working in VueJS 2 but not 3

1 Comment

While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review
0

if someone stumble on this post in the future and have this problem i found a quick detour solution.

is to wrap the canvasInstance with vue `markRaw()` https://vuejs.org/api/reactivity-advanced#markraw to prevent it to be converted to a proxy this solved the issue for me.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.