JS memo

お洒落にJavaScript。

2019年6月4日21:35

three.jsでカラフルな球体を作成

メインビジュアル

three.jsでカラフルな球体を作成

最近VRやARなど3Dデザインが注目を浴び、日常の様々な場面で活用されているのを見かけるようになりました。
流行りの技術を手に入れたい!という熱い思いとブログを2Dでデザインするのに飽きてしまった、、、という怠惰な思いから、 今回JavaScriptのAPI「WebGL」と3Dデザインが簡単に出来るJavaScriptのライブラリ「Three.js」でカラフルな球体アニメーションを作成してみました。

目次

  1. 完成した作品
  2. three.jsについて
  3. 作成手順
  4. おすすめ教材
  5. 3Dの需要について
  6. まとめ

完成した作品

まずカラフル球体を作成して行く前に今回作成するデザインを載せておきます。

一見難しそうですが、WebGLとthree.jsで簡単に描写出来るので頑張って行きましょう。

three.jsについて

three.jsの生まれ

まずthree.jsは、「コンピューター上で計算なしで3Dグラフィックを描写することができない」&「プログラミング言語は基本的に3Dの概念を理解することができない」という二つの理由から生み出されました。

ざっくりいうと3Dを表現するにはとっても複雑な計算が必要で、three.jsはそんな複雑な計算をシンプルなコードを書くだけで出来るようにしたい!という思いから作成されました。

もう少し具体的にthree.jsの仕様を見ていきたいと思います。

three.jsとWebGLについて

three.jsはWebGLを利用して<canvas>、<svg>内に2Dや3Dグラフィックを描くことができます。

WebGL

3Dグラフィックなどを描写する際にはかなりの膨大な計算量が必要になります。
この概念を前提としてハードウェアの話まで遡りますが、コンピューターで3D描写をする際に計算の中心的存在であるCPU(Central Processing Unit)で計算させるとどうしても遅くなってしまうので、CPUとは別にGPU(Graphics Processing Unit)と言われるグラフィック専用のハードウェアが備えられました。
しかしこのGPUを利用できるのはPhotoShopとかInstagramなどのネイティブアプリだけで、ブラウザ上でGPUを利用できる術がありませんでした。
そこで登場したのがJavaScriptのWebGL(API)で、WebGLのおかげでブラウザ上でもGPUを利用できるようになったということです。


three.js

WebGLはすごく便利なAPIなのですが、低レベルAPI(ハードウェアに近い(人間味がない))で、3Dの概念を理解していません。
そのため例えばWebGLで球体を描写をする場合には、使用する三角形全ての頂点の座標を計算し、「この頂点の座標は〇〇でこの頂点の座標は〇〇ね」みたいに細かな指示が必要になります。
そこで簡潔に「三角形〇〇個使って半径〇〇の球体書いて」みたいなお願いをするだけでWebGLを実行してくれるのがthree.jsです。


お待たせいたしました。three.jsをざっくりと説明したので、実際に実装方法を見ていきましょう。

作成手順

1. htmlの準備とthree.jsのライブラリーの読み込み

まず3Dを実装する基本的なhtmlとthree.jsのライブラリーをgoogle CDNで読み込み混んでおきます。

<html>
  <head>
    <title>My first three.js app</title>
  </head>
  <style>
    body{margin:0; height:100vh;}
    canvas{display: block;}
  </style>
  <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.js"></script>
    <!-- ここにthree.jsのコードを追加 -->
  </body>
</html>

2. Sceneをセットする

まず、3Dを描写するには3Dを描写するための空間をセットしてあげる必要があります。

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

3Dの空間を作るにはScene、Camera、Rendererの3要素が必要になってきます。

Sceneは3D空間の舞台のようなものでこの中に3D空間に表示する要素を詰め込んでいきます。

Cameraはどの視点から空間を映し出すかを定義したもので、透視投影または平行投影の2種類があります。
今回は透視投影(THREE.PerspectiveCamera)を使用しています。引数は順に、視野、アスペクト比、cameraが映す範囲の最小値、cameraが映す範囲の最大値です。

Rendererは3Dを2Dの空間に描写するために、先ほど説明したWebGLを設定します。引数に{antialias: true}を設定すると滑らかな3Dを描写してくれます。
3D空間のスケールの設定はrenderer.setSizeを使用します。
最後にこの空間をHTMLに追加して3D空間の設定は完了です。

3. geometryをセットする

空間の設定が終わったら次は実際に表示したい3Dの物体を設定していきます。

const geometry = new THREE.SphereGeometry(2, 8, 6);
const material = new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
camera.position.z = 5;

物体を設定するにはgeometryとmaterialの2つの要素を作成し、先ほど作成した3D空間(scene)に追加する必要があります。

geometryは物体の形状を指定することができ、立方体や球、球体など様々な形状が作成できます。今回は球体を作成するため、SphereGeometryを使用しています。
引数は順に半径、横分割数、縦分割数を示しています。(もっと指定できるけど、今回はこの3つのみ指定しています。)

materialはgeometryで作成した図形はまだ形しかないので、色や画像などを追加します。引数を{ vertexColors: THREE.FaceColors }にすることで各面に違う色を設定することができます。方法は次で説明します。

作成したgeometryにmaterialをmeshを用いて適用し、最後にsceneに追加します。

最後にcameraと3Dの物体が衝突して見えなくなってしまうので、camera.position.zを使ってcameraの位置をずらしてあげて完成です。

4. 面の色をカラフルにする

少し応用になりますが、球体の面の色をカラフルにしたいと思います。

for(let i=0; i<geometry.faces.length; i++){
  geometry.faces[i].color.set(Math.random() * 0xCC0000);
}

先ほど設定したgeometryはfacesというオブジェクトを持つのでforループでそれぞれの面にランダムで色を設定します。

5. レンダリングする

空間と物体の設定ができたので最後にレンダリングして完了です。

renderer.render(scene, camera);

6.【おまけ】アニメーションをつけた場合

アニメーションをつける場合、アニメーションを指定する関数を作成し、[5]のレンダリングはその関数の中に書きます。

function animate(){
  requestAnimationFrame(animate);
  mesh.rotation.x += 0.01;
  mesh.rotation.y += 0.01;
  renderer.render(scene, camera);
};
animate();

これでカラフルな3D球体が描写できました!

全体のコードを載せておきます。

<html>
  <head>
    <title>My first three.js app</title>
  </head>
  <style>
    body{margin:0; height:100vh;}
    canvas{display: block;}
  </style>
  <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.js"></script>
    <script>
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000 );
      const renderer = new THREE.WebGLRenderer({antialias: true});
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(renderer.domElement);
      const geometry = new THREE.SphereGeometry(2, 8, 6);
      const material = new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors });
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
      camera.position.z = 5;
      function animate(){
        requestAnimationFrame(animate);
        mesh.rotation.x += 0.01;
        mesh.rotation.y += 0.01;
        renderer.render(scene, camera);
      };
      animate();
    </script>
  </body>
<html>  

おすすめ教材

今回three.jsを使うのに参考にした教材はこちらです。

Three.js Crash Course for Absolute Beginners - 3D in the Browser

What is three.js?

まとめ

お疲れ様でした!少し長くなってしまいましたが、three.jsとは何かからカラフルな球体の実装までを書きました。
コピペだけでも3Dの実装はできますが、コードの意味を少しでも理解していただけたら嬉しいです!