【问题标题】:Galaxy Generation Algorithm星系生成算法
【发布时间】:2014-12-30 06:08:33
【问题描述】:

我正在尝试生成一组点(由 Vector 结构表示)大致模拟一个螺旋星系。

我一直在玩的 C# 代码如下;但我似乎只能让它生成银河系的一个“手臂”。

    public Vector3[] GenerateArm(int numOfStars, 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;
    }

【问题讨论】:

  • 看起来您需要基于 numOfArms 的第二个循环,并通过手臂之间的角距离偏移手臂角度。然后将您的内部迭代循环更改为 numOfStars / numOfArms。
  • 这不属于gamedev吗?
  • 这并不能完全解决问题,但“度数到弧度”函数的意义何在?为什么不首先以弧度生成角度?
  • 公平评论。我会试试的。

标签: c# procedural-generation


【解决方案1】:

检查这个。这是使用密度波理论对星系的模拟。代码可用。 http://beltoforion.de/galaxy/galaxy_en.html

【讨论】:

【解决方案2】:

我非常喜欢这个想法,我不得不自己尝试一下,这就是我的结果。 请注意,我使用的是 PointF 而不是 Vector3,但您应该能够在几个地方搜索和替换并添加 , 0)

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);
}

例子:

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

结果:

【讨论】:

    【解决方案3】:

    我会将该函数抽象为 createArm 函数。

    然后您可以将每条手臂存储为自己的星系(暂时)。

    因此,如果您想要 2 个手臂,请做 2 个 5000 的星系。然后,将其中一个围绕原点旋转 0 度(所以不移动),另一个围绕原点旋转 180 度。

    有了这个,你可以通过使用不同的旋转量来做任意数量的手臂。您甚至可以通过使旋转距离更加随机来为其添加一些“自然化”,例如使用范围而不是直线 (360 / n)。例如,5 个手臂是 0、72、144、216、288。但是通过一些随机化,您可以使其成为 0、70、146、225、301。

    编辑:

    一些快速的 google-fu 告诉我 (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.0 左右?我可以在每个点上使用旋转矩阵来做到这一点,但最好能够将“旋转偏移”值传递给 createArm 函数,并在生成时旋转点。
    • 是否有任何螺旋星系的臂数不是两个?我认为它不会发生,除非它可能是由于某种方式(合并/碰撞)而导致的暂时性特征。
    • @Chris 我添加了一些从 siggraph 中无耻撕下来的公式。
    • 该死的剪切+粘贴编码!
    • @Chris 太真实了。太真实了。每当我复制和粘贴时,我知道发生了两件事之一:我即将忘记更改复制代码和粘贴代码之间的细微差别,或者我正在复制真正应该重构的代码功能。复制/粘贴是原型程序员最好的朋友,也是维护程序员的噩梦!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 1970-01-01
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 2011-10-22
    相关资源
    最近更新 更多