Skip to content

Instantly share code, notes, and snippets.

@but80
Last active August 29, 2015 14:20
Show Gist options
  • Save but80/62994de8af9ce68f633e to your computer and use it in GitHub Desktop.
Save but80/62994de8af9ce68f633e to your computer and use it in GitHub Desktop.
Unityで 球面上の座標を20個の区間に等分(正二十面体に投影)し、区間IDを得るサンプル
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