1. Vector3 とは何者か
THREE.Vector3 は 3D空間で使う「3つ組の数」 を、ただの入れ物ではなく “3D計算の道具” として扱うためのクラス。
Three.js では、次のようなものが全部 Vector3 で表現される。
- 位置(どこにいるか): mesh.position
- 方向(どっちを向くか/どっちへ進むか)
- 速度(どれくらいの速さで動くか)
- 力(押す・引く)
- 法線(面がどちらを向いてるか:光や反射に関係)
「座標 = Vector3」だけじゃなくて、「向き・速度・力」みたいな “ベクトル”っぽいもの全般に使う。
まず「3Dの数」をイメージする
2Dなら (x, y) の2つで位置が決まる。 3Dだと高さが増えて (x, y, z) の3つになる。
- x: 横(右が+)
- y: 縦(上が+)
- z: 奥行き(手前/奥が±、Three.jsは手前が+奥が−…ではなく、カメラ等で体感が変わるので「奥行き軸」くらいでOK)
だから Vector3 は基本こういう形:
const p = new THREE.Vector3(1, 2, 3); // x=1, y=2, z=3
console.log(p.x, p.y, p.z);
配列との違い([1,2,3] ではダメ?)
配列でも x,y,z を持つこと自体はできる。
const p = [1, 2, 3];
でも Three.js の世界では、配列は「ただの数字の箱」なので、3Dで必要な計算をするたびに地獄になる。
例:距離
Vector3 ならこれだけ:
const d = a.distanceTo(b);
配列だと毎回こういう関数が必要:
function distance(a, b) {
const dx = b[0] - a[0];
const dy = b[1] - a[1];
const dz = b[2] - a[2];
return Math.sqrt(dx*dx + dy*dy + dz*dz);
}
例:方向(目標へ向かう向き)
Vector3(あなたが書いてたやつ):
const dir = new THREE.Vector3().subVectors(target, current).normalize();
配列なら:
function direction(target, current) {
const x = target[0] - current[0];
const y = target[1] - current[1];
const z = target[2] - current[2];
const len = Math.sqrt(x*x + y*y + z*z) || 1;
return [x/len, y/len, z/len];
}
この時点で「Vector3で良くね?」ってなる。
さらに致命的な違い
Three.js の API の多くは Vector3 前提。
- mesh.position が Vector3
- camera.position が Vector3
- raycaster.ray.origin が Vector3
- object.getWorldPosition() が Vector3
つまり配列で持っても、結局 Vector3 に変換が必要になりがち。
パフォーマンス面での利点(初心者向けに現実的な話)
「Vector3の方が速い」と断言するより、初心者はこう捉えるのが安全。
- Vector3を使うと“余計な自作関数”や“変換”が減る
- その結果、コードが短くなってバグも減り、処理も安定する
ただし、Three.jsでも毎フレーム new THREE.Vector3() を大量に作ると、ブラウザの GC(メモリ掃除)が増えて重くなることがある。
なので基本姿勢はこれ:
- 計算用の Vector3 は使い回す(後の章で扱う)
- clone() の乱用に注意
GPU パイプラインとの整合性(初心者向けに噛み砕く)
WebGL(GPUで描画する仕組み)は、内部で
- 位置
- 回転
- 拡大縮小
などを 行列(Matrix) で処理する。
Three.js はその面倒なところを隠してくれているけど、内部的には
- Vector3(位置など)
- Quaternion(回転)
- Matrix4(変換)
が連携して動くようにできてる。
だから Vector3 を使っていると、そのまま Three.js の内部の変換処理にスムーズに乗る。
初心者向けに一言で言うと:
- Vector3は、Three.jsの“標準の部品”だから相性が最高
ここで覚えるべき最小ポイント
- Vector3は「x,y,zの3つ組」だけじゃなく、3D計算の道具
- 配列でも持てるが、Three.jsのAPIや計算に弱すぎる
- Three.js世界では Vector3 を使うのが最短で、バグも減る
2. まずは基本操作
Three.js の Vector3 は、3D空間でよく使う計算を “1行で” 済ませる道具。 その基本操作を理解すると、以降の移動・回転・カメラ制御が一気にシンプルになる。
Vector3 の基本メソッドとその意味
まずはサンプルコードを見てみる:
const v = new THREE.Vector3(1, 2, 3);
v.add(new THREE.Vector3(1, 0, 0));
v.sub(new THREE.Vector3(0, 1, 0));
v.multiplyScalar(2);
v.normalize();
これらがどういう働きをするのか、初心者にも分かるように順番に解説する。
add() – ベクトルの足し算
v.add(new THREE.Vector3(1, 0, 0));
x,y,z の全部に一括で足し算する。
数値で考えるとこう:
v = (1,2,3)
v + (1,0,0) = (2,2,3)
これ何に使う?
- オブジェクトの位置に「移動量」を足す
- 速度に加速度を足す
3Dゲーム・WebXRでは頻出する。
sub() – ベクトルの引き算
v.sub(new THREE.Vector3(0, 1, 0));
x,y,z をまとめて差し引く。
(2,2,3) – (0,1,0) = (2,1,3)
よく使う場面
- ターゲットとの差(方向ベクトルの基礎)
- マウス操作時の位置差分の計算
- 距離測定の準備
multiplyScalar() – ベクトル全体に数を掛ける
v.multiplyScalar(2);
(2,1,3) × 2 = (4,2,6)
主な用途
- 速度 × delta(1秒あたりの速度 → フレーム速度へ変換)
- 方向ベクトル × スピード = 移動量
- 距離の拡大縮小
“全成分に一括で掛け算”が地味に強い。
normalize() – 長さを「1」にする(方向だけ残す)
v.normalize();
これは初心者が一番つまずくところ。
normalize が何をするか
v の長さ(距離)を 1 にする。 つまり 向きだけを取り出した状態 にする。
元が (4, 2, 6) だとしても normalize すると「その方向を向いた長さ1の矢印」になる。
方向を維持 → 長さだけを1に変換
これが重要な理由
方向ベクトルをそのまま使うと、距離(長さ)がバラバラなので不安定になる。
例:
const direction = target - position; // 近いと小さく、遠いと大きい
このままだと 遠いと急加速 → 近いとスロー みたいな妙な挙動になる。
normalize すると安定する:
const direction = new THREE.Vector3()
.subVectors(target, position)
.normalize();
position.add(direction.multiplyScalar(speed));
これで「どんな距離でも一定速度で移動」になる。
単位ベクトルのメリット(初心者にも分かる形で)
normalize した結果できる「長さ1のベクトル」を 単位ベクトル と呼ぶ。
単位ベクトルのメリット:
- 方向が分かりやすい
- 速度や距離と掛け合わせしやすい
- 計算が安定する
- 複数のオブジェクトで共通処理にできる
特に Three.js では、 「方向 = normalizeしたVector3」 という前提が多い。
■ 初心者が陥りやすいポイント
- normalize() したら元の数値は変わる(元の値は保持されない)
- dir = target - pos のまま使うと速度が不安定になる
- 単位ベクトルは「方向専用」であり、「位置」には使わない
ここを理解すれば、Three.js の動きが一気に読みやすくなる。
3. 方向ベクトルの作り方(ゲームで最も使う部分)
3Dゲーム・WebXR・Three.jsで一番よく出るのが 「方向ベクトル」。 方向が分かれば、移動も回転も当たり判定も作れるようになる。
まずは完成形の一行:
const dir = new THREE.Vector3().subVectors(target, origin).normalize();
これが「origin → target へ進む向き(方向)」を作っている。
なぜ (target - origin) で方向になるのか
先に結論だけ示すと:
- 位置の差 = 向いている方向
数学としては
方向 = target位置 − origin位置
で求まる。
イメージしやすい例
origin = (0, 0, 0) target = (3, 1, -2)
なら差は
(3 - 0, 1 - 0, -2 - 0)
= (3, 1, -2)
これは「origin から見てどっち方向に target があるか」を示す矢印そのもの。
向き(方向)というのは 基本的に“差分” で決まる ということだけ覚えれば充分。
なぜ normalize するのか(方向だけ取り出すため)
(target - origin) のままでは、向き+距離が混ざった ただの差ベクトル。
近いほど小さく、遠いほど大きくなる。
ゲーム処理で使う場合は 向きだけ必要なことが多いので、
.normalize()
をつけて 長さ1の矢印(単位ベクトル)に変換しておく。
単位ベクトルにする意味
- どんな距離でも 一定速度で移動できる
- 速度の大きさを直接掛け算できる
- 回転処理が安定する
- 行動AIやパーティクル処理で扱いやすい
差ベクトルのまま使うと、距離によって挙動が狂いやすい。 normalize は必須。
速度と掛け算すれば「移動ベクトル」に変わる
方向ベクトル dir は「向きだけ」。 そこに速度 speed を掛けると「進むための量」になる。
model.position.add(dir.multiplyScalar(speed));
この3つの処理で キャラが“ターゲットへまっすぐ進む” が完成する。
- 方向を作る
- 速度でスケールする
- 位置に足す
ゲームエンジンも Three.js も、 移動の基本は“方向 × 速度” で統一されている。
方向ベクトルを使う典型ケース
- プレイヤーがターゲットへ移動する
- 敵がプレイヤーへ追尾する
- パーティクルが一定方向に飛ぶ
- カメラが対象物を追いかける
- Raycaster の方向を決める
- LookAt の仕組みを自前で書く
方向ベクトルは 3D の動きの土台そのもの。
つまずきポイント
- subVectors(target, origin) と subVectors(origin, target) を逆にすると逆方向になる
- normalize を忘れると速度が不安定になる
- multiplyScalar は「dir を汚しながら進む」ので、必要に応じて clone の使いどころがある
(ここは後の章で丁寧に扱っても良い)
ここまで理解できていれば、もう「3Dキャラを自由に動かす基礎」が身についている。次は距離の扱いに進むと、当たり判定や到達処理が自然に読めるようになる。
4. 距離の扱い(distanceTo の正しい使い方)
Vector3.distanceTo() は、2点間の“直線距離”を求めるためのメソッド。 Three.js で距離計算をするなら、まずこれを使う。
const distance = v1.distanceTo(v2);
計算しているのは数学でいうユークリッド距離:
distance = √((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2)
3D空間で「どれくらい離れているか」を知る標準の方法。
使い所①:衝突判定(当たり判定の基本)
キャラクター同士、またはキャラとオブジェクトが「近づきすぎたら当たり」とする場合、距離で判定できる。
if (v1.distanceTo(v2) < hitRadius) {
// 衝突!
}
球体ベースの判定は軽く、初心者にも扱いやすい。
使い所②:ターゲットへの到達チェック
移動処理で、目的地に着いたかを判断するのにも使う。
if (model.position.distanceTo(target) < threshold) {
// 到着!
}
threshold は「だいたいこのくらいでゴール」を決める小さい値。
使い所③:カメラ距離でエフェクトを調整
代表例:
- カメラが近いと透明にする
- カメラが遠いとエフェクトを強くする
- FPS 視点で「近すぎる物体を消す」
例:
const d = camera.position.distanceTo(model.position);
if (d < 2) mesh.visible = false;
else mesh.visible = true;
距離を使うことで、自然な視覚効果が作れる。
distanceTo の誤用例
「移動量」と混同するケース
初心者がよくやるのがこれ:
const distance = position.distanceTo(target);
position.add(direction.multiplyScalar(distance)); // ← 間違い
これだと、ターゲットが遠いほど移動量が激増しておかしくなる。
distance は「距離」であって「移動量ではない」。 移動には必ず 速度を掛ける必要がある。
正しくは:
const direction = new THREE.Vector3()
.subVectors(target, position)
.normalize();
position.add(direction.multiplyScalar(speed)); // 速度で移動
distance はあくまで「距離を知るため」にだけ使うのがポイント。
補足:距離²で比較するとさらに高速(上級)
衝突判定など大量に比較する場合:
if (v1.distanceToSquared(v2) < radius * radius) {
// 衝突
}
平方根を避けるので高速。 最初は無理に覚えなくてもよいが、効率化の基本テクニック。
distanceTo をしっかり理解すると、 移動・衝突・到達・視認距離など、3D演出の幅がかなり広がる。
5. 内積と外積
ここから先は 3D数学の核心部分。 とはいえ、Three.js で必要なところだけ理解すれば十分使える。
内積(dot):2つのベクトルが“どれくらい同じ方向を向いているか”
const d = v1.dot(v2);
内積は 向きの一致度 と覚えるのが一番わかりやすい。
内積の値が示す意味
| 値 | 意味 |
|---|---|
| 1 | 完全に同じ方向 |
| 0 | 直角(90度)で交わる、つまり横向き |
| -1 | 真逆の方向 |
たったこれだけで 「見てる/見てない」 「向いてる/向いてない」 が判断できる。
1. 視野判定(AI / 当たり判定の応用)
敵キャラがプレイヤーを見ているか判定:
const forward = enemy.getWorldDirection(new THREE.Vector3());
const toPlayer = new THREE.Vector3().subVectors(player.position, enemy.position).normalize();
if (forward.dot(toPlayer) > 0.7) {
// だいたい敵の正面方向(約45°以内)にプレイヤーがいる
}
ゲーム開発で超頻出する。
2. 角度の計算(向きの変化を数値化)
角度を出すなら:
const angle = v1.angleTo(v2); // ラジアン
dot() の内部で角度計算しているようなもの。
3. ライティング(光の当たり具合)
光の方向ベクトルと、面の法線ベクトルの内積で その面がどれだけ光を受けているか が求まる。
dot() が 1 に近いほど明るく、0に近づくほど暗くなる。
外積(cross):2つのベクトルに対して“垂直な方向”を作る
const cross = v1.clone().cross(v2);
外積は 「v1 と v2 の両方に垂直なベクトル」を作り出す計算。
3D空間で“上下”や“表裏”を判定したいときに使う。
外積の用途例
1. 地形に接地した法線(上向きベクトル)の取得
地面の傾斜から 正しい上方向(normal) を取れる。
const normal = edge1.clone().cross(edge2).normalize();
これは照明にも影響するし、接地処理にも必須。
2. 回転軸の生成
2つの方向ベクトルから「回転すべき軸」を作る。
例: キャラをある方向に向けるとき、 今の向き v1 と 目標方向 v2 から
const axis = v1.clone().cross(v2).normalize();
この axis を軸に回転すれば、自然に目標方向を向く。
3. LookAt の補正
Three.js の LookAt が意図した軸回転をしない場合、 外積を使って正しい矢印(up方向)を作り直す。
内積と外積は“3Dに必須の感覚”
初心者は最初ここでつまずくけど、 感覚としてはたったこれだけ:
- 内積:どれくらい同じ方向か
- 外積:2つから垂直方向を作る
この2つが理解できると、 移動・回転・照明・AI・カメラ制御 が一気に読みやすくなる。
6. 行列・クォータニオンとの連携(本格3D)
Three.js の 3D空間は、 位置(Vector3)・回転(Quaternion)・変換(Matrix4) の3つがセットで動いている。
Vector3 を扱うなら、 行列(Matrix4) と クォータニオン(Quaternion) の使い方は避けて通れない。
Three.js はこれを非常に分かりやすい API にしてくれている。
applyMatrix4():行列による空間変換をベクトルへ適用する
vector.applyMatrix4(matrix);
行列(Matrix4)は Three.js の “変換の塊”。
行列がまとめてできること:
- 移動(Translate)
- 回転(Rotate)
- 拡大縮小(Scale)
- ローカル座標 → ワールド座標への変換
- 視点変換(カメラ行列)
Vector3 を applyMatrix4() すると、 行列に含まれているすべての変換を一度に適用できる。
行列は「まとめて変換できる道具」
たとえば:
- プレイヤーのローカル座標
- ボーンアニメーションの変換
- モデルの親子構造(親オブジェクトの回転 → 子オブジェクトに伝播)
こういう「階層構造の変換」は すべて行列で表現される。
Three.js は内部で 親 → 子 → 孫 と行列を掛け合わせて最終的なワールド座標を作っている。
その変換をベクトルに直接適用できるのがこれ:
vector.applyMatrix4(object.matrixWorld);
これで「オブジェクトのワールド空間での位置や方向」が正しく得られる。
applyQuaternion():回転だけを Vector3 に適用
vector.applyQuaternion(q);
クォータニオン(Quaternion)とは、 3Dの回転を安定して扱うための数学表現。
Euler(オイラー角)には以下の問題がある:
- ジンバルロック(特定角度で回転軸が死ぬ)
- 回転順序問題
- 補間がガタつく
Three.js は内部的に回転をすべて Quaternion で保持している。
applyQuaternion() は ベクトルを“クォータニオンが表す角度”だけ回転させるためのメソッド。
Quaternion の代表的な用途
- LookAt の実装
- スムーズな回転補間(SLERP)
- ボーンアニメーションの回転
- カメラの向き制御
- VR空間のデバイス姿勢の取得
方向ベクトルを回転する場面は非常に多い。
例: キャラの「前方向ベクトル」をモデルの回転に同期させる:
const forward = new THREE.Vector3(0, 0, -1); // 初期の前方向
forward.applyQuaternion(model.quaternion); // モデルが向いている方向に変換
これで正確な「モデルが今どっちを向いているか」が取れる。
行列・クォータニオンは“Vector3を正しく扱うための裏側の仕組み”
3D空間は 位置(Vector3) × 回転(Quaternion) × 変換(Matrix4) の三位一体。
Vector3 は “矢印” Quaternion は “回転” Matrix4 は “空間の変形と座標変換”
という役割分担になっている。
Three.js はこの複雑な処理を内部で自動化してくれているけど、 Vector3 を本格的に扱うなら、このつながりを知っておくと理解が一気に深くなる。
7. 「よくある罠」まとめ
Three.js の Vector3 を扱い始めると、多くの人が同じ場所でつまずく。 ここを押さえておくと、動きのバグや “なんか変な挙動” が一気に減る。
1. normalize を忘れて速度が毎フレーム変わる問題
よくある誤り:
const dir = new THREE.Vector3().subVectors(target, position);
position.add(dir); // ← ダメ
dir は 距離の大きさを含んでいるので、
- 遠いと大ジャンプ
- 近いとチョロっと動く
という 距離依存の不安定な移動になる。
正解:
const dir = new THREE.Vector3().subVectors(target, position).normalize();
position.add(dir.multiplyScalar(speed));
方向と距離の切り分けは超重要。
2. clone しないで参照が全部同じになる問題
Vector3 はオブジェクトなので、代入すると 参照がコピーされるだけ になる。
悪い例:
const a = new THREE.Vector3(1, 2, 3);
const b = a; // ← 同じVector3を指している
b.x = 10;
console.log(a.x); // 10 になる(初心者が驚くポイント)
独立したベクトルにしたいなら必ず clone:
const b = a.clone();
特に計算用のテンポラリが絡むと、ここでバグる。
3. subtract の順番を間違えて「逆方向になる」
方向ベクトルのあるあるミス:
const dir = new THREE.Vector3().subVectors(origin, target); // ← 逆方向
正しいのは:
subVectors(target, origin);
// 「origin → target」方向
逆にすると「ターゲットから遠ざかる」挙動になる。
見た目では気づきにくいぶん、バグの温床。
4. 毎フレーム new して GC(ガベージコレクション)負荷が増える問題
初心者コードでありがちなパターン:
function update() {
const dir = new THREE.Vector3(); // 毎フレーム new
dir.subVectors(target, position).normalize();
position.add(dir.multiplyScalar(speed));
}
このように毎フレーム new Vector3() が多発すると、 メモリ負荷 → GC → フレーム落ち が起きやすい。
最適化した書き方:
const dir = new THREE.Vector3(); // 再利用
function update() {
dir.subVectors(target, position).normalize();
position.add(dir.multiplyScalar(speed));
}
Three.jsでは “不要な new を減らし、再利用する” がパフォーマンスの基本。
その他の細かい罠(補足)
✔ applyQuaternion の後 normalize が必要なときがある 回転後の方向ベクトルは長さが変わる場合がある。
✔ distanceTo の使いすぎは重い(大量の物体の場合) distanceToSquared() を使うと高速化できる。
✔ 複雑な連続演算では、clone を挟んで意図を明確化 読みやすさと安全性が上がる。
ここを理解しておくと、Three.js の Vector3 を実戦レベルで扱えるようになる。次は応用パターンに行くと、さらに “使いどころ” がクリアに見えるようになる。
8. 応用サンプルコードセット
ここからは 実戦で使う「Vector3 の典型パターン」 をまとめて紹介する。 あなたがゲームシステム・WebXR・Three.jsでよくやる処理ばかりを選んでいる。
プレイヤー追尾(AI)
敵がプレイヤーへまっすぐ進む最も基本的な追尾処理。
const dir = new THREE.Vector3()
.subVectors(player.position, enemy.position) // 向き
.normalize(); // 単位ベクトル化
const speed = 0.05;
enemy.position.add(dir.multiplyScalar(speed));
ポイント:
- 差分 → normalize → speed の3ステップは追尾の基本形
- normalize で距離によらず一定速度になる
カメラの追跡(スムーズ追従)
カメラがプレイヤーに“ゆっくり追いつきながら”追跡する処理。
const targetPos = player.position;
const camPos = camera.position;
const dir = new THREE.Vector3()
.subVectors(targetPos, camPos)
.normalize();
const followSpeed = 0.02;
camera.position.add(dir.multiplyScalar(followSpeed));
camera.lookAt(player.position);
ポイント:
- lookAt と組み合わせて安定した追従が作れる
- 距離によってスピードが変わらないので自然なカメラ移動になる
パーティクルの進行方向
パーティクル1つ1つの「飛ぶ方向」をベクトルで持たせて動かす。
particle.direction = new THREE.Vector3(
Math.random() * 2 - 1,
Math.random() * 2 - 1,
Math.random() * 2 - 1
).normalize();
particle.velocity = 0.1;
function updateParticle(particle) {
particle.position.add(
particle.direction.clone().multiplyScalar(particle.velocity)
);
}
ポイント:
- direction は単位ベクトルにしておく
- velocity の値で調整するだけなので管理が楽
Raycaster と組み合わせた当たり判定
Ray(線)をベクトルで飛ばして「何かに当たったか」を調べる典型パターン。
const origin = camera.position.clone();
const direction = new THREE.Vector3(0, 0, -1);
direction.applyQuaternion(camera.quaternion); // カメラの向きに合わせる
direction.normalize();
raycaster.set(origin, direction);
const hits = raycaster.intersectObjects(scene.children, true);
if (hits.length > 0) {
console.log("Hit:", hits[0].object);
}
ポイント:
- Raycaster の向きは Vector3 で指定する
- camera.quaternion を apply して正確な向きを作る
LookAt の裏側をベクトルで書く(内部で何が起きてるか)
object.lookAt(target) を自前でやるとこうなる。
// 前方向を作る(target - object)
const forward = new THREE.Vector3()
.subVectors(target, object.position)
.normalize();
// 現在のforward方向
const currentForward = object.getWorldDirection(new THREE.Vector3());
// 回転軸(外積)
const axis = currentForward.clone().cross(forward).normalize();
// 回転角(内積 → angleTo)
const angle = currentForward.angleTo(forward);
// クォータニオンを作って回転
const q = new THREE.Quaternion().setFromAxisAngle(axis, angle);
object.quaternion.multiply(q);
これが lookAt が内部でやっている“方向を合わせる数学”。
ポイント:
- 外積 → 回転軸
- 内積 → 回転角
- Quaternion → 実際に回す
この理解があると、LookAt が意図しない回転をしたときでも調整できる。
Vector3 をここまで使えるようになると、3Dでの「移動・回転処理」がほぼ読めるようになる。 次に書く章(WebDev 出身者が勘違いしがちな部分)まで行けば、記事としても完成度が高くなる。
9. WebDev から Three.js に来た人が誤解しがちなポイント
Three.js に入ってくる多くの Web 開発者が、必ず抱く“勘違いポイント”がいくつかある。 2D/DOM の世界観と、3D/線形代数の世界観はまったく違うため、最初にここを理解しておくとつまずきが減る。
「配列で持ってもよくね?」の誤解
Web 開発者はよくこう思う:
const pos = [1, 1, 1]; // これで良くない?
気持ちは分かるけど Three.js では 決定的に困る。
理由:
- 配列には加算・減算・法線計算・距離計算などの 3D数学メソッドが全く無い
- Three.js の API のほとんどが Vector3 前提 → 結局どこかで Vector3 に変換する必要がある
- 行列計算や回転(Quaternion)との連携ができない → 3D空間の変換が破綻する
「配列でやる」という選択は 長期的に必ず損をする。
Three.js では Vector3 を使う方が圧倒的に自然で安全。
「DOM は2Dだけど Three.js は数学の世界」
Web の世界は基本 2D + レイアウトルール で動いている。
- 左上スタート
- 座標は x,y のみ
- CSS がレイアウトを解決
- 回転は transform がやる
- 距離や角度を手計算することは少ない
対して Three.js は 3D数学が土台。
- x,y,z の3軸で位置が決まる
- 奥行きの概念がある
- 視点(カメラ)の存在
- 回転は Quaternion または行列で処理
- 距離・角度・方向は自分で計算
DOM に慣れた人ほど初期に混乱する。 しかし Three.js に慣れると、この数学的世界がむしろ直感的に感じてくる。
「線形代数を避けても結局後で理解が必要になる」
最初はベクトルや行列を「なんとなく使う」でも動く。
けれど Three.js に深く踏み込むと、 必ずこういうシーンに出会う:
- カメラが変な方向を向く
- アニメーションが不自然な回転をする
- LookAt が急にグルっと回る
- 衝突判定が不安定
- WebXR で視線がズレる
- 親子モデルの位置調整が破綻する
これらはほぼすべて 「ベクトル・行列・クォータニオンの理解不足」が原因。
数学が目的ではないけど、 “3Dを自在に操るための最低限の知識” として避けられない。
Three.js の強みは、 複雑な部分を簡単に扱える API が揃っていること。 だからこそ、基礎をちょっと理解しておけば 急に世界がシンプルに見えてくる。
💬 コメント