„Számítógépes grafika házi feladat tutorial” változatai közötti eltérés

Rohamcsiga (vitalap | szerkesztései)
Rohamcsiga (vitalap | szerkesztései)
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 ==