スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

境界球生成プログラム ~完成版!~

【リンク】 ◆解説系TOP◆

境界球生成 後編です! \(`・ω・´)/

前回は、球の頂点の算出までやりました。

------------------------------------------
【1】頂点の順番の定義
【2】三角形の数の算出

------------------------------------------
今回は この2つを解説します。↑

まず、 頂点の順番の定義について。

円の真上と真下は、 頂点1つ と 頂点複数とのポリゴンになっています。
(真上と真下以外は、複数 対 複数の頂点とのポリゴンになっている。)

【参考画像】
頂点結びつけ

よって、真上と真下に限っては
D3DPT_TRIANGLEFANで頂点を定義した方が良いのですが、

ここはあえて、 
全てD3DPT_TRIANGLESTRIPで
行きます。


何でかと言うと、上記の球で行くと
Device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,TriNum,&sphere[0],sizeof(TEST));
Device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,TriNum,&sphere[0],sizeof(TEST));
Device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,TriNum,&sphere[0],sizeof(TEST));

Device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,TriNum,&sphere[0],sizeof(TEST));

こんな感じに何度もDrawPrimitiveUPをしなければならなくなるので面倒だからです。
それに、球の頂点数を変えたら
Device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,TriNum,&sphere[0],sizeof(TEST));
Device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,TriNum,&sphere[0],sizeof(TEST));
Device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,TriNum,&sphere[0],sizeof(TEST));
Device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,TriNum,&sphere[0],sizeof(TEST));
Device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,TriNum,&sphere[0],sizeof(TEST));

Device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,TriNum,&sphere[0],sizeof(TEST));
↑こんな風に、描画部分のコードも書き換えないといけないので面倒です。

なので、
---------------------------------------------------------------
1.全てD3DPT_TRIANGLESTRIPで統一
2.それらを縮退三角形でつなぐ

---------------------------------------------------------------
と言う風にします。
【リンク】"縮退三角形"について


では、頂点1つ 対 複数の頂点 (真上・真下)の部分から。
まず、全ての頂点情報は下記の様なvectorの2次元配列で管理されてます。

【参考画像】
頂点結びつけ3

そして、上から見ると 下記の様に頂点が並んでいる事が分かると思います。

【参考画像】
頂点結びつけ4

これらの頂点を、中心の点 + 外周の点2つで組み合わせて、
(今回は) 合計8個の三角ポリゴンで構成します。

【参考画像】
頂点結びつけ5

※頂点を重複させている部分(灰色の部分)は、三角ポリゴンを繋ぐための縮退三角形です。
また、プログラムはこのようになります。

【参考画像】
球_コード

で、プログラムを提示した直後でアレなんですが、このコードには欠陥があります。
コチラをご覧下さい。

【参考画像】
球3

何かおかしいですね。頂上付近が。
一応、色々と調べて原因は判明しました。

原因は、 この3要素のコンボです。
-------------------------------------------
・背面カリングON
・縮退三角形
・D3DPT_TRIANGLESTRIPの仕様

-------------------------------------------
※説明の前に、知っておかないといけない前提を書きます。

-------------------------------------------------------------------------------------
ポリゴンの表と裏・・・頂点を時計回りに定義⇒表、反時計回りに定義⇒裏ポリゴンとなる。
背面カリング・・・負担軽減の為に、裏面のポリゴンを描画しないモード。
D3DPT_TRIANGLESTRIP・・・表、裏、表、裏の順になっているポリゴンが、描画される。
縮退三角形・・・離れたポリゴンを繋いだ時、描画されない三角ポリゴンが、4つ増える。
-------------------------------------------------------------------------------------


で、説明に戻りますが、 普通に三角ポリゴンを縮退三角形でつないで行った場合、
D3DPT_TRIANGLESTRIPで裏ポリゴンが来なければいけない所に、
表ポリゴンが一回置きにやってくるんです。


【参考画像】
頂点結びつけ6

ですから、一回おきに表示されない三角ポリゴンが誕生してしまう、という訳です。
(上記の画像を見たら、交互に消えているのが分かると思います)

なので、三角ポリゴンを繋ぐ場合、
偶数番目は裏ポリゴン(反時計回り)にしないといけません。
それを踏まえたコードはこちら↓

【参考画像】
球_コード2

※多少 分かりづらくなりますが、下記の様にしてif文を消すことも出来ます。

【改良版】
球_コード3

次に、真上と真下以外の部分について。
コレは普通に頂点をジグザグに辿れるので、下記の様にすればOKです。
真上の部分と真下の部分よりかは 恐らく簡単でしょう。

【参考画像】
球_コード4
頂点結びつけ7

※真下の部分は、真上の部分とやり方は同じなので省略。

最後に、 三角形の数の計算方法を書きます。

int tNum = sizeof(degree) / sizeof(degree[0]);
int tP = ((tNum - 2)<<2) + 4;
TriangleNum += ((((tP - 1)<<2) + tP)<<1); //注1
TriangleNum += ((tNum - 2)<<1) * (tP<<1); //注2
TriangleNum += (((tNum - 1)<<1) - 1)<<2; //注3

以上です。

多分、意味不明だと思うので詳細。
まず、degreeが4つの要素の配列だとします。
float degree[] = {90.0f, 60.0f, 30.0f, 0.0f};

で、これらの1象限の角度を反転して円周りにいくつの頂点が出来るか?を算出します。

【参考画像】
球_点
※円周りの頂点の数 = tP です。

次に、真上と真下の部分の三角形の数を計算します。
今回は、上記の図を見ても分かるように tP = 12です。
そして、それらを縮退三角形(見えない三角形4つ)でつなぐので、
(12 - 1) * 4 個 三角形が増えます。

この式を、tPとシフト演算で置き換えると(tP - 1)<<2 となり、
合計は ((tP - 1)<<2) + tPで表されます。

最後に、真上と真下があるので、上の式を2倍(1ビットシフト)すれば三角形の数が出ます。
((((tP - 1)<<2) + tP)<<1)
↑真上と真下の合計(注1の式)


真上・真下の三角形の次に、真上・真下以外の三角形の数を求めます。
まず、真下・真上以外に何段の側面があるか?を調べます。
何段あるかは、((tNum - 2)<<1)で出せます。 (今回は4段
※上の画像の、異なるY座標にある 赤い頂点の個数を調べる、と考えると分かりやすいかも。

【参考画像】
球_点2

で、真上・真下の時と同じように円の周りの頂点の数だけ三角形が出来るので、
頂点の数(tP)だけ 掛け算をします。
ただ、真上・真下と違い、複数 対 複数 の頂点を結び付ける ので、
三角形の数が2倍になることに注意します。

【参考画像】
頂点結びつけ8
※真上・真下と比べて、2倍になっているのが分かる。
 真上・真下の場合は、普通に 円の周りの頂点数 = 三角形の数

よって、式は 真上・真下以外の段数 × (円周上の頂点の数×2)
tNum等の変数を用いると、((tNum - 2)<<1) * (tP<<1)になります。
注2の式)

最後は、段と段をつなぐ縮退三角形の数です。
今回は、下記の様な球になっています。(2つ前の画像を見ると分かりやすいかと)
-----------
真上
1段目
2段目
3段目
4段目
真下

-----------
まだ、段ごとの縮退三角形を考慮してなかったので、これを計算します。

真上縮退三角形1段目縮退三角形2段目/中略/縮退三角形真下
※↑こんな感じで、全てのポリゴンが繋がれてます。

で、段と段との間の数は(((tNum - 1)<<1) - 1)で求める事が出来るので、
あとはコレに、 (縮退三角形の数)をかければOKです。
(((tNum - 1)<<1) - 1)<<2 ←最終的な式(注3の式)

以上で三角形の出し方は終わりです。
色々と複雑な事をやりましたが、おかげで描画部分(DrawPrimitiveUP)は、
Device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,TriangleNum,&sphere[0],sizeof(TEST));
この一行で済みます。

更に、degreeを下記の様に変更するだけで、表示される球の滑らかさを変えられます。
-------------------------------------
float degree[] = {90.0f, 60.0f, 0.0f};
-------------------------------------
※角度の大きさをデタラメな順番で定義しないで下さい。 壊れます。
※第1象限 以外の角度を入れないで下さい。 壊れます。
※要素数を2つ以下にしないで下さい。 壊れます。
※変な事をして大量のvector配列がメモリリークしても責任は負いかねます。すいません。

一応、何種類かのdegree[]をコメントアウトしてあるので、それらの角度を使って下さい。

【ソースコード】
Sphere_h.txt
Sphere_cpp.txt
スポンサーサイト

テーマ : ゲーム製作 関連 - ジャンル : ゲーム

コメント
コメントの投稿
管理者にだけ表示を許可する



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。