スタートページJavascriptCANVASWebGL

WebGL Three.js イントロダクション


WebGL, THREE.js とは

WebGL(Web Graphics Library)は、3次元グラフィックスを描画する技術仕様(API)です。ほとんどのWebブラウザが標準装備している JavaScript と CANVVAS を用いて描画できます。
WebGL は、OpenGLの派生仕様で、豊富な機能がありますが、生で記述するのはあまりにもコードが長くなり複雑になります。

それを解決するために、多様なライブラリが公表されていますが、THREE.js は代表的なライブラリです。
これも多様な機能をもっていますが、基本的な機能を用いるだけで、容易に3次元グラフィックスを作成できます。

ここでは、私がWebにあるいくつかの入門サイトを参考にして、「それなりに理解してコーディングしたら、思ったように描けた」ことをまとめたものです。
「基本のk」だけであり、基本の中でも「被写体の各面に独自の色をつける」ことや「床に影を付ける」ことすら未解決な状態で、私が今後勉強するときの足掛かりとしようとするものです。

入門・解説 ICS MEDIA「Three.js入門サイト」https://ics.media/tutorial-three/
公式ドキュメント 「Three.js - Javascript 3D Livrary」https://threejs.org/

THREE.js によるコーディング

右図を作成するソースコードを、別ウインドウに表示します。

THREE.js のCDN

THREE.js をインストールして使うこともできますが、次の指定をすれば利用できます。
(three@0.140.2 はバージョンです。最新版はこのサイトで確認してください。
  <script src="https://unpkg.com/three@0.140.2/build/three.min.js"></script>

撮影環境の設定

甚だ手抜きですが、この部分は、次のようにコピー&ペーストするのが通常です。
シーン(scene)とは、カメラに写される仮想的な3次元空間のこと。
この中に被写体が置かれます。
レンダラーとは、そのシーンを2次元の CANVAS に適切に描画するためのものです。
  var renderer = new THREE.WebGLRenderer({  // A
    canvas: document.querySelector("#myCanvas") // B
  });
  renderer.setPixelRatio(window.devicePixelRatio);  // C
  renderer.setSize(width, height);          // D
  var scene = new THREE.Scene();         // E

A:レンダラーにはいくつかの種類がりますが THREE.WebGLRenderer は最も標準的なレンダラーです。
B:これにより、描画する CANVAS との関係づけをします。   HTML 側では、<canvas id="myCanvas"></canvas< と記述しておきます。
  ここで width, height を記述することもありますが、Dで指定するのが通常です。
C:レンダラーのリサイズに必要な指定らしいですが、私には理解できません。
E:これでシーンが作られます。
この後、カメラや被写体をシーンの中に追加すれば、最後に renderer.render(scene, camera); として描画できます。

シーンのオプション
 シーンの背景色。光源がないときはシーン全体は暗闇(黒一色)になっています。次により背景色を変えることができます。
 色の指定は、0x808080 (""で囲まない)のような16進表示が標準ですが "silver" のような形式も使えます。
  scene.background = new THREE.Color("silver");
 座標軸(後述)の表示。右図の赤と緑の細線が表示されます。
  var axes = new THREE.AxesHelper(1000);
  scene.add(axes);

THREE.js での座標系(ソースコードにはありません)

シーンは3次元空間なので、位置や大きさは (x,y,z) で与える必要があります。ところが CANVAS は2次元平面です。
上のDで、CANVAS を width = 400, height = 300 とすると、
  CANVAS の中央 (200, 150) が原点 (0,0,0) になります。
  X軸は右側は+、Y軸は上方向が+になります。
  Z軸は、原点から手前に垂直で手前が+になります。見えません。
ここで、CANVAS に入る範囲 xmin~xmax, ymin~ymax がどう設定されるのか私にはわかりませんが、
どうも CANVAS での width, height で計算されているようで、カメラが原点にあるよきは、-400~400になるようです。
Z軸は目盛りはX・Y軸と同じですが、範囲には制限がないようです。
参照:CANVAS での位置関係

カメラ(camera)の設定

基本設定
  var camera = new THREE.PerspectiveCamera(fov, aspect); // A
  camera.position.set(positionx, positiony, positionz);     // B

オプション
  var camera = new THREE.PerspectiveCamera(fov, aspect, near, far); // C
  camera.lookAt(new THREE.Vector3(x, y, z));   // D

A:カメラの特性
  Perspective 遠近法。カメラに近い部分は大きく、遠い部分は小になります。通常はこれになります。
  Orthographic 平行法。遠近の差はありません。ここでは省略します。
  fov;カメラの視角。標準値 = 45。これを変えると広角撮影、望遠撮影になります。
  aspect:カメラ撮影による横縦比。一般には CANVAS の width/height に一致させます。
B:カメラの位置です。カメラはシーンの外部にあるので、positionz を大きい値にする必要があります。
  カメラはシーンの構成要素ではないので、Bだけで登録したことになります。
C:カメラに撮影する距離を、near~far に限定します。近写体、遠写体を消すのに有効です。
D:カメラの向きを (x,y,z) に向けます。この指定がないと (0, 0, 0) を向いています。
  ((positionx, positiony,0) を向いているのではとも思うのですが、未確認です)

被写体(object)の設定

実際の3次元グラフィックスでは、自動車、建物、人物など複雑な被写体を対象になりますが、それには高度な技術、センス、複雑な作業を伴います。THREE.js でも多様な幾何学的被写体が標準的に提供していますが、ここでは立方体と球体に限定します。

被写体(object)の設定には、次の5行が基本になります。
  var geometry = new THREE.BoxGeometry(width, height, depth); // A
  var material = new THREE.MeshNormalMaterial();  // B
  var box = new THREE.Mesh(geometry, material);   // C
  box.position.set(positionx, positiony, positionz);    // D
  scene.add(box);       // E

A:geometry とは形状のこと。Box(直方体), Sphere(球体)など多くの標準形状があります。
  width などは、幅(X軸)、高さ(Y軸)、奥行(Z軸)のサイズです。これらのパラメタは形状により異なります。
  参照:「geometry(被写体の形状)」
B:material は、被写体の表面の性状です。色の指定、光の影響などです。
  Normalは、面を一様にベタ塗りし、光の影響を受けません。パラメタを省略すると自動的に彩色されます。
  PhongMaterial は光を敏感に受ける方法です。光がないと全てが黒色になります。
  参照:「material(1)」
C:geometry と material が与えられれば、被写体が定義されます。ここではその被写体を box と命名しています。
D:position は被写体 box が存在する位置を与えます。
E:scene.add とは、この box をシーンに追加することです(DとEの順序は逆でもかまいません)。
このようにして、いくつもの被写体をシーンに取り込むことができます。

光源(light)の設定

光源がないときは、シーン全体は背景色一色になっています。MeshFaceMaterialなど受光をベースにした material の被写体は黒体になっており、光源を与えることにより、明暗のある物体として見えます。

A以外は「被写体の設定」と同じです。
  var light = new THREE.PointLight(色, 強さ);  // A
  light.position.set(positionx, positiony, positionz);    // D
  scene.add(light);       // E
A:光源のタイプには、Ambient(環境光源)、Directional(平行光源)、Point(点光源)、Spot(スポットライト)などがあり、組合せて使うことができます。
  参照:「光源と影」

被写体の位置などの変更

先に scene.add て追加した object の位置や角度を変更することができます。
光源やカメラの位置や向きの指定など、多様な変更ができますが、最も代表的なものは、被写体の位置や角度でしょう。
  sphere.position.x = -200; // sphere の中心のx座標を -200 に変更する。
  box.rotation.x = 15;    // box をX軸に対して15°回転させる。

レンダリング(撮影)

3次元空間であるシーンを、カメラの位置や向きにより、2次元平面である CANVAS に描画することです。
その基本方法は、「撮影環境の設定」で定義され、ここでは renderer となっています。
撮影の記述は、次の1行だけです。
  renderer.render(scene, camera);

被写体の連続移動(動画)

3Dグラフィックの魅力は、被写体やカメラを連続的に移動して、動画を作成できることでしょう。
右図では、sphere の平行移動と box の回転をさせています。

移動の基本パターン
  var interval = 20;             // 1回の移動・撮影の遅延期間 20/1000秒
  var i = 0;                    // 繰返し回数のカウント
  var timerId = setInterval(function(){    // ループの開始
                           // 移動の指定
    sphere.position.x += 2;              // 1回にx軸方向へ 2 移動
      :
    box.rotation.x += 0.05;                // 1回に 0.1°回転
      :
    renderer.render(scene, camera);        // レンダリング(撮影)
                            // 移動の変更が必要な場合
    if ( (i%50) ) …                  // 50回ごとに…
    if (sphere.position.x >= 300) …         // 右側端に達したら…
      :
    if (i >= imax) clearInterval(timerId);   // 回転打切条件
    i = i+1;
  }, interval);                // ループの終了

参照:「被写体の移動」「カメラの移動」

多くの Three.js の解説では、次の方法が紹介されています。
利点があるのかもしれませんが、速度の変更や回転終了などを指定する方法を私は知りません。
  tick(); // 回転させる関数の呼び出し
  // 回転関数
  function tick() {
    :
    renderer.render(scene, camera);
    requestAnimationFrame(tick);
  }