
Twilog
Syndicate this site

Processingでスクリーン座標を3D座標に変換今、巷では技術系Advent Calendarというのが流行っているらしく、 まぁ、12月頭からクリスマスまでの間、各言語やテーマに沿った記事を1日1つ、 そんなわけでProcessing Advent Calendar 2011の12/2担当記事はこちら。 「Processingでスクリーン座標を3D座標に変換する方法」です。 Processingで3D空間の座標(モデル座標、オブジェクト座標)をスクリーン上の2D空間に変換するには、 では、スクリーン座標を3Dのモデル座標に変換するには、どうしたらいいでしょう。 そんなときにあるのがmodelX(x, y)、modelY(x, y)といった関数――だといいのですが、そうではなく。 OpenGLの関数、gluUnprojectを使えばスクリーンの2D空間の座標を3Dの座標に変換できますが、それだけのためにOpenGL関数やOpenGLレンダラーを使うのはどうも……。 というわけで、今回はこれをProcessingの関数のみで計算してみます。 2D→3D変換の前に、まず3D→2D変換のための行列を作りましょう。 // モデル座標をスクリーン座標に変換する行列を取得 PMatrix3D getModelToScreenMatrix() { PMatrix3D projection = new PMatrix3D(); matrixMode(PROJECTION); getMatrix(projection); PMatrix3D modelview = new PMatrix3D(); matrixMode(MODELVIEW); getMatrix(modelview); PMatrix3D viewport = new PMatrix3D(); viewport.m03 = viewport.m00 = width * 0.5f; viewport.m13 = viewport.m11 = height * 0.5f; PMatrix3D m = new PMatrix3D(modelview); m.preApply(projection); m.preApply(viewport); return m; } モデルビュー行列やプロジェクション行列の取得方法は、リファレンスには載っていませんが、
3D→2D変換の行列ができれば、目的の8割は達成したといえます。 // モデル座標をスクリーン座標に変換 PVector projectScreen(PVector v) { PMatrix3D m = getModelToScreenMatrix(); return matrixCMult(m, v); } projectScreen関数内では、getModelToScreenMatrixで取得した3D→2D変換行列を // 行列で変換したベクトル(wで割ったもの)を返す PVector matrixCMult(PMatrix3D m, PVector v) { PVector ov = new PVector(); ov.x = m.m00*v.x + m.m01*v.y + m.m02*v.z + m.m03; ov.y = m.m10*v.x + m.m11*v.y + m.m12*v.z + m.m13; ov.z = m.m20*v.x + m.m21*v.y + m.m22*v.z + m.m23; float w = m.m30*v.x + m.m31*v.y + m.m32*v.z + m.m33; if(w!=0) ov.mult(1.0f / w); return ov; } 中身はともかく、projectScreen関数は、以下のように呼び出せばOK。 PVector modelPos = new PVector(10, 20, 30); PVector screenPos = projectScreen(modelPos); screenPos.x、screenPos.y に それぞれ screenX や screenY 関数で計算したときと これをふまえて、2D→3D変換の関数を作ります。 // スクリーン座標をモデル座標に変換 PVector unprojectScreen(PVector v) { PMatrix3D m = getModelToScreenMatrix(); m.invert(); return matrixCMult(m, v); } 違うのは関数名の他に1行だけ。 m.invert(); と、変換行列を逆行列にしているだけですね。 unprojectScreen関数を使うときは、以下のように呼び出せばOK。 PVector mouse3D = unprojectScreen(new PVector(mouseX, mouseY, 0)); さらにunprojectScreenでZ値を1にした座標やカメラ位置と 詳しいところはサンプルをいじって確認してみましょう。 # 本当は別の少しクレイジーなネタを書くつもりだったのですが、 Tag : Processing, 開発 Trackback(0) |