Nody - czyli animacje OpenGL w ROOT
Generowanie kryształu w OpenGL
Zacznę od w miarę prostego przykładu generującego fragment kryształu.
#define sizeBase 20.0 #define sphere_radii 0.3 TGeoVolume *top ; TGeoManager *geom ; TGeoMedium *medSolid; Int_t objects; struct Point{ Double_t x,y,z; }; void InitGeo(){ objects =0; geom = new TGeoManager("LODTest", "GL viewer LOD test"); TGeoMaterial *matEmptySpace = new TGeoMaterial("EmptySpace", 0, 0, 0); matEmptySpace->SetFillColor(kBlack); TGeoMaterial *matSolid = new TGeoMaterial("Solid" , .938, 1., 10000.); TGeoMedium *medEmptySpace = new TGeoMedium("Empty", 1, matEmptySpace); medSolid = new TGeoMedium("Solid", 1, matSolid); top = geom->MakeBox("WORLD", medEmptySpace, sizeBase, sizeBase, sizeBase); top->SetFillColor(kBlack); top->SetLineColor(kBlack); geom->SetTopVolume(top); gRandom->SetSeed();("Empty", 1, matEmptySpace); medSolid = new TGeoMedium("Solid", 1, matSolid); top = geom->MakeBox("WORLD", medEmptySpace, sizeBase, sizeBase, sizeBase); top->SetFillColor(kBlack); top->SetLineColor(kBlack); geom->SetTopVolume(top); gRandom->SetSeed(); matSolid->SetFillColor(kBlack); } void AddBall(Point point){ TGeoVolume *Point =geom->MakeSphere("sphere",medSolid,0,sphere_radii); Point->SetLineColor(kRed); TGeoTranslation *trans = new TGeoTranslation(point.x,point.y,point.z); TGeoRotation *rot = new TGeoRotation("z",90,0,0); top->AddNode(Point,objects,new TGeoCombiTrans(*trans, *rot)); objects++; } void kulki(){ InitGeo(); Point pkt; pkt.x =1.0; pkt.y =1.0; pkt.z = 1.0; for(int i=0;i<5;i++){ for(int j=0;j<5;j++){ for(int k=0;k<5;k++){ pkt.x=i-2.5; pkt.y=j-2.5; pkt.z=k-2.5; AddBall(pkt); } } } geom->CloseGeometry(); top->Draw("ogl"); }
W kodzie są dwie główne funcje - InitGeo i AddBall. InitGeo tworzy "świat". Proces przebiega w kilku etapach:
- utworzeniu TGeoManagera
- utworzeniu TGeoMaterial czyli materiałów z których będą budowane TGeoMedium
- z TGeoMaterial tworzy się TGeoMedium czyli ośrodek z którego już możmna budować jakieś obiekty
- następnie tworzy się tzw. TopVolume - czyli wolumen "wszechświata" do którego "wsadzane" będą mniejsze obiekty
.
Jak dodawać wolumeny
Po utworzeniu "wszechświata" trzeba go jakoś wypełnić. W tym celu należy utworzyć tzw. TGeoVolume - czyli wolumeny zawierającę konkretne bryły, sam wolumen ma określone medium z któretgo jest zrobiony i własne wymiary. Można też na tym etapie zmieniać kolor danego wolumenu. Żeby jednak dodac wolumen do wszechświata trzeba mu jeszcze podać położenie (TGeoTranslation, które koresponduje z geometrycznym środkiem wstawianego wolumenu a nie niego krawędzią) i orientację kątową (TGeoRotation które w przypadku kuli akurat nie gra roli ze wzlędu na symetrię kątową tej bryły). Po stworzeniu i ustawieniu wolumenu można go dodać do topowego nodu, zamknąć geometrię i wyświetlić.
Jeśli chodzi o dodawanie wolumenów to należy zwrócić uwagę na dwie rzeczy:
- nie trzeba dodawać wszystkich nodów do nodu Top, geometria jest tu opisana podobnie jak w Geantie tj. moduł Top jest babką która może mieć córki z których każda może mieć do siebie dodane córki-wnuczki, i tak dalej i tak dalej
- kąty są podawane w specyficznym układzie - tj. konwencji Eulera - najpierw obracamy bryłę wzłuż OZ potem wzdłuż OX' (' bo obrót na OZ wymusił zmainę) a następnie wokół OZ ' (obrót na OX też zmienia układ), poniżej graficzne wyjaśnienie jak należy rozumieć ideę tych kątów
Poniżej lista obiektów jakie możemy stworzyć (zaczerpnięta z root users guide);
Rzuty, pozycja kamery
Oczywiście to nie wszystkie możliwości tego co można zrobić z OpenGL. Oprócz możliwości narysowania czegokolwkiek poprzez składanie z prostych obiektów czegoś bardziej złożonego można np. zmienić ustawienie kamery czy oświetlenia, można tego dokonać zarówno z panelu TGLViewera klikając odpowiednie opcje, jak i można wymusić takie zmiany w kodzie przykładowo:
... top->Draw("ogl"); TGLViewer * v = (TGLViewer *)gPad->GetViewer3D(); v->SetClearColor(kGray); v->SetCurrentCamera(TGLViewer::kCameraOrthoZOY);
Wymusi zmianę koloru tła i rotację kamery. Poniżej dla porównania zamieściłem wykres przed i po zastowaniu tego kodu. Domyślnie bowiem wyświetli się obrazek:
Obrazek po ustawieniu kamery ortogonalnie będzie zaś wyglądał tak:
Co więcej po ustawieniu kamery nie będziemy mogli bezpośrednio "kręcić" całym obrazkiem, można jednak kręcenie oblokować poprzez Camera>Orho Allow Rotate. Innym potencjalnym zastosowaniem OpenGL jest możliwość tworzenia animacji co można zrobić na dwa sposoby: klikając myszką na odpowiednie opcje - co daje możliwość zoomowania, obracania modelem 3D, zmieniania oświetlenia, a także daje możliwość tworzenia obrazków, serii obrazków bądź animowanych gif-ów. Druga opcja to manipulowanie kodem które poprzez oprócz zmian dokonanych wcześniej można dodatkowo zmieniać geometrię obiektu (np. poprzez usuwanie i wstawianie od nowa nodów) co pozwala wykonywać animacje jak np. taka (z góry sorry za literówkę):