D3DXCreateSphereってどんな関数?

何を作りたいのかが定まっていない人間が中途半端に何かを作ろうとするつまらないページです。
とりあえずVisual C++ 2008 Express EditionとDirectX 9.0 SDK Update (Summer 2004)なー。

定義

この関数は、球を多面体で近似した形状を作ります。
とりあえず定義を引用しておきます。

構文
HRESULT D3DXCreateSphere(
    LPDIRECT3DDEVICE9 pDevice,
    FLOAT Radius,
    UINT Slices,
    UINT Stacks,
    LPD3DXMESH *ppMesh,
    LPD3DXBUFFER *ppAdjacency
);
パラメータ
pDevice
[in] IDirect3DDevice9 インターフェイスへのポインタ。作成される球メッシュに関連付けられるデバイスを表す。
Radius
[in] 球の半径。この値は 0.0f 以上である必要がある。
Slices
[in] 主軸を回転軸としたスライスの数。
Stacks
[in] 主軸に沿ったスタック数。
ppMesh
[out] 出力形状である ID3DXMesh インターフェイスへのポインタのアドレス。
ppAdjacency
[out] ID3DXBuffer インターフェイスへのポインタのアドレス。メソッドが返ると、このパラメータには、メッシュに含まれる各面の 3 つの隣接面を指定する、1 面あたりの 3 つの DWORD の配列が入力される。NULL を指定できる。
(D3DXCreateSphere 関数 ()から引用)

戻り値はどうせSUCCEEDEDかFAILEDかぐらいしか見ないのでほっときます。注意事項についてはあとでまた触れます。

とりあえず使ってみる

めちゃくちゃはしょってますがこんな感じです。引数は適当です。

LPD3DXMESH pMesh = NULL;
if (FAILED(
    D3DXCreateSphere(
        pDevice,        // 描画先のデバイス
        radius,         // 半径。0.0fでも実はOK。マイナスはNG
        10,             // スライスの数。増やすときれいな球になるはず
        7,              // スタック数。増やすときれいな球になるはず
        &pMesh,         // 出力するメッシュ
        NULL            // あまり使わないらしいんでNULLにしといた
    )
) return E_FAIL;
pMesh->DrawSubset(0);   // サブセットっつっても1個しかないんでこれでOK
pMesh->Release();       // 使い終わったメッシュはしまっちゃおうね~

pDeviceとかradiusがしっかりしていれば次のような表示になると思います。

図1 球らしきもの
図1 球らしきもの

どこに球が出てくる?

さて、球は中心座標と半径で定義されるものですが、D3DXCreateSphere関数では指定しませんでした。どこに出てくるのでしょうか?これはちゃんとMSDNライブラリに書いてあります。

注意
作成される球は、中心が原点となり、軸は z 軸方向となる。
(D3DXCreateSphere 関数 ()から引用)

要するにローカル座標で作られるからワールド変換行列で適切な位置に移動しなけりゃならんということです。細かいところを気にするなら回転もしたほうがいいんでしょうかね。

スライスとスタックってなんだ?

ではスライスとスタックは?
よく分からず0にしてエラーを起こした人もいるかもしれません。これは要するに分割数です。
それでは表示をワイヤーフレームにして先ほど設定したスライス数10、スタック数7の球を見てみましょう。

図2 ワイヤーフレーム正面から
図2 ワイヤーフレーム正面から

図3 ワイヤーフレーム横から
図3 ワイヤーフレーム横から

見た感じでは、以下のように分かれているようです。なお、数値を振る順番は私の好みです。

図4 スライスとスタックの分け方
図4 スライスとスタックの分け方

スライスは中心を通るように分けて、スタックは輪切りの数のようですね。そしていずれも角度が等分になるように分けているようです。ただし、スライスとスタックを同じ数に設定した場合、分ける角度はスタックの輪切りのほうが半分に細かくなるようです。

図5 スライスとスタックを同じにした場合
図5 スライスとスタックを同じにした場合

上図はスライスとスタックを同じ10にしたものです。真ん中のポリゴンが縦に伸びているのが見て取れますね。スライスはスタックの2倍程度にしたほうがよさそうです。

Slicesの最小値

SlicesとStacksを増やせばきれいな球ができるわけですが、私はローポリ低解像度が好きなので、SlicesとStacksを小さくしてみます。
まずはSlicesが小さい範囲での挙動を確認するため、Stacksは充分に大きく(Stacks = 128)取っておきます。

Slices = 0

分割数0なのでもちろんエラーです。

Slices = 1

やっぱりエラーです。

Slices = 2

一応動きますが…。

図6 Slices = 2 の場合の「球」
図6 Slices = 2 の場合の「球」

あれれ?

図7 Slices = 2 の場合の「球」(別の角度から)
図7 Slices = 2 の場合の「球」(別の角度から)

角度をずらしたら見えてきました。

図8 Slices = 2 の場合の「球」(更に別の角度から)
図8 Slices = 2 の場合の「球」(更に別の角度から)

平面の円ができていました。これはこれで使える?
一応Slicesの最小値は2で決まりのようですね。

Slices = 3 以上

3にまですると一応立体にはなります。

図9 Slices = 3 の場合の「球」
図9 Slices = 3 の場合の「球」

…が、球と呼ぶには無理がありすぎますね…。
8あたりからいびつながらもそれっぽい姿になってきます。

図10 Slices = 8 の場合の「球」
図10 Slices = 8 の場合の「球」

Stacksの最小値

今度はStacksのほうを小さくしてみます。Slicesは128にしておきます。

Stacks = 0

分割数0なので当然エラーです。

Stacks = 1

予想通りエラーです。

Stacks = 2

最小値は同じく2ですが、こちらはちゃんと立体になります。

図11 Stacks = 2 の場合の「球」
図11 Stacks = 2 の場合の「球」

双円錐ですけどね!

Stacks = 3 以上

図12 Stacks = 3 の場合の「球」
図12 Stacks = 3 の場合の「球」

さっきよりは近いですがやはり球とは別の立体です。
4でもまだ厳しいのですが、5や6ぐらいになると、気の持ちようで球に見えなくもないレベルになってきます。

図13 Stacks = 6 の場合の「球」
図13 Stacks = 6 の場合の「球」

おわりに

今回はD3DXユーティリティライブラリのD3DXCreateSphere関数を、Slices、Stacks引数を中心に見てきました。途中に貼り付けておいた図4が全てなのでここで改めては述べませんが、最後にこの2つの引数を変えていろいろレンダリングした結果を並べておきます。

図14 Slices = 2, Stacks = 2 (正方形。同関数でできる最小の図形)
図14 Slices = 2, Stacks = 2 (正方形。同関数でできる最小の図形)

図15 Slices = 3, Stacks = 2 (双三角錐。同関数でできる最小の立体)
図15 Slices = 3, Stacks = 2 (双三角錐。同関数でできる最小の立体)

図16 Slices = 8, Stacks = 6 (小さく表示されるだけならこれでも何とかなりそう)
図16 Slices = 8, Stacks = 6 (小さく表示されるだけならこれでも何とかなりそう)

図17 Slices = 16, Stacks = 8 (細かいことを気にしないならこれで充分)
図17 Slices = 16, Stacks = 8 (細かいことを気にしないならこれで充分)

図18 Slices = 32, Stacks = 16 (非常に滑らかですが近寄ればポリゴンの判別は可能です)
図18 Slices = 32, Stacks = 16 (非常に滑らかですが近寄ればポリゴンの判別は可能です)

図19 Slices = 64, Stacks = 32 (最早これ以上はポリゴン数の無駄でしょう)
図19 Slices = 64, Stacks = 32 (最早これ以上はポリゴン数の無駄でしょう)