minecraftnoisevoxelprocedural

How Do I Generate Procedural Cube Asteroid Formations?


I'm trying to find the best way to generate perlin-noise-based cube voxel asteroids, but cannot seem to find a consistent method to do so.

I've tried to use this perlin noise library: https://github.com/warmwaffles/Noise/blob/master/src/prime/PerlinNoise.java

Along with this static method to get 3D noise out of it:


    public static double Perlin3D(PerlinNoise noise, double x, double y, double z)
        {
            double AB = noise.getHeight(x, y);
            double BC = noise.getHeight(y, z);
            double AC = noise.getHeight(x, z);

            double BA = noise.getHeight(y, x);
            double CB = noise.getHeight(z, y);
            double CA = noise.getHeight(z, x);

            double ABC = AB + BC + AC + BA + CB + CA;
            return ABC / 6;
        }

And this method to make the actual asteroids:

    public void Generate()
        {
            PerlinNoise p = new PerlinNoise(seed, persistence, frequency, amplitude, octaves);

            GameObject newUnit = Instantiate(unit, genPoint, Quaternion.identity);
            newUnit.transform.SetParent(transform);

            for (int x = 0; x < maxDistanceFromCenter * 2; x++)
            {
                for (int y = 0; y < maxDistanceFromCenter * 2; y++)
                {
                    for (int z = 0; z < maxDistanceFromCenter * 2; z++)
                    {
                        int targetX = genPoint.x - maxDistanceFromCenter + x;
                        int targetY = genPoint.y - maxDistanceFromCenter + y;
                        int targetZ = genPoint.z - maxDistanceFromCenter + z;

                        Vector3Int targetPos = new Vector3Int(targetX, targetY, targetZ);
                        Vector3 targetVector3d = new Vector3(targetX, targetY, targetZ).normalized;

                        double distFromCenter = Vector3.Distance(genPoint, targetPos);

                        double maxDistFromCenter = (NoiseHelper.Perlin3D(p, targetVector3d.x, targetVector3d.y, targetVector3d.z));

                        print(maxDistFromCenter);

                        if (distFromCenter < maxDistFromCenter)
                        {
                            GameObject newUnit2 = Instantiate(unit, targetPos, Quaternion.identity);
                            newUnit2.transform.SetParent(transform);
                        }
                    }
                }
            }
        }

Unfortunately I'm getting results that look like this.

When I'm really looking for results like this Blender mock-up I made..

By the looks of it, you can see that I'm using Unity to do this as a medium to see what my code outputs. By no means am I looking for a Unity answer to this, this is entirely conceptual for uses in multiple coding projects.

I'm hoping to get some guidance, answers, or suggestions on achieving what I'm intending. Thank you for all of the help in advanced and I really appreciate your time in lending me a hand,

Cheers.


Solution

  • I'm not quite sure exactly what you are doing so I'll just tell you how I generally do it. My voxels use some variation of marching cubes so I'll change it a bit to suit what you're doing.

    First you can loop though all your voxels and take the center point. Then normalize it. I'm assuming your asteroid has (0.0,0.0,0) in the middle, if not just offset everything. In any case that gives you points around a unit sphere. You can then multiply those points by some constant to get a bigger sphere of points, like say 5 or 10. The bigger the number the higher the frequency of your noise. Play with it until it looks good to you. Next plug those points in 3D nose, Perlin or simplex. Simplex is generally better. This will give you a value from around -1 to 1 for every voxel.

    Then you just need to have a base radius for your asteroid. For instance if your voxels go from -10 to +10 in all dimensions you can use a base radius of say 8. If you add that to your noise you get values of roughly 7 to 9 for every voxel all the way around the sphere. If the distance of the center of a voxel to the origin is less than it's calculated number it's solid. If it's greater, it's non-solid. Bingo you're done.

    You can also scale your noise up and down to give you higher peaks and lower valleys. And then there are various ways to combine noise to get a lot of different kinds of terrain. The Ridged Multi-Fractal is one of my favorites. With low resolution it's not so important however since you won't see the details anyway.