【360度動画】Vue3でthree.jsを使ってみた【ソースコードあり】
2023.07/03
こんにちは、エンジニアのSです!
早速ですが今回は、Vue3でThree.jsを用い360度動画を再生させてみました!
“VueでThree.jsを使う”という記事がなかなか見つからなかったのですが、Vueだってjavascriptで書かれています。
ならば「Three.jsも使えるだろう!」というもので使ってみました。
コンポーネント化できたのがかなり便利で、面倒な処理などを省くことができたのが良かったなぁと…!
■Three.jsとは?
WebGLで3Dコンテンツを手軽に制作できるライブラリです。
3Dのモデルを表示して回転させたり、オブジェクトを操作することなど幅広い利用法があります。
公式の方で豊富なサンプルが紹介されていますので覗いてみることをオススメします!
■環境
・Vue …… 3.2.31
・three.js …… 0.152.2
Step1.読み込み準備
npmを使ってThree.jsをインストールしたので、importで読み込みを行います。
OrbitControlsはカメラを操作するのに使用します。
後はrefやonMountedなど適宜必要なものをimport、ついでにHTMLで動画を再生させる場所を用意します。
- <script setup>
- import * as THREE from "three";
- import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
- import { ref, onMounted } from "vue";
- const videoPlayer = ref(null);
- </script>
- <template>
- <div id="videoSphere" ref="videoPlayer"></div>
- </template>
Step2.コンポーネントのpropsを設定
目指すのはコンポーネントとして使いまわす、なので親から渡されるデータを考えます。
とりあえず適当に「ファイルパス」、「横・縦の長さ」でいいでしょう。
- const props = defineProps({
- path: String,
- width: Number,
- height: Number,
- });
Step3.変数の用意
Three.jsの動画再生に当たって、必要な変数を用意します。
- let video; // video要素
- let texture; // video要素から生成したテクスチャ
- let camera; // カメラ
- let controls; // カメラコントローラー
- let renderer; // レンダラー
- let scene; // シーン
Step4.javascriptでvideo要素を生成
以降の処理はonMounted内で行います。
video要素を生成し、ここに動画のパスを指定します。
このvideo要素と連動して、Canvasに描画していくことになります。
ビデオ要素のイベント(例:エラー発生時)などはここでまとめて記述できます。(onMounted内ならいつでもできます)
- // video要素の生成
- video = document.createElement("video");
- // video要素の属性付与
- video.crossOrigin = "anonymous";
- video.playsInline = true;
- video.loop = true;
- video.muted = true;
- video.src = props.path;
Step5.video要素からテクスチャを生成し、カメラ、シーン、レンダラーを生成
- // video要素からテクスチャを生成
- texture = new THREE.VideoTexture(video);
- texture.minFilter = THREE.LinearFilter;
- // カメラを生成
- camera = new THREE.PerspectiveCamera(
- 90,
- props.width / props.height,
- 1,
- 2000
- );
- camera.position.set(0, 0, 1);
- // シーンを生成
- scene = new THREE.Scene();
Step6.球体を生成し、video要素から生成したテクスチャを貼り付ける
360度動画を再生するので、平面のままでは歪んだ状態で再生されます。
なので球体を生成し、その内側にテクスチャを貼り付けます。
『球体の中にカメラを配置すると、プラネタリウムのように動画が見える』というイメージです。
- // 球体の生成
- let geometry = new THREE.SphereGeometry(500, 60, 40);
- geometry.scale(-1, 1, 1);
- // 球体にvideo要素から生成したテクスチャを貼り付け
- let mesh = new THREE.Mesh(
- geometry,
- new THREE.MeshBasicMaterial({ map: texture })
- );
- // シーンに追加
- scene.add(mesh);
Step7.レンダラーの生成
動画を描画するレンダラーを生成します。
- // レンダラーの生成
- renderer = new THREE.WebGLRenderer();
- renderer.setPixelRatio(window.devicePixelRatio);
- renderer.setClearColor(0x000000);
- renderer.setSize(props.width, props.height, true);
- // カメラコントローラーを生成
- controls = new OrbitControls(camera, renderer.domElement);
- controls.enableDamping = true;
- controls.dampingFactor = 0.2;
- // 動画を再生させる場所にレンダラーを配置する
- videoPlayer.value.appendChild(renderer.domElement);
- // 描画開始
- video.play();
- animate();
上記で設定完了です!
全文を一度表示します。
- <script setup>
- import * as THREE from "three";
- import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
- import { ref, onMounted } from "vue";
- const videoPlayer = ref(null);
- const props = defineProps({
- path: String,
- width: Number,
- height: Number,
- });
- let video; // video要素
- let texture; // video要素から生成したテクスチャ
- let camera; // カメラ
- let controls; // カメラコントローラー
- let renderer; // レンダラー
- let scene; // シーン
- onMounted(() => {
- // video要素の生成
- video = document.createElement("video");
- // video要素の属性付与
- video.crossOrigin = "anonymous";
- video.playsInline = true;
- video.loop = true;
- video.muted = true;
- video.src = props.path;
- // video要素からテクスチャを生成
- texture = new THREE.VideoTexture(video);
- texture.minFilter = THREE.LinearFilter;
- // カメラを生成
- camera = new THREE.PerspectiveCamera(
- 90,
- props.width / props.height,
- 1,
- 2000
- );
- camera.position.set(0, 0, 1);
- // シーンを生成
- scene = new THREE.Scene();
- // 球体の生成
- let geometry = new THREE.SphereGeometry(500, 60, 40);
- geometry.scale(-1, 1, 1);
- // 球体にvideo要素から生成したテクスチャを貼り付け
- let mesh = new THREE.Mesh(
- geometry,
- new THREE.MeshBasicMaterial({ map: texture })
- );
- // シーンに追加
- scene.add(mesh);
- // レンダラーの生成
- renderer = new THREE.WebGLRenderer();
- renderer.setPixelRatio(window.devicePixelRatio);
- renderer.setClearColor(0x000000);
- renderer.setSize(props.width, props.height, true);
- // カメラコントローラーを生成
- controls = new OrbitControls(camera, renderer.domElement);
- controls.enableDamping = true;
- controls.dampingFactor = 0.2;
- // 動画を再生させる場所にレンダラーを配置する
- videoPlayer.value.appendChild(renderer.domElement);
- // 描画開始
- video.play();
- animate();
- });
- const animate = () => {
- // カメラコントローラーを更新
- controls.update();
- // レンダリング
- renderer.render(scene, camera);
- requestAnimationFrame(animate);
- };
- </script>
- <template>
- <div id="videoSphere" ref="videoPlayer"></div>
- </template>
このコンポーネントを表示したいページで呼ぶと、360度動画が再生されます。
動画の再生・停止などのコントローラーがありませんので、こちらは適宜実装していかなければなりません。
MDNにてコントローラの作成についての記事がありますので、参考になると思います!
Creating a cross-browser video player
以上、Vue3で360度動画を再生させる方法でした。
技術的にはまだ拙い部分もありますが、何かの参考になれば幸いです!!
表示動画:http://xn--hhro09bn9j8uh.com/movie113vr3.html