渋谷ほととぎす通信

完全趣味でやってるUnityメモ。説明できないところを説明できるようにするための個人ブログ。昨日の自分より少しでも大きくなれるように。。。 ※所属団体とは一切関係がありません

Unity 動的に球のメッシュを描画をしてみる


3年前に執筆した↑記事の続きです。

f:id:esakun:20181204194132p:plain:w450
先の記事シリーズでは、三角形を1個描画するところで終わっていますが、今回は↑のような球を動的に描画してみます。
パット見ハードルが一気に上がってそうですが、地道に1つずつ頂点の配置と順序を考えていけば大丈夫でした。

※注意 : 完全我流です。もっとシンプルな実装があるかもしれません。

f:id:esakun:20181205110707p:plain:w400

本記事では説明しやすいように、分割数を少なくしています。横分割6、縦分割4です。
(上から見たら正六角形、横から見たら4つの面が縦に並んでいる状態です)


f:id:esakun:20181204213702p:plain:w450

  • 天面
  • 側面
  • 底面

に分けて頂点座標配列とインデックス配列を作ります。

先の記事で説明していますが、Unityで動的にメッシュを作るにはVector3型の頂点座標配列int型配列の頂点インデックス配列が必要なので、これらを作成します。

頂点座標配列

  • 球の半径
  • 横分割数
  • 縦分割数

今回これらのパラメータを変更できるようにしています。 天面、底面の頂点はそれぞれ、(0, r, 0), (0, -r, 0)となります。
※rは半径

問題は側面の頂点です。
f:id:esakun:20181204223944p:plain:w400
球を横から見てみます。

θaは180度 / 縦分割数(ここでは4)で算出した角度(この場合45度)です。 緑のラインが頂点のy座標になるため、 y = consθa;になります。
薄いピンクは高さの頂点における円の半径になり、x座標、z座標を割り出し際に使用します。ここではtmpLenとします。 tmpLen = sinθaで割り出せます。

f:id:esakun:20181204222523p:plain:w400
次に上から見てみます。
θbは360度 / 横分割数で算出した中心角です。
緑ラインがx座標、青ラインがz座標ということになります。

x = tmpLen * sinθbとなり、z = tmpLen * cosθbです。

この処理を分割数分for文で回すだけです。
縦の分割数に関しては、天面、底面は別の処理なので、その分イテレーションを減らす必要があります。

頂点座標配列を算出するコードはこちらです。

これで頂点座標配列は作成完了しました。
次に頂点インデックス配列の作成入ります。

頂点インデックス配列を作る

個人的には、頂点座標配列より、こちらの方が数倍複雑と感じました。
重要なのは頂点のIndex番号を頭の中で把握しておくことだと思います。

f:id:esakun:20181204225208p:plain:w400
上から見た分割数を減らした球に、頂点番号を記載しました。

天面の頂点Index配列

f:id:esakun:20181205100204p:plain:w400
緑の部分の天面の頂点Index配列を作っていきます。

天面は全て三角形なので想像しやすく、以下のような配列になるようにします。

0, 1, 2,
0, 2, 3,
0, 3, 4,
~~~略~~~
0, 6, 1

コードはこんな感じです。

こんな感じで0始まりで三角形を作っていきます。注意点は1つだけ。最後の0, 6, 1の部分で、ループして1を使うところです。

側面の頂点Index配列

f:id:esakun:20181205100254p:plain:w400
次に緑の部分の側面です。
上の画像は側面の一部ですが、他側面も実装する内容はほぼ同じです。

f:id:esakun:20181205100825p:plain:w400
上の画像のように①〜⑤の順に頂点Index配列を作っていきます。

f:id:esakun:20181205100945p:plain:w320
①から見ていきます。

1, 7, 8,
1, 8, 2

という順に頂点を結んで、三角形を2つ作ります。
四角形を一つ作り終えたら、開始のIndexをインクリメントして同じ処理を走らせます。簡単です。

この部分のコードはこんな感じになります。

①の四角形の作りを上記のコードから確認していきます。

1, 7, 8,
1, 8, 2

繰り返しになりますが、上のインデックス配列で三角形2つを作成して①の四角形を作成しています。

Index番号 1, 7, 8の三角形
  • Index番号 1・・・初回はindices[1]に格納されているので、それを代入。2度目の四角形からはインクリメントされていく(indices[1]はstartIndexに格納)
  • Index番号 7・・・startIndex + divideXで算出できる
  • Index番号 8・・・startIndex + divideXに1を加算するだけ
Index番号 1, 8, 2の三角形
  • Index番号 1・・・先と同様なので省略
  • Index番号 8・・・先と同様なので省略
  • Index番号 2・・・startIndexに1を加算するだけ

ただ、上記のコードだと次の処理が抜けています。

f:id:esakun:20181205103732p:plain:w240

  • 1周した時(⑥のIndex)、ループさせるために1, 7を取得する
  • 1周した後、次の側面のIndexを取得する

それらを諸々考慮したコードは次になります。


底面の頂点Index配列

f:id:esakun:20181205105213p:plain:w400

最後に底面です。 以下のような配列を作ります。

13, 14, 19,
14, 15, 19,
15, 16, 19,
~~~~略~~~~~
17, 18, 19


天面とほぼ同じ(for文が逆になりますが)なので、説明は割愛しますが、コードはこうなります。


最後にこれらの配列をmeshにセットして描画します。この辺りは以前の記事で説明しているのでご参考ください。


テストコードも含めた全体コードはコチラ。
このコンポーネントをGameObjectにくっつければ球が生成されます。

f:id:esakun:20181204194923p:plain:h150f:id:esakun:20181205110110p:plain:h150
このようにメッシュの分割数も変更することもできます。

まとめ

三角形から飛躍して球のメッシュを動的に描画してみました。
地道に考えればできます。分割数を減らして考えるとより理解しやすい気がします。

この延長線でカプセル、トーラス辺りをやろうと思います。

ちなみに、UV座標を頂点に埋め込んでいないため、この球にテクスチャは貼れません。いつかやります。


以上

その他の動的にメッシュを生成するシリーズ

Unity動的にメッシュを生成するシリーズ - 渋谷ほととぎす通信