## Camera Class using Mouse Deltas

Sage
Posts: 1,066
Joined: 2004.07
Post: #1
I've figured that my problem is the math of rotating my camera. The old code took the screen coordinates of the mouse, rotated the camera based on that, and then set the mouse back to the center of the screen. With my new code I'm using mouse deltas so there is a small problem :/. Here's some of the code. If anybody has some code for a camera class that uses deltas and Objective-C (or C++ works I guess) I would appreciate that.

PLEASE remember that this code DOES NOT work. I don't want somebody searching for this thinking it works. In the second method where the variables mouseDeltaX and mouseDeltaY are, those used to be screen coordinates, not deltas which is what's throwing my class into a fury. If you have any ideas how to fix this, I'm willing to try anything.

Code:
```- (void)rotate: (float)angle : (float)x : (float)y : (float)z {     Vector *newView;     newView = [[Vector alloc] init];     view = [view subtract: position];          float cosTheta = (float)cos(angle);     float sinTheta = (float)sin(angle);          [newView setX: ((cosTheta + (1 - cosTheta) * x * x) * [view x])];     [newView addX: (((1 - cosTheta) * x * y - z * sinTheta) * [view y])];     [newView addX: (((1 - cosTheta) * x * z + y * sinTheta) * [view z])];          [newView setY: (((1 - cosTheta) * x * y + z * sinTheta) * [view x])];     [newView addY: ((cosTheta + (1 - cosTheta) * y * y) * [view y])];     [newView addY: (((1 - cosTheta) * y * z - x * sinTheta) * [view z])];          [newView setZ: (((1 - cosTheta) * x * z - y * sinTheta) * [view x])];     [newView addZ: (((1 - cosTheta) * y * z + x * sinTheta) * [view y])];     [newView addZ: ((cosTheta + (1 - cosTheta) * z * z) * [view z])];          view = [view add: newView]; } - (void)setViewOnMouse {     float angleY,angleZ;     static float currentRotX;          angleY = (float)( mouseDeltaX ) / 1000.0f;     angleZ = (float)( mouseDeltaY ) / 1000.0f;          currentRotX -= angleZ;            if(currentRotX > 1.0f)         currentRotX = 1.0f;     else if(currentRotX < -1.0f)         currentRotX = -1.0f;     else     {         Vector *tempVector = [view subtract: position];         Vector *tempVector2 = [tempVector crossProduct: up];         [tempVector2 normalize];                  [self rotate: angleZ : [tempVector2 x] : [tempVector2 y] : [tempVector2 z]];         [self rotate: angleY : 0 : 1 : 0];     } }```
codeman9
Unregistered

Post: #2
Looks like you are trying the camera tutorials from Gametutorials.com. Here is my solution to converting that code. I put this in my mouseMoved event handler as you can see:

Code:
```- (void)mouseMoved:(NSEvent *)event {     //NSLog(@"mouseMoved");     float deltaX = [event deltaX] / 500;     float deltaY = [event deltaY] / 500;     float currentRotX = 0.0;          currentRotX -= deltaX;          if (currentRotX > 1.0) {         currentRotX = 1.0;     } else if (currentRotX < -1.0) {         currentRotX = -1.0;     } else {         Vector3 *tempAxis = [Vector3 cross:[Vector3 sub:[camera view] v2:[camera position]] v2:[fpCamera up]];         tempAxis = [Vector3 normalize:tempAxis];                  [camera rotateView:-deltaY axis:tempAxis];         [camera rotateView:-deltaX axis:[[Vector3 alloc] initWithValues:0.0 y:1.0 z:0.0]];     } }```

And then my rotate camera method is:

Code:
```- (void)rotateView:(float)angle axis:(Vector3 *)axis { //x:(float)x y:(float)y z:(float)z {     Vector3 *newView;     Vector3 *tempView = [Vector3 sub:view v2:position];     float tempViewX = [tempView x];     float tempViewY = [tempView y];     float tempViewZ = [tempView z];          axis = [Vector3 normalize:axis];     float axisX = [axis x];     float axisY = [axis y];     float axisZ = [axis z];          float cosTheta = (float)cos(angle);     float sinTheta = (float)sin(angle);          float newX = (cosTheta + (1 - cosTheta) * axisX * axisX) * tempViewX;     newX +=         ((1 - cosTheta) * axisX * axisY - axisZ * sinTheta) * tempViewY;     newX +=         ((1 - cosTheta) * axisX * axisZ + axisY * sinTheta) * tempViewZ;          float newY = ((1 - cosTheta) * axisX * axisY + axisZ * sinTheta) * tempViewX;     newY +=         (cosTheta + (1 - cosTheta) * axisY * axisY) *       tempViewY;     newY +=         ((1 - cosTheta) * axisY * axisZ - axisX * sinTheta) * tempViewZ;          float newZ = ((1 - cosTheta) * axisX * axisZ - axisY * sinTheta) * tempViewX;     newZ +=         ((1 - cosTheta) * axisY * axisZ + axisX * sinTheta) * tempViewY;     newZ +=         (cosTheta + (1 - cosTheta) * axisZ * axisZ)     * tempViewZ;          newView = [[Vector3 alloc] initWithValues:newX y:newY z:newZ];          view = [Vector3 add:position v2:newView]; }```

Pretty much straight from the tutorial with a few minor changes.
I'm sure there are many other solutions to this, but mine seems to work well.

Good luck!
Cody
Sage
Posts: 1,066
Joined: 2004.07
Post: #3
codeman9 Wrote:
Code:
```[Vector3 cross:[Vector3 sub:[camera view] v2:[camera position]] v2:[fpCamera up]]; [Vector3 normalize:tempAxis]; [Vector3 sub:view v2:position]; axis = [Vector3 normalize:axis]; view = [Vector3 add:position v2:newView]; }```

Can you explain those methods a bit for me? I have different Vector methods and I'm not sure what yours are doing compared to mine. Thanks a lot for this code, though.
codeman9
Unregistered

Post: #4
Yeah, sure. My original problem with these methods were with the normalize method. At first I just had all the calculations done in a return statement. That was not working, but once I added some temporary variables and returned them, things seemed to behave better. For example:

Code:
```+ (Vector3 *)scaDiv:(float)num v1:(Vector3 *)v1 {     Vector3 *tempVector =  [[Vector3 alloc] initWithValues:[v1 x] / num y:[v1 y] / num z:[v1 z] / num];     return tempVector; } + (float)magnitude:(Vector3 *)v1 {     float x1 = [v1 x];     float y1 = [v1 y];     float z1 = [v1 z];          float magnitude = sqrt((x1 * x1) + (y1 * y1) + (z1 * z1));          return magnitude; } + (Vector3 *)normalize:(Vector3 *)v1 {     float magnitude = [self magnitude:v1];          v1 = [self scaDiv:magnitude v1:v1];          return v1; }```

Basically the methods are what the tutorial has, I just made them class methods and didn't use operator overloading. The other problem I initially had was that I wasn't assigning my new normalized vector to anything because the way my normalize method works is a little different than his. Anyway, I hope this helps a bit. Lemme know if you need anything else.

Cody
Sage
Posts: 1,066
Joined: 2004.07
Post: #5
I've tried the code but with a slight change which may be the problem. I'm going to try later. The slight change is the placement. I have the code that you placed in the mouseMoved method in a method of my camera. The mouseMoved gets the deltas and then a method sends those numbers to the camera which directly uses them so I'm not sure why that matters. Anyways it's still making my camera do flips constantly and then I don't see anything so I'm really confused. I'll keep trying things.
Thanks for the help.
codeman9
Unregistered

Post: #6
Yeah, I see what you mean. I removed that code from the camera class and put it in my controller class because it made no sense to me to have the camera know about the mouse at all. Doing that seems to work for me. I have the tutorial's checkForMovement function in my controller method which I have modified to tell the camera to do the rotation, and the mouseMoved method just sets a boolean value and the deltas to pass into the checkForMovement. I originally had the code like you had it and it wasn't working for me, so I had to do a slight rewrite rather than mucking around trying to fix the conversion problem using the sample code of Nutzy's engine to make the event loop. If you want, I could email you my classes so you can take a look.

Good luck!
Cody
Sage
Posts: 1,066
Joined: 2004.07
Post: #7
If you could email them to nickgravelyn@gmail.com that'd be great. I'm getting really frustrated with Cocoa because I'm very new to the way it works. I've been using SDL and C++ for about 3 months now.