Edited at
PORTDay 2

three.jsを軽くさわってみる

「PORT」アドベントカレンダー2日目。

今年の4月に新卒でフロントエンドエンジニアとして入った三輪です。

案件で軽くthree.jsについてさわる機会があったので、共有していきたいと思います。


three.jsとはなにか

詳しくはThree.js-Wikipediaを見ていただければと思いますが、

簡単にいうとHTML5で3Dコンテンツを制作するためのJavaScriptライブラリ。

WebGLだけで3D表現しようとするとJavascriptGLSLコードなどで必要があるので、Three.jsを使うことにより、JavaScriptの知識だけで3D表現を行うことができる。


作っていく上で参考にしたサイト一覧


作ったものについて

今回作ったものは球体っぽい図形をまわしているものです。

完成しているものをすぐに見たい場合はこちらを見ればわかります。

See the Pen three-end by miwa_shuntaro (@miwashutaro0611) on CodePen.


制作を行なった手順


3D表示用のHTML,CSS,JSのベース部分を作成


HTML

<canvas class="stage"></canvas>


CSS

body {

margin: 0;
padding: 0;
overflow: hidden;
}


JS

function init() {

//canvasに描画する要素の大きさ
const width = window.innerWidth;
const height = window.innerHeight;
//この下にコードを記述していきます。
}
window.addEventListener('load', init);


Three.jsの読み込み

とりあえずこの記事ではCDNで読み込みを行います。


CDNで読み込みを行う

cdnjsへアクセスして、three.jsの読み込みを行います。

今回使っていくものは

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.min.js"></script>

になります。


NPMで読み込みを行う

この記事では使いませんがnpmで使っていく場合には、

$ npm install three

を行なって

import * as THREE from "three";

で読み込みを行うことができます。


シーンの作成

物体(メッシュ)を置くためのステージ(シーン)を用意します。

function init() {

// シーンを作成
const scene = new THREE.Scene();
}

この状態では表示するときの土台ができただけなので、何も表示はされていません。


メッシュを作成

土台はできたので、次にメッシュを作成します。

今回は形状を指定するgeometryと素材を指定するmaterialを使っていきます。

function init() {

// ジオメトリーを作成
const geometry = new THREE.IcosahedronGeometry( 100, 1 );
// マテリアルを作成
const material = new THREE.MeshBasicMaterial({color: 0xa6b5d7, wireframe: true});
// メッシュを作成
const cube = new THREE.Mesh(geometry, material);
// 3D空間にメッシュを追加
scene.add(cube);
}

これで今回使う物体についてはできました。


補足


geometryについて

今回使った図形以外にも

BoxGeometry(立方体)、SphereGeometry(球体)、CylinderGeometry(円柱)などいろいろな図形を作ることができます。

//BoxGeometry(立方体)

const geometry = new THREE.BoxGeometry(幅, 高さ, 奥行き);
const geometry = new THREE.BoxGeometry(70, 100, 200);

//SphereGeometry(球体)
const geometry = new THREE.SphereGeometry(半径, 経度分割数, 緯度分割数, 開始経度, 経線中心角, 開始緯度, 緯線中心角);
const geometry = new THREE.SphereGeometry(50, 20, 20);

//CylinderGeometry(円柱)
const geometry = new THREE.CylinderGeometry(上面の半径, 底面の半径, 高さ,円周の分割数, 高さの分割数, フタをしない:true,フタをする:false;
const geometry = new THREE.CylinderGeometry(100, 100, 50, 30, 5, false);

もっといろいろな図形を見たい場合にはBoxGeometry - three.js docsの赤い枠の部分から図形を見ることができます。

スクリーンショット 2018-12-01 23.32.25.png


materialについて

materialについては


  • MeshBasicMaterial : 質感が一番低い。光源の影響を受けないので陰がつかない。

  • MeshLambertMaterial : MeshBasicMaterialより質感が高い。影がつく。

  • MeshPhongMaterial : 質感が一番高い。影も光も綺麗につく。

などがあります。

もっと見たい場合にはMeshBasicMaterial - three.js docsの赤い枠の部分から見ることができます。

スクリーンショット 2018-12-01 23.43.19.png


カメラを作成

カメラごしに物体をみるイメージなので、シーンにカメラを設置します。

function init() {

// カメラを作成
const camera = new THREE.PerspectiveCamera(45, 1.0);
camera.aspect = width / height;
camera.updateProjectionMatrix();
camera.position.set(0, 0, +600);
}

下のコードの部分でカメラのアスペクト比を正しており、

camera.aspect = width / height;

camera.updateProjectionMatrix();

camera.position.setでは、

camera.position.set(x方向, Y方向, Z方向);

camera.position.set(0, 0, +600);

のようにセットを行います。


補足

カメラの基本関数について、


  • PerspectiveCamera : 透視投影。通常生活における物の見え方。

  • OrthographicCamera : 正投影。どこから見ても物体のサイズは同じ。

がある。

どちらも画角アスペクト比ニアークリップファークリップの値を渡すことができる


画角

カメラに写る光景の範囲を角度で表したもの


アスペクト比

画面の長辺対短辺(横対縦)の比率を表したもの


ニアクリップ

視点から、光景が見え始める面までの距離


ファークリップ

視点から最も遠い面までの距離

実際に

new THREE.PerspectiveCamera(画角, アスペクト比, ニアークリップ, ファークリップ)

new THREE.OrthographicCamera(画角, アスペクト比, ニアークリップ, ファークリップ)

のように記載する。

こちらも詳細はPerspectiveCamera - three.js docsの赤い部分から確認ができます。

スクリーンショット 2018-12-02 0.48.08.png


レンダラーの作成

ここまではあくまでも図形の設定などについての記載なので、その情報をHTMLに記載していきたいと思います。

function init() {

// レンダラーを作成
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('.stage'),
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
renderer.render(scene, camera);
}

下のコードの部分でレンダラーのサイズを調整しており、

renderer.setPixelRatio(window.devicePixelRatio);

renderer.setSize(width, height);

renderer.renderでは、

renderer.render(scene, camera);

のように記載してレンダリングを行う。

これで3D画像が表示されたと思うので、現状は下のような状態になります。

See the Pen three-1 by miwa_shuntaro (@miwashutaro0611) on CodePen.


補足

もっと詳しく知りたい場合はWebGLRenderer - three.js docsの赤い部分を参照。

スクリーンショット 2018-12-02 1.06.22.png


回転させる

もう少し3Dをおしゃれに見せていこうと思うので、回転させていきます。

function init() {

//回転のアニメーション
tick();
function tick() {
renderer.render(scene, camera); //この部分はtickの中に移動させる
cube.rotation.x += 0.005;
cube.rotation.y += 0.01;
requestAnimationFrame(tick);
}
}

See the Pen three-2 by miwa_shuntaro (@miwashutaro0611) on CodePen.

この状態で画像が回転していてば図形は完成です。


リサイズの処理を入れる

図形自体は上のものでいいのですが、リサイズをすると図形の場所やcanvasがおかしくなるので、修正をしていきます。

function init() {

//リサイズした時の処理
onResize();
window.addEventListener('resize', onResize);
function onResize() {
const width = window.innerWidth;
const height = window.innerHeight;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}

前の状態までで記載した

//canvasに描画する要素の大きさ

const width = window.innerWidth;
const height = window.innerHeight;
// レンダラーを作成
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
renderer.render(scene, camera);
// カメラを作成
camera.aspect = width / height;
camera.updateProjectionMatrix();

の部分についてはリサイズとの処理と重複してしまうので、削除してください。

これでリサイズを行なっても


  • 図形は中央にある


  • canvasのサイズはウィンドウの幅

になりました。

完成したものはこちらになります。

See the Pen three-end by miwa_shuntaro (@miwashutaro0611) on CodePen.


最後に

今回は軽くさわっただけですが、Three.js公式サイトを見てみるといろいろとあるので、またどこかのタイミングでThree.jsについてまとめていきたいと思います。