Trying to generate a cube split into 100+ different objects

I’m trying to generate a cube using the “mesh” class, which is fairly simple but the thing is I need the cube to not be 1 mesh, but rather for example 100 different meshes/objects that make up an entire cube. The reason I need this is because I’m making a procedurally generated planet, and the way I do it is I take a cube and using some math / Perlin noise distort it into a planet shape. (the different pieces of the cube would be chunks to load/unload/use for a LOD system)

Currently I’m using a cube I made in blender split into 24 parts. (picture) (all their origin points are in the center, which is important) Then using a for loop I distort each one into the sphere shape. That gives me 24 chunks. (picture) I want to generate larger planets, though, so obviously I need more chunks. That’s why I need to be able to procedurally generate a cube in hundreds of sections.

I really got no clue where to even start on this, though, since I’m pretty bad with the mesh class. If someone could help me out that’d be awesome, thanks.

Why cubes ? You want to do something like this ?

There was a huge discussion thread back in 2010 with some breakdown of how the voxel system works as well as some source code. You might want to start there. Be prepared for a very long read though. It’s 57 pages and still somewhat active.

Hey, thanks for the reply. No, I’m not trying to make a Minecraft-like world. I’m trying to make procedural terrain except spherical, so it looks like a planet. I’m currently using a cube model split up into 24 chunks and turning it into a sphere. (“sphere-ifying” it, if you will. pictures in original post)

24 chunks can only make a very small planet, though. So what I’m asking is, how can I procedurally generate a cube split up into, let’s say, 100 parts. (my original 24 part cube was done manually in blender)

I’ll take a look but I’m not sure how much this is going to help me since I’m not using voxels nor looking to make a Minecraft clone.

@everyone If my explanations are confusing maybe it’ll make sense if you look at the code. Here’s what I got so far:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using CoherentNoise.Generation.Fractal;
using System.IO;
using System;

public class Planet : MonoBehaviour
{
    private Mesh mesh;
    private Vector3[] vertices;
    public float radius = 1f;
    public float noiseModifier = 0.1f;
    public List<GameObject> chunks = new List<GameObject>();
    private MeshCollider meshCollider;
    public AnimationCurve heightCurve;
    public int seed;

    void Start()
    {
        GeneratePlanet();
    }

    public void GeneratePlanet()
    {
        chunks = new List<GameObject> ();
        for (int c = 0; c < 24; c++) {
            chunks.Add(GameObject.Find("c"+(c+1)));
        }
        PinkNoise noise = new PinkNoise(seed);
        for (int c = 0; c < chunks.Count; c++) {
            mesh = chunks[c].GetComponent<MeshFilter>().sharedMesh;
            //meshCollider = GetComponent<MeshCollider>();
            vertices = mesh.vertices;

            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i] = (vertices[i].normalized * (radius + heightCurve.Evaluate(noise.GetValue(vertices[i].normalized)) * noiseModifier));
            }
            mesh.vertices = vertices;
            mesh.RecalculateNormals();
            mesh.RecalculateBounds();

            if (chunks[c].GetComponent<MeshCollider>() == null)
                chunks[c].AddComponent<MeshCollider>();

            chunks[c].GetComponent<MeshCollider>().sharedMesh = mesh;
        }
    }
}

Cube model I’m using: [download .blend]

To set it up and see, place down the cube at 0, 0, 0, then add the Planet script to the parent object of all the chunks. (“SplitCube”, should be the name of the object). In the inspector set Noise Modifier to 3, Radius to 75, and then pick one of the defaults from Height Curve.

Here’s my attempt at creating a semi-procedural cube, (split up into many parts) to then “sphere-ify”, just like I did with the blender cube model:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using CoherentNoise.Generation.Fractal;
using System.IO;
using System;

public class DynamicPlanet : MonoBehaviour
{
    private Mesh gameMesh;
    private Vector3[] vertices;
    public float radius = 1f;
    public float noiseModifier = 0.1f;
    public List<GameObject> chunks = new List<GameObject>();
    public int chunkCount = 0;
    private MeshCollider meshCollider;
    public AnimationCurve heightCurve;
    public int seed;
    public GameObject chunk;
    public Transform front;
    public Transform top;
    public int offsetIncrement;

    void Start() {
        GenerateCube();
    }

    public void GenerateCube() {
        GenerateSide();
    }

    private int id = 1;

    public void GenerateSide() {
        Vector3 offset = new Vector3(0, 0, 0);
        //multiplier switches every other plane spawned, so that the origin point is always in the center
        int multiplier = -1;
        for (int x = 0; x < chunkCount; x++) {   
            SpawnPlane (new Vector3(offset.x * multiplier, offset.y, 4), "c"+id);
            id++;
            for (int y = 0; y < chunkCount; y++) {   
                SpawnPlane (new Vector3(offset.x * multiplier, (offset.y+2), 4), "c"+id);
                id++;
                offset.y += offsetIncrement;
            }
            if (multiplier == -1) {
                offset.x += offsetIncrement;
            }
            offset.y = 0;
            multiplier = multiplier * -1;
        }
        GeneratePlanet ();
    }

    public void SpawnPlane(Vector3 offset, String id) {
        GameObject c = (GameObject)Instantiate (chunk, transform.position, Quaternion.identity);
        Mesh cMesh = c.GetComponent<MeshFilter> ().mesh;
        Vector3[] verts = cMesh.vertices;
        for (int v = 0; v < verts.Length; v++) {
            verts [v].x += offset.x;
            verts [v].y += offset.y;
            verts [v].z += offset.z;
        }
        cMesh.vertices = verts;
        c.name = id;
        chunks.Add (c);
    }

    public void GeneratePlanet() {
        for (int c = 0; c < chunks.Count; c++) {
            chunks[c] = GameObject.Find("c"+(c+1));
        }
        PinkNoise noise = new PinkNoise(seed);
        for (int c = 0; c < chunks.Count; c++) {
            gameMesh = chunks[c].GetComponent<MeshFilter>().sharedMesh;
            vertices = gameMesh.vertices;

            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i] = (vertices[i].normalized * (radius + heightCurve.Evaluate(noise.GetValue(vertices[i].normalized)) * noiseModifier));
            }
            gameMesh.vertices = vertices;
            gameMesh.RecalculateNormals();
            gameMesh.RecalculateBounds();

            if (chunks [c].GetComponent<MeshCollider> () == null) {
                chunks [c].AddComponent<MeshCollider> ();
            }

            chunks[c].GetComponent<MeshCollider>().sharedMesh = gameMesh;
        }
    }
}

Basically, I’m just taking a flat plane I made in Blender, (the plane has lots of vertices, though, for detailed terrain) and spawning a lot of them next to each other make a larger and split up side of the cube. Except instead of moving the object position when spawning, I offset all the vertice positions so that all the planes can have the same origin point.

This works fine, I get 1 side of the cube, and thus a partial planet. Now I’m not sure how to go about getting all the other sides of the cube to generate. I mean, sure I could just mess around with numbers until the sides align but the goal here is to have a procedural planet that I can adjust the size of and still work fine.

I once did a procedural planet, but I created the terrain as a plane and then used polar coordinates to turn it into a sphere. You will get singular poles that way, though, which is a drawback. I did it in the Vertex Shader, since I needed it as a visual effect only, but is should be not too taxing doing it on the CPU, depending on the polycount, of course.

I never did that before but the first thing that come to my mind is at first generate a Cube with the subdivison needed and in a second pass to push all vertexes outside using trigonometric functions with perlin noise as weights.

Here you have ready to use scripts to generate primitives: http://wiki.unity3d.com/index.php/ProceduralPrimitives

I figured out how to make the cube in separate parts (semi-procedurally…) and for them all to have the same origin/pivot. Here’s the code:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using CoherentNoise.Generation.Fractal;
using System.IO;
using System;

public class DynamicPlanet : MonoBehaviour
{
    private Mesh gameMesh;
    private Vector3[] vertices;
    public float radius = 1f;
    public float noiseModifier = 0.1f;
    public List<GameObject> chunks = new List<GameObject>();
    public int chunkCount = 0;
    private MeshCollider meshCollider;
    public AnimationCurve heightCurve;
    public int seed;
    public GameObject chunkFront;
    public GameObject chunkBack;
    public GameObject chunkTop;
    public GameObject chunkBottom;
    public GameObject chunkLeft;
    public GameObject chunkRight;
    public Transform front;
    public Transform back;
    public Transform top;
    public Transform bottom;
    public Transform left;
    public Transform right;
    public int offsetIncrement;

    void Start() {
        GenerateCube();
    }

    public void GenerateCube() {
        GenerateSide("front");
        GenerateSide("back");
        GenerateSide("top");
        GenerateSide("bottom");
        GenerateSide("left");
        GenerateSide("right");
        GeneratePlanet();
    }

    private int id = 1;

    public void GenerateSide(String side) {
        Vector3 offset = new Vector3(0, 0, 0);
        int multiplierX = 1;
        for (int x = 0; x < chunkCount; x++) {
            for (int y = 0; y < chunkCount; y++) {   
                if (side == "front")
                    SpawnPlane (new Vector3 (offset.x * multiplierX, (float)(offset.y - ((float)chunkCount - 1)), chunkCount), "c" + id, chunkFront, side);
                if (side == "back")
                    SpawnPlane (new Vector3 (offset.x * multiplierX, (float)(offset.y - ((float)chunkCount - 1)), chunkCount * -1), "c" + id, chunkBack, side);
                if (side == "top")
                    SpawnPlane (new Vector3 (offset.x * multiplierX, chunkCount, (float)(offset.y - ((float)chunkCount - 1))), "c" + id, chunkTop, side);
                if (side == "bottom")
                    SpawnPlane (new Vector3 (offset.x * multiplierX, chunkCount * -1, (float)(offset.y - ((float)chunkCount - 1))), "c" + id, chunkBottom, side);
                if (side == "left")
                    SpawnPlane (new Vector3 (chunkCount, offset.x * multiplierX, (float)(offset.y - ((float)chunkCount - 1))), "c" + id, chunkLeft, side);
                if (side == "right")
                    SpawnPlane (new Vector3 (chunkCount * -1, offset.x * multiplierX, (float)(offset.y - ((float)chunkCount - 1))), "c" + id, chunkRight, side);
                   
                   
                id++;
                offset.y += offsetIncrement;
            }
            multiplierX = multiplierX * -1;
            if (multiplierX == -1) {
                offset.x += offsetIncrement;
            }
            offset.y = 0;
        }
    }

    public void SpawnPlane(Vector3 offset, String id, GameObject chunkObj, String side) {
        GameObject c = (GameObject)Instantiate (chunkObj, transform.position, Quaternion.identity);
        Mesh cMesh = c.GetComponent<MeshFilter> ().mesh;
        Vector3[] verts = cMesh.vertices;
        for (int v = 0; v < verts.Length; v++) {
            verts [v].x += offset.x;
            verts [v].y += offset.y;
            verts [v].z += offset.z;
        }
        cMesh.vertices = verts;
        c.name = id;
        if (side == "front")
            c.transform.SetParent(front);
        if (side == "back")
            c.transform.SetParent(back);
        if (side == "top")
            c.transform.SetParent(top);
        if (side == "bottom")
            c.transform.SetParent(bottom);
        if (side == "left")
            c.transform.SetParent(left);
        if (side == "right")
            c.transform.SetParent(right);
        chunks.Add (c);
    }

    public void GeneratePlanet() {
        for (int c = 0; c < chunks.Count; c++) {
            chunks[c] = GameObject.Find("c"+(c+1));
        }
        PinkNoise noise = new PinkNoise(seed);
        for (int c = 0; c < chunks.Count; c++) {
            gameMesh = chunks[c].GetComponent<MeshFilter>().mesh;
            vertices = gameMesh.vertices;

            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i] = (vertices[i].normalized * (radius + heightCurve.Evaluate(noise.GetValue(vertices[i].normalized)) * noiseModifier));
            }
            gameMesh.vertices = vertices;
            gameMesh.RecalculateNormals();
            gameMesh.RecalculateBounds();

            if (chunks [c].GetComponent<MeshCollider> () == null) {
                chunks [c].AddComponent<MeshCollider> ();
            }

            chunks[c].GetComponent<MeshCollider>().sharedMesh = gameMesh;
        }
        transform.localScale = new Vector3 (100, 100, 100);
    }
}

I couldn’t figure out how to rotate the chunks by moving vertices, so instead I just have 6 different chunk models that all point in the correct directions, then use those accordingly.

There is still a problem, though. Each chunk’s vertices align perfectly but the normals/shading makes an ugly seam between each chunk. Does anyone know how I can fix this?

You should maybe calculate the normals by yourself.
Also, be aware of that:

Just wanted to say thanks to everyone who gave their thoughts & ideas. I’ve got it to the point now where it is 100% procedural, no pre-made models used whatsoever. Which also means I was able to create a LOD system so that large planets don’t kill the FPS. (along with many other optimizations) The code is a few hundred lines now, so I probably won’t just post it.

Once it gets really good, though, (detailed textures, complex terrain, biomes, prop populating, etc) I may put it on the asset store for a few bucks to anyone who is interested.

Nice ! I will be interested to see that when it’s done.

There is something similar to what you are doing but standalone:
http://www.ignishot.com