- Home /
How do you make a sphere from 6 planes?
Hi all,
I have been attempting to create a sphere from 6 planes, so that I may later edit these planes to give the sphere a procedural generated surface (so as to create unique planets).
To take 6 planes and make them into a sphere, I have been using this code:
public function MakeSphereFromPlanes()
{
var positionArr : Vector3[] = [
new Vector3(0,this.radius,0),
new Vector3(0,-this.radius,0),
new Vector3(0,0,this.radius),
new Vector3(0,0,-this.radius),
new Vector3(this.radius,0,0),
new Vector3(-this.radius,0,0)
];
var rotationArr : Vector3[] = [
Vector3.zero,
Vector3.zero,
new Vector3(90,0,0),
new Vector3(90,0,0),
new Vector3(0,0,90),
new Vector3(0,0,90)
];
for(var p : int = 0;p<6;p++)
{
//make 6 planes for the sphere in this loop
var newPlane : GameObject = GameObject.CreatePrimitive(PrimitiveType.Plane);
newPlane.transform.localScale = Vector3(this.radius,this.radius,this.radius);
newPlane.transform.SetParent(this.gameObject.transform);
newPlane.transform.position = positionArr[p];
newPlane.transform.eulerAngles = rotationArr[p];
var vertices : Vector3[] = newPlane.GetComponent(MeshFilter).mesh.vertices;
for (var i = 0; i < vertices.Length; i++)
{
vertices[i] = vertices[i].normalized * this.radius;
}
newPlane.GetComponent(MeshFilter).mesh.vertices = vertices;
newPlane.GetComponent(MeshFilter).mesh.RecalculateNormals();
newPlane.GetComponent(MeshFilter).mesh.RecalculateBounds();
}
}
The issue I am running into is that this code seems to produce this:
And I am not entirely sure why, or how to get it working. Does anyone have any thoughts on this, or know what I am doing wrong?
Answer by DiegoSLTS · Mar 22, 2015 at 01:29 PM
I've tested that and fixed it in C#, I hope this helps, it shouldn't be hard to translate it back to UnityScript.
First make sure your planes form a 1x1x1 cube around the origin, only then transform the vertices. You don't need the radius to create the cube, so some of the code can be simplified:
Vector3[] positionArr = {
new Vector3(0,0.5f,0),
new Vector3(0,-0.5f,0),
new Vector3(0,0,0.5f),
new Vector3(0,0,-0.5f),
new Vector3(0.5f,0,0),
new Vector3(-0.5f,0,0)
};
and:
newPlane.transform.localScale = new Vector3(0.1f,0.1f,0.1f);
Also, to create a cube with planes you have to consider the "face" of the planes, you're rotating parallel planes in the same direction, but they should face the opposite direction from each other (note the values and the signs):
Vector3[] rotationArr = {
Vector3.zero,
new Vector3(180,0,0),
new Vector3(90,0,0),
new Vector3(-90,0,0),
new Vector3(0,0,-90),
new Vector3(0,0,90)
};
And the last part, when you want to transform a vertex note that you have it's value relative to the plane itself (it's a "local" point), but you need the position of that point in the world. Once you know where is that point in the world you can normalize and stretch the value to match the radius, and then you have to convert it back to local coordinates, since the vertex is still a point of the Plane. So, for each vertex:
vertices[i] = newPlane.transform.InverseTransformPoint(newPlane.transform.TransformPoint(vertices[i]).normalized * this.radius);
The full script I created looks like this:
using UnityEngine;
using System.Collections;
public class PlanesToSphere : MonoBehaviour {
public float radius;
void Start() {
Vector3[] positionArr = {
new Vector3(0,0.5f,0),
new Vector3(0,-0.5f,0),
new Vector3(0,0,0.5f),
new Vector3(0,0,-0.5f),
new Vector3(0.5f,0,0),
new Vector3(-0.5f,0,0)
};
Vector3[] rotationArr = {
Vector3.zero,
new Vector3(180,0,0),
new Vector3(90,0,0),
new Vector3(-90,0,0),
new Vector3(0,0,-90),
new Vector3(0,0,90)
};
for(int p = 0; p<6; p++)
{
//make 6 planes for the sphere in this loop
GameObject newPlane = GameObject.CreatePrimitive(PrimitiveType.Plane);
newPlane.transform.SetParent(transform);
newPlane.transform.localScale = new Vector3(0.1f,0.1f,0.1f);
newPlane.transform.position = positionArr[p];
newPlane.transform.eulerAngles = rotationArr[p];
Vector3[] vertices = newPlane.GetComponent<MeshFilter>().mesh.vertices;
for (var i = 0; i < vertices.Length; i++)
{
vertices[i] = newPlane.transform.InverseTransformPoint(newPlane.transform.TransformPoint(vertices[i]).normalized * this.radius);
}
newPlane.GetComponent<MeshFilter>().mesh.vertices = vertices;
newPlane.GetComponent<MeshFilter>().mesh.RecalculateNormals();
newPlane.GetComponent<MeshFilter>().mesh.RecalculateBounds();
}
}
}
Just add that script to an empty game object, set the radius in the inspector and press play.
One more advice, try to make complex things in a new scene with the minimium you need for it. It's clear from your script and your screenshot that you're trying to to this sphere thing inside a complex scene with more things going on. It's harder to work that way, and you might end up with references you don't really need.