6. DynamicStereoCamera クラス

6.1. ウィンドウの指定

固定のカメラを使う場合に指定する視錐体の代わりに、ダイナミックカメラを使う場合はウィンドウを指定しなければなりません。ニアクリップ面とファークリップ面も同様に指定が必要です。

6.1.1. 仮想空間でのサイズを基にウィンドウを指定

カメラ中心からウィンドウの幅と深さを決めることができます。ウィンドウはカメラの Z 軸が中心になり、高さは本体の上画面と同じアスペクト比となるよう幅から計算されます。

ウィンドウ幅の比とウィンドウの深さが FOV を定めていることに注意してください。

この方法は、画像がスクリーン全体に表示されることを想定しています。

コード 6-1. SetWindowFromSize() の定義
void SetWindowFromSize(const f32 windowWidth,
                       const f32 nearDepth,
                       const f32 windowDepth,
                       const f32 farDepth);

6.1.2. ベースカメラ視錐体を基にウィンドウを導出

ベースカメラ視錐体の左辺、右辺、底辺、上辺への角度(タンジェント値)を指定することが可能です。この視錐体とウィンドウ深度の面との共通集合をウィンドウと定義します。この方法は、スクリーン全体をカバーしない場合のビューポート表現にも使えます。ビューポート境界のタンジェント値は、スクリーン正面の標準的なユーザー位置から計算されるべきです。ビューポート表現に合致する、スクリーンの最大領域に画像表示することを想定しています。

コード 6-2. SetWindowFromTangent() の定義
void SetWindowFromTangent(const f32 tangentLeft,
                          const f32 tangentRight,
                          const f32 tangentBottom,
                          const f32 tangentTop,
                          const f32 nearDepth,
                          const f32 windowDepth,
                          const f32 farDepth);

6.1.3. ビューポートからウィンドウを設定

スクリーンを部分的にカバーするビューポートを扱う場合、スクリーンのどこがビューポートなのかを知る必要があります。スクリーンを部分的にカバーするビューポートや現実感のある FOV を使う場合には、以下のメソッドが有用です。

コード 6-3. SetWindowFromViewport() の定義
void SetWindowFromViewport(const f32 screenHorizontalHalfFOVTangent,
                           const f32 viewportLeftInUnitSceen,
                           const f32 viewportRightInUnitSceen,
                           const f32 viewportBottomInUnitSceen,
                           const f32 viewportTopInUnitSceen,
                           const f32 nearDepth,
                           const f32 windowDepth,
                           const f32 farDepth);

6.1.4. 既存のプロジェクション行列を基にウィンドウを設定

視錐体を計算するベースカメラのプロジェクション行列とウィンドウ深度を指定することが可能です。

左右対称の視錐体を前提とした上画面全体をターゲットとするプロジェクション行列の場合にしか、この方法は使えません。

コード 6-4. SetWindowFromProjectionMatrix() の定義
void SetWindowFromProjectionMatrix(const nn::math::Matrix44 *proj,
                                   const f32 windowDepth);

6.2. ベースカメラビューの指定

コード 6-5. SetView() の定義
void SetView(const nn::math::MTX34* viewMatrix);
void SetView(const nn::math::VEC3& position,
             const nn::math::VEC3& upDirection,
             const nn::math::VEC3& forwardDirection);

nn::math::MTX34LookAt のような関数で生成されるビュー行列を指定する、もしくはベースカメラ位置を直接指定してください。ビュー行例や nn::math::Vector3 引数を指定するときに、CTR のグラフィックシステムに合うように右手座標系を使うことに注意してください。

6.3. 左目カメラと右目カメラの計算

コード 6-6. ComputeViewsAndProjections() の定義
f32 ComputeViewsAndProjections(
    nn::math::Matrix44* projL, nn::math::Matrix34* viewL,
    nn::math::Matrix44* projR, nn::math::Matrix34* viewR,
    const nn::math::VEC2* leftEyeTangent,
    const nn::math::VEC2* rightEyeTangent,
    const Setting& setting,
    const nn::math::PivotDirection pivot = nn::math::PIVOT_UPSIDE_TO_TOP
) const;

この関数は左目用画像と右目用画像をレンダリングするためのプロジェクション行列とビュー行列の生成に使います。

この関数では液晶から最適視認距離ほど離れた位置にユーザーがいると想定しています。現実に即したビューも、以下で説明する setting 引数に基づいた現実に即したわけではない(芸術的な)ビューも生成可能です。加えて、この関数はユーザーの頭の位置を考慮してダイナミックパースペクティブを調整することも可能です。

leftEyeTangent 引数と rightEyeTangent 引数はスクリーンに対するユーザーの左目の位置と右目の位置を表します。これらの値は nn::qtm::CTR::GetTrackingData 関数で取得できます。

leftEyeTangentrightEyeTangent のいずれかが null の場合、この関数の動作は(ダイナミックではない)静的な立体視カメラと同じになります。CTR 本体向けの開発であれば、この引数は null となるはずです。

生成されるプロジェクション行列のカメラの上向き方向が、pivot 引数で規定される上向き方向になります。pivot 引数に nn::math::PIVOT_NONE が設定された場合、回転は適用されません。pivot 引数に無効な値が指定されたら、関数はアサーションで止まります。デフォルトでは nn::math::PIVOT_UPSIDE_TO_TOP が指定されます。

返り値はカメラ間の距離の係数 ƒIです。付録で説明します。

6.4. Setting クラス

コード 6-7. Setting クラスの定義
struct Setting
{
    f32 StereoFactor;
    f32 ParallaxDistanceLimit;
    f32 DynamicPerspectiveAmplitudeX;
    f32 DynamicPerspectiveAmplitudeY;
    f32 DynamicPerspectiveClampingLeft;
    f32 DynamicPerspectiveClampingRight;
    f32 DynamicPerspectiveClampingBottom;
    f32 DynamicPerspectiveClampingTop;
    f32 RealisticFovFactor;
    f32 WideFovMotionFactor;
    bool TiltEnabled;
}

ComputeViewsAndProjections 関数の Setting 引数を使って立体視カメラの振る舞いを調整できます。

  • StereoFactor4.7. 3D ボリュームと立体視係数 節で説明したように立体視効果を調整します。
  • ParallaxDistanceLimit はミリメートルで指定する視差の限界値です。左目用画像のオブジェクトと右目用画像のオブジェクトの間の最大視差を意味します。4.6. 限界視差 節に説明があります
  • DynamicPerspectiveAmplitudeXDynamicPerspectiveAmplitudeY はユーザーの位置に乗算される係数です。頭の動きに対してダイナミックパースペクティブの効果を増幅させたり低減させたりするのに使います。
  • DynamicPerspectiveClampingLeftDynamicPerspectiveClampingRightDynamicPerspectiveClampingBottomDynamicPerspectiveClampingTop はユーザー位置の水平方向および垂直方向のクランプに使います。これらは 0 から 1 の範囲の値をとります。1 が設定された場合は、GetTrackingData で取得できる限界値で位置がクランプされます。中間の値が設定された場合は、限界値にたいして設定値に比例した位置でクランプされます。0 が設定された場合は、カメラは指定の方向には動かなくなります。DynamicPerspectiveAmplitude による増幅の前にクランプがされることに注意してください。
  • RealisticFovFactor4.2. 現実に即した FOV 係数 節で説明した現実に即したカメラとベースカメラの間にくるカメラ位置の補間に使われます。
  • WideFovMotionFactor4.1. ワイド FOV 節で説明したワイド FOV の状況で、ユーザーの動き応じてカメラがどのように動くかを調整します。
  • TiltEnabled4.5. 傾きと立体カメラの改善 節で説明した、傾きの有効無効を示します。

6.5. 占有領域

コード 6-8. OccupancyVolume 構造体の定義
struct OccupancyVolume
(
    math::VEC3 CameraCenter;
    math::VEC3 ForwardDirection;
    math::VEC3 OrthoUpDirection;
    math::VEC3 RightDirection;
    f32 NearPlaneDepth;
    f32 NearLeft;
    f32 NearRight;
    f32 NearBottom;
    f32 NearTop;
    f32 CameraLeft;
    f32 CameraRight;
    f32 CameraBottom;
    f32 CameraTop;
};

OccupancyVolume 構造体を使ってカメラの占有領域を表現できます。オブジェクトと交わることで不自然な見た目にならないことを保証するため、この領域にオブジェクトを置くべきではありません。

  • CameraCenter はダイナミックパースペクティブを無効化したときのカメラ位置です。RealisticFovFactor が 0 の場合、この位置は SetView メソッドで指定される位置と同じです。0 より大きい場合、前方向の軸に沿ってカメラ位置が調整され、現実に即した FOV に近づきます。ダイナミックパースペクティブでカメラが動ける面のことをカメラ面と呼びます。

  • ForwardDirection は前方向を示す単位ベクトルです。SetView メソッドで指定された値と同じです。
  • OrthoUpDirection は上方向を示す単位ベクトルです。ForwardDirection と直交します。
  • RightDirection は右方向を示す単位ベクトルです。ForwardDirectionOrthoUpDirection と直交するため、それらの外積を計算することで、右方向のベクトルを求めることができます。

RightDirection = ForwardDirection × OrthoUpDirection

  • NearPlaneDepth はカメラ位置からニアクリップ面までの距離です。
  • NearLeftNearRight はニアクリップ面における、(右方向ベクトルに沿った)水平方向の占有領域範囲です。
  • NearBottomNearTop はニアクリップ面における、(上方向ベクトルに沿った)垂直方向の占有領域範囲です。
  • CameraLeftCameraRight はカメラ面における水平方向の占有領域範囲です。
  • CameraBottomCameraTop はカメラ面における垂直方向の占有領域範囲です。
図 6-1. 占有領域のパラメータ

占有領域