2011-09-06 36 views
9

Estoy tratando de generar un conjunto de puntos (representado por una estructura Vector) que modela aproximadamente una galaxia espiral.Galaxy Generation Algorithm

El código de C# con el que he estado jugando está debajo; pero solo puedo lograr que genere un solo 'brazo' de la galaxia.

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

Parece que se necesita un segundo bucle en función de las numOfArms y contraídas el ángulo del brazo por la distancia angular entre los brazos. Luego cambie su ciclo de iteración interno para que sea numOfStars/numOfArms. –

+0

¿Esto no pertenece a gamedev? –

+0

También: http://stackoverflow.com/questions/348321/mathematical-question-procedural-generation-of-a-galaxy –

Respuesta

2

lo haría abstracta que funciona a cabo en una función createArm.

Luego puede almacenar cada brazo como su propia galaxia (temporalmente).

Así que si quieres 2 brazos, haz 2 galaxias de 5000. Luego, rota uno de ellos 0 grados alrededor del origen (para que no se mueva) y los otros 180 grados alrededor del origen.

Con esto puede hacer un número arbitrario de brazos utilizando diferentes cantidades de rotación. Incluso podría agregarle algo de "naturalización" haciendo que la distancia de rotación sea más aleatoria, como con un rango en lugar de recto (360/n). Por ejemplo, 5 brazos serían 0, 72, 144, 216, 288. Sin embargo, con un poco de aleatorización que podrían hacer que sea 0, 70, 146, 225, 301.

Editar:

Algunos rápida Google-fu me dice (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

¿Alguna idea de cómo podría cambiar el algoritmo para 'girar' todos los valores alrededor de 0.0? Podría hacerlo con una matriz de rotación en cada punto, pero sería mejor poder pasar un valor 'offset de rotación' a la función createArm, y hacer rotar los puntos en la generación. –

+0

¿hay galaxias espirales con un número de brazos distinto de dos? No creo que suceda a menos que tal vez sea una característica transitoria debido a una interrupción de alguna manera (fusión/colisión). –

+0

@Chris Agregué algunas fórmulas desvergonzadas arrancadas de Siggraph. – corsiKa

4

Mira esto. Es una simulación de galaxia usando la teoría de ondas de densidad. El código está disponible. http://beltoforion.de/galaxy/galaxy_en.html

+0

el enlace está muerto, pero para todos aquellos que aún quieran leerlo, utilice el siguiente enlace https://web.archive.org/web/20140119101505/http://beltoforion.de/galaxy/galaxy_en.html – Peter

4

Me gustó tanto esta idea que tuve que jugar sola y este es mi resultado. Tenga en cuenta que utilicé PointF en lugar de Vector3, pero debería poder buscar y reemplazar y agregar , 0) en algunos lugares.

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

Ejemplo:

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

Resultado: Galaxy