PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Frage zur KameraRotation bei Direct3D


Nasenbaer
2003-04-29, 21:30:23
Hi,
ich möchte in D3D eine ViewMatrix erstellen wodurch ich die Kamera um ihre Achsen rotieren lassen kann.
Bisher habe ich dafür Sinus und Cosinus benutzt und jedes mal einen neue ViewMatrix erstellt. Und zwar so:


D3DXMATRIX mView;
float LookAtX, LookAtZ;

Sichtwinkel -= 0.0079f; // 0.5 Grad
if( SichtwinkelH <= 0.0f )
{
SichtwinkelH = D3DX_PI * 2.0f;
}

LookAtX = cos( SichtwinkelH );
LookAtZ = sin( SichtwinkelH );
D3DXMatrixLookAtLH( &mView, &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
&D3DXVECTOR3( LookAtX, 0.0f , LookAtZ ),
&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );

m_pDevice->SetTransform( D3DTS_VIEW, &mView );


Das funktioniert soweit nur habe ich 2 Probleme.
Einerseits sind sin() und cos() sicherlich recht langsam und zum Anderen weiß ich nicht wie ich vorgehen soll, wenn ich um mehr als eine Achse rotieren will.
IMO müsste sowas auch mit Metrizenrechnung klappen allerdings weiß ich nicht wie ich das in D3D anstelle bei diesem Beispiel.

Mfg Nasenbaer

Demirug
2003-04-29, 23:23:58
Das mit dem cosinus und sinus geht schon in Ordnung man macht das ganze ja nicht so oft (maximal 1 mal pro Rendertarget pro frame).

Mit Matrix Rechnungen hat das ganze schon was zu tun. Allerdings hängt die genaue Vorgehensweise davon ab welche Art von Camera man genau bauen möchte. So wird eine First Person Camera anders programmiert wie eine als eine Third Person Camera. Und dann spielen natürlich auch noch die optionen die man braucht eine Rolle. Soll man nur noch rechts und Links schauen können oder auch noch nach oben und unten. Ist ein seitliches Kopfneigen erforderlich. ...

PS: Bei D3DXMatrixLookAtLH ist Lookat ein absoluter Vector. Wenn man also die Camera bewegt muss man Lookat auch bewegen sonst schaut man immer auf den gleichen Punkt und wundert sich das irgendwas nicht stimmen kann.

Nasenbaer
2003-04-29, 23:56:20
Ich will eigentlich eine Cockpit-Ansicht für einen WeltraumShooter ala Wing Commander realisieren.

Mfg Nasenbaer

KiBa
2003-04-30, 02:20:36
schau mal im sdk nach "quaternion", damit sollte sowas am einfachsten gehen...

stabilo_boss13
2003-04-30, 11:24:01
Vektorrotation:

Bei der Drehung um eine der Raumachsen bleibt immer diejenige Koordiante unberührt, um deren Achse gedreht wird.

Drehung eines Punktes um die x-Achse mit dem Winkel alpha:
y'' = y' * cos (alpha) - z * sin (alpha)
z' = y' * sin (alpha) + z * cos (alpha)

Drehung eines Punktes um die y-Achse mit dem Winkel alpha:
x'' = x' * cos (alpha) - z' * sin (alpha)
z'' = x' * sin (alpha) + z' * cos (alpha)

Drehung eines Punktes um die z-Achse mit dem Winkel alpha:
x' = x * cos (alpha) - y * sin (alpha)
y' = x * sin (alpha) + y * cos (alpha)

Mit Hilfe einer Matrix kann man folgendermaßen rotieren (Auszug):


public void rotate(double ax, double ay, double az) {
// x-Rotation
if (ax!=0.0) {
double xmat[][] = new double[4][4];

xmat[0][0]=1; xmat[0][1]=0;
xmat[0][2]=0; xmat[0][3]=0;

xmat[1][0]=0; xmat[1][1]=Math.cos(ax);
xmat[1][2]=Math.sin(ax); xmat[1][3]=0;

xmat[2][0]=0; xmat[2][1]=-1*Math.sin(ax);
xmat[2][2]=Math.cos(ax); xmat[2][3]=0;

xmat[3][0]=0; xmat[3][1]=0;
xmat[3][2]=0; xmat[3][3]=1;

}

// y-Rotation
if (ay!=0.0) {
}

// z-Rotation
if (az!=0.0) {
}
}

Nasenbaer
2003-04-30, 14:00:03
Originally posted by Demirug
PS: Bei D3DXMatrixLookAtLH ist Lookat ein absoluter Vector. Wenn man also die Camera bewegt muss man Lookat auch bewegen sonst schaut man immer auf den gleichen Punkt und wundert sich das irgendwas nicht stimmen kann.
Gibt es ne andere Funktion mit der man ne ViewMatrix anlegen kann und Lookat nur die Blickrichtung und nicht den Zielpunkt beschreibt?

@stabilo_boss13
Thx. Aber da ich von Matrizenrechnung leider nicht viel Ahnung habe und sowas mittlerweile nicht mal mehr auf Gymnasien gelehrt wird möchte ich gern auf eine eigene Implementierung verzichten und stattdessen auf Funktionen von DirectX zurückgreifen da ich nicht gerne Dinge im Code habe, die ich selber nicht verstehe.

Mfg Nasenbaer

Demirug
2003-04-30, 14:31:33
Originally posted by Nasenbaer

Gibt es ne andere Funktion mit der man ne ViewMatrix anlegen kann und Lookat nur die Blickrichtung und nicht den Zielpunkt beschreibt?

Nein aber das mit der Blickrichtung geht ganz einfach.

Einfach den Richtungsvector zum Positionsvector addieren und fertig ist der Lookat Vector.

Ich habe hier auch noch irgendwo den Code für eine Raumschiffcamera rumliegen. Der ist allerdings so das ich den ohne zusätzliche Erklärungen nicht rausgeben kann. Ich werden dir später (heute nacht oder morgen) mal eine erklärung schreiben wie man eine solche Camera baut im moment ist es aber gerade schlecht.

Nasenbaer
2003-04-30, 14:50:55
@Demirug
Das wäre wirklich nett. :)

Ich habe einen Code-Ausschnitt gefunden mit dem ich die Kamera rotieren und bewegen kann aber scheinbar habe ich einige Verständnisprobleme damit.

Hier erstmal der Code:

D3DXVECTOR3 vCamPos; //Kamerapostion
vCamPos.x = 0.0f;
vCamPos.y = 0.0f;
vCamPos.z = 0.0f;
float fRotX = 0.0f,fRotY = 0.4f,fRotZ = 0.0f; //Rotationswinkel

//**************************************

//Bewegungsmatrix erzeugen

D3DXMATRIX matMove;

D3DXMatrixIdentity(&matMove); //Einheitsmatrix erzeugen
matMove._41 = -vCamPos.x;
matMove._42 = -vCamPos.y;
matMove._43 = -vCamPos.z;

//Rotationsmatrix erzeugen
D3DXMATRIX matRotX,matRotY,matRotZ;
D3DXMatrixRotationX(&matRotX,fRotX);
D3DXMatrixRotationY(&matRotY,fRotY);
D3DXMatrixRotationZ(&matRotZ,fRotZ);

//Viewmatrix berechnen[Die Monstermatrix ;) ]
D3DXMATRIX matView,matTemp;
D3DXMatrixMultiply(&matView,&matRotX,&matMove);
D3DXMatrixMultiply(&matTemp,&matRotY,&matView);
D3DXMatrixMultiply(&matView,&matRotZ,&matTemp);

m_pDevice->SetTransform(D3DTS_VIEW,&matView);


Wenn ich nun bei vCamPos Werte eingebe, dann wird der sichtbare Bereich um diese Werte verschoben. (Und bleibt dann dort)
Ich dachte eigentlich, dass die Kamera bei jedem Durchlauf dieses Codes erneut um die entspr. Werte verschoben werden - vCam also die Änderungswerte zum vorhergehenden Frame darstellen. Gleiches gilt für die Rotation.
Beispiel:
Wenn ich die Kamera um 1 nach vorn bewege so werden die Weltkoordinaten mit 1 subtrahiert. Im nächsten Frame ist die Kamera dann wieder im Nullpunkt des Weltkoordinatensystems. Wird die Kamera dann erneut um 1 nach vor bewegt findet die Subtraktion wieder statt.
Dann befinde ich mich im Endeffekt an der Position 0,0,2 aber dem ist wohl nicht so. :\
Dies würde die Sache allerdings erleichtern da man bei vCam keine Überlauf zu erwarten hat.

Mfg Nasenbaer

Demirug
2003-04-30, 16:51:26
Kamera für einen Weltraumsimulation.

Eine solche Kamera erfordert vollständige Bewegungsfreiheit in allen 3 Achse daher ist es notwendig das man auch mit 3 Achsen arbeitet.

Wir brauchen also
1. Die Positions als absoluten Vector (x,y,z) = Pos
2. Einen Richtungsvektor (x,y,z) für die Bewegungsrichtung relative zur Position = Look
3. Einen Vektor welcher Senkrecht zum Richtungsvektor steht und nach oben (Dach) verweist (ebenfalls relative) = up
4. Einen Vektor welcher Senkrecht zum Richtungsvektor steht und zur Seite verweist (ebenfalls relative) = right

Beim Start werden die Vectoren wie folgt initialisiert:

Pos = (0|0|0)
look = (0|0|1)
up = (0|1|0)
right=(1|0|0)

Die View Matrix wird nun immer wie folgt berechnet LookAtLH (Pos, Pos+look, up)

primär haben wir 4 mögliche Bewegungen

vor/zurück: Hierzu wird einfach zur Position (pos) der entsprechenden skalierte look Vektor addiert:

pos = pos + look*scale (wenn scale negative ist geht es rückwärts)

rechts/links drehen: Dabei werden die Vektoren look und right um den vector up gedreht.

Dazu erzeugen wir und zuerst eine Rotationsmatrix mit rot = MatrixRotationAxis (up, angle). Diese Matrix wird nun benutzt um look und right zu transformieren. (D3DXVec3TransformNormal)

hoch/runter drehen: Das Verfahren ist identisch mit dem rechts/links drehen nur wird die matrix mit dem right Vecktor erzeugt und die look und up vectoren werden transformiert.

rollen: Nocmal das gleiche. der look vector dient zum erzeuegen der Matrix und up, right werden transformiert.

Ich hoffe das ich das alles noch richtig im Kopf hatte ;)

Nasenbaer
2003-04-30, 22:02:56
Danke einwandfrei! :)

Nur ein kleiner Bug ist drin
Und zwar funktioniert das hoch/runter Drehen sprich Nicken nur, wenn man nach unten dreht.
Will man nach oben drehen so findet eine Drehung um mehr als eine Achse statt.

Ich habe mal den Code hochgeladen, falls du da rein sehen willst ab die wichtigen Funktioen poste ich mal hier.

//Die Camerastruktur
struct CAM
{
D3DXVECTOR3 *Position;
D3DXVECTOR3 *LookAt;
D3DXVECTOR3 *Up;
D3DXVECTOR3 *Right;
};

//Hier wird die Camera initialisiert
CDirect3D::CDirect3D( void )
{
m_Cam.Position = new D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
m_Cam.LookAt = new D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
m_Cam.Up = new D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
m_Cam.Right = new D3DXVECTOR3( 1.0f, 0.0f, 0.0f );

//...
}

// Diese Funktion ist fürs Nicken zuständig
void CDirect3D::CameraRotatePitch( float angle )
{
D3DXMATRIX matRotatePitch;

D3DXMatrixRotationAxis( &matRotatePitch, m_Cam.Right, angle );

D3DXVec3TransformNormal( m_Cam.Up, m_Cam.Up, &matRotatePitch );
D3DXVec3TransformNormal( m_Cam.LookAt, m_Cam.LookAt, &matRotatePitch );
}




//Hier wird die ViewMatrix zugewiesen
HRESULT CDirect3D::Tick()
{
//KameraBewegung


D3DXMatrixLookAtLH( &m_matView, m_Cam.Position,
&(*m_Cam.Position + *m_Cam.LookAt),
m_Cam.Up );

m_pDevice->SetTransform(D3DTS_VIEW,&m_matView);


// Objekte Rendern
}


//In der MsgProc(..)
case VK_HOME:
{
Direct3D.CameraRotatePitch( 0.057f );
}
break;

case VK_END:
{
Direct3D.CameraRotatePitch( -0.057f );
}


Mich wundert halt warum er zwar in die eine Richtung richtig nicht aber nicht in die andere.

Hier die Sources samt vorkompilierter Exe um sich den Effekt mal anzuschauen: ->Download (www.clan-smk.de/viewmatrix.zip)

Mfg Nasenbaer

stabilo_boss13
2003-04-30, 23:00:13
Müsste der zweite Parameter in D3DXMatrixRotationAxis nicht ein Pointer auf D3DXVECTOR3 sein.

D3DXMatrixRotationAxis( &matRotatePitch, &m_Cam.Right, angle );

Nasenbaer
2003-04-30, 23:09:08
Originally posted by stabilo_boss13
Müsste der zweite Parameter in D3DXMatrixRotationAxis nicht ein Pointer auf D3DXVECTOR3 sein.

D3DXMatrixRotationAxis( &matRotatePitch, &m_Cam.Right, angle );


struct CAM
{
D3DXVECTOR3 *Position;
D3DXVECTOR3 *LookAt;
D3DXVECTOR3 *Up;
D3DXVECTOR3 *Right;
};

CAM m_Cam; // <-- steht im Header

Ist es auch. :)

Mfg Nasenbaer

Demirug
2003-04-30, 23:29:23
Also im Moment bin ich da auch überfragt. Ich analysiere das mal bei gelegenheit.

Nasenbaer
2003-05-02, 15:22:06
JUHHU! Ich habe den Fehler gefunden.
Und die Berechnungen von dir sind vollkommen in Ordnung.
Hier der Fehler:

case VK_HOME:
{
Direct3D.CameraRotatePitch( 0.057f );
}
break;

case VK_END:
{
Direct3D.CameraRotatePitch( -0.057f );
}
break; // <--- das hat gefehlt

case VK_DELETE:
{
Direct3D.CameraRotateRoll( 0.057f );
}
break;

case VK_NEXT:
{
Direct3D.CameraRotateRoll( -0.057f );
}
break;

Darauf hätte eigentlich auch selbst kommen können. Naja nun funzt alles perfekt.

Mfg Nasenbaer

Demirug
2003-05-02, 15:37:27
Ja das alte Problem mit dem Durchfallen bei Switch Anweisungen.