¿Cómo se genera programáticamente una esfera?

25

¿Podría alguien explicar cómo sería posible crear una esfera de vértices, índices y coordenadas de textura? Hay una sorprendente falta de documentación sobre cómo hacerlo y es algo que me interesa aprender.

He intentado lo obvio, buscando en Google, buscando en gamedev.net, etc. Sin embargo, nada cubre las generaciones de puntos esféricos, indexándolos y texturizando.

judeclarke
fuente
66
No voy a rechazar o votar para cerrar esto, pero ¿realmente me está diciendo que no fue útil un solo resultado de google.com/search?q=how+to+generate+a+sphere+vertices ? Si ese es el caso, deberá explicar cuál es su problema con más detalle.
Busca la icosfera. Mucho más inteligente que la tonta "esfera polar" que produce caras inútiles.
Notabene
3
Vale la pena señalar que, para algunos propósitos simples, una "esfera" perfectamente fina es un quad con una textura circular frente a la cámara.
aaaaaaaaaaaa
Así es como lo implementé para el skydome en mi juego.
danijar

Respuestas:

36

Hay dos enfoques generales:

ingrese la descripción de la imagen aquí

El extremo izquierdo se denomina esfera ultravioleta y el extremo derecho una icosfera.

GLUT tiende a usar el enfoque uv: mira la función glutSolidSphere()en el código fuente de freeglut .

Aquí hay un excelente artículo sobre la producción de una icosfera: http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html

La esfera ultravioleta parece un globo. Para muchos propósitos, está perfectamente bien, pero para algunos casos de uso, por ejemplo, si desea deformar la esfera, es desventajoso que la densidad de los vértices sea mayor alrededor de los polos. Aquí la icosfera es mejor, sus vértices se distribuyen de manera uniforme.

También puede encontrar esto interesante: http://kiwi.atmos.colostate.edu/BUGS/geodesic/text.html describe un enfoque para organizar las caras en zonas.

http://vterrain.org/Textures/spherical.html ofrece una excelente descripción de cómo puede elegir texturizarlos.

Será
fuente
2
Si bien la idea general es buena, subdividir un politopo Schläfli {3,5} no es la única forma de hacerlo. En general, prefiero trabajar con la familia Schläfli {4, *} ({4,3} en el caso de una esfera) con fines de mapeo UV.
Martin Sojka
Las esferas icosaédricas finamente teseladas son un poco más caras de generar debido a la necesidad de subdividir recursivamente las caras.
bobobobo
9

Hay 2 formas de hacerlo:

  1. Recorre theta y phi en coordenadas esféricas, genera caras y tris

  2. Crea un icosaedro y subdivide recursivamente las caras hasta que se alcance la teselación deseada.

Esfera utilizando coordenadas esféricas a pie

Por primera vez, solo usa un doble anidado para caminar theta y phi. A medida que caminas theta y phi, giras triángulos para crear tu esfera.

ingrese la descripción de la imagen aquí

El código que lo haga se verá así:

for( int t = 0 ; t < stacks ; t++ ) // stacks are ELEVATION so they count theta
{
  real theta1 = ( (real)(t)/stacks )*PI ;
  real theta2 = ( (real)(t+1)/stacks )*PI ;

  for( int p = 0 ; p < slices ; p++ ) // slices are ORANGE SLICES so the count azimuth
  {
    real phi1 = ( (real)(p)/slices )*2*PI ; // azimuth goes around 0 .. 2*PI
    real phi2 = ( (real)(p+1)/slices )*2*PI ;

    //phi2   phi1
    // |      |
    // 2------1 -- theta1
    // |\ _   |
    // |    \ |
    // 3------4 -- theta2
    //

    //vertex1 = vertex on a sphere of radius r at spherical coords theta1, phi1
    //vertex2 = vertex on a sphere of radius r at spherical coords theta1, phi2
    //vertex3 = vertex on a sphere of radius r at spherical coords theta2, phi2
    //vertex4 = vertex on a sphere of radius r at spherical coords theta2, phi1

    // facing out
    if( t == 0 ) // top cap
      mesh->addTri( vertex1, vertex3, vertex4 ) ; //t1p1, t2p2, t2p1
    else if( t + 1 == stacks ) //end cap
      mesh->addTri( vertex3, vertex1, vertex2 ) ; //t2p2, t1p1, t1p2
    else
    {
      // body, facing OUT:
      mesh->addTri( vertex1, vertex2, vertex4 ) ;
      mesh->addTri( vertex2, vertex3, vertex4 ) ;
    }
  }
}

Tenga en cuenta lo anterior, es importante enrollar la tapa superior y la tapa inferior usando solo tris, no quads.

Esfera icosaédrica

Para usar un icosaedro, solo genera los puntos del icosaedro y luego enrolla triángulos a partir de él. Los vértices de un icosaedro sentado en el origen son:

(0, ±1, ±φ)
1, ±φ, 0)
(±φ, 0, ±1)
where φ = (1 + 5) / 2 

Luego, solo tiene que mirar un diagrama de un icosaedro y caras de viento de esos verts. Ya tengo un código que lo hace aquí .

bobobobo
fuente
alguna idea de cómo obtener el medio cuerpo, como de theta = pi / 4 a theta = 3pi * 4? Al igual que esta imagen: i.stack.imgur.com/Jjx2c.jpg He estado pasando días en esto, no pude resolverlo.
Tina J
3

Si los puntos no tienen que ser localmente uniformes, pero deben ser globalmente uniformes, y no tienen que seguir ningún patrón establecido, puede usar una variante del algoritmo de lanzamiento de dardos para distribuir n puntos en una esfera con radio r , en promedio puntos dist separados. Estos valores son entonces aproximadamente:

  1. Si quieres tener una cantidad específica de vértices:
    • n = (cantidad deseada de vértices)
    • dist = 2 × r × √ ( π / n )
  2. Si desea tener una distancia promedio específica entre los vértices:
    • n = 4 × π × ( r / dist ) 2
    • dist = (distancia media deseada)

En el caso más simple, puede seleccionar puntos al azar de manera uniforme seleccionando dos variables uniformemente distribuidas u y v de (0, 1) y calculando las coordenadas polares a partir de ellas de acuerdo con las fórmulas θ = 2 × π × u y ϕ = arco cos (2 × v - 1); luego descartar cualquier punto que se encuentre demasiado cerca de los puntos ya seleccionados. Para un algoritmo un poco más complejo y con un rendimiento significativamente mejor, vea " Dart Throwing on Surfaces " de Cline, Jeschke, White, Razdan y Wonka.

Después de elegir sus primeros cuatro puntos (suponiendo que no tres de ellos estén degenerados , es decir, no se encuentran en el mismo gran círculo, pero es muy poco probable), puede crear cuatro caras entre ellos, y cada vez que agrega un nuevo punto, puede dividir la cara a la que pertenece en tres subcaras.

Para fines de texturizado, puede asignar los puntos a un mapa de cubos.

Martin Sojka
fuente