• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by TCGM · Jun 19, 2014 at 01:54 AM · randomcubegenerationmappingplanet

Mapping Cube to Sphere - Using 64 planes as a cube "side"

I'm trying to make a procedural planet engine.

I've gone over tutorials teaching me how to map a 6 sided cube to a sphere using 6 different plane meshes. This I can do perfectly fine. However, I'd like the planets in my engine to use just a tad higher resolution than a single mesh plane can provide. I want to use 64x64 vertices per plane, 64x64 planes per cube side, versus 64x64 vertices on a single plane as a cube side. Thus, spherifying them is a little more difficult.

I currently generate gameobjects with their transform.position in the dead center of the plane model I generate for them, and align them to a cube shape, as seen in this image.

alt text

I then apply a spherification script I wrote/adapted from net sources for each of these planes. It adds the transform position of the plane's gameobject to the vertice it's working on to apply relativity to the planet's center. The result is this:

alt text

This is not the result I want, obviously, but I cannot for the life of me figure out where I went wrong. Any help would be appreciated.

For reference, my scripts:


GenMesh (manager script):

 using UnityEngine;
 using System.Collections;
 using System;
 
 public class GenMesh : MonoBehaviour {
     int id;
     Mesh mesh;
     Spherify spheremaker;
     CreatePlane maker;
     GameObject[] meshList;
     GameObject sideParent;
     int i=0,k=0,side=0,index=0;
     public Vector2 cubeSize;
     public Vector2 tileSize;
     public int vertDensity;
     float xx,yy,zz;
     Vector3 dir;
     Material planeMat;
     Mesh finalMesh;
     ArrayList vertList,triList,uvList;
     
     //Generation Variables
     
     //Passes array; tracks the generation passes which have been completed.
     //Guide: Initial Square Mesh Generation, Spherifying Operation, Mesh Collider Pass, N/A, N/A
     bool[] passes={false,false,false,false,false};
     int pass=0;
     bool nextpass=false;
     bool canrepeat=true;
     float iterSpeed=0.001f;
     
     // Use this for initialization
     void Start () {
         finalMesh=new Mesh();
         vertList=new ArrayList();
         triList=new ArrayList();
         uvList=new ArrayList();
         mesh=gameObject.GetComponent<MeshFilter>().mesh;
         maker=GameObject.FindGameObjectWithTag("GameController").GetComponent<CreatePlane>();
         spheremaker=GameObject.FindGameObjectWithTag("GameController").GetComponent<Spherify>();
         sideParent=new GameObject();
         sideParent.name="Side0";
         planeMat=Resources.Load ("Materials/RockGround") as Material;
         
         StartCoroutine("repeater");
         meshList=new GameObject[(int)((cubeSize.x*cubeSize.y)*6)];
         //mesh.RecalculateBounds();
         //mesh.RecalculateNormals();
         
         /*while(side<=5) {
             makeMesh();
         }*/
     }
     
     // Update is called once per frame
     void Update () {
         
     }
     
     IEnumerator repeater() {
         yield return new WaitForSeconds(iterSpeed);
         switch(pass) {
         case 0:
             makeMesh();
             if(side>5)
                 nextpass=true;
             else
                 nextpass=false;
             break;
         case 1:
             if(index==meshList.GetLength(0)-1)
             {
                 //nextpass=true;
             }
             else
             {
                 nextpass=true;
                 //combineMesh();
             }
             break;
         case 2:
             if(index>=meshList.GetLength(0)-1)
                 canrepeat=false;
             else
             {
                 nextpass=false;
                 spherify();
             }
             /*if(index==meshList.GetLength(0)-1)
             {
                 nextpass=true;
                 canrepeat=false;
             }
             else
             {*/
                 //nextpass=true;
                 //canrepeat=false;
                 //spherify();
             //}
             break;
         }
         index++;
         if(nextpass==true) {
             index=0;
             i=0;
             k=0;
             pass++;
             Debug.Log ("Pass "+pass+" finished.");
         }
         if(canrepeat==true) {
             StartCoroutine("repeater");
         }
     }
     
     void OnGUI() {
         GUI.BeginGroup(new Rect(0,0,100,20));
         GUI.Box (new Rect(0,0,100,20),id.ToString());
         GUI.EndGroup();
     }
 
     void combineMesh() {
         if(index>=meshList.GetLength(0)-1) {
             finalMesh.vertices=(Vector3[])vertList.ToArray(typeof(Vector3));
             finalMesh.triangles=(int[])triList.ToArray(typeof(int));
             finalMesh.uv=(Vector2[])uvList.ToArray(typeof(Vector2));
             mesh=finalMesh;
             mesh.RecalculateBounds();
             mesh.RecalculateNormals();
             nextpass=true;
             return;
         }
         MeshFilter reference=meshList[index].GetComponent<MeshFilter>();
         vertList.AddRange(reference.mesh.vertices);
         triList.AddRange(reference.mesh.triangles);
         uvList.AddRange(reference.mesh.uv);
     }
     
     void spherify() {
         iterSpeed=0.001f;
         GameObject g=meshList[index];
         MeshFilter meshFilter=g.GetComponent<MeshFilter>();
         meshFilter.mesh=spheremaker.MapToPlanet(meshFilter.mesh,10000f,g.transform.position);
         meshFilter.mesh.RecalculateBounds();
         meshFilter.mesh.RecalculateNormals();
         /*mesh=spheremaker.MapToPlanet(mesh,10000f,transform.position);
         mesh.RecalculateBounds();
         mesh.RecalculateNormals();*/
     }
     
     void applyMeshColliders() {
         iterSpeed=1f;
         GameObject g=meshList[index];
         g.AddComponent(typeof(MeshCollider));
         //index++;
     }
     
     void makeMesh() {
         
         iterSpeed=0.001f;
         
         if(i>cubeSize.x-1 && k==cubeSize.y-1)
         {
             side++;
             k=0;
             i=0;
             
             if(side==6)
             {
                 return;
             }
             else {
                 sideParent=new GameObject();
                 sideParent.name="Side"+side;
             }
         }
         
         if(i>cubeSize.x-1) {
             k++;
             i=0;
         }
         
         GameObject plane=new GameObject();
         plane.transform.parent=sideParent.transform;
         MeshFilter meshFilter = (MeshFilter)plane.AddComponent(typeof(MeshFilter));
         MeshRenderer meshRenderer = (MeshRenderer)plane.AddComponent(typeof(MeshRenderer));
         Mesh mesh=new Mesh();
         mesh.Clear();
         mesh=maker.create(vertDensity,vertDensity,tileSize.x,tileSize.y);
         meshFilter.mesh=mesh;
         meshFilter.mesh.RecalculateNormals();
         meshFilter.mesh.RecalculateBounds();
         meshRenderer.material=planeMat;
         switch (side) {
             //Top Side
         case 0:
             xx=i*tileSize.x;
             yy=((cubeSize.y*tileSize.y)/2f)+tileSize.y;
             zz=k*tileSize.y;
             dir=-Vector3.down;
             break;
             //Left Side
         case 1:
             xx=0;
             yy=((cubeSize.y*tileSize.y)/2f)+(k*-tileSize.y);
             zz=i*tileSize.x;
             dir=Vector3.left;
             break;
             //Bottom Side
         case 2:
             xx=i*tileSize.x;
             yy=((cubeSize.y*-tileSize.y)/2f)+tileSize.y;
             zz=(k*tileSize.y)-tileSize.y;
             dir=Vector3.down;
             break;
             //Right Side
         case 3:
             xx=(cubeSize.x*tileSize.x);
             yy=(((cubeSize.y*tileSize.y)/2f)+tileSize.y)+(k*-tileSize.y);
             zz=i*tileSize.x;
             dir=-Vector3.left;
             break;
             //Front Side
         case 4:
             xx=i*tileSize.y;
             yy=((cubeSize.y*tileSize.y)/2f)+(k*-tileSize.y);
             zz=(cubeSize.y*tileSize.y)-tileSize.y;
             dir=Vector3.forward;
             break;
             //Back Side
         case 5:
             xx=i*tileSize.y;
             yy=(((cubeSize.y*tileSize.y)/2f)+tileSize.y)+(k*-tileSize.y);
             zz=-tileSize.y;
             dir=-Vector3.forward;
             break;
         }
         
         plane.transform.position=new Vector3(xx,yy,zz);
         plane.transform.up=dir;
         plane.name=i+","+k+","+side+","+index;
         
         meshList[index]=plane;
         
         i++;
         //index++;
     }
 }



CreatePlane (mesh creation script):

 using UnityEngine;
 using UnityEditor;
 using System.Collections;
 using System;
 
 
 public class CreatePlane : MonoBehaviour
 {
     
     public enum Orientation
     {
         Horizontal,
         Vertical
     }
     
     public enum AnchorPoint
     {
         TopLeft,
         TopHalf,
         TopRight,
         RightHalf,
         BottomRight,
         BottomHalf,
         BottomLeft,
         LeftHalf,
         Center
     }
     
     //public int widthSegments = 1;
     //public int lengthSegments = 1;
     //public float width = 1.0f;
     //public float length = 1.0f;
     public Orientation orientation = Orientation.Horizontal;
     public AnchorPoint anchor = AnchorPoint.Center;
     public bool addCollider = false;
     public bool createAtOrigin = true;
     public bool twoSided = false;
     public string optionalName;
     
     
     /*void OnWizardUpdate()
     {
         widthSegments = Mathf.Clamp(widthSegments, 1, 254);
         lengthSegments = Mathf.Clamp(lengthSegments, 1, 254);
     }*/
     
     
     public Mesh create(int widthSegments, int lengthSegments, float width, float length)
     {
         
         Vector2 anchorOffset;
         string anchorId;
         switch (anchor)
         {        
         case AnchorPoint.Center:
         default:
             anchorOffset = new Vector2(-width/2.0f,length/2.0f);
             anchorId = "TL";
             break;
         }
 
         /*GameObject plane = new GameObject();
         
         if (!string.IsNullOrEmpty(optionalName))
             plane.name = optionalName;
         else
             plane.name = "Plane";
 
         plane.transform.position = Vector3.zero;
         
         MeshFilter meshFilter = (MeshFilter)plane.AddComponent(typeof(MeshFilter));
         plane.AddComponent(typeof(MeshRenderer));
         
         string planeAssetName = plane.name + widthSegments + "x" + lengthSegments + "W" + width + "L" + length + anchorId + ".asset";*/
         Mesh m = new Mesh();
         //m.name = plane.name;
         
         int hCount2 = widthSegments+1;
         int vCount2 = lengthSegments+1;
         int numTriangles = widthSegments * lengthSegments * 6;
         numTriangles *= 2;
         int numVertices = hCount2 * vCount2;
         
         Vector3[] vertices = new Vector3[numVertices];
         Vector2[] uvs = new Vector2[numVertices];
         int[] triangles = new int[numTriangles];
         
         int index = 0;
         float uvFactorX = 1.0f/widthSegments;
         float uvFactorY = 1.0f/lengthSegments;
         float scaleX = width/widthSegments;
         float scaleY = length/lengthSegments;
         for (float y = 0.0f; y < vCount2; y++)
         {
             for (float x = 0.0f; x < hCount2; x++)
             {
                 vertices[index] = new Vector3(x*scaleX - width/2f - anchorOffset.x, 0.0f, y*scaleY - length/2f - anchorOffset.y);
                 uvs[index++] = new Vector2(x*uvFactorX, y*uvFactorY);
             }
         }
         
         index = 0;
         for (int y = 0; y < lengthSegments; y++)
         {
             for (int x = 0; x < widthSegments; x++)
             {
                 triangles[index]   = (y     * hCount2) + x;
                 triangles[index+1] = ((y+1) * hCount2) + x;
                 triangles[index+2] = (y     * hCount2) + x + 1;
                 
                 triangles[index+3] = ((y+1) * hCount2) + x;
                 triangles[index+4] = ((y+1) * hCount2) + x + 1;
                 triangles[index+5] = (y     * hCount2) + x + 1;
                 index += 6;
             }
             if (twoSided) {
                 // Same tri vertices with order reversed, so normals point in the opposite direction
                 for (int x = 0; x < widthSegments; x++)
                 {
                     triangles[index]   = (y     * hCount2) + x;
                     triangles[index+1] = (y     * hCount2) + x + 1;
                     triangles[index+2] = ((y+1) * hCount2) + x;
                     
                     triangles[index+3] = ((y+1) * hCount2) + x;
                     triangles[index+4] = (y     * hCount2) + x + 1;
                     triangles[index+5] = ((y+1) * hCount2) + x + 1;
                     index += 6;
                 }
             }
         }
         
         m.vertices = vertices;
         m.uv = uvs;
         m.triangles = triangles;
         //m.RecalculateNormals();
     
         //meshFilter.sharedMesh = m;
         //m.RecalculateBounds();
 
         return m;
     }
 }



Spherify (self-explanatory):

 using UnityEngine;
 using System.Collections;
 using System;
 using System.Collections.Generic;
 
 public class Spherify : MonoBehaviour {
     
     // Use this for initialization
     void Start () {
         //MapToPlanet ();
     }
     
     // Update is called once per frame
     void Update () {
         
     }
     public Mesh MapToPlanet(Mesh mesh,float radius, Vector3 offset){
         Vector3[] vertices = mesh.vertices;
         
         for (var i=0; i<vertices.Length; i++) {
             
             vertices[i]=(offset+vertices[i]).normalized*radius;
             
         }
         
         mesh.vertices = vertices;
         mesh.RecalculateNormals();
         mesh.RecalculateBounds();
 
         return mesh;
     }
 }



Comment
DevYHeavy

People who like this

1 Show 0
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image

Answer by Komak57 · Jan 08, 2015 at 09:29 AM

The problem with your code is that normalized works by locking the direction from the origin, allowing you to move the vertex away from said point. This given point is what's know as the pivot. This pivot coordinate MUST be the same point used for all vertices, and should be deducted from the vertex coordinate, so that the normalized vertex ray will expand outwards by the given radius.

Next, having so many 64x64 planes will make for an extremely smooth sphere in most cases, you're talking about rendering up to 33,554,432 triangles. The render time for which will be flat out rediculous. What you'll want to look for, instead, is a basic plane with just enough vertices to keep the sphere from looking too blocky, and then applying various LOD methods to it to get better definition where the camera needs it. These methods include, but are not limited to, geo clipmapping, geo mipmapping, quad tree, octo tree, dynamic subdivision, etc.

Comment
DevYHeavy

People who like this

1 Show 0 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

3 People are following this question.

avatar image avatar image avatar image

Related Questions

Generate Random Terrain on Start 1 Answer

Detecting position of an object above another object to make the object under unwalkable. 2 Answers

Voxel Tree Generator Project 0 Answers

Block ground generation 2 Answers

How can I show a random integer on a cube 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges