なぜないんでしょう……
単位ベクトルとは?
この記事でいう単位ベクトルとは、x, y, zのどれか一要素だけが±1のベクトルのことです。UnityでいうVector3.right
, Vector3.up
, Vector3.forward
などに相当します。
普通こういったよく使う定数は静的プロパティとして定義されているはずなのですが、three.jsではなぜかそれらしきものが見当たりません(.add()
などの関数が破壊的になっている設計思想と関係しているのかも)。
なので、作ります。
ダメな例
一番簡単な方法はTHREE
に定数を直接セットする方法です。
const THREE = require("three");
THREE.X_AXIS = new Three.Vector3(1, 0, 0);
THREE.Y_AXIS = new Three.Vector3(0, 1, 0);
THREE.Z_AXIS = new Three.Vector3(0, 0, 1);
[X,Y,Z]_AXIS
は普通のベクトルのため、以下のようにうっかり破壊的な操作を加えてしまうと大変なことになります。
> THREE.X_AXIS = new THREE.Vector3(1, 0, 0);
< Vector3 {x: 1, y: 0, z: 0, isVector3: true, set: function, ...}
> THREE.X_AXIS.add(new THREE.Vector3(1, 1, 1));
< Vector3 {x: 2, y: 1, z: 1, isVector3: true, set: function, ...}
> THREE.X_AXIS
< Vector3 {x: 2, y: 1, z: 1, isVector3: true, set: function, ...} // 単位ベクトルのはずが...
提案手法
プロパティを変更できないVector3
クラスを作ります。
const ImmutableVector3 = class extends THREE.Vector3 {
constructor(x=0, y=0, z=0) {
super();
this.x_ = x;
this.y_ = y;
this.z_ = z;
this.init_ = true;
}
get x() { return this.x_; }
get y() { return this.y_; }
get z() { return this.z_; }
set x(v) { if(this.init_) throw new Error(); }
set y(v) { if(this.init_) throw new Error(); }
set z(v) { if(this.init_) throw new Error(); }
}
ImmutableVector3
のsuper()
ではthis.[x,y,z]
への代入が行われるため、コンストラクタ中(this.init_
がtrue
でない間)は.[x,y,z]
を参照してもエラーが発生しないようにしています。
このクラスを使って
THREE.X_AXIS = new ImmutableVector3(1, 0, 0);
THREE.Y_AXIS = new ImmutableVector3(0, 1, 0);
THREE.Z_AXIS = new ImmutableVector3(0, 0, 1);
とすればOKです。
実行例
> const v = new THREE.Vector3(1, 2, 3);
< Vector3 {x: 1, y: 2, z: 3, isVector3: true, set: function, ...}
> v.add(THREE.X_AXIS);
< Vector3 {x: 2, y: 2, z: 3, isVector3: true, set: function, ...}
> THREE.X_AXIS.add(v);
< Error
X_AXIS
を破壊しない操作は普通のVector3
と同様に行えますが、X_AXIS
を破壊するような操作はエラーが発生します。
追記(2018/2/16):
Vector3
のclone()
ではコンストラクタを使って複製を行うようで、X_AXIS.clone().add(v)
などとするとエラーとなってしまいます。この場合はImmutableVector3
に
clone() { return new Three.Vector3(this.x, this.y, this.z); }
を追加すれば解決できます。