GrafikaGyakorloAnimacio

A VIK Wikiből
A lap korábbi változatát látod, amilyen (vitalap) 2012. október 21., 19:58-kor történt szerkesztése után volt. (Új oldal, tartalma: „{{GlobalTemplate|Infoalap|GrafikaGyakorloAnimacio}} ===Mintakérdések a Számítógépes grafika és képfeldolgozás tárgy vizsgájára való felkészüléshez=== …”)
(eltér) ← Régebbi változat | Aktuális változat (eltér) | Újabb változat→ (eltér)
Ugrás a navigációhoz Ugrás a kereséshez

Ez az oldal a korábbi SCH wiki-ről lett áthozva. Az eredeti változata itt érhető el.

Ha úgy érzed, hogy bármilyen formázási vagy tartalmi probléma van vele, akkor kérlek javíts rajta egy rövid szerkesztéssel.

Ha nem tudod, hogyan indulj el, olvasd el a migrálási útmutatót


Mintakérdések a Számítógépes grafika és képfeldolgozás tárgy vizsgájára való felkészüléshez

Animáció

116. Írjon Animate függvényt C++-ban, amely egy galaxis égitestjeinek a helyzetét (newtoni) fizikai animációval számítja ki a t időpillanatra. Összesen 100 égitest van, amelyek tömegei az m[100] tömbben, sugaraik az r[100] tömbben vannak. Az égitestek kezdeti helyzetei (x[100], y[100], z[100]) tömbökben találhatók. A t=0 időpillanatban az égitestek állnak. Az égitestek ütközése teljesen rugalmatlan (figyelem, az impulzus megmarad!), azaz ütközéskor összetapadnak, innentől úgy tekintjük őket, mint egy gömböt, amelynek sugarai a találkozó gömbök sugarainak összege. A Newton-féle gravitációs állandó f.

  • Még pár globális változó, amire szükség van: vx, vy, vz tömbök a sebességet tárolják, prevT a legutóbbi időpillanatot, amikor meg volt hívva az Animate, nextIter két hívás közt tárolja, hanyadik iteráció következik majd, dt a szimuláció lépésköze, num az aktuális száma az objektumoknak (az összetapadások miatt ez változhat).
  • Animate minden híváskor kiszámolja, hány lépésnyit kell futtatni a szimulációt. Minden lépésben először az összes objektum gyorsulását számolja a helyzete alapján, majd a sebességét a gyorsulása, aztán a helyzetét a sebessége alapján, végül meghívja checkMerge-et. checkMerge minden objektumpárra megvizsgálja, érintkeznek-e, és ha igen, merge segítségével (az impulzus- és tömegközéppontmegmaradási tételt figyelembe véve) egyesíti őket. Az egyesítés hatására keletkezhetnek új érintkezések, ezért ilyenkor mindig újra végignéz mindent.
float vx[100], vy[100], vz[100];
float prevT=0;
int nextIter=0;
float dt=0.01;
int num=100;

void getAccel(int obj, float* ax, float* ay, float* az) {
  float dx, dy, dz, temp;
  ax=ay=az=0;
  for (int i=0; i<num; i++) {
	 dx=x[i]-x[obj];
	 dy=y[i]-y[obj];
	 dz=z[i]-z[obj];
	 temp=pow(dx*dx+dy*dy+dz*dz, -1.5)*f*m[i];
	 ax+=dx*temp;
	 ay+=dy*temp;
	 az+=dz*temp;
  }
}

void merge(int i, int j) {
  float c=m[i]/(m[i]+m[j]);
  x[i]=x[i]*c+x[j]*(1-c);
  y[i]=y[i]*c+y[j]*(1-c);
  z[i]=z[i]*c+z[j]*(1-c);
  vx[i]=vx[i]*c+vx[j]*(1-c);
  vy[i]=vy[i]*c+vy[j]*(1-c);
  vz[i]=vz[i]*c+vz[j]*(1-c);
  r[i]=r[i]+r[j];
  for (int k=j+1; k<num; k++) {
	 x[k-1]=x[k];
	 y[k-1]=y[k];
	 z[k-1]=z[k];
	 vx[k-1]=vx[k];
	 vy[k-1]=vy[k];
	 vz[k-1]=vz[k];
	 r[k-1]=r[k];
	 m[k-1]=m[k];
  }
  num--;
}

void checkMerge() {
  bool merged=true;
  float dx, dy, dz;
  while (merged) {
	 merged=false;
	 for (int i=0; i<num; i++) {
		for (int j=i+1; j<num; j++) {
		  dx=x[i]-x[j];
		  dy=y[i]-y[j];
		  dz=z[i]-z[j];
		  if (dx*dx+dy*dy+dz*dz<(r[i]+r[j])*(r[i]+r[j])) {
			 merge(i, j);
			 merged=true;
		  }
		}
	 }
  }
}

void Animate(float t) {
  float ax, ay, az;
  for (int i=nextIter; i<(int)(t/dt); i++) {
	 for (int j=0; j<num; j++) {
		getAccel(j, &ax, &ay, &az);
		vx[j]+=ax*dt;
		vy[j]+=ay*dt;
		vz[j]+=az*dt;
	 }
	 for (int j=0; j<num; j++) {
		x[j]+=vx[j]*dt;
		y[j]+=vy[j]*dt;
		z[j]+=vz[j]*dt;
	 }
	 checkMerge();
  }
  prevT=t;
  nextIter=(int)(t/dt);
}

117. Inverz kinematika. Cél. Új állapot meghatározása. Pszeudo-inverz. Algoritmus.

  • Animációban, robotikában szokott előállni az a helyzet, hogy valaminek a helyzetét egy összetett transzformációval lehet meghatározni. Pl. a váll helyzetéből egy eltolással és forgatással kapjuk meg a könyök helyzetét, abból hasonlóan a csuklóét. Mindkét transzformációnak vannak bizonyos szabadságfokai: a felkarnak a hossza állandó, de az iránya bármilyen lehet, és csavarodhat is a tengelye körül, az alkarnak is állandó a hossza, de (a könyökízület jellege miatt) csak egy körön mozoghat, és csavarodni is kevésbé tud. Másfajta szabadságfokok (pl. 122., 123., 128. feladat) is előfordulhatnak.
  • Ha ismerjük az egyes szabadságfokok állapotát (pl. váll- és könyökízület szöge, csavarodása), akkor általában könnyű számítani a kar végének (end effektor) helyét és helyzetét, a gyakorlatban viszont gyakrabban van szükség a fordítottjára: adott helyre, adott pályán akarjuk mozgatni a kart, hogyan vezéreljük ehhez a csuklókat?
  • Általában az összetett transzformáció nemlineáris, és több szabadságfokunk van, mint ahány paramétere az end effektornak (pl. két gömbcsukló összesen 4 szabadságfok, de ha az end effektornak csak a helyzete érdekel, az csak 3 beállítandó paraméter), tehát egy több megoldású nemlineáris egyenletrendszert kell megoldanunk. Erre közelító módszereket szoktak használni, az egyik a Jacobi-mátrix pszeudoinverze.
  • Ha [math] E_i [/math] az end effektor i. paramétere, és [math] S_j [/math] a j. szabadságfok, akkor a Jacobi-mátrix i. sorának j. eleme [math] \frac{\partial E_i}{\partial S_j} [/math] Ha ugyanannyi szabadságfok van, mint end effektor paraméter, akkor ez egy négyzetes mátrix, és az inverze segítségével számítható, hogy egy kicsi [math] \Delta\underline{E} [/math] változáshoz hogyan változtassuk [math] \underline{S} [/math]-t. Általában nem ez a helyzet, és az inverz helyett a nem négyzetes mátrixokra is értelmezett pszeudoinverzet kell használni: [math] J^+=(J^T J)^{-1}J^T [/math] Így, felbontva az end effektor kívánt mozgását kicsi [math] \Delta\underline{E} [/math] lépésekre, mindegyikhez előállítható az állapotváltozók szükséges változtatása: [math] \Delta\underline{S}=J^+ \Delta\underline{E} [/math]
  • Wikipédia: pszeudoinverz
  • Wikipédia: Inverz kinematika
  • Wikipédia: Animáció inverz kinematikával

118. Adja meg a forward és inverz kinematikát alkalmazó mozgástervezés lépéseit és hasonlítsa össze lehetőségeit!

119. Adott egy kör alakú biliárdasztal. Az asztal középpontjában vesszük fel a koordinátarendszerünket. Az asztal sugara R. Írjon Animate függvényt C++-ban, amely kiszámítja egy biliárdgolyó helyzetét a t időpillanatra, feltételezve, hogy t=0-ban a golyót az (x0, y0) pontból és (vx, vy) kezdősebességgel indítottuk el, csak ez az egyetlen golyó az asztalon, a golyó az asztal oldalával tökéletesen rugalmasan ütközik, és a súrlódást elhanyagoljuk.

120. Vesse össze a Lagrange interpolációs görbét, a B-spline-t és a NURBS-t az animációs mozgásgörbék szempontjából. Táblázatosan mutassa be, hogy milyen előnyös és hátrányos tulajdonságaik vannak. A tulajdonságok között feltétlenül szerepeljenek az alábbiak: konvex burok tulajdonság, lokális kontroll, paraméter-idő hozzárendelés, interpolációs tulajdonság.

121. Egy labda pattogását a magasságfüggvény kulcspozícióival (keyframe) adjuk meg: t=0: y=0; t=1: y=1; t=3: y=0; t=6: y=1. Mi a labda y koordinátája t=2-kor, ha Catmull-Rom spline-t használunk interpolációra (a Catmull-Rom spline a Kochanek-Bartels spline speciális esete, amikor [math] \tau [/math] zérus, [math] \beta [/math] pedig 0.5).

122. Adott egy, a koordinátarendszer origójában rögzített csukló, amely a z tengely körüli elfordulását és a hosszát képes változtatni. Írja fel a rendszer Jacobi mátrixát. Írjon programot, amely csukló másik végpontját a [1,1], [0, 2] pontok között egyenletes sebességgel végigvezeti. Feltételezheti, hogy az adott programozási nyelven a mátrixműveletek rendelkezésre állnak.

123. Adott egy 2D világban mozgó robotkar, amelynek egyik vége az origóhoz rögzített. A robotkar a rögzített vége körül el tud fordulni, és a hosszát is meg tudja változtatni. Írja fel a robotkar Jacobi mátrixát, állítsa elő a mátrix pszeudoinverzét. Írjon C++ függvényt, amely dt időszeletenként lépdelve kiszámítja a robotkar elfordulási szögét és hosszát, ha annak nem rögzített végét az x(t), y(t) pályán kell végigvezetni.

124. Egydimenziós mozgást kulcskeret animációval definiál. A tárgy a t=0 időpillanatban az x=0 pontban, a t=1 időpillanatban az x=1 pontban, a t=2 időpillanatban megint az x=0 pontban van. A mozgás nyugalmi helyzetből indul és így is fejeződik be (sebesség zérus). Hol van a tárgy a t=0.4 időpontban, ha Catmull-Rom spline-nal interpolálunk?

125. Saját magát szeretné egy animációs filmben szerepeltetni, amint éppen egy lépcsőfokra föllép. Írja le pontokként, hogy ehhez mit kell tenni, ha kulcskeret (keyframe) animációs eljárást használ.

126. Saját magát szeretné egy animációs filmben szerepeltetni, amint éppen egy lépcsőfokra föllép. Írja le pontokként, hogy ehhez mit kell tenni, ha mozgáskövető (motion tracking) animációs eljárást használ.

127. Egy létező tárgy 3D modelljét szeretné létrehozni. Hogyan valósítható meg a sztereolátás alkalmazásával? Mi változik, ha 2-nél több kamerát használ?

128. Adott egy két transzlációs csuklót tartalmazó robot. A transzlációs csukló orientációja állandó, csak a hosszát képes változtatni. Az ábra szerint, az első csukló x irányú eltolást, a második y irányú eltolást jelenthet. Írja fel a robot Jacobi mátrixát! Adja meg a mátrix pszeudoinverzét! Hogyan kell vezérelni a csuklókat, hogy az endeffektor egy körön menjen végig [math] 2\pi [/math] szögsebességgel?


Ezen a helyen volt linkelve a Clipboard05.png nevű kép a régi wiki ezen oldaláról. (Kérlek hozd át ezt a képet ide, különben idővel el fog tűnni a régi wikivel együtt)


  • Ha az első csukló állapotát (itt: hosszát) [math] S_1 [/math]-gyel jelöljük, a másodikét pedig [math] S_2 [/math]-vel jelöljük, a kar végpontjának helyzetét pedig [math] (r, \phi) [/math]-vel (mivel majd körön akarunk mozgatni, ezért a polárkoordinátás leírás a célszerű), akkor [math] (r, \phi)=(\sqrt{S_1^2+S_2^2}, atan \frac{S_2}{S_1}) [/math]. A Jacobi-mátrix: [math] J=\left[\begin{array}{cc} \frac{\partial r}{\partial S_1} & \frac{\partial r}{\partial S_2} \\ \frac{\partial \phi}{\partial S_1} & \frac{\partial \phi}{\partial S_2}\end{array}\right] = \left[\begin{array}{cc} \frac{S_1}{\sqrt{S_1^2+S_2^2}} & \frac{S_2}{\sqrt{S_1^2+S_2^2}} \\ \frac{-S_2}{S_1^2+S_2^2} & \frac{S_1}{S_1^2+S_2^2} \end{array}\right][/math]
  • Négyzetes, invertálható mátrix pszeudoinverze megegyezik a szokásos inverzével, azaz itt az inverz: [math] J^+ = \left[\begin{array}{cc} \frac{S_1}{\sqrt{S_1^2+S_2^2}} & -S_2 \\ \frac{S_2}{\sqrt{S_1^2+S_2^2}} & S_1 \end{array}\right][/math] A megkövetelt deriváltja az end effektor helyzetének: [math] (0, 2\pi) [/math], mivel a sugár nem változik, a szög pedig konstans szögsebességgel. Ez alapján a csuklók állapotára: [math] \left[\begin{array}{c} dS_1 \\ dS_2 \end{array}\right] = J^+ \left[\begin{array}{c} 0 \\ 2\pi \end{array}\right] = \left[\begin{array}{cc} -2\pi S_2 \\ 2\pi S_1 \end{array}\right] [/math] és ez alapján a kezdőpozíció felhasználásával már ki lehet számítani (pl. iteratív módszerrel), hogy melyik pillanatban hogyan változzon a csuklók állapota.
  • Inverz kinematika

129. Egy egység tömegű test tömegközéppontjának pályáját egy síkbeli Bézier görbével adhatjuk meg, amelynek vezérlőpontjai: (0,0), (1,1), (2,0). Mekkora eredő erő hat a testre a t=0.33 időpillanatban?

  • A test helyzetének időfüggvénye: [math] r(t)=(x(t), y(t))=(0, 0)(1-t)^2+(1, 1)(2t(1-t))+(2, 0)t^2 = (2t, 2t-t^2) [/math] a rá ható erő pedig a helyvektorának a második deriváltja (a gyorsulása) szorozva a tömegével (ami 1): [math] F(t)=m\cdot(x^{\prime\prime}, y^{\prime\prime})=1\cdot(0, -4)=(0, -4) [/math], tehát a rá ható eredő erő konstans 4, és a negatív y irányba mutat.

130. Egy labdát szeretne animálni kulcskeret animációval, Catmull-Rom spline alkalmazásával. A kulcskeretek a következők (t-vel az időt jelöljük és másodpercben értelmezzük):

  • t=0: a labdát a [0, 1, 0] pontból [1, 1, 0] sebességgel elhajítjuk.
  • t=1: a labda az [1, 2, 0] pontban repül.
  • t=2: a labda a [2, 0, 0] pontba csapódik [1,-1,0] sebességgel, és tökéletesen rugalmatlanul ütközik a talajjal.
  • Tételezzük fel, hogy az előző feladat megoldásául kapott paraméteres egyenletet egy Vector r(float t) függvényben már megvalósítottuk. Egészítse ki az alábbi programot a Labda( ) függvény implementációjával, amely a labda mozgását OpenGL segítségével animálja. A labda fehér, 40x40 háromszögre tesszellált gömb, amelynek sugara 2.*
struct Vector{float x, y, z; };
GLUquadricObj * labda;
Vector r( float t );

void Labda( ) { ... }

main( argc, argv ) {
	  glutInitWindowSize(width, height);  glutInit(&argc, argv);
	  glutInitDisplayMode(GLUT_RGBA| GLUT_DOUBLE | GLUT_DEPTH);
	  glutCreateWindow("Labda");
	  glMatrixMode(GL_PROJECTION); 
	  glLoadIdentity(); 
	  gluPerspective(60, 1, 1, 1000);
	  glMatrixMode(GL_MODELVIEW); 
	  glLoadIdentity();	 
	  labda = gluNewQuadric( );
	  glEnable(GL_DEPTH_TEST);
	  glutDisplayFunc( Labda ); 
	  glutIdleFunc( Labda ); 
	  glutMainLoop();
}  

Segítség: a következő OpenGL függvényekből érdemes válogatni (nem szükségképpen mindet!): glPushMatrix( ), glPopMatrix( ), glColor3f(), glVertex3f(), glTranslatef( ), glRotatef( ), glScalef( ), gluSphere( ); glClearColor( ); glutSwapBuffers(), glTexCoord2f(), glBindTexture(), glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glutGet(GLUT_ELAPSED_TIME);

131. Egy háromszög csúcsainak koordinátái a lokális modellezési koordinátarendszerben [0,0,0], [1,0,0], [0,1,0]. Animálja a háromszöget keyframe (kulcskeret) animáció segítségével úgy, hogy a háromszög orientációja állandó maradjon, a pozíciót pedig a kulcskeretekből lineáris interpolációval számítsa ki! Tételezze fel, hogy a kulcskeretek időértékei a float t[] globális tömbben, az első csúcs pozíciója pedig ezekben a kulcskeretekben a Vector v[] tömbben vannak. A kulcskeretek száma int nf. A rajzolást OpenGL hívásokkal végezze el. Feltételezheti, hogy IdleCallback-ként az Idle függvényt regisztráltuk, tehát csak az Idle-t kell megírni, az inicializálási és kamerabeállító részt nem. A rajzolást GL_TRIANGLES beállítással végezze, a háromszög színe fehér. Az alkalmazás indítása óta eltelt időt glutGet(GLUT_ELAPSED_TIME) hívással kérdezheti le. Segítségnek az ajánlott OpenGL parancsok: glBegin, glEnd, glFlush, glVertex3f, glColor3f, glTranslatef, glPushMatrix, glPopMatrix, glLoadIdentity, glutSwapBuffers, glClear. Mit és hogyan kell változtatni a programban ahhoz, hogy ne lineáris, hanem Catmull-Rom spline interpolációval dolgozzon (a Catmull-Rom spline a Kochanek-Bartels spline speciális esete, amikor [math] \tau [/math] zérus, [math] \beta [/math] pedig 0.5)?

  • Először meghatározzuk, melyik időszeletben vagyunk, vagyis melyik két kulcskeret közt, és hogy annak a szakasznak "hány százalékánál" tartunk. Majd interpoláljuk a két kulcskeretet, megkapva ezzel, hogyan kell eltolni a koordinátarendszert rajzolás előtt.
void Idle() {
  float time=glutGet(GLUT_ELAPSED_TIME), param;
  int interval=-1;
  for (int i=0; i<nf-1; i++) {
	 if (t[i]<=time && time<=t[i+1]) {
		interval=i;
		break;
	 }
  }
  if (interval==-1) return;
  param=(time-t[interval])/(t[interval+1]-t[interval]);
  Vector translate=param*v[interval+1]+(1-param)*v[interval];
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glPushMatrix();
  glTranslate3f(translate.x, translate.y, translate.z);
  glBegin(GL_TRIANGLES);
  glColor3f(1, 1, 1);
  glVertex3f(0, 0, 0);
  glVertex3f(1, 0, 0);
  glVertex3f(0, 1, 0);
  glEnd();
  glPopMatrix();
  glutSwapBuffers();
  glFlush();
}
  • A Catmull-Rom spline a harmadfokú spline speciális esete, ezért az n. és n+1. kulcspont között harmadfokú polinomokkal interpolálunk, amihez felhasználjuk a görbe kulcspontokban felvett deriváltját (v0, v1). Ez Catmull-Rom spline-nál az n-1. és n+1., illetve az n. és n+2. kulcshelyzetekből számítható, illetve a 0. és utolsó kulcspontban külön meg kell adni (vStart, vEnd).
void Idle() {
  /* az eleje ugyanaz, a paraméter kiszámításáig */
  Vector v0, v1;
  if (interval==0 && interval+1==nf) {
	 v0=vStart;
	 v1=vEnd;
  } else if (interval==0) {
	 v0=vStart;
	 v1=(v[interval+2]-v[interval])/2;
  } else if (interval+1==nf) {
	 v0=(v[interval+1]-v[interval-1])/2;
	 v1=vEnd;
  } else {
	 v0=(v[interval+1]-v[interval-1])/2;
	 v1=(v[interval+2]-v[interval])/2;
  }
  float p2=p*p, p3=p*p*p;
  translate=v0*(p3-2*p2+p)+v1*(p3-p2)+v[interval]*(2*p3-3*p2+1)+v[interval+1]*(-2*p3+3*p2);
  /* a rajzoló rész ugyanaz... */
}

132. Az alábbi lövedék röpül a hegyes végét elől tartva (úgy, ahogy egy tisztességes lövedéktől elvárható) a 3D virtuális térben (lásd a lenti rajzot). A lövedék hengeres részének magassága 4 m, a kúpos részének magassága 2 m, átmérője 1.5 m. A lövedék végének középpontja az [x0, y0, z0] pontról indul [vx0, vy0, vz0] kezdősebességgel. A lövedék az ágyúcső hornyolása miatt f [fok/sec] szögsebességgel forog a főtengelye körül. A nehézségi gyorsulás g [m/sec2], a közegellenállás elhanyagolható, ütközés nincs. Írjon C függvényt, amely képletanimációval meghatározza a t pillanatban érvényes mozgásállapotot, és OpenGL függvényhívások segítségével fel is rajzolja a lövedéket. A rajzoláshoz felhasználhatja a Henger() függvényt, amely egy 1 m magasságú, origo középpontú, z tengelyű, 1 m átmérőjű hengert jelenít meg, és a Kúp() függvényt, amely egy xy síkon álló, 1 m magas, 1 m átmérős alapkörrel rendelkező kúpot rajzol fel.


Ezen a helyen volt linkelve a Clipboard06.png nevű kép a régi wiki ezen oldaláról. (Kérlek hozd át ezt a képet ide, különben idővel el fog tűnni a régi wikivel együtt)


  • Frenet kereteket használunk; ez egy speciális, a mozgó test pályájához igazodó koordinátarendszer. Az origója a testhez van rögzítve (nem pontszerű testnél pl. a tömegközépponthoz lehet), z tengelye a mozgás irányába mutat (vagyis a helyvektor első deriváltjával párhuzamos), y tengelye pedig gyorsulással (a helyvektor második deriváltjával) ellentétes irányba. Hogy a tengelyek merőlegesek legyenek, ezért y nem a második derivált ellentettje, hanem annak a z-re merőleges komponense, x pedig értelemszerűen y és z vektorszorzata. Képletekkel: [math] \underline{z}(t)=(\underline{r}(t)^\prime)^0,\; \underline{y}(t)=((\underline{r}^{\prime\prime}(t) \times \underline{r}^\prime(t)) \times \underline{r}^\prime(t))^0,\; \underline{x}(t)=\underline{y}(t) \times \underline{z}(t) [/math] ahol a 0-s kitevő azt jelenti, hogy egységvektor.
  • A test mozgása nagyon egyszerű: [math] \underline{r}^{\prime\prime}(t)=(0, -g, 0) [/math], mert g-vel gyorsul lefelé. Az első deriváltra a kezdetiérték-feltétel: [math] \underline{r}^\prime(0)=(v_{0x}, v_{0y}, v_{0z}) [/math] ez alapján [math] \underline{r}^\prime(t)=(v_{0x}, v_{0y}-gt, v_{0z}) [/math] A hely kezdeti értéke: [math] \underline{r}(0)=(r_{0x}, r_{0y}, r_{0z}) [/math], így [math] \underline{r}(t)=(r_{0x}+v_{0x}t, r_{0y}+v_{0y}t-g\frac{t^2}{2}, r_{0z}+v_{0z}t) [/math]
  • Rajzoláskor először kiszámítjuk a hely-, sebesség- és gyorsulásvektorokat, majd ezekből a Frenet keret bázisvektorait. Először a keretbe transzformálunk, majd a lövedék forgása miatt f*t-vel forgatunk a lövedék tengelye (z) körül, valamint ahhoz, hogy a Kup() és Henger() jó helyre és jó méretben rajzoljon, még kell pár plusz transzformáció.
class Missile {
  Vector r0;
  Vector v0;
  float f;
  void drawCone() {
	 glPushMatrix();
	 glScalef(1.5, 1.5, 2);
	 Kup();
	 glPopMatrix();
  }
  void drawCylinder() {
	 glPushMatrix();
	 glTranslatef(0, 0, -2);
	 glScalef(1.5, 1.5, 4);
	 Henger();
	 glPopMatrix();
  }
  void draw(float t) {
	 Vector r(r0.x+v0.x*t, r0.y+v0.y*t-g*t*t/2, r0.z+v0.z*t);
	 Vector v(v0.x, v0.y-g*t, v0.z);
	 Vector a(0, -g, 0);
	 Vector frenetZ=a.normalize();
	 Vector frenetY=((a%v)%v).normalize();
	 Vector frenetX=frenetY%frenetZ;
	 float frenetTransform[16]={frenetX.x, frenetX.y, frenetX.z, 0,\
										 frenetY.x, frenetY.y, frenetY.z, 0,\
										 frenetZ.x, frenetZ.y, frenetZ.z, 0,\
										 r.x,		 r.y,		 r.z,		 1};
	 glMatrixMode(GL_MODELVIEW);
	 glPushMatrix();
	 glMultMatrix(frenetTransform);
	 glRotatef(f*t, 0, 0, 1);
	 drawCone();
	 drawCylinder();
	 glPopMatrix();
  }
};

133. Egy pontszerű test kétdimenziós mozgását Catmull-Rom spline-nal adja meg. A kulcspontok:

  • t=0: x=0, y=0, vx=VX, vy=VY
  • t=1: x=VX, y=H
  • t=2: x=2VX, y=0, vx=VX, vy=-VY
  • A VX, VY, H értékek konstansok. Adja meg az x(t), x(t) mozgásgörbék algebrai alakján a [0, 1] időintervallumban! (segítség: a Catmull-Rom spline a Kochanek-Bartels spline speciális esete, amikor [math] \tau [/math] zérus, [math] \beta [/math] pedig 0.5).*

134. Marcus Aurelius a barbárok ellen hadakozik. A barbárok kőhajítókkal támadnak, Marcus bátran és mozdulatlanul áll. A sziklák lényegesen kövérebbek Marcusnál, tehát nem lehetne Marcus belsejében elrejteni azokat, viszont nem feltétlenül magasabbak, mint Marcus. Készítsen C++/OpenGL függvényt, amely megjeleníti Marcust és a sziklát a képernyőn, és diszkrét idejű ütközésdetektálási eljárással eldönti, hogy a szikla eltalálja-e Marcust. A függvény bemeneti paraméterei:

  • Marcust definiáló háromszögek tömbje (Tomb hMarcus), Marcus jelenlegi állapotában;
  • a sziklát definiáló háromszögek tömbje (Tomb hSzikla), a szikla referencia állapotában;
  • a szikla jelenlegi helyzetét és orientációját definiáló homogén lineáris transzformáció (float tSzikla[4][4]).
  • Akkor mondjuk, hogy Marcust a szikla eltalálja, ha a szikla AABB-je (axis-aligned bounding box) Marcus valódi geometriájával ütközik (azaz az AABB Marcus bármely belső pontját tartalmazza). Feltételezheti, hogy Marcust definiáló háromszögháló zárt felület. Ütközés esetén a függvény TRUE értékkel tér vissza, egyébként FALSE-szal. Az ütközés felismeréshez használja fel az előző feladat Vagas függvényét. Marcus textúra azonosítója tMarcus, a szikláé tSzikla. A textúra kép betöltésével és a kamera, illetve az ablak beállításával nem kell foglalkozni. A következő OpenGL függvényeket alkalmazza: glBegin, glEnd, glVertex3d, glTexCoord2d, glBindTexture. Segítség: A sziklák és Marcus kövérségére vonatkozó feltétel arra utal, hogy nem kell foglalkozni azzal az esettel, amikor Marcus teljes egészében tartalmazza a sziklát. A Marcus magasságára vonatkozó megjegyzés szerint viszont előfordulhat, hogy egy szikla Marcus háromszöglistájának egyetlen csúcspontját sem tartalmazza, mégis ütközik vele, mert Marcus háromszögei metszik a szikla AABB-jét.*
  • Az inkrementációs képszintézis 94. feladatának dolgait (Vagas függvény, Tomb metódusai, stb.) használtam. A feladatban a szikla textúrájának és transzformációjának neve ugyanaz volt, ezért a textúrákat átneveztem tex*-ra, a transzformációt trans*-ra.
  • Először kiszámítjuk a (transzformált) szikla AABB-jét. Ehhez végigmegyünk mindegyik háromszögének mindegyik csúcsán, és megkeressük mindegyik koordinátának a maximumát és minimumát (min és max függvények a vektorokon koordinátánként működnek). A maximális koordináták lesznek az egyik sarka a bennfoglaló téglatestnek, a minimálisak a másik. Majd, erre a téglatestre vágjuk Marcus összes háromszögét, és megnézzük, van-e olyan háromszög, ami (legalább részben) beleesik a szikla AABB-jébe: ha van, ütköztünk, ha nincs, nem.
  • Ezután egyszerűen kirajzoljuk mindkettőt, majd visszaadjuk, volt-e ütközés.
void draw(Tomb triangles, int tex, float trans[4][4]) {
  glBindTexture(tex);
  glBegin(GL_TRIANGLES);
  for (int i=0; i<hSzikla.Size(); i++) {
	 for (int j=0; j<3; j++) {
		Vector v=triangles.Elem(i).T(j);
		glTexCoord2d(v.x, v.y);
		v=triangles.Elem(i).P(j).transform(trans);
		glVertex3d(v.x, v.y, v.z);
	 }
  }
  glEnd();
}

bool marcus(Tomb hMarcus, Tomb hSzikla, float transSzikla[4][4]) {
  Vector AABBmax(-FLOAT_MAX, -FLOAT_MAX, -FLOAT_MAX);
  Vector AABBmin(FLOAT_MAX, FLOAT_MAX, FLOAT_MAX);
  Tomb temp;
  bool collision=false;
  for (int i=0; i<hSzikla.Size(); i++) {
	 for (int j=0; j<3; j++) {
		Vector v=hSzikla.Elem(i).P(j).transform(transSzikla);
		AABBmax=max(AABBmax, v);
		AABBmin=min(AABBmin, v);
	 }
  }
  Vagas(hMarcus, AABBmin, AABBmax, &temp);
  if (temp.Size()>0) collision=true;
  draw(hSzikla, texSzikla, transSzikla);
  float identity[4][4]={{1, 0, 0, 0},{0, 1, 0, 0}{0, 0, 1, 0}{0, 0, 0, 1}};
  draw(hMarcus, texMarcus, identity);
  return collision;
}

-- G - 2008.12.26.