Last active
August 29, 2015 14:20
-
-
Save but80/62994de8af9ce68f633e to your computer and use it in GitHub Desktop.
Unityで 球面上の座標を20個の区間に等分(正二十面体に投影)し、区間IDを得るサンプル
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
/** | |
* 球面上の座標を20個の区間に等分(正二十面体に投影)し、区間IDを得るサンプル | |
* (適当にCreateEmptyしたオブジェクトにアタッチして実行) | |
* https://twitter.com/bucchigiri/status/595572141325594625 | |
* | |
* [説明] | |
* 正二十面体を XY平面, YZ平面, ZX平面 を境として8つに分断すると、各象限は | |
* すべて鏡像の関係にあり、たとえば +X+Y+Z 象限では以下の計4つの三角形が現れる。 | |
* ・ +X+Y平面, +Y+Z平面, +Z+X 平面内に1つずつ頂点を持つ正三角形 (T) | |
* ・ Tの1辺を斜辺とし、その斜辺の一端から +X軸, +Y軸, +Z軸 に降ろした | |
* 垂線を底辺とする直角三角形 (U, V, W) | |
* U, V, W は隣り合う象限から分かたれた正三角形の半面である。 | |
* | |
* 原点 および Tの1辺 を含む平面で空間を分断すると、 | |
* ある点がそのどちら側に属すかを調べることにより、 | |
* どの面に投影されるかを判定することができる。 | |
*/ | |
public class IcosaherdaMapper : MonoBehaviour { | |
private static readonly Vector3 nX; // 原点, pXY, pZX を含む平面の法線ベクトル | |
private static readonly Vector3 nY; // 原点, pYZ, pXY を含む平面の法線ベクトル | |
private static readonly Vector3 nZ; // 原点, pZX, pYZ を含む平面の法線ベクトル | |
// 初期化 | |
static IcosaherdaMapper() { | |
float phi = (1f + Mathf.Sqrt(5f)) / 2f; | |
Vector3 pXY = new Vector3(phi, 1f, 0f); // T の +X+Y 平面上の頂点 | |
Vector3 pYZ = new Vector3(0f, phi, 1f); // T の +Y+Z 平面上の頂点 | |
Vector3 pZX = new Vector3(1f, 0f, phi); // T の +Z+X 平面上の頂点 | |
nX = Vector3.Cross(pXY, pZX); | |
nY = Vector3.Cross(pYZ, pXY); | |
nZ = Vector3.Cross(pZX, pYZ); | |
} | |
// 面を特定するID | |
enum Plane : int { | |
Skew_XnYnZn = 0x00, | |
Skew_XpYnZn = 0x01, | |
Skew_XnYpZn = 0x02, | |
Skew_XpYpZn = 0x03, | |
Skew_XnYnZp = 0x04, | |
Skew_XpYnZp = 0x05, | |
Skew_XnYpZp = 0x06, | |
Skew_XpYpZp = 0x07, | |
ContactAxis_Xn_Zn = 0x08, | |
ContactAxis_Xn_Zp = 0x09, | |
ContactAxis_Xp_Zn = 0x0A, | |
ContactAxis_Xp_Zp = 0x0B, | |
ContactAxis_Yn_Xn = 0x0C, | |
ContactAxis_Yn_Xp = 0x0D, | |
ContactAxis_Yp_Xn = 0x0E, | |
ContactAxis_Yp_Xp = 0x0F, | |
ContactAxis_Zn_Yn = 0x10, | |
ContactAxis_Zn_Yp = 0x11, | |
ContactAxis_Zp_Yn = 0x12, | |
ContactAxis_Zp_Yp = 0x13 | |
} | |
// 任意の座標から面IDを求める | |
public static int Map(Vector3 p) { | |
int xs = p.x < 0 ? 0 : 1; | |
int ys = p.y < 0 ? 0 : 1; | |
int zs = p.z < 0 ? 0 : 1; | |
p.Set(p.x*(xs-.5f), p.y*(ys-.5f), p.z*(zs-.5f)); | |
p.Normalize(); | |
if (0 < Vector3.Dot(p, nX)) return (int)Plane.ContactAxis_Xn_Zn | zs | xs<<1; | |
if (0 < Vector3.Dot(p, nY)) return (int)Plane.ContactAxis_Yn_Xn | xs | ys<<1; | |
if (0 < Vector3.Dot(p, nZ)) return (int)Plane.ContactAxis_Zn_Yn | ys | zs<<1; | |
return (int)Plane.Skew_XnYnZn | xs | ys<<1 | zs<<2; | |
} | |
/////////////////////////////////// demo /////////////////////////////////// | |
int plotMaxCount = 20000; | |
int plotSpeed = 20; | |
static readonly int[] colors = new int[20] { | |
0x000, 0xF00, 0x0F0, 0xFF0, 0x00F, 0xF0F, 0x0FF, 0xFFF, | |
0x080, 0x08F, 0xF80, 0xF8F, | |
0x008, 0xF08, 0x0F8, 0xFF8, | |
0x800, 0x8F0, 0x80F, 0x8FF | |
}; | |
void Update() { | |
if (plotMaxCount <= 0) return; | |
for (int i=0; i<plotSpeed; i++) { | |
Vector3 p = Random.onUnitSphere; | |
int j = Map(p); | |
GameObject obj = new GameObject("plot-" + i.ToString()); | |
obj.transform.LookAt(-p); | |
obj.transform.position = p; | |
obj.transform.localScale = Vector3.one * .025f; | |
TextMesh text = obj.AddComponent<TextMesh>(); | |
text.text = "■" + new string(new char[]{ (char)(j + 'A') }); | |
text.alignment = TextAlignment.Left; | |
text.anchor = TextAnchor.MiddleCenter; | |
text.richText = false; | |
text.fontSize = 9; | |
int c = colors[j]; | |
text.color = new Color((c>>8&15)/15f, (c>>4&15)/15f, (c&15)/15f); | |
} | |
plotMaxCount -= plotSpeed; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment