リトルロード製作中9 座標系
ゲームで使用する座標系がいい感じにこんがらがってきました。
初心に帰って座標とは何かというところから考え直してみます。
座標とは、ある1点の位置を数値で表現するための仕組みであり、座標系はその表現方法の規格のようなものです。
例えば、岐阜県にある岐阜高校は、岐阜駅から見て西へ約700m、北へ約1700mの地点にあります(てきとう)。
これだけでは西だの北だのいう単語が入ってしまうので、仮に「1つ目の数値は東方向への距離、2つ目の数値は北方向への距離」という規格を作ったとします。逆方向はマイナス値で現します。そうすれば「岐阜高校の岐阜駅からの相対位置」は(-700,1700)という数値のペアだけで表すことができます。
上記の例では1つ目の数値を東西とし、かつ東がプラス値としましたが、こういった規格は用途や文化によりコロコロ変わるので扱いが難しくなります。
コンピュータでグラフを描くときは、主に1つ目の数値(X)が左右で右がプラス、2つ目の数値(Y)が上下で上がプラスの座標系を使用します。
これは、例えば売上推移グラフの場合、時間の経過という1つしかない要素が右に向かって進行し、売上額という複数の要素が高いほど上に向かって積むという慣例からきていると思われます。
ところが、コンピュータの内部の仕組みとなると上下関係が逆転しています。
これは欧文(横書き)の文章を記述するとき、左から順に1文字ずつ右へ向かって文字を配置し、右端に来るか文章の区切りになると次の行を下に書くという慣例からきていると思われます。
Windows用プログラムをGDIを使って作成する場合、そのほとんどは下がプラスの座標系になっています。しかしビットマップバッファは何故か上がプラスの格納形式が採用されていますし、SetMapModeを適用して物理単位との整合性を取る時も上がプラスの座標系になるのでややこしくなります。Y座標が逆転する例を挙げたらキリがありません。
2Dですらこんな有様ですので、3Dとなるともう十人十色に近い状態です。
三次元空間では二次元平面に1つ次元を足したような座標系を使用します。つまり、XYに次ぐ第三の要素、Zが登場するわけです。
地図や建物の見取り図はたいてい地面・床をXY平面に見立てていますので、これに追加する第三要素は高さです。
しかし、コンピュータのディスプレイや人間の網膜は大抵地面に対して垂直に存在し、元々左右・上下を二次元要素としているため、追加する第三要素は奥行きです。
私個人としては高さをZとする座標系が直感的で分かりやすいと思うのですが、どうも3Dグラフィックの世界では奥行きをZにするのが標準っぽい感じ(?)なので、そちらを使うようにしています。
次は奥行きであるZについて、手前をプラスにするか奥をプラスにするかです。
手前をZプラスとし、Yを上、Xを右とするのが最も一般的らしいです。XYZを親指・人差し指・中指に当てはめて「右手系」と呼ばれます。
私の愛用しているメタセコイアでもデフォルトとして採用されています。また、OpenGLでglOrtho(-1, 1, -1, 1, -1, 1)という単純なビュー行列を設定したときもこの座標系になります。
リトルロードでも採用しようと思っています。
対して奥をZプラスとしたのが左手系です。
さきほどOpenGLが右手系かのような記述をしましたが、実際にはglLoadIdentity()を実行した時点では左手系になっています。アプリケーション側でどんな座標系を使おうと、ジオメトリ演算が行われた結果の描画用座標は左手系になります。
ソフトウェアレンダリングの研究なんかをしてみても、視点から遠い場所にあるほどZ値が大きくなる左手系の方がずっと扱いやすい気がします。
ここからはリトルロードのマップ構成について。
リトルロードはスタート地点から直線的なマップを走ってゴールへ向かいます。なので、マップ構成上はスタート地点が原点で、ゴールへ向かうほどZ値が増えていくため左手系です。
ところが、ゲーム内ではメタセコイアで作成するモデルデータと整合性をあわせるために右手系を前提としてプログラムを組みます。キャラクタ座標やスクロール値からマップデータを参照するときは、Z値の符号を逆転しなければなりません。
そして、ゲーム内で算出された各種座標をディスプレイに3D映像として出力する段階になると、今度は奥がZプラスになる左手系、と思いきや、描画バッファにあわせて下がYプラスになる座標系にまで変換するため、奥がZプラスであるにもかかわらず右手系です。
……何これ。何でこうなった?どこで間違えた?このお役所仕事のような座標系のたらい回しは何なの?
私に技術やセンスがないからこんな結果になるんでしょうか。切ないなぁ。
初心に帰って座標とは何かというところから考え直してみます。
座標とは、ある1点の位置を数値で表現するための仕組みであり、座標系はその表現方法の規格のようなものです。
例えば、岐阜県にある岐阜高校は、岐阜駅から見て西へ約700m、北へ約1700mの地点にあります(てきとう)。
これだけでは西だの北だのいう単語が入ってしまうので、仮に「1つ目の数値は東方向への距離、2つ目の数値は北方向への距離」という規格を作ったとします。逆方向はマイナス値で現します。そうすれば「岐阜高校の岐阜駅からの相対位置」は(-700,1700)という数値のペアだけで表すことができます。
上記の例では1つ目の数値を東西とし、かつ東がプラス値としましたが、こういった規格は用途や文化によりコロコロ変わるので扱いが難しくなります。
コンピュータでグラフを描くときは、主に1つ目の数値(X)が左右で右がプラス、2つ目の数値(Y)が上下で上がプラスの座標系を使用します。
これは、例えば売上推移グラフの場合、時間の経過という1つしかない要素が右に向かって進行し、売上額という複数の要素が高いほど上に向かって積むという慣例からきていると思われます。
ところが、コンピュータの内部の仕組みとなると上下関係が逆転しています。
これは欧文(横書き)の文章を記述するとき、左から順に1文字ずつ右へ向かって文字を配置し、右端に来るか文章の区切りになると次の行を下に書くという慣例からきていると思われます。
Windows用プログラムをGDIを使って作成する場合、そのほとんどは下がプラスの座標系になっています。しかしビットマップバッファは何故か上がプラスの格納形式が採用されていますし、SetMapModeを適用して物理単位との整合性を取る時も上がプラスの座標系になるのでややこしくなります。Y座標が逆転する例を挙げたらキリがありません。
2Dですらこんな有様ですので、3Dとなるともう十人十色に近い状態です。
三次元空間では二次元平面に1つ次元を足したような座標系を使用します。つまり、XYに次ぐ第三の要素、Zが登場するわけです。
地図や建物の見取り図はたいてい地面・床をXY平面に見立てていますので、これに追加する第三要素は高さです。
しかし、コンピュータのディスプレイや人間の網膜は大抵地面に対して垂直に存在し、元々左右・上下を二次元要素としているため、追加する第三要素は奥行きです。
私個人としては高さをZとする座標系が直感的で分かりやすいと思うのですが、どうも3Dグラフィックの世界では奥行きをZにするのが標準っぽい感じ(?)なので、そちらを使うようにしています。
次は奥行きであるZについて、手前をプラスにするか奥をプラスにするかです。
手前をZプラスとし、Yを上、Xを右とするのが最も一般的らしいです。XYZを親指・人差し指・中指に当てはめて「右手系」と呼ばれます。
私の愛用しているメタセコイアでもデフォルトとして採用されています。また、OpenGLでglOrtho(-1, 1, -1, 1, -1, 1)という単純なビュー行列を設定したときもこの座標系になります。
リトルロードでも採用しようと思っています。
対して奥をZプラスとしたのが左手系です。
さきほどOpenGLが右手系かのような記述をしましたが、実際にはglLoadIdentity()を実行した時点では左手系になっています。アプリケーション側でどんな座標系を使おうと、ジオメトリ演算が行われた結果の描画用座標は左手系になります。
ソフトウェアレンダリングの研究なんかをしてみても、視点から遠い場所にあるほどZ値が大きくなる左手系の方がずっと扱いやすい気がします。
ここからはリトルロードのマップ構成について。
リトルロードはスタート地点から直線的なマップを走ってゴールへ向かいます。なので、マップ構成上はスタート地点が原点で、ゴールへ向かうほどZ値が増えていくため左手系です。
ところが、ゲーム内ではメタセコイアで作成するモデルデータと整合性をあわせるために右手系を前提としてプログラムを組みます。キャラクタ座標やスクロール値からマップデータを参照するときは、Z値の符号を逆転しなければなりません。
そして、ゲーム内で算出された各種座標をディスプレイに3D映像として出力する段階になると、今度は奥がZプラスになる左手系、と思いきや、描画バッファにあわせて下がYプラスになる座標系にまで変換するため、奥がZプラスであるにもかかわらず右手系です。
……何これ。何でこうなった?どこで間違えた?このお役所仕事のような座標系のたらい回しは何なの?
私に技術やセンスがないからこんな結果になるんでしょうか。切ないなぁ。
粒子のシミュレーション
パチンコ玉のような粒子が二次元平面を流れる様子をシミュレーションしてみました。
粒子の数量は200個、粒子同士の干渉は原始的なビリヤードタイプ、判定高速化には領域分割を使用しています。
水平または垂直の壁をマウスで配置でき、それにより作成された通路を粒子が流れます。粒子同士のめり込みを真面目に扱っていないため、圧力のような要素は再現できていません。
粒子の数量は200個、粒子同士の干渉は原始的なビリヤードタイプ、判定高速化には領域分割を使用しています。
水平または垂直の壁をマウスで配置でき、それにより作成された通路を粒子が流れます。粒子同士のめり込みを真面目に扱っていないため、圧力のような要素は再現できていません。