Hatena::ブログ(Diary)

Imaginable Reality

2016-01-04

Processingで3Dグラフィックスを扱う上での注意点

 Processingのグラフィックスの描画系は内部でOpenGLを利用していますが、ProcessingのAPIは特有の癖があるのでOpenGLと同じ感覚でやっていると時々戸惑うことがあります。3DグラフィックスまわりのProcessing特有の仕様について、気をつけておくべき点をここにメモしておきます(Processing 2.2.1において動作確認)。


座標系

  • Processingは左手系。OpenGLは右手系。
  • 視点に対する各軸の向きは、x軸が右方向、y軸が下方向、z軸が手前方向となっている。

f:id:kougaku-navi:20160104103420p:image:w400

視点の初期位置

  • 視点の初期状態は以下の通り。
    • 目の位置:( width/2, height/2, (height/2)/tan(PI/6) )
    • 注視点の位置:( width/2, height/2, 0 )
  • これは、画面の左上隅が(0, 0, 0)、右下隅が(width, height, 0)にそれぞれ対応するような視点の配置になっている。ただし、これは透視投影の視野角がデフォルトの60度であることを考慮した計算のため、perspective()などで視野角が変更されるとこの関係はくずれる。

f:id:kougaku-navi:20160104104715p:image:w600


毎フレームの行列の初期化

  • 毎フレーム、draw()開始時に、モデルビュー行列が自動的に初期化される。
    • 問題は何で初期化されるかであるが、ここはちょっと注意が必要。
    • デフォルトでは、camera()にデフォルトパラメータを与えた時の行列(すなわち上図のカメラ配置にするための行列)で毎フレーム初期化される。具体的には、以下の形になっている。ここでwidthとheightは画面サイズ。
 1    0    0       -width/2
 0    1    0       -height/2
 0    0    1    -(height/2)/tan(PI/6)
 0    0    0          1
    • resetMatrix()を実行すると、それ以降、毎フレーム「単位行列」で初期化されるようになる。
    • camera()を実行すると、それ以降、毎フレームそのcamera()で指定したパラメータによって決まる行列で初期化されるようになる。
    • ただし、resetMatrix()やcamera()を実行している箇所をpushMatrix()・popMatrix()で囲んでいた場合はこの限りではない。
  • この挙動については、ビューイング変換の情報がシステム内部で常に保持されていて、draw()開始時にモデリング変換の情報のみを毎回単位行列にリセットしているのだ、と考えるとよいかも。
  • draw()の冒頭で毎回resetMatrix()やcamera()を実行している場合は特に気にする必要はないが、draw()の外や特定のタイミングでそれらを実行する場合は留意したい。

camera()の仕様

  • camera()はOpenGLのgluLookAt()に似ているが、挙動が若干違う。
    • 現在のモデルビュー行列をクリアする(乗算ではない)。
    • draw()開始時の行列の状態にも影響を与える(前述の通り)。
    • 実質的にワールド座標系に対するカメラの位置・姿勢を与える関数である(ローカル座標系に対してではない)。
    • (upX, upY, upZ)は(downX, downY, downZ)じゃないの?という疑念がある。Y軸が下に向いているのに(0, 1, 0)で上方向を表わすのは気持ち悪い。フォーラムでも同様の指摘がある。

プロジェクション行列とモデルビュー行列の取得方法

 Processing 2.2.1では以下のように書くと取得できる。

// 行列への「参照」が欲しい場合(内部のパラメータを直接書き変えたい場合)
PMatrix3D projection = ((PGraphics3D)g).projection; // プロジェクション行列
PMatrix3D modelview = ((PGraphics3D)g).modelview;   // モデルビュー行列

// 行列の「コピー」が欲しい場合
PMatrix3D projection = ((PGraphics3D)g).projection.get(); // プロジェクション行列
PMatrix3D modelview = ((PGraphics3D)g).modelview.get();   // モデルビュー行列

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/kougaku-navi/20160104/p1