PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Visualisierung - Kamerasteuerung


instinct
2010-01-28, 20:16:20
Es werden 3D-Objekte aller Art visualisiert. Der Benutzer soll die Möglichkeit haben mit einer FPS-Kamera durch die Szene zu bewegen (Fly-Mode).
Allerdings gelingt es mir nicht so richtig.

Ich mache folgendes:
Eingabe: Kamera-Punkt, LookAt-Punkt, Up-Vector, FOV, Screen-Resolution
Daraus errechne ich mir mein Kamerasystem und speichere die drei Vektoren
spaltenweise in eine Matrix.

Sobald der Benutzer in das Fenster klickt, wird die Maus zentriert und ab dann wird die Rotation anhand des relativen Pixelunterschieds berechnet.
Mein Code tut folgendes:

{
// Compute rotation angles
float angleX = DEG2RAD((pixelPos.second - newPixelPos.second) / SENSITIVITY_X);
float angleY = -DEG2RAD((pixelPos.first - newPixelPos.first) / SENSITIVITY_Y);

// Set up rotation matrix around x axis
float rotMatrixX[] =
{
1, 0, 0,
0, cosf(angleX), -sinf(angleX),
0, sinf(angleX), cosf(angleX)
};

// Set up rotation matrix around y axis
float rotMatrixY[] =
{
cosf(angleY), 0, -sinf(angleY),
0, 1, 0,
sinf(angleY), 0, cosf(angleY),
};

mat33 rotx, roty;
memcpy(rotx.data, rotMatrixX, 9 * sizeof(float));
memcpy(roty.data, rotMatrixY, 9 * sizeof(float));
rotx *= roty;
base *= rotx;

// Accumulate matrices
pixelPos = newPixelPos;
}


'base' ist hierbei die oben beschriebene Matrix.
Lasse ich entweder nur die Rotation um X oder um Y zu funktionierts prima. Der Benutzer kann sich nach links/rechts oder oben/unten drehen. Sobald ich aber beide Rotationen (wie im Code oben) anwende und ich mir der Maus kleine Kreise im Fenster drehe, dann wird ebenfalls um die z-Achse des Kamerakoordinatensystems rotiert. Das sollte aber nicht sein. Kann mir jemand sagen, was ich hier falsch mache?

Neomi
2010-01-28, 21:55:45
Dein Problem dabei kommt dadurch zustande, daß du eine Matrix inkrementell updatest. Wenn du erst nach oben schaust und dann seitlich drehst, dann geschieht die seitliche Drehung um die alte lokale Y-Achse, die aber nicht mehr mit der globalen Y-Achse übereinstimmt.

Die Lösung ist, die vorhandenen Winkel (Yaw, Pitch und Roll, wobei du letzteres ja nicht benötigst) persistent zu halten und für jeden Frame die Kameramatrix daraus neu zu generieren. Dann hast du auch gleich das Problem gelöst, daß du deine Matrix nicht neu normierst und orthogonalisierst. Die diversen Float-Ungenauigkeiten würden sich sonst über die Zeit ebenfalls aufaddieren.

instinct
2010-01-29, 17:51:44
Also irgendwie will es nicht. Wie berechne ich denn die Kameramatrix neu? Muss ich dann den Kamera-Punkt und den LookAt-Punkt mit der aus yaw und pitch gewonnenen Matrix multiplizieren und danach die Orthonormalbasis aufstellen?

Neomi
2010-01-29, 21:17:21
Das sind zwei Dinge, die du nicht vermischen solltest. Wenn du einen Zielpunkt hast (LookAt), dann kannst du daraus, aus der Kameraposition und aus dem UpVector eine fertige Matrix bauen.

Ein kleiner Auszug (statische Konstruktionsmethode) aus einer älteren Matrix-Klasse, die ich mal vor längerer Zeit gebaut habe:

Matrix4x4 Matrix4x4::LookAt(const Vector3& aEye, const Vector3& aAt, const Vector3& aUp)
{
Vector3 vz = aAt - aEye;
Vector3 vx = CrossProd(aUp, vz);
Vector3 vy = CrossProd(vz, vx);

vx = Normalize(vx);
vy = Normalize(vy);
vz = Normalize(vz);

Vector3 eye = -Vector3(DotProd(vx, aEye), DotProd(vy, aEye), DotProd(vz, aEye));

return Matrix4x4( vx.x, vy.x, vz.x, 0.0f,
vx.y, vy.y, vz.y, 0.0f,
vx.z, vy.z, vz.z, 0.0f,
eye.x, eye.y, eye.z, 1.0f);
}

Damit ist die Kameramatrix dann schon fertig. YawPitchRoll ist eine Alternative, und zwar eine freie Kamera. Die beiden darfst du nicht vermischen, sonst kommt Murks raus.

Was hast du denn überhaupt, um damit eine Kamera zu berechnen? Hast du Position und Ziel? Dann werden die von Frame zu Frame aktualisiert und zusammen mit einem konstanten UpVector (0, 1, 0) wird eine Matrix berechnet. Die Matrix aus dem Frame davor wird gar nicht in die Berechnung einbezogen, sondern komplett ersetzt.

Wenn du Winkel hast (Yaw, Pitch und Roll, wobei letzteres bei dir ja 0 ist), dann werden die pro Frame aktualisiert. Dann berechnest du die Einzelrotationen aus den Winkeln um die jeweils richtigen Achsen, verkettest die in der richtigen Reihenfolge (Translationsmatrix mit der Kameraposition nicht vergessen) und bist fertig. Auch hier wird die alte Matrix aus dem letzten Frame nicht verwendet.

instinct
2010-01-29, 21:21:05
Vielen Dank für deine Hilfe. Ich habs nun doch hinbekommen mit Yaw, Pitch and Roll. Ich hatte lediglich 2 Einträge der Matrix vertauscht und dadurch kamen komische Resultate zustande.