Build Sphere From Scratch

The planet we want to build cannot use the 3D sphere provide by Unity. As the result, we need to build the sphere from scratch to control the number of vertices. To build the sphere we used 6 different mesh to build the cube. And normalize it to build the sphere. Basically, in this step, we need to make 2 scripts.

The terrainfaces.cs script uses to construct the mesh and build the triangle inside the mesh. This script also builds the triangle inside the mesh. The number of vertices will be controlled in this script. The planet script has two main functions, to add the terrainfaces to the planet gameobject and to add meshfilter and connected mesh with shader.

TerrainFaces

public class TerrainFaces{

Mesh mesh;
int resolution;
Vector3 localUp;
Vector3 axisA;
Vector3 axisB;

public TerrainFaces(Mesh mesh, int resolution, Vector3 localUp)
{
this.mesh = mesh;
this.resolution = resolution;
this.localUp = localUp;

axisA = new Vector3(localUp.y, localUp.z, localUp.x);
axisB = Vector3.Cross(localUp, axisA);
}

public void ConstructMesh()
{
Vector3[] vertices = new Vector3[resolution * resolution];
int[] triangles = new int[(resolution - 1) * (resolution - 1) * 6];
int triIndex = 0;

for (int y= 0; y<resolution; y++)
{
for (int x = 0; x < resolution; x++)
{
int i = x + y * resolution;
Vector2 percent = new Vector2(x, y) / (resolution - 1);
Vector3 pointOnUnitCube = localUp + (percent.x - .5f) * 2 * axisA + (percent.y - .5f) * 2 * axisB;
Vector3 pointOnUnitSphere = pointOnUnitCube.normalized;
//vertices[i] = pointOnUnitCube;
vertices[i] = pointOnUnitSphere;

if (x != resolution - 1 && y != resolution - 1)
{
triangles[triIndex] = i;
triangles[triIndex + 1] = i + resolution + 1;
triangles[triIndex + 2] = i + resolution;

triangles[triIndex + 3] = i;
triangles[triIndex + 4] = i + 1;
triangles[triIndex + 5] = i + resolution + 1;
triIndex += 6;
}
}
}
mesh.Clear();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
}

Planet

public class Planet : MonoBehaviour {

[Range(2, 256)]
public int resolution = 10;

[SerializeField, HideInInspector]
MeshFilter[] meshFilters;
TerrainFaces[] terrainFaces;

private void OnValidate()
{
Initialize();
GenerateMesh();
}

void Initialize()
{
if (meshFilters == null|| meshFilters.Length == 0)
{
meshFilters = new MeshFilter[6];
}

terrainFaces = new TerrainFaces[6];

Vector3[] directions = { Vector3.up, Vector3.down, Vector3.left, Vector3.right, Vector3.forward, Vector3.back};

for (int i = 0; i < 6; i++)
{
if (meshFilters[i] == null)
{
GameObject meshObj = new GameObject("mesh");
meshObj.transform.parent = transform;

meshObj.AddComponent<MeshRenderer>().sharedMaterial = new Material(Shader.Find("Standard"));
meshFilters[i] = meshObj.AddComponent<MeshFilter>();
meshFilters[i].sharedMesh = new Mesh();
}

terrainFaces[i] = new TerrainFaces(meshFilters[i].sharedMesh, resolution, directions[i]);
}
}

void GenerateMesh()
{
foreach (TerrainFaces face in terrainFaces)
{
face.ConstructMesh();
}
}
}

 

(Visited 7 times, 1 visits today)

Related Post

Leave a Reply