# Mathematics? (Peculiar Camera Rotation)

• 04-11-2005
Epo
Mathematics? (Peculiar Camera Rotation)
Hullo all, I've attached an image so you kind of get the idea of what I'm rendering (The actual thing is fullscreen and not so condensed)...(And on a sidenote, the textures aren't showing up on the object, which is why it's all white, but that's another problem for another day) :)

I'm trying to recreate first-person camera movement, so when you move the mouse left, the camera turns left, and so forth. I've almost gotten the x-axis to work, here's the code I use (Note, uses DirectInput):
Code:

```void cDX::DIProcessMouse(void) {         DIMOUSESTATE MouseState;         if(FAILED(DIMouseDevice->GetDeviceState(sizeof(MouseState),(LPVOID)&MouseState)))             return;         DIMouseX += MouseState.lX;         DIMouseY += MouseState.lY;         DIMouseZ += MouseState.lZ;         if(MouseState.lX != 0)         {                 Camera3DYRotation += (float)(MouseState.lX / 1000.0f);                 if(Camera3DYRotation > (D3DX_PI + D3DX_PI))                 {                         Camera3DYRotation -= (D3DX_PI + D3DX_PI);                 }                 else if(Camera3DYRotation < 0.0000f) //Thought numbers were getting truncated, so I tried this. Didn't fix it.                 {                         Camera3DYRotation += (D3DX_PI + D3DX_PI);                 }                 bCamera3DUpdate = true;         }         if(bCamera3DUpdate == true)         {                 Camera3DRotate(0.0f, Camera3DYRotation, 0.0f);                 Camera3DUpdate();         } }```
The above pretty much keeps the X Rotation number between 0 and 2Pi radians.

The Camera3DRotate() function (responsible for converting the rotation to screen coordinates) looks like this:
Code:

```void cDX::Camera3DRotate(float X, float Y, float Z) {         Camera3DLookAt.x = Camera3DFocus * sinf(Y) + Camera3DPosition.x;         Camera3DLookAt.z = Camera3DFocus * cosf(Y) + Camera3DPosition.z; }```
As you can see, it's just simple trig going on to figure out the proper (X,Z) point to focus on.

The update isn't as important, but here it is anyways so you see what I'm doing:
Code:

```void cDX::Camera3DUpdate(void) {         D3DXMatrixLookAtLH(&Camera3DMatrix, &Camera3DPosition, &Camera3DLookAt, &Camera3DUp);         D3DDevice->SetTransform(D3DTS_VIEW, &Camera3DMatrix);         bCamera3DUpdate = false; }```
Again, just a simple update to the camera.

Now, in the picture below, that's what gets rendered to the screen right when the program starts, with the mouse centered right in the middle of the ship (Yes, it's a ship...just go with it) :)

If I fling the mouse around the screen a lot, and I try to recentre the ship so that the camera is looking at (0.00,0.00), then the mouse is off-centre. And not just by a little bit. If I fling it around enough, it can be off ridiculously.

I'm wondering if anybody has any ideas what could be causing this? (Just to note, I'm using the MouseState.lX variable to update camera movement, which calculates the change in X since last call. I was very careful not to hit the edge of my screen, which would've caused the camera to still rotate, but the mouse to "stay still". So the offset isn't because of that...)

If anyone's got any ideas (or they just see something I'm doing horribly wrong, even if it's not related to this) I'm always open to suggestions :) Thanks for givin' this a read
• 04-11-2005
Darkness
Okay lets see, so you are saying that when you move the mouse, the ship rotates a bunch, but that when you want the ships orientation to be set back to the way it was when the program first started, the mouse cursor's position is not at the middle of the screen (where you expect it to be).

I'm just not 100% sure I understand your problem. That is, however, a very sweet spaceship. I'm not going to lie to you.

So, you aren't re-setting the mouse cursor position every frame however? In my application, the way I solved this problem was I calculate the deviation from the center of the screen, in screen coordinates. Then, I reset its position to the center of the screen each frame (and from the amount the mouse deviated I compute pitch and yaw angles).
• 04-11-2005
Epo
Haha, I'm thinking of ignoring the whole texture problem with the ship and just going with it. Just look at all its beauty. (Bubba better watch out, I'm right on his tail with stellar graphics) :)

I'll try again...(And that blue thing in the picture...that's supposed to be a mouse cursor...printscreen doesn't copy it when I hit it, so I had to create another fantastic and lifelike copy)

Both ship and camera are on the X-Z plane (Y value 0), with the Ship on the origin and the camera 50 units out (on the Z axis)...incase anybody really really wanted to know that.

So, to my pictures...

The first section shows how the display is rendered when the program first starts. Everything is fine. Note the cursor in the middle of the ship.

The next section, I move the mouse to the right (I.e. turn camera right). Everything A-okay.

Same for the third section, I move the mouse to the left side (Turn camera left).

But when I recenter the camera to be looking at (0,0) (Ship back in middle), my cursor no longer lines up to where it *should* be. And the more I move the cursor around, the further away it gets.

I'm hoping to get this fixed before I start hiding the cursor cause I've gotten it to points where it's so far off that controlling the camera is just too weird (you have to move much further than expected to actually turn the camera to where you want it).

Hope it's a touch more clear, and resetting the mouse is actually a good idea...it might get a bit trickier after for some of the things I'm planning to toss in, but probably nothing a few flags can't handle. I'll keep that in mind. If there're any thoughts on this though I'd still be happy to hear them.
• 04-11-2005
Perspective
Everytime you process rotation from the mouse coords, set the coords to 0,0. That way each calculation can just calculate the offset from the origin and any wonkyness from one calculation won't propagate to the next ones. (Though it really shouldnt in the first place)
• 04-11-2005
Darkness
By wonkyness he means floating point error. That's what I was going suggest, but I don't know if there's also a math error somewhere in there (doesn't appear to be).
• 04-11-2005
Epo
I'm not so sure anymore that resetting the mouse to 0,0 will fix this problem...

Each frame the mouse doesn't move, MouseState.lX becomes equal to 0.

The DIMouseDevice->GetDeviceState() function fills my MouseState struct (long integers), with the change in each coordinate (X, Y, and Z...Z's the MouseWheel) since the last call. Whether the mouse is positioned at 0,0 or anywhere else, I think the same problem would arise, since it'd still only be using the change in values.

When you say floating point error, do you mean when I typecast the long int to a float? Or just the whole representation of numbers not being able to be 100% accurate even with floats (that whole bag of problems)?

Does anybody know much about "Device Units" by any chance? That's what MouseState.lX is measured by...I tested the smaller values, and each pixel movement of the mouse turned out to be one Device Unit as well, so I just took it that one pixel would always equal one device unit. But perhaps something's getting changed with bigger numbers or something?

Hopefully somebody knows :) I sure don't. I'll look into it, and I'll still try to implement setting the mouse to (0,0). I'm writing this inbetween bursts of exam studying, so it might take me until tomorrow to actually throw the code together, but I'll let you know how it turns out.

Thanks again for the input guys.
• 04-12-2005
VirtualAce
First off, DX returns mouse coordinates as relative coordinates unless you specify you want absolute.

Second you are computing the rotations incorrectly for your view matrix.

Perhaps this might help.

Code:

```void Camera::walk(float units) {         // move only on xz plane for land object         if( _cameraType == LANDOBJECT )                 _pos += D3DXVECTOR3(_look.x, 0.0f, _look.z) * units;         if( _cameraType == AIRCRAFT )                 _pos += _look * units; } void Camera::strafe(float units) {         // move only on xz plane for land object         if( _cameraType == LANDOBJECT )                 _pos += D3DXVECTOR3(_right.x, 0.0f, _right.z) * units;         if( _cameraType == AIRCRAFT )                 _pos += _right * units; } void Camera::fly(float units) {         if( _cameraType == AIRCRAFT )                 _pos += _up * units; } void Camera::pitch(float angle) {                 D3DXMATRIX T;         D3DXMatrixRotationAxis(&T, &_right,        angle);         // rotate _up and _look around _right vector         D3DXVec3TransformCoord(&_up,&_up, &T);         D3DXVec3TransformCoord(&_look,&_look, &T); } void Camera::yaw(float angle) {         D3DXMATRIX T;         // rotate around world y (0, 1, 0) always for land object         if( _cameraType == LANDOBJECT )                 D3DXMatrixRotationY(&T, angle);         // rotate around own up vector for aircraft         if( _cameraType == AIRCRAFT )                 D3DXMatrixRotationAxis(&T, &_up, angle);         // rotate _right and _look around _up or y-axis         D3DXVec3TransformCoord(&_right,&_right, &T);         D3DXVec3TransformCoord(&_look,&_look, &T); } void Camera::roll(float angle) {         // only roll for aircraft type         if( _cameraType == AIRCRAFT )         {                 D3DXMATRIX T;                 D3DXMatrixRotationAxis(&T, &_look,        angle);                 // rotate _up and _right around _look vector                 D3DXVec3TransformCoord(&_right,&_right, &T);                 D3DXVec3TransformCoord(&_up,&_up, &T);         } } void Camera::getViewMatrix(D3DXMATRIX* V) {         // Keep camera's axes orthogonal to eachother         D3DXVec3Normalize(&_look, &_look);         D3DXVec3Cross(&_up, &_look, &_right);         D3DXVec3Normalize(&_up, &_up);         D3DXVec3Cross(&_right, &_up, &_look);         D3DXVec3Normalize(&_right, &_right);         // Build the view matrix:         float x = -D3DXVec3Dot(&_right, &_pos);         float y = -D3DXVec3Dot(&_up, &_pos);         float z = -D3DXVec3Dot(&_look, &_pos);         (*V)(0,0) = _right.x; (*V)(0, 1) = _up.x; (*V)(0, 2) = _look.x; (*V)(0, 3) = 0.0f;         (*V)(1,0) = _right.y; (*V)(1, 1) = _up.y; (*V)(1, 2) = _look.y; (*V)(1, 3) = 0.0f;         (*V)(2,0) = _right.z; (*V)(2, 1) = _up.z; (*V)(2, 2) = _look.z; (*V)(2, 3) = 0.0f;         (*V)(3,0) = x;        (*V)(3, 1) = y;    (*V)(3, 2) = z;      (*V)(3, 3) = 1.0f; }```
I recommend reading the book Directx9 Game Programming - this camera class is in that book. You can use it for basic stuff. However I'm finding out that to implement more advanced things I probably will have to re-design it at some point.
• 04-12-2005
Epo
Quote:

First off, DX returns mouse coordinates as relative coordinates unless you specify you want absolute.
Had no clue I could specify that, it's good to know though, 'cause I don't doubt it'll come in handy

Quote:

Second you are computing the rotations incorrectly for your view matrix.
Aww, I put so many hours into that code. Are you sure? Well, I'm gonna assume the skips and jumps I was seeing once I started trying for more rotation axes is because of the whole computing wrong problem. It seems like a good thing to blame ;)

That code is very helpful. I could've sworn there were D3DX calls for rotation, but I couldn't remember them, so I guess I just found trig (although it was wrong trig) to be easier than looking it up....lesson learned I guess :)

And my online tutorials are slowly running out of tutorials (Hyena and Andy) so I just may end up getting a hardcopy of something soon. I'll keep that book in mind.

Thanks Bubba
• 04-14-2005
Epo
I've begun trying to convert the code above to work with mine. I've started trying the simple walk() function, but I'm having issues:
Code:

```void Camera::walk(float units) {         // move only on xz plane for land object         if( _cameraType == LANDOBJECT )                 _pos += D3DXVECTOR3(_look.x, 0.0f, _look.z) * units;         if( _cameraType == AIRCRAFT )                 _pos += _look * units; }```
Just thinking it through my head, would the following problems not arise?
1. If we're looking at the origin, the object will end up not moving anywhere
2. If we're looking at very large numbers, one step forward will end up being larger than a step forward at smaller numbers
3. If we walk all the way up to our _look point and cross it, our view will all of a sudden be facing the wrong way (backwards)

EDIT: I see that this code if from the book, but is it also used in your game?
I'm assuming this is your code for your spaceship game? So obviously (from all the screenshots), it must be working. Is there something extra you're doing (or I'm not seeing) to avoid these problems?

The code I came up with, using ideas from yours is this:
Code:

```void cCamera::Walk(float Units) {         D3DXVECTOR3 Forward = (Position - LookAt); //Can multiply here by D3DXVECTOR3(1.0f, 0.0f, 1.0f) to include/omit certain directions         D3DXVec3Normalize(&Forward, &Forward);         Position += Forward * Units;         LookAt += Forward * Units; }```
Then the only thing I need to do to update the camera is:
Code:

```void cCamera::Update(IDirect3DDevice9* D3DDevice) {         D3DXMatrixLookAtLH(&matView, &Position, &LookAt, &Up);         D3DDevice->SetTransform(D3DTS_VIEW, &matView); }```
I tested it from different angles and it seems to work no matter the Position/LookAt vectors.

I know this is a very general question, but are there any mathematical issues that people see arising from this method? (I'm familiar with vectors, but I'm sure there are plenty of people of people who know them in-depth more than I do. This method fixes #1 and #3 from above, but I think #2 may still be an issue...).
• 04-14-2005
VirtualAce
Well I'm not sure of the problem you are having but the class works as is in my system. You can move anywhere in space at any time at any angle and any speed and it all works correctly.
• 04-14-2005
Epo
With this line though:
_pos += D3DXVECTOR3(_look.x, 0.0f, _look.z) * units;

If _look.x and _look.z equal 0 (looking at the origin), then _pos (regardless of units) will keep on adding 0s to its x, y, and z values; no movement...That is, until something else causes the _look vector to change...

Also, say we're looking at (0, 0, 0), and given that movement actually does work...If I'm located at (0, 0, 50), then I move forwards to (0, 0, 25), and keep moving forwards to (0, 0, 1). Then, if I keep moving forward to (0, 0, -5), the _look vector is still at (0, 0, 0), so as I cross that point, the direction of my looking will flip...

I don't see where a new _look vector is being set based on movement. I.e. If I'm located at (0, 0, 50), looking at (0, 0, 0), then when I move to (0, 0, 25), I should be looking at (0, 0, -25), no?

I'm not doubting that it's working, I just can't figure out how you're getting around these problems, with the code up there...