Autor Wątek: Prosty generator siatki brył  (Przeczytany 3112 razy)

Offline Reeevas

  • Użytkownik

# Październik 28, 2011, 15:20:48
Witam

Chciałbym stworzyć prosty generator siatki brył, czyli tworzę sześcian, czworościan kulę itp. i teraz chciałbym mieć możliwość zagęszczenia siatki (docelowo naciskam przycisk siatka na bryle zagęszcza się) i w drugą stronę czyli zniejszenie gęstości. Drugim celem byłoby za pomocą kursora wybranie jakiegoś punktu na siatce i np. możliwość przesunięcia tego punktu przyczym brł by się deformowała. Można powiedzieć, że zaczynam zabawę z opengl, ale już co nieco wiem i chciałbym abyście podpowiedzieli mi jak wykonać właśnie coś takiego. Ogólnie piszę przy użyciu visual stduio 2008 c# i biblioteki Tao.Framework, ale to chyba nie ma większego znaczenia, jesli macie jkieś linki z przykładami to chetnie bym poczytał ewentualnie jakby ktoś mógł jakiś prosty fragment kodu napisać, naprowadzić mnie na tok działania.

Taka przykładowa bryła.



Może lepiej do tego wykorzystać jakiś silnik graficzny?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline beem

  • Użytkownik
    • Wordpress Blog

# Październik 28, 2011, 15:50:20
Rozwiązania szukaj pod hasłami: subdivision surface, teselation, Catmull–Clark algorythm, powierzchnie NURBS. Jeśli masz kartę zgodną z DX11 lub OGL4.0 możesz taki algorytm przeprowadzić sprzętowo po stronie GPU.

Offline Reeevas

  • Użytkownik

# Październik 28, 2011, 16:13:05
Czyli tworząc prostą siatkę sześcianu

O taką:



Używając metod subdivision Opengl automatycznie zagęści mi siatkę chodzi mi czy stworzy coś takiego jak ta siatka tego rysunku z mojego pierwszego posta (tego jajka)? Czy tak zagęszczoną siatkębęde mógł edytować, wybierając np. któryś wierzchołek.

Offline beem

  • Użytkownik
    • Wordpress Blog

# Październik 28, 2011, 16:22:50
To zależy od algorytmu. Catmull-Clark zagęści i równocześnie wygładzi, więc sześcian z każdym krokiem podziału trójkątów będzie zamieniał się w kulę. Natomiast co do edycji wierzchołków podstawowa sprawa to możliwość wybrania odpowiedniego wierzchołka za pomocą np. kursora. Wtedy trzeba poczytać sobie o mouse picking.

Offline Reeevas

  • Użytkownik

# Październik 28, 2011, 16:27:35
Dzieki za szybkie odpowiedzi, w takim razie powiedz mi czego miałbym użyć jakiego algorytmu o ile taki istnieje powiedzmy taką siatkę:



Czy trzeba to robić na około samemu. Czyli dla nowej gęstości przeliczać jeszcze raz punkty siatki.

Offline beem

  • Użytkownik
    • Wordpress Blog

# Październik 28, 2011, 16:41:15
Dla takich prostych kanciastych brył typu sześcian, ostrosłup itp. czyli tam, gdzie chcemy uniknąć wygładzania krawędzi a jedynie zagęścić siatkę, najlepszą metodą byłoby przeliczanie na nowo wierzchołków zgodnie ze stopniem podziału. Dla bardziej skomplikowanych, niekanciastych brył, gdy przy podziale chcesz uzyskać gładsze powierzchnie, wtedy stosujesz któryś z powyższych algorytmów.

Offline Reeevas

  • Użytkownik

# Październik 28, 2011, 16:58:25
Hmmm... ee przeliczanie bleh no ok, dokładniej to mi chodzi o coś takiego (nie tyle o samo wygładzanie ) co o powstanie nowej "niestandardowej bryły"

Czyli łapie za punkt narysowałem to na rysunku, przeciągam w prawo i zmieniam kształt i to nie ważne, czy dla sześcianu czy sfery czy czworoboku... Dzięki za cierpliwość i wyrozumiałość, myślę, że temat ciekawy dla wielu osób.

Rysunek w linku bo coś niedziała z tego serwera tutaj rysunek.

http://imageshack.us/photo/my-images/836/secondlifecuberegularme.jpg/

Mam nadzieję, że dzrozumiale wytłumaczyłem.
« Ostatnia zmiana: Październik 28, 2011, 17:00:34 wysłana przez Reeevas »

Offline beem

  • Użytkownik
    • Wordpress Blog

# Październik 28, 2011, 17:16:45
Ale o co właściwie pytasz? Jak odkształcić bryłę przesuwając wierzchołki? Musisz przelecieć pętlą po wszystkich wierzchołkach i zmieniasz pozycję tylko tego i o taką wartość, jaką sobie zażyczysz. A który to ma być wierzchołek, zależy od tego który sobie np. wybierzesz myszą (właśnie korzystając z mouse picking).

Offline voytech

  • Użytkownik

# Październik 28, 2011, 19:53:39
To zależy od algorytmu. Catmull-Clark zagęści i równocześnie wygładzi, więc sześcian z każdym krokiem podziału trójkątów będzie zamieniał się w kulę.

będzie to kula ale pod jednym warunkiem. Algorytm musi operować  na modelu złożonym z quadów, bo jak wcześniej dokonamy triangulacji to wygładzony tym algorytmem model będzie co najwyżej okrągły a nie kulisty :)

@Reeevas
Najlepiej zrobić tak jak w Blenderze, czyli modyfikatory. W ramie mamy siatkę we własnym formacie, gdzie możemy mieć dowolne n-gony a nie tylko same trójkąty i dołączony do modelu modyfikator np. Sub-surf, któremu można ustawiać dowolny stopień podziału.

Przesuwamy sobie tylko wierzchołki modelu bazowego i po każdej takiej zmianie, wywołujemy metodę/funkcję updateVBO(), która tworzy dodatkowe fejsy, przerabia na same trójkąty dla GPU  i wysyła do VBO.

Można dodać dodatkowo metodę ApplyModyfier, która siatkę bardziej szczegółową kopiuje w miejsce bazowej, żeby później edytować te dodatkowe wierzchołki.

Offline Reeevas

  • Użytkownik

# Październik 29, 2011, 01:12:09
Oooo... zbliżamy się właśnei do tego co chcę zrobić, gdzie mogę poczytać na temat tych modyfikatorów, albo inaczej od czego mam zacząć żeby właśnie coś takeig ostworzyć.

Offline voytech

  • Użytkownik

# Październik 29, 2011, 12:23:38
No nie wiem, można zacząć od takich prostych struktur:

class Mesh {}
class GPUmesh {}

class Object {
   Mesh *base_mesh;
   GPUmesh *render_mesh;
   
   bool subsurf;
   int subsurf_level;
   Mesh *subsurf_mesh;

   void updateSubSurfMesh() {}
   void updateRenderMesh(Mesh *mesh) {}
   ...
}

Klasa Mesh to model bazowy z n-gonami, wtedy algorytmy podziału i inne będą lepiej działały. Klasa GPUmesh to tylko same trójkąty, żeby dane były zgodne z API OGL lub Direct3D.

Następna to klasa Object, która musi przechowywać siatkę bazową, siatkę renderowalną i parę zmiennych dla subsurfa. Metoda updateRenderMesh() wywoływana w odpowiednim dla niej momencie, powinna konwertować Mesh => GPUmesh, czyli najczęściej robić triangulację n-gonów. Wywołanie powinno wyglądać mniej więcej tak:
if (subsurf) {
    updateRenderMesh(subsurf_mesh);
} else {
    updateRenderMesh(base_mesh);
}

wygląda to jak w starym Blenderze, jeden wkomponowany na stałe w obiekt modyfikator subsurf. Proste w implementacji. Jak chcesz mieć stos modyfikatorów to musisz stworzyć jakąś klasę "class Modifier {}" i w Object trzymać listę modyfikatorów.

Offline Reeevas

  • Użytkownik

# Październik 29, 2011, 14:00:04
Hmmm... jezeli chodzi o drugą cześć to chyba mnie więcej łapię Twój pomysł poprostu modyfikator nie zmieniałby siatki od której zaczynam i byłaby ona edytowalna cały czas?...
Nie mogę jednak pojąć pierwszej cześci, w jaki sposób stworzyć własny format siatki? Miałaby być to klasa z obiektami typu sześcian, sfera, czworościan itp. i dla każdej z nich napisać algorytm podziału jej na części?

Offline voytech

  • Użytkownik

# Październik 29, 2011, 16:08:57
Hmmm... jezeli chodzi o drugą cześć to chyba mnie więcej łapię Twój pomysł poprostu modyfikator nie zmieniałby siatki od której zaczynam i byłaby ona edytowalna cały czas?...

Dokładnie. Tak robi to np. Blender, jak dasz mu subsurfa to na ekranie widać wygładzony model ze zwiększoną ilością fejsów, ale przesuwać możesz tylko wierzchołki modelu bazowego. Jak chcesz modyfikować ten malutkie fejsy to trzeba wcisnąć "Apply" na modyfikatorze, czyli zmienić model bazowy na ten dokładniejszy. W przykładowym kodzie mogłoby to wyglądać tak:
void applySubsurf() {
    delete base_mesh;
    base_mehs = subsurf_mesh;
    subsurf_mesh = 0;
    subsurf = false;
    updateRendeMesh(base_mesh);
}

Nie mogę jednak pojąć pierwszej cześci, w jaki sposób stworzyć własny format siatki? Miałaby być to klasa z obiektami typu sześcian, sfera, czworościan itp. i dla każdej z nich napisać algorytm podziału jej na części?

nie, własny format siatki to klasa, która przechowuje fejsy o dowolnej ilości trójkątów:
struct Face {
    unsigned int *verticeis;
    int num_of_verts; // 3 or more
    Vec3 face_normal;
    bool smooth;
    ...
}

struct GPUface {
    unsigned int v1, v2, v3;
}

zauważ jak uboga jest struktura GPUface. Niestety tylko takie coś akceptuje karta grafiki i przy edycji byłoby to uciążliwe, bo np. użytkownik zaznacza jeden wierzchołek sześcianu, a faktycznie w kodzie trzeba przeszukać całą tablicę bo tam są akurat 3 punkty. Każdy face może mieć inne cieniowanie (smooth,flat), różny materiał, kolor, współrzędne uv, itd. Mesh oprócz listy wierzchołków i fejsów może przechowywać listę krawędzi, które mają stopień ostrości wpływający na subsurfa.  Lepiej więc chyba trzymać siatki we własnym formacie, bo różne algorytmy do modyfikacji geometrii mogą być prostsze w implementacji. Twój wybór

Co do sześcianu, sfery, czworościanu ..., to wszystkie mogą być obiektami klasy Mesh, a jedynie trzeba stworzyć funkcje tworzące te proste bryły geometryczne:
Mesh* createCube(float size);
Mesh* createSphere(int segments, int rings, float size);
Mesh* createFromOBJFile(char* filename);

Proste bryły możesz ładować z pliku, z zasobów, ich dane zaszyć w kodzie albo generować je jakimś algorytmem.

Offline Reeevas

  • Użytkownik

# Październik 29, 2011, 17:25:50
Dzięki voytech za szybkie odpowiedzi.... normalnie peirwsze forum na ktróym ludzie mają pojęcie o tym co mówią....
Załóżmy teraz, że chciałbym narazie tworzyć jedynie siatki trójkątów, czyli z techo co napisałeś coytech mógłbym np. wykorzystać bibliotekę glut i stworzyć np. sferę za pomocą tego:
void glutWireSphere( GLdouble radius, GLint slices, GLint stacks )
I co dalej jak tworzytć te siatki w tej kalsie mesh? Zebym mógl je zagęszczać....
Sorry, że tak męczę, ale myślę, że temat cieakwy dla wielu osób... nie tylko dal mnie i przydatny innym w przyszłości.

Offline Kuba D.

  • Użytkownik

# Październik 29, 2011, 18:27:14
Nie, w glut-owskich siatkach nie sposob sie dobrac do wierzcholkow. Generowanie geometrii dla sfery to jest w zasadzie tylko zabawa sin/cos.