続・ポリゴンできれいな球を作る

先週は面積が均一なポリゴンで球を作れなかったので、Java3DのプリミティプであるSphereクラスの球を参考にすることにした。

テストアプリ(Java3D)の起動ページへ
(今回のはカーソルキーの左右とPageUp/PageDownキーで回転します)
ソースコード
画面サンプル

Sphereクラスのコンストラクタのdivisionsの値を変えることにより、ポリゴンの密度を変えることができる。右端から反時計回りに、divisionsの値が4,8,12,16,24,32の球である。
それぞれの三角形の面積が大体等しい、きれいな球面である。どういう仕組みなのだろうか。

まず、試しにdivisionsの値を変えながら重ねて表示してみると、5,6,7,8は同じ球、9,10,11,12も同じ球であることがわかった。どうやらdivisionsの値は4の倍数に切り上げられて使われるらしい。
また、divisions=4だと正8面体で、divisionsがいくらでも、その正8面体の辺を球面に投影した(球と同じ半径の)3つの円周で球面が8分割されていることがわかる。さらに、その3つの円周の1つと平行な円周で球面が輪切りにされていることがわかる。

より細かい分割方法の特徴を明確にするために、divisions=28の球面でさらに調べてみる。(ここまでで既に出てきた3や8の倍数は避け、divisions=20は正20面体と関係するかも知れないので避ける)

赤い線で囲まれた部分が、球面の1/8である。赤い線は内接正8面体の頂点を結ぶ円周の弦、水色の線は下の方の赤い線と接する円周(以下、赤道)と平行な円周(以下、緯線)の弦である。
赤道と残り2つの経線上に、それぞれ赤い線分が7つある。おそらく、divisionsの値は赤道や残り2つの経線を何等分するかという値であろう。この1/8球面において、赤道は7分割、その上の緯線は6分割、その上は5分割、以下同様に分割されている。1/8球面を三角形に見立てると、三角形を各辺に平行な線で等分割する要領である。

という訳で、その三角形を等分割する点(線形補間)を球面に投影した点でポリゴンを作ってみる。
テストアプリの起動ページへ
ソースコード
画面サンプル

大きな三角形の頂点の辺りは密で、辺の辺りは疎になった。先週のエントリーで書いたのと同じ問題である。やはり線形補間だとうまくいかない。

そこで、Sphereクラスに習って緯線に沿った円周補間に変える。
…と思ったが、クォータニオンを使った球面補間なら上のソースコードのVector3fをQuat4fに変えるだけだし、球面補間の方が1/8球面を均等に分けられるはずなので、球面補間にする。(Sphereクラスも球面補間か?)
テストアプリの起動ページへ
ソースコード
画面サンプル

うむ、丸い。


何だ、簡単ではないか。
先週は頭がフラクタルに染まって抜け出せなかったようだ。

ポリゴンの球面を加工するために、Sphereクラスが作ったポリゴンの頂点を取得したいと思っているが、やり方がわからない。
Shape3Dの基本的な使い方から推測して、Sphere#getShape()で取得したShape3DのnumGeometries()がポリゴンの頂点の数を返すのではないかと期待したが、実際には1が返された。それに、Shape3D#getGeometry()で取得するGeometryが実際にはどのクラスのインスタンスなのかがわからない。実はGeometryCompressorなどというクラスのインスタンスなのかも知れないし、もし筆者の環境でたまたまそうでも全ての環境でそうとは限らない(Object#getClass()しろというのは置いといて)。プリミティブのポリゴンの頂点を取得する、動作が保証された方法は存在しないのだろうか。
Triangulatorというクラスが近いことをしてくれそうな情報を得たが、実際に使われるポリゴンと同じものが返されるというようなことは書かれていない(いや、原理的には同じものが返されるに決まっているのだが)。というか、力尽きたのでまだ試せていない。