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

Euler2a

Poniżej lista obiektów jakie możemy stworzyć (zaczerpnięta z root users guide);

 Klasa Wygląd                    
TGeoBBox  060001B6  
TGeoPara 060001B7  
TGeoTrd1  060001B8  
TGeoTrd2  060001B9  
TGeoTrap  image443  
TGeoGtra  060001BB  
TGeoArb8  080001BC  
TGeoTube  060001BD  
TGeoTubeSeg  060001BE  
TGeoCtub  060001BF  
TGeoEltu  060001C0  
TGeoHype 080001C1   
TGeoCone  060001C2  
TGeoConeSeg  060001C3  
TGeoSphere  060001C4  
TGeoTorus  060001C5  
TGeoParaboloid  080001C6  
TGeoPcon 060001C7   
TGeoPgon  060001C8  
TGeoXtru 030001C9  
     

 

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ę):