„Számítógépes grafika házi feladat tutorial” változatai közötti eltérés
| 2 174. sor: | 2 174. sor: | ||
| http://i.imgur.com/vGETS3t.png || http://i.imgur.com/3benYFM.png | | http://i.imgur.com/vGETS3t.png || http://i.imgur.com/3benYFM.png | ||
|} | |} | ||
=== Egyszerű kamera === | |||
A végleges házikban a kamera általában valamilyen mozgatható objektumot követ. Ennek az implementálása nagyon egyszerű, minden rajzolás elején egységmátrixot töltünk a GL_MODELVIEW-ba, majd a gluLookAt(objektum pozíciója, objektum pozíciója + orientációja, felfele) függvényhívással megoldható. | |||
Viszont ezzel nehézkes a debuggolás, nem lehet igazán jól körülnézni, és valós játékokban is ritka az ennyire egyszerű kamera. | |||
Én egy egyszerű szabadon-repülő kamera egy implementációjához adok ötletet, ez még a negyedik házinál sokat segíthet a debuggoláshoz. | |||
Kétféle input érdekel minket, a billentyűlenyomások (W,A,S,D), és az egér mozgatása (úgy, hogy közbe az egyik egérgomb le van nyomva). | |||
A billentyűlenyomásokat nem kezelhetjük egyszerűen az onKeyboard-ban, ez akkor generál eseményeket, amikor egy karaktert begépelnénk, ami pl megtörténik először a billentyű lenyomásakor, aztán jelentős ideig (kb. 0.3 - 0.5 sec) nem generálódik újabb esemény, majd után másodpercenként kb. 10-20 karakterbeütés-t generál. És ez nekünk nagyon jó, helyette inkább tároljuk el, hogy az egyes billentyűk mikor vannak lenyomott állapotban. | |||
<br/> <syntaxhighlight lang="c"> | |||
enum ControllKeys {W, A, S, D, keys_num}; | |||
bool keys_down[keys_num]; | |||
void onKeyboard(unsigned char key, int, int) { | |||
switch(key) { | |||
case 'w': case 'W': | |||
keys_down[W] = true; | |||
break; | |||
case 's': case 'S': | |||
keys_down[S] = true; | |||
break; | |||
case 'a': case 'A': | |||
keys_down[A] = true; | |||
break; | |||
case 'd': case 'D': | |||
keys_down[D] = true; | |||
break; | |||
} | |||
} | |||
void onKeyboardUp(unsigned char key, int, int) { | |||
switch(key) { | |||
case 'w': case 'W': | |||
keys_down[W] = false; | |||
break; | |||
case 's': case 'S': | |||
keys_down[S] = false; | |||
break; | |||
case 'a': case 'A': | |||
keys_down[A] = false; | |||
break; | |||
case 'd': case 'D': | |||
keys_down[D] = false; | |||
break; | |||
} | |||
} | |||
</syntaxhighlight> <br/> | |||
Ahhoz, hogy ezt fel tudjuk használni, a kamerának tudnia kell, hogy hol van, merre néz, és milyen gyorsan tud mozogni. | |||
<br/> <syntaxhighlight lang="c"> | |||
Vector fwd, pos; | |||
const float speed; | |||
void updatePos(float dt) { | |||
Vector up = Vector(0, 1, 0), right = cross(fwd, up).normalize(); | |||
up = cross(right, fwd).normalize(); | |||
if(keys_down[W] && !keys_down[S]) { | |||
pos += fwd * speed * dt; | |||
} else if(keys_down[S] && !keys_down[W]) { | |||
pos -= fwd * speed * dt; | |||
} | |||
if(keys_down[D] && !keys_down[A]) { | |||
pos += right * speed * dt; | |||
} else if(keys_down[A] && !keys_down[D]) { | |||
pos -= right * speed * dt; | |||
} | |||
} | |||
</syntaxhighlight> <br/> | |||
Ennek a meghívását pl az onIdle-ben tehetjük meg az alábbi módon: | |||
<br/> <syntaxhighlight lang="c"> | |||
void onIdle() { | |||
static float last_time = glutGet(GLUT_ELAPSED_TIME); | |||
float time = glutGet(GLUT_ELAPSED_TIME); | |||
float dt = (time - last_time) / 1000.0f; | |||
last_time = time; | |||
camera.updatePos(dt); | |||
glutPostRedisplay(); | |||
} | |||
</syntaxhighlight> <br/> | |||
Továbbá az egér mozgatást is kezelnünk kell. | |||
<br/> <syntaxhighlight lang="c"> | |||
const float mouse_speed; | |||
void updateDir(int dx, int dy) { | |||
Vector y_axis = Vector(0, 1, 0), right = cross(fwd, y_axis).normalize(); | |||
Vector up = cross(right, fwd).normalize(); | |||
// Ha teljesen felfele / lefele néznénk, akkor ne forduljon át a kamera | |||
float dot_up_fwd = dot(y_axis, fwd); | |||
if(dot_up_fwd > 0.95f && dy > 0) { | |||
dy = 0; | |||
} | |||
if(dot_up_fwd < -0.95f && dy < 0) { | |||
dy = 0; | |||
} | |||
// Módosítsuk az nézeti irányt | |||
fwd += mouse_speed * (right * dx + up * dy); | |||
fwd.normalize(); | |||
} | |||
</syntaxhighlight> <br/> | |||
Ennek a meghívására pedig az onMouseMotion függvény alakalmas: | |||
<br/> <syntaxhighlight lang="c"> | |||
int last_x, last_y; | |||
void onMouse(int, int, int x, int y) { | |||
last_x = x; | |||
last_y = y; | |||
} | |||
void onMouseMotion(int x, int y) { | |||
camera.updateDir(x-last_x, last_y-y); | |||
last_x = x; | |||
last_y = y; | |||
} | |||
</syntaxhighlight> <br/> | |||
A kamera beállítása ezek után már csak egyetlen függvényhívás: | |||
<br/> <syntaxhighlight lang="c"> | |||
gluLookAt(pos.x, pos.y, pos.z, pos.x+fwd.x, pos.y+fwd.y, pos.z+fwd.z, 0, 1, 0); | |||
</syntaxhighlight> <br/> | |||
Egy ilyesfajta kamera már a közepesen komplex jelenetek összeállításban is nagyon sokat tud segíteni. Például az én verzióm így néz ki működés közben: | |||
http://oi59.tinypic.com/2gtdb0i.jpg | |||
== Utóhang == | == Utóhang == | ||