あずまの日記

日々のVRChatの暮らし

任意の場所を常に向くカメラ

 VRChat 公式のカメラには Look at me モードがあって、常に自分の顔?を向いてくれるようになる。これを、任意の点を向けるようにしたい。

できたもの

 VirtualLens2 を使って、レンズが常に白い Cube を向くようにした。写真の向き (縦にしたり斜めにしたり) は、持っているカメラの向きで変えられるようにしてある。
 あとは白い Cube (とカメラ本体) がカメラ上で見えないようにしたいのだけど、 UI Layer に変えても写ってしまって困ってる……(どうしたらいいのか??)

詳しく

 ツイートしていたら教えてもらったので、その通り VirtualLens2 と Aim Constraint でやってみることにした。

booth.pm
docs.unity3d.com

 Aim Constraint は、指定したものを向くための Component で、単純にアバターの顔を指定すれば Look at me 相当のことができる。今回は、それを任意の場所にしたいので、ワールド固定した Object を向くようにする。なので作戦としては、ワールド固定を習得してから、 Aim Constraint を習得する二段階。

ワールド固定

 見たのはこのあたり。後半に仕組みも書かれていて面白かった。 Position Constraint でアバターと逆の移動をさせることでその場に置き去りにする、という手法で、ものすごいなるほど感がある。 Rotation Constraint は単に無効化するために負数を指定するというのも面白い。

note.com

 今回は、ワールド固定する白い Cube は (手ではなく) カメラのレンズの前にくっつけるということにしたので、↑の記事での手順のうち、手に持たせる代わりにカメラのレンズに入れた。この後やる Aim Constraint で指定するので、 Aim Constraint をつける Object の子には入れないように気をつける (子に入れてしまうと、 Aim Constraint で向く→ Cube の位置も変わる→向く……という無限ループになって高速に回転してしまう)。

Aim Constraint

 上でやったワールド固定できる Cube を向くように、カメラのレンズに Aim Constraint を追加する。 Unity の様子はこういう感じ。

 しかし Aim Constraint を指定すると、 (Z軸が Cube を向いてくれるのはいいとして) レンズの向き (Z軸回転) が必ず初期位置から 90度ずれてしまって困った。色々試すと、 Up Vector という設定を変えると挙動が変わることがわかった。これは本当に理解が難しかった…… (Unity のドキュメントには「アップ軸を指定」とか「上方向を指定」とか書かれていてよくわからない (英語でも「specify the up axis」とか「to specify the upward direction」とかなので翻訳のせいではなさそう))。

Aim Constraint の Up Vector

 Up Vector というのは、「Aim Constraint で向く際にどこを常に上とするか」という設定である、と言えそう。

 まず Aim Constraint というのは、「指定した Object に向かって、 (Transform を基準とした) あるベクトルを向ける Component」である。今回はカメラのレンズの真正面が Z軸そのものだったので、 (0, 0, 1) というベクトルを指定した。例えばカメラの斜め上のほうを何かに向けたいときは、 (1, 2, 3) みたいなベクトルも指定できるということになる。
 ここで、そのベクトルを向けた後の状態を考えると、そのベクトルを軸にいくら回転してもよいことがわかる。例えば今回の場合、 Z軸回転をどれだけやっても、 Z軸が Cube に向いているというのは変わりがない。なので向きが一意にならない (多分)。
 Up Vector を使うと、その向きを一意に決めることができる。例えばレンズの Y軸 (0, 1, 0) を Up Vector にして、 World Up Type を Scene Up にすると、レンズ Y軸が Scene の上 (Scene の Y軸) に常に向く。公式カメラの Auto level (常に水平になるモード) と同じような動きになる。デフォルトは Scene Up なので、上で書いていた「レンズの向き (Z軸回転) が必ず初期位置から 90度ずれてしまって困った」というのはこれだった。

 ドキュメントにはこういう表がある。

Up Vector このゲームオブジェクトのアップ軸を指定します。例えば、ゲームオブジェクトが常に正の Y 軸が上を指すように指定するには、X、Y、Z 軸にそれぞれ 0、1、0 の__Up Vector__ を入力します。
World Up Type 上方向の軸を指定します。エイムコンストレイントは、このベクトルを使用してゲームオブジェクトのアップ軸をこの上方向に整列させます。
Scene Up シーンの Y 軸。
Object Up World Up Object が参照するゲームオブジェクトの Y 軸。
Object Up Rotation World Up Object が参照するゲームオブジェクトの World Up Vector によって指定される軸。
Vector ワールドアップベクトル。
None ワールドアップベクトルを使用しません。
World Up Vector World Up Type で Object Up Rotation と Vector の選択時に使用するベクトルを指定します。
World Up Object World Up Type で Object Up と Object Up Rotation の選択時に使用するゲームオブジェクトを指定します。
https://docs.unity3d.com/ja/2019.4/Manual/class-AimConstraint.html

 今回は、レンズの Y軸をカメラの Y軸に合わせたかったので、 Object Up を使うことにした。小さな Cube をもうひとつ足し、カメラの Y軸側にちょっとだけずらしておいたものを、 World Up Object に指定する。 Up Vector を Y軸にすることで、小さな Cube に常にレンズの Y軸が向くので、カメラを縦にしたり横にしたりするとそのように画面が変わるようになった (一番上の動画でもわかる)。

 ちなみに None にしたときにどういう挙動になっているのかはよくわからなかった。回転が一意に定まらないはずだけど、大体決まった場所で決まった向きになっているので、何かの基準にフォールバックしているような気もする。
 あと World Up Type の Vector に今気づいた。これを使うと、レンズの Y軸を常に Scene の X軸に向けて必ず縦の写真を撮れるようにする、みたいなことができそう。