文章目录
1.概述
球体比较复杂,涉及到极点位置会出现聚集的问题,本文采用常规方法绘制球体,然后借鉴他人的方法,通过正八面体拆分的方法生成球体mesh。
2.常规方法
常规方法就是通过极坐标系,分别计算球体表面的坐标,然后依次生成三角形。问题在于当划分较细时,球体两端的网格会比较细,比较聚集。
2.1 基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))]
public class CreateMeshBase : MonoBehaviour
{
MeshFilter meshFilter;
protected Mesh mesh;
protected virtual Vector3[] Vertices { get; }
protected virtual int[] Triangles { get; }
protected virtual Vector3[] Normals { get; }
protected virtual Vector4[] Tangents { get; }
protected virtual Vector2[] Uvs { get; }
protected virtual string MeshName { get; }
protected virtual void Start()
{
GetMeshFilter();
}
protected virtual void Reset()
{
GetMeshFilter();
}
protected virtual void OnValidate()
{
GetMeshFilter();
}
void GetMeshFilter()
{
if (meshFilter == null)
{
meshFilter = GetComponent<MeshFilter>();
mesh = new Mesh();
}
mesh.triangles = null;
mesh.uv = null;
mesh.vertices = null;
mesh.tangents = null;
mesh.name = MeshName;
mesh.vertices = Vertices;
mesh.triangles = Triangles;
mesh.uv = Uvs;
mesh.normals = Normals;
mesh.tangents = Tangents;
meshFilter.mesh = mesh;
}
private void OnDrawGizmos()
{
if (Vertices == null) return;
Gizmos.color = Color.red;
Gizmos.DrawSphere(Vector3.zero, 0.5f);
Gizmos.color = Color.blue;
for (int i = 0; i < Vertices.Length; i++)
{
Gizmos.DrawSphere(Vertices[i], 0.3f);
}
}
}
2.2 球体mesh
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreateSphere : CreateMeshBase
{
public float radius = 10;
public int horizontalSize = 10;
public int verticalSize = 10;
protected override string MeshName
{
get
{
return "Sphere mesh";
}
}
protected override Vector3[] Vertices
{
get
{
Vector3[] vertices = new Vector3[(horizontalSize + 1) * (verticalSize + 1)];
float horizontalDelta = 2 * Mathf.PI / horizontalSize;
float verticalDelta = 2 * Mathf.PI / verticalSize;
for (int i = 0; i < verticalSize + 1; i++)
{
float rad = i * verticalDelta;
float subRadius = radius * Mathf.Sin(rad);
float y = radius * Mathf.Cos(rad);
for (int j = 0; j < horizontalSize; j++)
{
int index = i * (horizontalSize + 1) + j;
float x = subRadius * Mathf.Cos(j * horizontalDelta);
float z = subRadius * Mathf.Sin(j * horizontalDelta);
vertices[index] = new Vector3(x, y, z);
}
}
return vertices;
}
}
protected override int[] Triangles
{
get
{
int[] triangles = new int[horizontalSize * verticalSize * 2 * 3];
for (int i = 0; i < verticalSize; i++)
{
for (int j = 0; j < horizontalSize; j++)
{
int index = (i * horizontalSize + j) * 6;
triangles[index] = i * (horizontalSize + 1) + j + 1;
triangles[index + 2] = i * (horizontalSize + 1) + j;
triangles[index + 1] = (i + 1) * (horizontalSize + 1) + j;
triangles[index + 3] = i * (horizontalSize + 1) + j + 1;
triangles[index + 5] = (i + 1) * (horizontalSize + 1) + j;
triangles[index + 4] = (i + 1) * (horizontalSize + 1) + j + 1;
}
}
return triangles;
}
}
}
3.正八面细分法
正八面体球则是通过正八面体,对边长进行划分,生成一系列的点,将这些点归一化即可得到单位球体,原文再此。
3.1 代码
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);
}
private void OnValidate()
{
DrawSphere(subdivisions, radius);
}
public void DrawSphere(int subdivisions = 0, float radius = 1)
{
if (subdivisions > 4)
{
subdivisions = 4;
}
//gameObject.GetComponent<MeshRenderer>().material = mat;
Mesh mesh = GetComponent<MeshFilter>().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;
}
}
}
81192_csdn
发布了141 篇原创文章 · 获赞 0 · 访问量 1798
私信
关注