Jak programowo generujesz kulę?

25

Czy ktoś mógłby wyjaśnić, w jaki sposób możliwe byłoby utworzenie kuli wierzchołków, wskaźników i współrzędnych tekstury? Zaskakujący jest brak dokumentacji, jak to zrobić i to jest coś, czego jestem zainteresowany.

Próbowałem tego, co oczywiste, google, przeglądanie na gamedev.net itp. Jednak nic nie obejmuje generacji punktów kulistych, indeksowania ich i teksturowania.

judeclarke
źródło
6
Nie zamierzam głosować ani głosować za zamknięciem tego, ale czy naprawdę mówisz mi, że ani jeden wynik z google.com/search?q=how+to+generate+a+sphere+vertices był przydatny? W takim przypadku musisz bardziej szczegółowo wyjaśnić problem.
Szukaj icosfery. Znacznie mądrzejsza niż głupia „kula polarna”, która wytwarza bezużyteczne twarze.
Notabene
3
Warto zauważyć, że do prostych celów idealnie delikatna „kula” to quad o okrągłej fakturze skierowany w stronę aparatu.
aaaaaaaaaaaa
Oto jak zaimplementowałem go dla skydome w mojej grze.
danijar

Odpowiedzi:

36

Istnieją dwa ogólne podejścia:

wprowadź opis zdjęcia tutaj

Najbardziej na lewo nazywa się kulę UV, a najbardziej na prawo - icosfera.

GLUT zwykle stosuje podejście UV: spójrz na funkcję glutSolidSphere()w kodzie źródłowym Freeglut .

Oto doskonały artykuł na temat tworzenia icosfery: http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html

Kula UV wygląda jak globus. Dla wielu celów jest całkowicie w porządku, ale w niektórych przypadkach użycia, np. Jeśli chcesz zdeformować kulę, niekorzystne jest to, że gęstość wierzchołków jest większa wokół biegunów. Tutaj icosfera jest lepsza, jej wierzchołki są rozmieszczone równomiernie.

To może być również interesujące: http://kiwi.atmos.colostate.edu/BUGS/geodesic/text.html opisuje podejście do organizowania twarzy w strefy.

http://vterrain.org/Textures/spherical.html daje doskonały opis tego, jak możesz je teksturować.

Wola
źródło
2
Chociaż ogólny pomysł jest dobry, podzielenie polytopa Schläfli {3,5} nie jest jedynym sposobem na zrobienie tego. Zasadniczo wolę pracować z rodziną Schläfli {4, *} ({4,3} w przypadku kuli) do celów mapowania UV.
Martin Sojka
Generowanie drobno mozaikowanych kulek dwudziestościennych jest nieco droższe ze względu na konieczność rekurencyjnego dzielenia powierzchni.
bobobobo
9

Można to zrobić na 2 sposoby:

  1. Spaceruj theta i phi we współrzędnych sferycznych, generuj twarze i tris

  2. Utwórz dwudziestościan i rekurencyjnie dziel twarze, aż do osiągnięcia żądanej teselacji.

Kula za pomocą kulistych współrzędnych chodzić

Po pierwsze, wystarczy użyć podwójnie zagnieżdżonego do chodzenia theta i phi. Idąc theta i phi, obracasz trójkąty, aby stworzyć swoją kulę.

wprowadź opis zdjęcia tutaj

Kod, który to robi, będzie wyglądał mniej więcej tak:

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

Pamiętaj więc, że ważne jest, aby nakręcić górną i dolną czapkę używając tylko tris, a nie quadów.

Kula dwudziestościenna

Aby użyć dwudziestościanu, wystarczy wygenerować punkty dwudziestościanu, a następnie nakręcić z niego trójkąty. Na wierzchołkach icosahedron siedzi przy pochodzenia są:

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

Następnie wystarczy spojrzeć na schemat dwudziestościanu i ścian wiatru z tych wierzchołków. Mam już kod, który to robi tutaj .

Bobobobo
źródło
jakieś pomysły, jak uzyskać pół ciała, na przykład od theta = pi / 4 do theta = 3pi * 4? Jak ten obraz: i.stack.imgur.com/Jjx2c.jpg Spędziłem dni nad tym, nie mogłem tego rozwiązać.
Tina J
3

Jeśli punkty nie muszą być lokalnie jednorodne, ale powinny być globalnie jednolite i nie muszą być zgodne z żadnym ustalonym wzorem, możesz użyć wariantu algorytmu rzucania rzutkami, aby rozdzielić n punktów na kuli o promieniu r , średnio dist punktów od siebie. Wartości te są z grubsza następujące:

  1. Jeśli chcesz mieć określoną liczbę wierzchołków:
    • n = (pożądana liczba wierzchołków)
    • dyst = 2 × r × √ ( π / n )
  2. Jeśli chcesz mieć określoną średnią odległość między wierzchołkami:
    • n = 4 × π × ( r / dist ) 2
    • dist = (pożądana średnia odległość)

W najprostszym przypadku możesz następnie równomiernie wybierać punkty losowo, wybierając dwie równomiernie rozmieszczone zmienne u i v z (0, 1) i obliczając z nich współrzędne biegunowe zgodnie ze wzorami θ = 2 × π × u i ϕ = łuk cos (2 × v - 1); następnie odrzucając wszystkie punkty, które leżą zbyt blisko już wybranych punktów. Aby uzyskać nieco bardziej złożony i znacznie wydajniejszy algorytm, zobacz „ Rzucanie strzałkami po powierzchniach ” Cline, Jeschke, White, Razdan i Wonka.

Po wybraniu pierwszych czterech punktów (zakładając, że żadne trzy z nich nie są zdegenerowane , to znaczy - nie leżą w tym samym wielkim kole, ale jest to bardzo mało prawdopodobne), możesz utworzyć między nimi cztery twarze i za każdym razem dodawać nowy punkt, możesz podzielić twarz, do której należy, na trzy pod-ściany.

Dla celów teksturowania możesz następnie zmapować punkty na mapę sześcianu.

Martin Sojka
źródło