Integrated Sebastian Lague's Planet Generator Created Tour function in SectorRenderer which makes the camera follow each terrestrial planet in turn
157 lines
No EOL
4.6 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
} |