2011-09-06 76 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