LoginSignup
2
0

More than 5 years have passed since last update.

なぜthree.jsには単位ベクトルがないのか?

Last updated at Posted at 2018-02-15

なぜないんでしょう……

単位ベクトルとは?

この記事でいう単位ベクトルとは、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(); }
}

ImmutableVector3super()では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):
Vector3clone()ではコンストラクタを使って複製を行うようで、X_AXIS.clone().add(v)などとするとエラーとなってしまいます。この場合はImmutableVector3
clone() { return new Three.Vector3(this.x, this.y, this.z); }
を追加すれば解決できます。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0