【Three.js】テクスチャを貼り付ける

JavaScript,Three.js

いい!

はじめに

3D空間上の物体に画像を貼り付けてみます。ついでに、前回サラッと流してしまったThree.jsの基本的なところの解説も。

できあがり

デモサイトはこちら

暗闇に浮かぶ美女の顔…。スポットライトが当たってとてもキレイですね。では解説いってみましょう。

コード全体

とりあえずHTMLファイルの全体を眺めてみましょう。

<!DOCTYPE html>

<html lang="ja">

<head>
  <meta charset="UTF-8">
  <title>球体にテクスチャを貼る</title>
  <script type="text/javascript" src="libs/three.min.js"></script>
  <style>
      body {
          margin: 0;
          overflow: hidden;
      }
  </style>
</head>

<body>

  <div id="WebGL-output"></div>
  
  <script type="text/javascript">

    window.onload = function() {

      // シーン
      var scene = new THREE.Scene();
  
      // カメラ
      var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.z = 30;
      camera.lookAt(scene.position);
  
      // レンダラー
      var renderer = new THREE.WebGLRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.getElementById("WebGL-output").appendChild(renderer.domElement);
      
      // ライト
      var spotLight = new THREE.SpotLight(0xffffff);
      spotLight.position.set(-20, 10, 30);
      scene.add(spotLight);

      // テクスチャ
      var textureLoader = new THREE.TextureLoader();
      var texture = textureLoader.load("assets/textures/kiyoko256.png");
      
      // 球体
      var sphereGeometry = new THREE.SphereGeometry(5,20,20);
      var sphereMaterial = new THREE.MeshPhongMaterial();
      sphereMaterial.map = texture;
      var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
      scene.add(sphere);  

      // 描画
      renderScene();

      // 描画関数
      function renderScene() {
        sphere.rotation.y += 0.02;
        requestAnimationFrame(renderScene);
        renderer.render(scene, camera);
      }

    }
  </script>
</body>
</html>

どうでしょうか。

「3Dだからきっとスゴイことやってんだろうな」と思ったそこのアナタ!意外とコード短いと思いませんか?これだけでできてしまうんです。すべてThree.jsのおかげです。それでは上から順に見ていきましょう。

ライブラリを読み込む

<head>タグのなかでThree.jsライブラリを読み込みます。

<script type="text/javascript" src="libs/three.min.js"></script>

<div>タグを用意する

<div id="WebGL-output"></div>

あとで説明しますが、JavaScriptが動くと、この<div>要素のなかに<canvas>要素ができます。その<canvas>に描画されることで3D空間が出来上がります。

CSSを書く

CSSは少ししかないので<head>タグの中に書いています。

body {
    margin: 0;
    overflow: hidden;
}

JavaScriptを書く

ここからが本番です。ひとつずつ見ていきましょう。

// シーン
var scene = new THREE.Scene();

シーンというのは3D空間全体のことです。Sceneのコンストラクタを呼び出してSceneオブジェクトを作ります。

このシーンの中に表示したい物体やライトなんかを入れていくことになります。

// カメラ
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 30;
camera.lookAt(scene.position);

次はカメラを作ります。コンストラクタに渡すのは「視野角」「アスペクト比」「近平面」「遠平面」です。

「近平面」というのは「カメラから見てどのくらい近くから画面に映すか」というものです。「近平面」より近くにある物体は画面に映りません。逆に「遠平面」より遠くにある物体も画面に映らなくなります。

// レンダラー
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("WebGL-output").appendChild(renderer.domElement);

次はレンダラー。画面に描画をしてくれるとても大事なモノ。"setSize"で描画するシーンの大きさを設定します。

そして"getElementById"で<div>要素を取得し、"appendChild"でその<div>要素の中にレンダラーを配置します。これで<div>の子要素として<canvas>ができます。

// ライト
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-20, 10, 30);
scene.add(spotLight);

ライトを作って物体を照らしてあげます。コンストラクタの引数で光の色を16進数で指定しています。今回は白ですが、赤にするとその光で照らされた物体も赤っぽくなります。

“position.set(x, y, z)"でカメラの位置を設定します。xは左右方向、yは上下方向、zは手前奥方向です。

もろもろ設定できたら"scene.add(spotLight)"でシーンの中にライトを入れてあげましょう。

// テクスチャ
var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load("../assets/textures/kiyoko256.png");

そして今回の本題。テクスチャです。TextureLoaderオブジェクトの"load"関数で画像を読み込みます。この画像を物体に貼り付けるわけですね。その前に物体を作ります。

// 球体
var sphereGeometry = new THREE.SphereGeometry(5,20,20);
var sphereMaterial = new THREE.MeshPhongMaterial();
sphereMaterial.map = texture;
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);  

物体はメッシュ(Mesh)で作られます。そしてメッシュはジオメトリ(Geometry)とマテリアル(Material)からできています。

ジオメトリは物体の形状のことです。

マテリアルは色や質感といった、物体の表面を決めるものです。先ほど読み込んだテクスチャをマテリアルの"map"プロパティに設定してあげると、この物体の表面に画像が張り付きます。

そしてジオメトリとマテリアルをメッシュのコンストラクタに渡してあげれば物体のできあがりです。分かりやすい仕組みですね。

// 描画
renderScene();

// 描画関数
function renderScene() {
  sphere.rotation.y += 0.02;
  requestAnimationFrame(renderScene);
  renderer.render(scene, camera);
}

最後は描画です。

レンダラーの"render"関数にシーンとカメラを渡してあげれば、レンダラーが描画してくれます。静止画ならこれだけで終わりですが、今回は球体をくるくる回転させたいので、描画を何度も何度も繰り返してもらわなければいけません。球体をちょっと回して描画。またちょっと回して描画。そうすると動いているように見えると。パラパラ漫画みたいな感じですね。

そのためには"requestAnimationFrame"関数を使います。引数に繰り返し実行したい関数を指定します。なんか理屈がよく分かりませんが、再帰関数みたいな感じなんでしょうか?とりあえずそういう事にしておきましょう。

あとがき

はい。というワケでできましたね。でもこんなもんじゃない。もっとすごいの作りたい。そう思わせてくれるThree.jsはとてもステキですね。もっと勉強しておしゃれなものを作っていきたいと思います。ありがとうございました。

おしゃれ度

★★★☆☆

Posted by ナカタ