Three.js

2023-04-13

Three.js

Toc

Three.jsとは

手軽に3Dコンテンツを制作できる商用利用可能なJavaScriptライブラリ

JSライブラリの容量も126KB(GZIP)しかなく、とても軽量

参考

https://ics.media/entry/14771/ https://ics.media/tutorial-three/

How to use

  • 公式サイトからライブラリをダウンロードし(zip)解凍する。
  • 新規プロジェクトフォルダー作成して、ライブラリ(three.js-master)から/build/three.jsファイルをコピー。CDNも利用可能。htmlファイルで読み込み。
<script src="https://unpkg.com/three@0.146.0/build/three.min.js"></script>
  • index.jsファイル作成
window.addEventListener("DOMContentLoaded", init); function init() { // 処理を追加 }
  • index.htmlファイル作成
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Three.js Project</title> <script src="three.js"></script> // 追加 <script src="index.js"></script> // 追加 </head> <body> <canvas id="myCanvas"></canvas> // 追加 </body> </html>

レンダラー作成

WebGLにレンダリングするため

// レンダラー作成 const renderer = new THREE.WebGLRenderer({ canvas: document.querySelector("#myCanvas") }); // サイズ調整 const width = 820; const height = 540; renderer.setSize(width, height); // デバイスピクセル比設定:ぼやけ対策 renderer.setPixelRatio('window'.devicePixelRatio);

シーン作成

オブジェクトや光源の置き場

// シーン作成 const scene = new THREE.Scene(); // 背景色設定 scene.background = new THREE.Color( 0xffffff );

カメラ作成

THREE.Sceneで作成した3D空間をカメラで取得し、レンダラーを介してcanvasで描画される

// カメラ作成 params(画角, アスペクト, 描画開始距離, 描画終了距離) const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 10000 ); // カメラの初期座標設定 (x: 0, y: 0, z: 0) camera.position.set(0, 0, 1000);

オブジェクト(立方体)作成

メッシュで作成:ジオメトリ(形状)とマテリアル(素材)を用意する

ジオメトリ:頂点情報、面情報を持つ。様々なジオメトリが用意されている

箱状の形状を生成するBoxGeometryを使用

// ジオメトリ生成 props(width, height, depth) const geometry = new THREE.BoxGeometry(200, 200, 200); // マテリアル生成 const material = new THREE.MeshStandardMaterial({ color: 0x86A8E7 }); // メッシュ作成 params(ジオメトリ, マテリアル) const box = new THREE.Mesh(geometry, material); // シーンに追加 scene.add(box);

ライトの作成

// ライト作成 param(color); const light = new THREE.DirectionalLight(0x5FFBF1); light.intensity = 2; // 光の強さを倍にする light.position.set(1, 1, 2); // ライトの方向 scene.add(light); // シーンに追加 const light1 = new THREE.DirectionalLight(0xD16BA5); light1.intensity = 2; // 光の強さを倍にする light1.position.set(-1, -1, 2); // ライトの方向 scene.add(light1); // シーンに追加

描画(静的表示)、アニメーション(更新によるコマ送り)

// アニメーション function tick() { requestAnimationFrame(tick); // 引数の関数を毎フレーム実行 box.rotation.x += 0.01; // 箱回転 box.rotation.y += 0.01; // 箱回転 renderer.render(scene, camera); // 描画 } tick(); // 初回実行

学習の方向性

引用元: 参考URL

基本構造

THREE.Sceneクラス:3D空間を表す。add()で追加表示

THREE.PerspectiveCameraクラス:3D空間の視点制御

THREE.WebGLRendererクラス:

レンダリング、描画を行う。内部的にはWebGLのAPIを使用して表示している。

requestAnimationFrame のタイミングでレンダリングを行う。

マテリアル

質感設定:カラーリング、画像・陰影の割り当て、ライティングの反射

THREE.MeshStandardMaterial クラスを使用して

  • 単色
  • 画像

マテリアルを実装

球形ジオメトリ

イメージ:widthは横に対しての骨の数、heightは骨間の縦に対しての層の数

https://threejs.org/docs/#api/en/geometries/SphereGeometry

// ジオメトリ生成 props(radius, width, height) const geometry = new THREE.SphereGeometry(100, 100, 100);

オブジェクト作成手順

// ジオメトリ生成 const geometry = new THREE.SphereGeometry(100, 100, 100); // マテリアル生成 const material = new THREE.MeshStandardMaterial({ color: 0x86A8E7 }); // メッシュ作成 params(ジメトリ, マテリアル) const sphere = new THREE.Mesh(geometry, material); // シーンに追加 scene.add(sphere);

ライティング:平行光源、環境光

THREE.DirectionalLight:平行光源

const light = new THREE.DirectionalLight(0xFFFFFF); light.intensity = 2; // 光の強さを倍にする light.position.set(1, 1, 2); // ライトの方向 scene.add(light); // シーンに追加

THREE.AmbientLight:環境光。空間全体を照らす

画像マテリアル

GPUの制約から、2の累乗の高さ・幅である画像のみが利用可能

// ジオメトリ生成 props(radius, width, height) const geometry = new THREE.SphereGeometry(100, 100, 100); const loader = new THREE.TextureLoader(); const metalTexture = loader.load('texture/metal_01.jpg'); // マテリアル生成 const metalMaterial = new THREE.MeshStandardMaterial({ color: 0x666666, map: metalTexture }); // メッシュ作成 params(ジオメトリ, マテリアル) const sphere = new THREE.Mesh(geometry, metalMaterial); scene.add(sphere);

new THREE.TextureLoader(); でインスタンスを生成し、load('パス'); でファイル読み込み、

mapで設定する

様々な形状

代表的形状

💡 Basic : 光源の影響を受けない

  • 平面

  • 円柱

  • ドーナツ形状

💡 Standard : 光源の影響を受ける

  • 直方体

  • 球体

  • 円錐

  • 三角錐
// ジオメトリ生成 props(radius, width, height) const geometry = new THREE.SphereGeometry(100, 100, 100); const planeGeometry = new THREE.PlaneGeometry(120, 120); const coneGeometry = new THREE.ConeGeometry(50, 100, 32); // (radius, height, radialSegments: 側面の数) const cylinderGeometry = new THREE.CylinderGeometry(50, 50, 100, 32); // (top-radius, bottom-radius, height, radialSegments) const torusGeometry = new THREE.TorusGeometry(50, 20, 16, 100); // (radius:ドーナツ自体の半径, tube:内部の半径, radialSegments, tubularSegments:パーツ数。多いと円に近づく) // マテリアル生成 const metalMaterial = new THREE.MeshStandardMaterial({ color: 0x86A8E7, map: metalTexture }); const standardMaterial = new THREE.MeshStandardMaterial({ color: 0x86A8E7 }); const basicMaterial = new THREE.MeshBasicMaterial({ color: 0x86A8E7 }); const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x86A8E7, side: THREE.DoubleSide }); // メッシュ作成 params(ジオメトリ, マテリアル) const sphere = new THREE.Mesh(geometry, metalMaterial); const plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.position.set(240, 0, 0); const cone = new THREE.Mesh(coneGeometry, standardMaterial); cone.position.set(-260, 0, 0); const cylinder = new THREE.Mesh(cylinderGeometry, basicMaterial); cylinder.position.set(-260, -200, 0); const torus = new THREE.Mesh(torusGeometry, basicMaterial); torus.position.set(0, -200, 0); // シーンに追加 scene.add(sphere); scene.add(plane); scene.add(cone); scene.add(cylinder); scene.add(torus);

カメラ制御

カメラを自由に回転、移動が可能。多彩な表現が可能

  • 自動回転型
  • マウスの位置連動型
  • マウスのドラッグ&ドロップ型

自動回転型

// アニメーション function tick() { requestAnimationFrame(tick); // 引数の関数を毎フレーム実行 // カメラ自動回転 let rot = 0; rot += 0.5; // フレーム毎に0.5度足す const radian = (rot * Math.PI) / 180; // ラジアン変換 camera.position.x = 1000 * Math.sin(radian); // 角度に応じてカメラの位置を設定 camera.position.z = 1000 * Math.cos(radian); // 注視方向を設定 camera.lookAt(new THREE.Vector3(0, 0, 0)); renderer.render(scene, camera); // 描画 } tick(); // 初回実行

マウスの横移動に応じた回転

let rot = 0; // 角度 let mouseX = 0; // マウス座標 // マウス座標取得イベント、条件設定 document.addEventListener("mousemove", (event) => { mouseX = event.pageX; }); // アニメーション function tick() { requestAnimationFrame(tick); // 引数の関数を毎フレーム実行 // マウス位置に応じて角度設定。マウスのX座標がステージ幅の何%の位置にあるか取得し、360°で乗算 const targetRot = (mouseX / window.innerWidth) * 360; // イージング公式で滑らかに。val += (goalVal - currentVal) * minusVal rot += (targetRot - rot) * 0.02; const radian = (rot * Math.PI) / 180; // ラジアン変換 camera.position.x = 1000 * Math.sin(radian); // 角度に応じてカメラの位置を設定 camera.position.z = 1000 * Math.cos(radian); // 注視方向を設定 camera.lookAt(new THREE.Vector3(0, 0, 0)); renderer.render(scene, camera); // 描画 } tick(); // 初回実行

カメラの動きを自動的に制御する

THREE.OrbitControls クラス

手軽である分、カスタマイズの自由度の制限がある

細かいカメラワークの実現では物足りない

機能

  • 周回起動を描くようにカメラを配置する
  • ポインター操作でカメラの配置、アングルを移動する

CDNを利用

<script src="https://unpkg.com/three@0.147.0/examples/js/controls/OrbitControls.js"></script>

※Three.js r148(2022年12月リリース)以降よりES Modulesでの利用が推奨

THREE.OrbitControlsのコンストラクタへカメラのインスタンスとDOM要素を引数として渡すことでマウスと連動してインタラクションが効く。

  • オービット(周回軌道): 左ボタンでドラッグ
  • ズーム: マウスホイール
  • パン: 右ボタンでドラッグ

第二引数はポインタの操作受付対象のDOM要素を指定する。

document.body (画面内のどこでも操作を受付)かcanvas要素

// カメラ作成 params(画角, アスペクト, 描画開始距離, 描画終了距離) const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 10000 ); // カメラの初期座標設定 (x: 0, y: 0, z: 0) camera.position.set(0, 0, 1000); // 追加箇所 カメラコントローラー作成 const controls = new THREE.OrbitControls(camera, document.body);

ポインタ操作対象をCanvasのみに絞る

function init() { // レンダラー作成 const canvasElement = document.querySelector("#myCanvas"); const renderer = new THREE.WebGLRenderer({ canvas: canvasElement, }); ~~~省略 // カメラコントローラー作成 const controls = new THREE.OrbitControls(camera, canvasElement);

コントロールを滑らかにする:インスタンスのプロパティを設定

// カメラコントローラー作成 const controls = new THREE.OrbitControls(camera, canvasElement); controls.enableDamping = true; controls.dampingFactor = 0.2; ~~~省略 // アニメーション function tick() { // カメラコントローラーを更新 プロパティ使用時に必須 controls.update(); ~~~省略
TOP PAGE