LoginSignup
2
2

More than 5 years have passed since last update.

GLKMatrix4MakeOrtho の使い方を勘違いしていた件

Last updated at Posted at 2015-12-31

Normalized Device Coordinate

OpenGL などでは、最終的なデバイスの上での表示座標は NDC(Normalized Device Coordinate)で X座標、Y座標も-1.01.0の範囲で表現できます。実際の表示エリアが、縦長か横長かに関係なく、-1.01.0で、中心が 0.0 となります。
3.png

さすがに、アプリがこのNDCを意識してコーディングするのは不便なので、3Dでは GLKMatrix4MakePerspective など、2D なら GLKMatrix4MakeOrtho を利用して、4x4 の Matrix(行列) を求め、この Matrix を 座標 の Vector と乗算して座標変換すれば、View の座標を NDC に変換する事ができます。

NDCの座標 = その行列(4x4) * Viewの座標(x,y,z,w)

行列の演算

Swift を使っているなら、行列の演算は * オペレータを使って実装したいですね。4x4 の行列同士の乗算の結果は 4x4 の行列になりますし、4x4 と 1x4 の行列の乗算の結果は 1x4 の行列になります。

func * (l: GLKMatrix4, r: GLKMatrix4) -> GLKMatrix4 {
    return GLKMatrix4Multiply(l, r)
}

func * (l: GLKMatrix4, r: GLKVector4) -> GLKVector4 {
    return GLKMatrix4MultiplyVector4(l, r)
}

GLKMatrix4MakeOrtho

GLKMatrix4MakeOrtho では View の上下左右を指定します。ドキュメントでは以下のような記述になっています。

func GLKMatrix4MakeOrtho(left: Float, _ right: Float, _ bottom: Float, _ top: Float, _ nearZ: Float, _ farZ: Float) -> GLKMatrix4
Parameters description
left The left coordinate of the projection volume in eye coordinates.
right The right coordinate of the projection volume in eye coordinates.
bottom The bottom coordinate of the projection volume in eye coordinates.
top The top coordinate of the projection volume in eye coordinates.
nearZ The near coordinate of the projection volume in eye coordinates.
farZ The far coordinate of the projection volume in eye coordinates.

よって、nearZfarZ をちょっと置いておいて、例えば画面のサイズが 1024x768 の場合、左下を原点にした場合と中心を原点にした場合のそれぞれをコードと図で表現すると以下のようになります。

1. 左下を原点にした場合

let matrix = GLKMatrix4MakeOrtho(0, 1024, 768, 0, -1, 1)

1.png

2. 中心を原点にした場合

let matrix = GLKMatrix4MakeOrtho(-512, 512, -384, 384, -1, 1)

2.png

勘違い

私はこれで、View の座標を NDC座標系に変換できると思っていたので、先の図の説明に使った座標系の座標と GLKMatrix4MakeOrtho の行列を演算すれば、簡単に座標の変換ができると思い込んでいました。が、

実は、二つのどちらの行列も原点 (0, 0) は View の中心に変換され、どちらにしようと結果が同じ結果が得られるという残念な結果に気がつきました。もっと早く気がついていれば楽になっていたのですがね。「右」とか「左」とか指定するならそう思っちゃうじゃないですかぁ。

let t1 = GLKMatrix4MakeOrtho(-512, 512, -384, 384, -1, 1)
let t2 = GLKMatrix4MakeOrtho(0, 1024, 768, 0, -1, 1)

// 座標 (-512, -384) → (-1, -1)
t1 * GLKVector4Make(-512, -384, 0, 0) // "[-1.0, -1.0, -0.0, 0.0 ]"
t2 * GLKVector4Make(-512, -384, 0, 0) // "[-1.0, -1.0, -0.0, 0.0 ]"

// 座標 (0, 0) → (0, 0)
t1 * GLKVector4Make(0, 0, 0, 0) // "[0.0, 0.0, 0.0, 0.0 ]"
t2 * GLKVector4Make(0, 0, 0, 0) // "[0.0, 0.0, 0.0, 0.0 ]"

// 座標 (512, 384) → (1, 1)
t1 * GLKVector4Make(512, 384, 0, 0) // "[1.0, 1.0, 0.0, 0.0 ]"
t2 * GLKVector4Make(512, 384, 0, 0) // "[1.0, 1.0, 0.0, 0.0 ]"

上下反転させたい場合

さて、最後に、GLKMatrix4MakeOrthotopbottom を入れ替えると(0768の順番に注意)、上下を反転させて変換できるようになります。

let t3 = GLKMatrix4MakeOrtho(0, 1024, 768, 0, -1, 1)
t3 * GLKVector4Make(-512, -384, 0, 0) // "[-1.0, 1.0, -0.0, 0.0 ]"
t3 * GLKVector4Make(0, 0, 0, 0) // "[0.0, 0.0, 0.0, 0.0 ]"
t3 * GLKVector4Make(512, 384, 0, 0) // "[1.0, -1.0, 0.0, 0.0 ]"

全体像はまだまだ

ここでは、GLKMatrix4MakeOrtho のみを扱ったが、 Model座標→ワールド座標など、全体を見れば一部の説明に過ぎないので注意されたい。

ハードルはやはり高い

GPU を使うプログラミング は門外漢(ES 1.1はかじった事があるけど)なので、単純に Core Graphics を使う場合などに比べて、何かとハードルが高い。間違いや勘違いの指摘など気がついたら教えていただければ幸いです。

2
2
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
2