2011-09-06 106 views
9

我试图生成一组点(由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; 
    } 
+0

看起来你需要根据numOfArms第二回路和offseting由臂之间的角距离的臂角度。然后将你的内部迭代循环改为numOfStars/numOfArms。 –

+0

这不属于gamedev吗? –

+0

另外:http://stackoverflow.com/questions/348321/mathematical-question-procedural-generation-of-a-galaxy –

回答

2

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

然后,您可以将每个手臂存储为自己的星系(暂时)。所以如果你想要2个武器,做2个5000的星系。然后,围绕原点旋转其中一个0度(围绕原点),然后旋转180度。

使用此功能,您可以通过使用不同的旋转量来执行任意数量的手臂。你甚至可以通过使旋转距离更随机,如使用范围而不是直线(360/n)来添加一些“归化”。例如,5个武器将是0,72,144,216,288,但与一些随机你可以把0,70,146,225,301

编辑:

一些快速谷歌福告诉我(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.0左右的所有值? 我可以在每个点上使用旋转矩阵来做到这点,但是最好能够将'旋转偏移量'值传递到createArm函数中,并在生成时旋转点。 –

+0

有两个以上的武器的任何螺旋星系吗?我不认为它会发生,除非它可能是由于某种方式中断(合并/碰撞)而导致的暂时性特征。 –

+0

@Chris我加了一些无耻的公式,从siggraph中撕下来。 – corsiKa

4

选中此项。这是利用密度波理论模拟星系。代码可用。 http://beltoforion.de/galaxy/galaxy_en.html

+0

链接已死,但对于所有仍需阅读的链接,请使用以下链接https://web.archive.org/web/20140119101505/http://beltoforion.de/galaxy/galaxy_en.html – Peter

4

我非常喜欢这个想法,所以我不得不自己动手,这是我的结果。 请注意,我使用了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); 

结果: Galaxy