开发者

Galaxy Generation Algorithm

I'm trying to generate a set of points (represented by a Vector struct) that roughly models a spiral galaxy.

The C# code I've been playing with is below; but I can only seem to get it to generate a single 'arm' of the galaxy.

    public Vector3[] GenerateArm(int num开发者_Go百科OfStars, int numOfArms, float rotation)
    {
        Vector3[] result = new Vector3[numOfStars];
        Random r = new Random();

        float fArmAngle = (float)((360 / numOfArms) % 360);
        float fAngularSpread = 180 / (numOfArms * 2);

        for (int i = 0; i < numOfStars; i++)
        {

            float fR = (float)r.NextDouble() * 64.0f;
            float fQ = ((float)r.NextDouble() * fAngularSpread) * 1;
            float fK = 1;

            float fA = ((float)r.NextDouble() % numOfArms) * fArmAngle;


            float fX = fR * (float)Math.Cos((MathHelper.DegreesToRadians(fA + fR * fK + fQ)));
            float fY = fR * (float)Math.Sin((MathHelper.DegreesToRadians(fA + fR * fK + fQ)));

            float resultX = (float)(fX * Math.Cos(rotation) - fY * Math.Sin(rotation));
            float resultY = (float)(fY * Math.Cos(rotation) - fX * Math.Sin(rotation));

            result[i] = new Vector3(resultX, resultY, 1.0f);
        }

        return result;
    }


Check this. It's a simulation of galaxy using density wave theory. Code is available. http://beltoforion.de/galaxy/galaxy_en.html


I liked this idea so much i had to play around with it on my own and here is my result. Note that i used PointF instead of Vector3, but you should be able to search and replace and add , 0) in a few places.

PointF[] points;

private void Render(Graphics g, int width, int height)
{
    using (Brush brush = new SolidBrush(Color.FromArgb(20, 150, 200, 255)))
    {
        g.Clear(Color.Black);
        foreach (PointF point in points)
        {
            Point screenPoint = new Point((int)(point.X * (float)width), (int)(point.Y * (float)height));
            screenPoint.Offset(new Point(-2, -2));
            g.FillRectangle(brush, new Rectangle(screenPoint, new Size(4, 4)));
        }
        g.Flush();
    }
}

public PointF[] GenerateGalaxy(int numOfStars, int numOfArms, float spin, double armSpread, double starsAtCenterRatio)
{
    List<PointF> result = new List<PointF>(numOfStars);
    for (int i = 0; i < numOfArms; i++)
    {
        result.AddRange(GenerateArm(numOfStars / numOfArms, (float)i / (float)numOfArms, spin, armSpread, starsAtCenterRatio));
    }
    return result.ToArray();
}

public PointF[] GenerateArm(int numOfStars, float rotation, float spin, double armSpread, double starsAtCenterRatio)
{
    PointF[] result = new PointF[numOfStars];
    Random r = new Random();

    for (int i = 0; i < numOfStars; i++)
    {
        double part = (double)i / (double)numOfStars;
        part = Math.Pow(part, starsAtCenterRatio);

        float distanceFromCenter = (float)part;
        double position = (part * spin + rotation) * Math.PI * 2;

        double xFluctuation = (Pow3Constrained(r.NextDouble()) - Pow3Constrained(r.NextDouble())) * armSpread;
        double yFluctuation = (Pow3Constrained(r.NextDouble()) - Pow3Constrained(r.NextDouble())) * armSpread;

        float resultX = (float)Math.Cos(position) * distanceFromCenter / 2 + 0.5f + (float)xFluctuation;
        float resultY = (float)Math.Sin(position) * distanceFromCenter / 2 + 0.5f + (float)yFluctuation;

        result[i] = new PointF(resultX, resultY);
    }

    return result;
}

public static double Pow3Constrained(double x)
{
    double value = Math.Pow(x - 0.5, 3) * 4 + 0.5d;
    return Math.Max(Math.Min(1, value), 0);
}

Example:

points = GenerateGalaxy(80000, 2, 3f, 0.1d, 3);

Result:

Galaxy Generation Algorithm


I would abstract that function out into a createArm function.

Then you can store each arm as its own galaxy (temporarily).

So if you want 2 arms, do 2 galaxies of 5000. Then, rotate one of them 0 degrees around the origin (so doesn't move) and the other 180 degrees around the origin.

With this you can do an arbitrary number of arms by using different rotation amounts. You could even add some "naturalization" to it by making the rotation distance more random, like with a range instead of straight (360 / n). For example, 5 arms would be 0, 72, 144, 216, 288. But with some randomization you could make it 0, 70, 146, 225, 301.

Edit:

Some quick google-fu tells me (source)

q = initial angle, f  = angle of rotation.

x = r cos q
y = r sin q

x' = r cos ( q + f ) = r cos q cos f - r sin q sin f
y' = r sin ( q + w ) = r sin q cos f + r cos q sin f

hence:
x' = x cos f - y sin f
y' = y cos f + x sin f 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜