next up previous
Next: OpenGL Up: Programmieren ohne CAVELib Previous: Programmieren ohne CAVELib

Berechnen des Frustums

Die Projektion eines Ausschnittes einer 3dimensionalen (virtuellen) Welt auf einen 2dimensionalen Bildschirm (auf die 3 Wände des Caves) erfolgt mit Hilfe eines Frustums (einer Pyramide mit abgeschnittener Spitze).

Die linke untere Ecke des Frustums hat also die Koordinaten (left/bottom/-near), die rechte obere Ecke (right/top/-near). Das Frustum kann somit durch Angabe dieser 2 Punkte und des Wertes far bestimmt werden.

Auf diese Weise kann natürlich auch ein nicht-symmetrisches Frustum erzeugt werden, so wie es im Cave benötigt wird (wenn sich der Betrachter nicht genau in der Mitte des Caves befindet)

\includegraphics[height=15cm]{frustum.eps}

Zunächst wird einmal der Viewpoint nach eyePos verschoben und die Blickrichtung normal auf die jeweilige Wand eingerichtet. Im Performer wird das etwa so aussehen:

pfChanView(channel, eyePos, dir), wobei dir einer dieser Vektoren sein könnte: (-90, 0, 0), (0, 0, 0), (90, 0, 0) (Drehung nach links, keine Drehung, Drehung nach rechts)

Jetzt müssen noch die Koordinaten von bottomLeft und topRight berechnet werden.

Sei d der Normalabstand von eyePos zur Cavewand.

$\overrightarrow{bottomLeft}, \overrightarrow{topRight}$ seien die Ortsvektoren zu den jeweiligen Punkten.

$\overrightarrow{eyePosA}$ sei der Vektor von eyePos nach A

$\overrightarrow{eyePosC}$ sei der Vektor von eyePos nach C

Dann können die beiden Vektoren $\overrightarrow{bottomLeft}$ und $\overrightarrow{topRight}$ ganz einfach berechnet werden:

$\overrightarrow{bottomLeft}=\overrightarrow{eyePosA}*near/d $

$\overrightarrow{topRight}=\overrightarrow{eyePosC}*near/d $

Mit den Koordinaten von bottomLeft(left/bottom/-near) und topRight(right/top/-near) kann ein passendes Frustum erzeugt werden:

pfChanNearFar(channel, near, far)

pfMakePerspChan(channel, left, right, bottom, top)



Beispielcode, der die Werte für left, right, bottom und top berechnet.

void calculateFrustum(float eye[3], float cave[3], 
        CAVE_WALL_ID wallID, float near, float frustum[4]) {

  float d, l, r, b, t;
  switch (wallID) {
  case CAVE_FRONT_WALL:
    d = 0.5 * cave[1] - eye[1];
    l = 0.5 * cave[0] + eye[0];
    r = 0.5 * cave[0] - eye[0];
    b = 0.5 * cave[2] + eye[2];
    t = 0.5 * cave[2] - eye[2];
    frustum[0] = -l * near / d;
    frustum[1] =  r * near / d;
    frustum[2] = -b * near / d;
    frustum[3] =  t * near / d;
    break;
  case CAVE_LEFT_WALL:
    d = 0.5 * cave[0] + eye[0];
    l = 0.5 * cave[1] + eye[1];
    r = 0.5 * cave[1] - eye[1];
    b = 0.5 * cave[2] + eye[2];
    t = 0.5 * cave[2] - eye[2];
    frustum[0] = -l * near / d;
    frustum[1] =  r * near / d;
    frustum[2] = -b * near / d;
    frustum[3] =  t * near / d;
    break;
  case CAVE_RIGHT_WALL:
    d = 0.5 * cave[0] - eye[0];
    l = 0.5 * cave[1] - eye[1];
    r = 0.5 * cave[1] + eye[1];
    b = 0.5 * cave[2] + eye[2];
    t = 0.5 * cave[2] - eye[2];
    frustum[0] = -l * near / d;
    frustum[1] =  r * near / d;
    frustum[2] = -b * near / d;
    frustum[3] =  t * near / d;
    break;
  case CAVE_FLOOR_WALL:
    d = 0.5 * cave[2] + eye[2];
    l = 0.5 * cave[0] + eye[0];
    r = 0.5 * cave[0] - eye[0];
    b = (0.5 * cave[1] - 60 ) + eye[1]; /* floor is 60cm shorter! */
    t = 0.5 * cave[1] - eye[1]; 
    frustum[0] = -l * near / d;
    frustum[1] =  r * near / d;
    frustum[2] = -b * near / d;
    frustum[3] =  t * near / d;
    break;
  }
}


next up previous
Next: OpenGL Up: Programmieren ohne CAVELib Previous: Programmieren ohne CAVELib
Mail to: Oliver Schönbrunner
Virtual Reality Center