Edited at

Vue.jsでthree.jsを使ってみる

Vue.jsでthree.jsを使うときに、知っておかないと動かないこととかあるのでまとめてみた。

vue-cliとか使ったり最近のvueに合わせたやり方に更新。


vue create

$ vue create three

でとりあえず、プロジェクトを作成する。vue-cliについては特に説明しないので、適当に調べてください。

今回、TypeScript使わないです。適当に必要なオプション付けてプロジェクトを作成します。

Vue CLI v3.7.0

? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Linter, Unit
? Pick a linter / formatter config: Prettier
? Pick additional lint features: Lint and fix on commit
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N)

今回はこんな感じでスタート。Router, Vuexとか必要に応じて追加してね。


three.jsのインストール

とりあえず、よくある箱をクルクルするサンプルを作る。

公式のチュートリアルをVue.jsでやる感じ。ってことで、とりあえずthree.jsがあれば動くやつ。

$ yarn add three

# あるいは
$ npm install three


rotate box

image.png

とりあえず、こんな感じでHelloWorld.vueを削除して、RotateBox.vueを作成。


App.vue

<template>

<div id="app">
<rotate-box></rotate-box>
</div>
</template>

<script>
import RotateBox from "./components/RotateBox";

export default {
name: "app",
components: {
RotateBox
}
};
</script>

<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>



RotateBox.vue

<template>

<canvas id="canvas" width="600" height="400"></canvas>
</template>

<script>
import * as THREE from "three";

export default {
name: "RotateBox",
data() {
const scene = new THREE.Scene();
const renderer = null;
const camera = new THREE.PerspectiveCamera(75, 600 / 400, 0.1, 1000);
const light = new THREE.DirectionalLight(0xffffff);
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshNormalMaterial();
const cube = new THREE.Mesh(geometry, material);
return { scene, renderer, camera, light, geometry, material, cube };
},
mounted() {
const $canvas = document.getElementById("canvas");
// canvasを後付けで設定する方法あったら教えてほしいー
this.renderer = new THREE.WebGLRenderer({
antialias: true,
canvas: $canvas
});

this.camera.position.set(0, 0, 2);
this.light.position.set(0, 0, 10);
this.scene.add(this.cube);
this.scene.add(this.light);

this.animate();
},
methods: {
animate() {
requestAnimationFrame(this.animate);

this.cube.rotation.x += 0.02;
this.cube.rotation.y += 0.02;

this.renderer.render(this.scene, this.camera);
}
}
};
</script>

<style></style>


とりあえず、動くかな。

まず、dataにデータを格納して、mountedで実際に組み立てをしていく。mountedとcreatedの違いについてだけど、createdでこれを実行すると動かない。document要素はcereatedではまだ有効化されていないので、動かないのでmountedで動かすことになる。


データバインディングの利用

回転速度の調整ができるようにしてみる。とりあえず、App.vueを編集。


App.vue

<template>

<div id="app">
+ <div>
+ <label for="speed">speed</label>
+ <input
+ v-model.number="speed"
+ name="speed"
+ id="speed"
+ type="range"
+ min="0.000"
+ max="0.1"
+ step="0.005"
+ />
+ </div>
- <rotate-box></rotate-box>
+ <rotate-box :speed="speed"></rotate-box>
</div>
</template>

<script>
import RotateBox from "./components/RotateBox";

export default {
name: "app",
components: {
RotateBox
},
+ data() {
+ return {
+ speed: 0.02
+ };
+ }
};
</script>

<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>


こんな感じ。inputでスピード調整できる感じ。


BoxRotate.vue

<template>

<canvas id="canvas" width="600" height="400"></canvas>
</template>

<script>
import * as THREE from "three";

export default {
name: "RotateBox",
+ props: {
+ speed: {
+ required: false,
+ type: Number,
+ default: 0.02
+ }
+ },
data() {
const scene = new THREE.Scene();
const renderer = null;
const camera = new THREE.PerspectiveCamera(75, 600 / 400, 0.1, 1000);
const light = new THREE.DirectionalLight(0xffffff);
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshNormalMaterial();
const cube = new THREE.Mesh(geometry, material);
return { scene, renderer, camera, light, geometry, material, cube };
},
mounted() {
const $canvas = document.getElementById("canvas");
// canvasを後付けで設定する方法あったら教えてほしいー
this.renderer = new THREE.WebGLRenderer({
antialias: true,
canvas: $canvas
});

this.camera.position.set(0, 0, 2);
this.light.position.set(0, 0, 10);
this.scene.add(this.cube);
this.scene.add(this.light);

this.animate();
},
methods: {
animate() {
requestAnimationFrame(this.animate);

- this.cube.rotation.x += 0.02;
- this.cube.rotation.y += 0.02;
+ this.cube.rotation.x += this.speed;
+ this.cube.rotation.y += this.speed;

this.renderer.render(this.scene, this.camera);
}
}
};
</script>

<style></style>


image.png

こんな感じ。つまみ回したら動くんじゃないかな。