1. _akoto_

    Posted

    _akoto_
Changes in title
+ゲーム数学の極座標系
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,105 @@
+この記事は、[数学ゲーム Advent Calendar 2018](https://adventar.org/calendars/3207) の6日目の記事です。
+
+
+今年のCEDECの[こちらの公演](https://2018.cedec.cesa.or.jp/session/detail/s5ab884cadf368)がきっかけで、最近、DirectXを勉強し直している、ゲーム会社に勤めるエンジニアです。
+DirectX 12を粛々と進めていたところ、ゲーム数学 Advent Calendarが空いているとの事を知り、やっていた事の振り返りも兼ねて、記事を投稿させていただきます。
+
+### この記事の対象者
+- サイエンスプログラムを覚えたい方
+
+普段から、サイエンスプログラムを書いているCGエンジニアの方には、見る必要はありません。
+
+### 本題
+今回、お話する内容は、極座標系についてです。
+式はこれです。
+
+```
+x = r sinΘ * cosφ
+y = r cosΘ
+z = r sinΘ * sinφ
+```
+
+r は、中心からの距離。Θ と φ は、それぞれ違う角度になります。
+y と z が逆になっている解釈もありますが、私の場合はこれで教えられました。
+
+
+では、この極座標系が、何に使えるのか?いう事例を紹介させていただきます。
+
+### 正二十面体の作成
+sphereを計算によって作成する事ができます。
+以下の画像は、正二十面体をプログラムによって作成した実行結果です。
+
+![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/153021/abfbcee4-5b62-74f8-61ee-069fbc8eb94a.png)
+
+正二十面体である為、正確には、sphereではありませんが、ちょっとしたデバッグ機能でCollider を表示したい時に、sphereのMeshをロードするのは勿体無い気がします。
+この疑似sphereは、プログラムで生成している為、頂点数や面数などを減らしたり、Lineだけでの描画にする事も可能です。
+
+実際に式を用いているプログラムは、以下になります。
+
+```
+//----------------------------------------------------
+// 極座標で正N面体を作る
+//----------------------------------------------------
+#define N = 20
+
+Vertex triangleVertices[N * N * 3];
+int herf_n = N / 2;
+for (int i = 0; i < N; i++)
+{
+ for (int j = 0; j < herf_n ; j++)
+ {
+ float radian = 2.0f * XM_PI / N;
+ int index = i * 6 * herf_n + j * 6;
+ triangleVertices[index].position.x = SPHERE_RADIUS * sinf(radian * j) * cosf(radian * i);
+ triangleVertices[index].position.y = SPHERE_RADIUS * cosf(radian * j);
+ triangleVertices[index].position.z = SPHERE_RADIUS * sinf(radian * j) * sinf(radian * i);
+ triangleVertices[index].color = XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f);
+
+ triangleVertices[index+1].position.x = SPHERE_RADIUS * sinf(radian * j) * cosf(radian * (i+1));
+ triangleVertices[index+1].position.y = SPHERE_RADIUS * cosf(radian * j);
+ triangleVertices[index+1].position.z = SPHERE_RADIUS * sinf(radian * j) * sinf(radian * (i+1));
+ triangleVertices[index+1].color = XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f);
+
+ triangleVertices[index+2].position.x = SPHERE_RADIUS * sinf(radian * (j+1)) * cosf(radian * i);
+ triangleVertices[index+2].position.y = SPHERE_RADIUS * cosf(radian * (j+1));
+ triangleVertices[index+2].position.z = SPHERE_RADIUS * sinf(radian * (j+1)) * sinf(radian * i);
+ triangleVertices[index+2].color = XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f);
+
+ triangleVertices[index+3].position.x = SPHERE_RADIUS * sinf(radian * (j+1)) * cosf(radian * i);
+ triangleVertices[index+3].position.y = SPHERE_RADIUS * cosf(radian * (j+1));
+ triangleVertices[index+3].position.z = SPHERE_RADIUS * sinf(radian * (j+1)) * sinf(radian * i);
+ triangleVertices[index+3].color = XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f);
+
+ triangleVertices[index+4].position.x = SPHERE_RADIUS * sinf(radian * j) * cosf(radian * (i+1));
+ triangleVertices[index+4].position.y = SPHERE_RADIUS * cosf(radian * j);
+ triangleVertices[index+4].position.z = SPHERE_RADIUS * sinf(radian * j) * sinf(radian * (i+1));
+ triangleVertices[index+4].color = XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f);
+
+ triangleVertices[index+5].position.x = SPHERE_RADIUS * sinf(radian * (j+1)) * cosf(radian * (i+1));
+ triangleVertices[index+5].position.y = SPHERE_RADIUS * cosf(radian * (j+1));
+ triangleVertices[index+5].position.z = SPHERE_RADIUS * sinf(radian * (j+1)) * sinf(radian * (i+1));
+ triangleVertices[index+5].color = XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f);
+ }
+}
+```
+
+テストプログラムである為、マクロを使用しています。
+スイカの皮のような10個のポリゴンを繋げたものを作成し、それを20個作成する事で実現しています。
+
+もう一つ、事例を紹介します。
+
+
+### Viewerのようなカメラの動きをする
+
+この式の強みは、ある中心からの距離(r) と 二つの角度(Θとφ)を渡す事で、360度どの位置でも座標を算出する事ができる点です。
+想像しやすいのが、360度どこからでもキャラを見ることができる Viewer 機能です。
+フリック操作の縦の指の移動量をΘに、横の移動量をφに同期させてやる事で、フリック操作でどの角度からでもキャラを見る事ができるUIを表現できます。
+拡大や縮小は、r を操作する事で表現可能です。
+注視点の移動は、計算された座標に、ベクトルを足す事で表現できます。
+
+三次元の表現ができる為、カメラの移動だけでなく、キャラクターの移動にも使用する事ができますので、是非、試してゲーム数学を楽しんでください。
+
+
+私からは以上になります。
+
+