Mac用プロットライブラリ-20「隠面消去」 [考え中 - プロットライブラリ]
隠面消去
奥にあるオブジェクトが手前のオブジェクトの後ろにある場合、奥のオブジェクトは隠されて見えなくなる。これをちゃんとシミュレートしなければ不自然な表現になる。これを隠面消去(稜線の場合陰線消去とも)という。隠面消去には、3次元オブジェクトを射影変換する過程(あるいはその直後)で行うものと、最終的に(ビットマップとして)表示される時点で行うものとがある。ピットマップ(描画ピクセルごと)にした時点で行う方が解像度の最小単位に関してやればいいので簡単になる。スキャンライン、Z-Buffering(Depth-Buffering)などがその簡単な方。
z-Buffering
OpenGLなどはいわゆるz-Bufferという奥行き方向の距離をすべてのピクセルが持っていて、新しいオブジェクトを描くときに既に描かれたz-Bufferの値を見て、新しいオブジェクトの方が小さければ描き、大きければ何もしない。これを表示のピクセルごとに行う。スキャンラインも基本的な考え方は同じ。
昔のあまり大きなメモリを持っていなかったころ、スキャンラインをソフトで実装するのが一般的だった(バッファが表示ラインの一列を使い回せるので。20年前のHPのワークステーションではグラフィクスライブラリにスキャンラインが実装されていたのを記憶している)。メモリが安くなった今はz-Bufferの方がハードウェアに実装しやすいので一般的になって、例えばOpenGLでは「やれ」と指定する(glutInitDisplayMode()に定数GLUT_DEPTHを渡す)だけでできてしまう。
実際に表示される直前にピクセルごとに処理するので、簡単で速い。だた、解像度に依存しない描画をしたい場合には使えないし、半透明物体の描画やアンチエイリアスは難しくなる。
単純な重ね描き
今回のライブラリの場合、ライブラリ内で解像度に依存する実装はできない。そこで今回は、奥にあるオブジェクトを先に描き、その上に順に手前のオブジェクトを重ね描きするという方法をとる。これをz-Sort法と呼ぶ人もいる。この場合、最終的に隠れて見えなくなるオブジェクトもすべて描画されるので無駄が多いが、カメラからの距離に従ってオブジェクトをソートできればいいので簡単で、しかも半透明物体の表現にも使える。
ところが、この場合も微妙な問題がある。ビットマップの場合は位置が量子化されているので「カメラから見て同じ位置」というのは自明だけど、このライブラリで扱うオブジェクトは一般に少数の位置の情報しか持っていない。例えばポリゴンは頂点の情報だけを持ったままで、最終的なNSBezierPathに渡されて描画されることになる。ポリゴンの状態で重なり具合を判断する必要がある。
ポリゴンの前後関係の判断
ふたつの四角形を考える。例えば図-6のような場合、小さい方の四角形は大きい方の前に出て大きい方を隠さなければならない。
ところが図-7の場合、大きい方の位置は変わらず、小さい方の視線方向の距離はかわらないのに前後関係は逆転する。
目で見ていると非常に当たり前なんだけど、ちょっと考えると非常に難しいことがわかる。つまり、「オブジェクトの何をもって前後を判断するか」と言う問題である。
図-6と図-7の場合は
- ふたつのオブジェクトはそれぞれの頂点の座標しか保持していない
- 2次元にしたとき(射影変換後)それぞれの頂点で視線方向に重なっているものはない
- 従って直接前後関係を比較できる場所はない
この図の例からわかるようにオブジェクトの奥行き方向の位置として、
- ひとつの頂点を代表させる
- 頂点の平均の位置を使う
ところで、こういうのを一人で悩んで考えるのもなかなか楽しい。今やってるのは新しい理論を発見したり新しい方法を思いついたりしたわけではなく、既にいろんなことが考えられている分野なので「全世界でただ一人の悩み」ではない。でも今考えていることの全体をコンシステントに保つ、つまり全体に整合性を与える作業である「設計という行為の面白さ」があるねえ。
ということで、ではどうするか、というと、またこんどにして寝よ。
コメント 0