(九)球體


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; } } } 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM