Aetheria/Assets/Plugins/Celestial Body/Scripts/SphereMesh.cs
Reinier Vens 53a91351b7 Procedural Planets
Integrated Sebastian Lague's Planet Generator
Created Tour function in SectorRenderer which makes the camera follow each terrestrial planet in turn
2020-12-05 23:43:02 +00:00

157 lines
No EOL
4.6 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using static UnityEngine.Vector3;
public class SphereMesh {
public readonly Vector3[] Vertices;
public readonly int[] Triangles;
public readonly int Resolution;
// Internal:
FixedSizeList<Vector3> vertices;
FixedSizeList<int> triangles;
int numDivisions;
int numVertsPerFace;
// Indices of the vertex pairs that make up each of the initial 12 edges
static readonly int[] vertexPairs = { 0, 1, 0, 2, 0, 3, 0, 4, 1, 2, 2, 3, 3, 4, 4, 1, 5, 1, 5, 2, 5, 3, 5, 4 };
// Indices of the edge triplets that make up the initial 8 faces
static readonly int[] edgeTriplets = { 0, 1, 4, 1, 2, 5, 2, 3, 6, 3, 0, 7, 8, 9, 4, 9, 10, 5, 10, 11, 6, 11, 8, 7 };
// The six initial vertices
static readonly Vector3[] baseVertices = { up, left, back, right, forward, down };
public SphereMesh (int resolution) {
this.Resolution = resolution;
numDivisions = Mathf.Max (0, resolution);
numVertsPerFace = ((numDivisions + 3) * (numDivisions + 3) - (numDivisions + 3)) / 2;
int numVerts = numVertsPerFace * 8 - (numDivisions + 2) * 12 + 6;
int numTrisPerFace = (numDivisions + 1) * (numDivisions + 1);
vertices = new FixedSizeList<Vector3> (numVerts);
triangles = new FixedSizeList<int> (numTrisPerFace * 8 * 3);
vertices.AddRange (baseVertices);
// Create 12 edges, with n vertices added along them (n = numDivisions)
Edge[] edges = new Edge[12];
for (int i = 0; i < vertexPairs.Length; i += 2) {
Vector3 startVertex = vertices.items[vertexPairs[i]];
Vector3 endVertex = vertices.items[vertexPairs[i + 1]];
int[] edgeVertexIndices = new int[numDivisions + 2];
edgeVertexIndices[0] = vertexPairs[i];
// Add vertices along edge
for (int divisionIndex = 0; divisionIndex < numDivisions; divisionIndex++) {
float t = (divisionIndex + 1f) / (numDivisions + 1f);
edgeVertexIndices[divisionIndex + 1] = vertices.nextIndex;
vertices.Add (Slerp (startVertex, endVertex, t));
}
edgeVertexIndices[numDivisions + 1] = vertexPairs[i + 1];
int edgeIndex = i / 2;
edges[edgeIndex] = new Edge (edgeVertexIndices);
}
// Create faces
for (int i = 0; i < edgeTriplets.Length; i += 3) {
int faceIndex = i / 3;
bool reverse = faceIndex >= 4;
CreateFace (edges[edgeTriplets[i]], edges[edgeTriplets[i + 1]], edges[edgeTriplets[i + 2]], reverse);
}
Vertices = vertices.items;
Triangles = triangles.items;
}
void CreateFace (Edge sideA, Edge sideB, Edge bottom, bool reverse) {
int numPointsInEdge = sideA.vertexIndices.Length;
var vertexMap = new FixedSizeList<int> (numVertsPerFace);
vertexMap.Add (sideA.vertexIndices[0]); // top of triangle
for (int i = 1; i < numPointsInEdge - 1; i++) {
// Side A vertex
vertexMap.Add (sideA.vertexIndices[i]);
// Add vertices between sideA and sideB
Vector3 sideAVertex = vertices.items[sideA.vertexIndices[i]];
Vector3 sideBVertex = vertices.items[sideB.vertexIndices[i]];
int numInnerPoints = i - 1;
for (int j = 0; j < numInnerPoints; j++) {
float t = (j + 1f) / (numInnerPoints + 1f);
vertexMap.Add (vertices.nextIndex);
vertices.Add (Slerp (sideAVertex, sideBVertex, t));
}
// Side B vertex
vertexMap.Add (sideB.vertexIndices[i]);
}
// Add bottom edge vertices
for (int i = 0; i < numPointsInEdge; i++) {
vertexMap.Add (bottom.vertexIndices[i]);
}
// Triangulate
int numRows = numDivisions + 1;
for (int row = 0; row < numRows; row++) {
// vertices down left edge follow quadratic sequence: 0, 1, 3, 6, 10, 15...
// the nth term can be calculated with: (n^2 - n)/2
int topVertex = ((row + 1) * (row + 1) - row - 1) / 2;
int bottomVertex = ((row + 2) * (row + 2) - row - 2) / 2;
int numTrianglesInRow = 1 + 2 * row;
for (int column = 0; column < numTrianglesInRow; column++) {
int v0, v1, v2;
if (column % 2 == 0) {
v0 = topVertex;
v1 = bottomVertex + 1;
v2 = bottomVertex;
topVertex++;
bottomVertex++;
} else {
v0 = topVertex;
v1 = bottomVertex;
v2 = topVertex - 1;
}
triangles.Add (vertexMap.items[v0]);
triangles.Add (vertexMap.items[(reverse) ? v2 : v1]);
triangles.Add (vertexMap.items[(reverse) ? v1 : v2]);
}
}
}
// Convenience classes:
public class Edge {
public int[] vertexIndices;
public Edge (int[] vertexIndices) {
this.vertexIndices = vertexIndices;
}
}
public class FixedSizeList<T> {
public T[] items;
public int nextIndex;
public FixedSizeList (int size) {
items = new T[size];
}
public void Add (T item) {
items[nextIndex] = item;
nextIndex++;
}
public void AddRange (IEnumerable<T> items) {
foreach (var item in items) {
Add (item);
}
}
}
}