关于画球一开始真是一点思路都没有,楼主也查了好多资料,比较有代表性的是两篇帖子。
一篇是Jasper Flick的帖子,一个很厉害的人:
http://www.binpress.com/tutorial/creating-an-octahedron-sphere/162#comments
这一篇的思路是根据柏拉图体,正八面体分割成的球。
第二篇是OpenGL或者XNA回答的思路,是根据柏拉图体正二十面体画的
http://gamedev.stackexchange.com/questions/31308/algorithm-for-creating-spheres#
如果你能直接看懂上面两篇中的任何一篇,那么楼主下面写的对于你来说都是废话,你可以直接不用看了。
简单的说下,首先是画出一个正八面体,这个我们上一篇文章:Unity Mesh(二) Mesh画立方体和八面体,已经写了怎么画正八面体,然后我们的思路是取每条边的重点,细分三角形,比如那正八面体的一个面来说,我们拆分一次的情况如图所示:
两次的情况如图:
以此类推,根据前面两篇我们可以了解到,Mesh画图形必须知道三角形的顶点和三角形的点顺序,这样的话我们需要知道的参数有三个,三角形的顶点数,三角形的个数,三角形的顶点顺序。
下面我们根据这三个数据的要求,一次进行计算说明。
private static int CreateLowerStrip(int steps, int vTop, int vBottom, int t, int[] triangles)
{
for (int i = 1; i < steps; i++)
{
triangles[t++] = vBottom;
triangles[t++] = vTop - 1;
triangles[t++] = vTop;
triangles[t++] = vBottom++;
triangles[t++] = vTop++;
triangles[t++] = vBottom;
}
triangles[t++] = vBottom;
triangles[t++] = vTop - 1;
triangles[t++] = vTop;
return t;
}
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class DrawOctahedronSphere1 : MonoBehaviour
{
public Material mat;
private static Vector3[] directions = {
Vector3.left,
Vector3.back,
Vector3.right,
Vector3.forward
};
void Start()
{
DrawSphere(1, 1);
}
public void DrawSphere(int subdivisions = 0, float radius = 1)
{
gameObject.GetComponent().material = mat;
Mesh mesh = GetComponent().mesh;
mesh.Clear();
int resolution = 1 << subdivisions;
Vector3[] vertices = new Vector3[(resolution + 1) * (resolution + 1) * 4 - 3*(resolution * 2 + 1)];
int[] triangles = new int[(1 << (subdivisions * 2 + 3)) * 3];
CreateOctahedron(vertices, triangles, resolution);
Debug.LogError(triangles.Length + " " + vertices.Length);
foreach (var item in triangles)
{
Debug.Log(item);
}
foreach (var item in vertices)
{
Debug.Log(item);
}
mesh.vertices = vertices;
mesh.triangles = triangles;
}
private static void CreateOctahedron(Vector3[] vertices, int[] triangles, int resolution)
{
int v = 0, vBottom = 0, t = 0;
vertices[v++] = Vector3.down;
for (int i = 1; i <= resolution; i++)
{
float progress = (float)i / resolution;
Vector3 from, to;
vertices[v++] = to = Vector3.Lerp(Vector3.down, Vector3.forward, progress);
for (int d = 0; d < 4; d++)
{
from = to;
to = Vector3.Lerp(Vector3.down, directions[d], progress);
t = CreateLowerStrip(i, v, vBottom, t, triangles);
v = CreateVertexLine(from, to, i, v, vertices);
vBottom += i > 1 ? (i - 1) : 0;
}
vBottom = v - 1 - i * 4;
}
for (int i = resolution - 1; i >= 1; i--)
{
float progress = (float)i / resolution;
Vector3 from, to;
vertices[v++] = to = Vector3.Lerp(Vector3.up, Vector3.forward, progress);
for (int d = 0; d < 4; d++)
{
from = to;
to = Vector3.Lerp(Vector3.up, directions[d], progress);
t = CreateUpperStrip(i, v, vBottom, t, triangles);
v = CreateVertexLine(from, to, i, v, vertices);
vBottom += i + 1;
}
vBottom = v - 1 - i * 4;
}
vertices[vertices.Length - 1] = Vector3.up;
for (int i = 0; i < 4; i++)
{
triangles[t++] = vBottom;
triangles[t++] = v;
triangles[t++] = ++vBottom;
}
}
private static int CreateVertexLine(Vector3 from, Vector3 to, int steps, int v, Vector3[] vertices)
{
for (int i = 1; i <= steps; i++)
{
vertices[v++] = Vector3.Lerp(from, to, (float)i / steps);
}
return v;
}
private static int CreateLowerStrip(int steps, int vTop, int vBottom, int t, int[] triangles)
{
for (int i = 1; i < steps; i++)
{
triangles[t++] = vBottom;
triangles[t++] = vTop - 1;
triangles[t++] = vTop;
triangles[t++] = vBottom++;
triangles[t++] = vTop++;
triangles[t++] = vBottom;
}
triangles[t++] = vBottom;
triangles[t++] = vTop - 1;
triangles[t++] = vTop;
return t;
}
private static int CreateUpperStrip(int steps, int vTop, int vBottom, int t, int[] triangles)
{
triangles[t++] = vBottom;
triangles[t++] = vTop - 1;
triangles[t++] = ++vBottom;
for (int i = 1; i <= steps; i++)
{
triangles[t++] = vTop - 1;
triangles[t++] = vTop;
triangles[t++] = vBottom;
triangles[t++] = vBottom;
triangles[t++] = vTop++;
triangles[t++] = ++vBottom;
}
return t;
}
}
private static void Normalize(Vector3[] vertices, Vector3[] normals)
{
for (int i = 0; i < vertices.Length; i++)
{
normals[i] = vertices[i] = vertices[i].normalized;
}
}
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class DrawOctahedronSphere : MonoBehaviour
{
public Material mat;
public int subdivisions;
public int radius;
private static Vector3[] directions = {
Vector3.left,
Vector3.back,
Vector3.right,
Vector3.forward
};
void Start()
{
DrawSphere(subdivisions, radius);
}
public void DrawSphere(int subdivisions = 0, float radius = 1)
{
if (subdivisions > 4)
{
subdivisions = 4;
}
gameObject.GetComponent().material = mat;
Mesh mesh = GetComponent().mesh;
mesh.Clear();
int resolution = 1 << subdivisions;
Vector3[] vertices = new Vector3[(resolution + 1) * (resolution + 1) * 4 - 3 * (resolution * 2 + 1)];
int[] triangles = new int[(1 << (subdivisions * 2 + 3)) * 3];
CreateOctahedron(vertices, triangles, resolution);
if (radius != 1f)
{
for (int i = 0; i < vertices.Length; i++)
{
vertices[i] *= radius;
}
}
Vector3[] normals = new Vector3[vertices.Length];
Normalize(vertices, normals);
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.normals = normals;
}
private static void CreateOctahedron(Vector3[] vertices, int[] triangles, int resolution)
{
int v = 0, vBottom = 0, t = 0;
vertices[v++] = Vector3.down;
for (int i = 1; i <= resolution; i++)
{
float progress = (float)i / resolution;
Vector3 from, to;
vertices[v++] = to = Vector3.Lerp(Vector3.down, Vector3.forward, progress);
for (int d = 0; d < 4; d++)
{
from = to;
to = Vector3.Lerp(Vector3.down, directions[d], progress);
t = CreateLowerStrip(i, v, vBottom, t, triangles);
v = CreateVertexLine(from, to, i, v, vertices);
vBottom += i > 1 ? (i - 1) : 0;
}
vBottom = v - 1 - i * 4;
}
for (int i = resolution - 1; i >= 1; i--)
{
float progress = (float)i / resolution;
Vector3 from, to;
vertices[v++] = to = Vector3.Lerp(Vector3.up, Vector3.forward, progress);
for (int d = 0; d < 4; d++)
{
from = to;
to = Vector3.Lerp(Vector3.up, directions[d], progress);
t = CreateUpperStrip(i, v, vBottom, t, triangles);
v = CreateVertexLine(from, to, i, v, vertices);
vBottom += i + 1;
}
vBottom = v - 1 - i * 4;
}
vertices[vertices.Length - 1] = Vector3.up;
for (int i = 0; i < 4; i++)
{
triangles[t++] = vBottom;
triangles[t++] = v;
triangles[t++] = ++vBottom;
}
}
private static int CreateVertexLine(Vector3 from, Vector3 to, int steps, int v, Vector3[] vertices)
{
for (int i = 1; i <= steps; i++)
{
vertices[v++] = Vector3.Lerp(from, to, (float)i / steps);
}
return v;
}
private static int CreateLowerStrip(int steps, int vTop, int vBottom, int t, int[] triangles)
{
for (int i = 1; i < steps; i++)
{
triangles[t++] = vBottom;
triangles[t++] = vTop - 1;
triangles[t++] = vTop;
triangles[t++] = vBottom++;
triangles[t++] = vTop++;
triangles[t++] = vBottom;
}
triangles[t++] = vBottom;
triangles[t++] = vTop - 1;
triangles[t++] = vTop;
return t;
}
private static int CreateUpperStrip(int steps, int vTop, int vBottom, int t, int[] triangles)
{
triangles[t++] = vBottom;
triangles[t++] = vTop - 1;
triangles[t++] = ++vBottom;
for (int i = 1; i <= steps; i++)
{
triangles[t++] = vTop - 1;
triangles[t++] = vTop;
triangles[t++] = vBottom;
triangles[t++] = vBottom;
triangles[t++] = vTop++;
triangles[t++] = ++vBottom;
}
return t;
}
private static void Normalize(Vector3[] vertices, Vector3[] normals)
{
for (int i = 0; i < vertices.Length; i++)
{
normals[i] = vertices[i] = vertices[i].normalized;
}
}
}