0

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.

  • I agree with Gnollrunner that Simplex type noise is generally better. This is due mainly to appearance and not showing the same type of grid alignment. We should consider the term "Perlin" synonymous with directional variety problems, rather than smooth values. To add, I don't recommend that "3D out of 2D" trick. First, it creates shadows of each 2D noise features along the remaining axis. It also looks involved because it combines 6 noises, but it effectively only combines 3. The ones sharing the same flipped axes merge as one noise. I recommend https://github.com/Auburn/FastNoiseLite/ – KdotJPG Mar 21 '21 at 19:34

1 Answers1

0

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.

  • Got it. Thank you for your response. I was actually pretty close to what you were talking about already, I just had to add some multipliers and constants. I ended up keeping the perlin noise values as 1 all across the board (persistence, frequency, amplitude, and octaves) and using this as a reference to get what I need: https://codepen.io/fvalla/pen/KKKNwWg (tweaking the k values and some of the constants that were plugged into the 3d perlin noise) – Agilapathy Mar 12 '21 at 20:16