# Help: Rotating Around Projection Axis

14 replies to this topic

### #1 stewrat

stewrat

GMC Member

• GMC Member
• 7 posts

Posted 24 June 2009 - 06:00 PM

Hey,
Here is the code I will be having questions about: d3d_set_projection(xfrom,yfrom,zfrom,xto,yto,zto,x
up,yup,zup)
Ok:
I was just wondering if is even possible to rotate the cammera around the "projection axis", that is the line from (xfrom,yfrom,zfrom) to ,(xto,yto,zto). I know that the xup,yup,zup is supposed to do something to this effect and I do get a little rotation around the projection axis if i set the xup and yup values to numbers with different signs, but I can't control the specifics. Setting any of the "up" variables to different values (as long as the signs are the same) seems to have no effect. It does the same thing at 1 as 10, -1 as -10 etc.

In my FPS game you are a pilot. I wan't to be able to roll, but in order to do this, I must be able to rotate the projection. Is this possible and if so how?
I've browsed a bunch of forums but haven't found anything this question.

stewrat
• 0

### #2 Tepi

Tepi

GMC Member

• Global Moderators
• 4203 posts
• Version:GM8.1

Posted 24 June 2009 - 06:22 PM

Yes, it is possible. You haven't found the answer because it's most likely only posted here once (by me).

The (xup,yup,zup) is a vector that represents the direction to which the camera will be inclined. Its length doesn't matter so it, just as expected, doesn't change a thing whether you use (0,0,1) or (0,0,n) (n>0).

Hmm... To the solution. Ok, I'm not sure if it's any use for me to explain the vector math behind the following, but if someone wants me to, I'll do it gladly. Here's the code:
```var d, D;
d = sqrt( sqr(yto - yfrom) + sqr(xto-xfrom) );
D = sqrt( sqr(yto - yfrom) + sqr(xto-xfrom) + sqr(zto-zfrom) );
xup = lengthdir_x(( xto - xfrom )*( zto - zfrom)/d/D, tiltangle) + lengthdir_y(( yfrom - yto )/d,tiltangle);
yup = - lengthdir_x(( yfrom - yto )*( zto - zfrom)/d/D, tiltangle) + lengthdir_y(( xto - xfrom )/d,tiltangle);
zup = - lengthdir_x(( sqr( yfrom - yto ) + sqr( xto - xfrom ) )/d/D, tiltangle);```
Where the arguments should be the same as in your projection code; tiltangle is the angle you want to tilt for. I believe I had tested this earlier. If, however it doesn't appear to work, I can fix it.

EDIT: See post #10 for a better version of the code.

Edited by Tepi, 26 June 2009 - 05:45 PM.

• 1

### #3 stewrat

stewrat

GMC Member

• GMC Member
• 7 posts

Posted 24 June 2009 - 11:05 PM

Thanks alot.
I would love for you to explain the math. I understand trig stuff I just don't understand exactly how that function (d3d_set_projection, up part) works. Also, the projection is upsidedown. I guess once I have the math explained to me I'll be able to fix that, but I'd love the adjusted code just as well, lol.
Thanks a ton!
• 0

### #4 stewrat

stewrat

GMC Member

• GMC Member
• 7 posts

Posted 24 June 2009 - 11:14 PM

var d, D;

d = sqrt( sqr(yto - yfrom) + sqr(xto-xfrom) ); //Ok; this is the hypotenuse of the y and x values

D = sqrt( sqr(yto - yfrom) + sqr(xto-xfrom) + sqr(zto-zfrom) ); //Hmm, don't understand this, a hypotenuse with 3 arguments?

xup = lengthdir_x(( xto - xfrom )*( zto - zfrom)/d/D, tiltangle) + lengthdir_y(( yfrom - yto )/d,tiltangle); //cant understand this until I understand above

yup = - lengthdir_x(( yfrom - yto )*( zto - zfrom)/d/D, tiltangle) + lengthdir_y(( xto - xfrom )/d,tiltangle); //same

zup = - lengthdir_x(( sqr( yfrom - yto ) + sqr( xto - xfrom ) )/d/D, tiltangle); //same

Also, could you explain how the "up" parts of the projection function work?
• 0

### #5 stewrat

stewrat

GMC Member

• GMC Member
• 7 posts

Posted 24 June 2009 - 11:23 PM

Hmm, I did some more experimenting and it went weird on me. In the game there is a variable that controls vertical to horizontal movement in the 3d world: MouseVer. Then there is the direction variable that devides the horizontal movement into the x and y components respectively: MouseHor. The code you gave me seems dependant on one or both of these variables as well as the tiltangle variable. Thus, when I bank and then move up or over, the bank angle changes. Do you know why?
• 0

### #6 stewrat

stewrat

GMC Member

• GMC Member
• 7 posts

Posted 24 June 2009 - 11:28 PM

Me again,
I got it right side up. Other questions are still out there though.
Here is the link to the flying thing: http://host-a.net/st...flying demo.gmk
Fly parallel to the ground and press 'a' and 'd' to change the tilt angle. Then climb to an altitude of 40000 and do a dive and do the same with 'a' and 'd'. Notice the difference. I think that something is not right with the MouseVer part of the deal.

Edited by stewrat, 25 June 2009 - 12:49 AM.

• 0

### #7 Tepi

Tepi

GMC Member

• Global Moderators
• 4203 posts
• Version:GM8.1

Posted 25 June 2009 - 12:12 PM

I'll get back to this later...and edit this post or make a new one.

But you've got to stop that quadruple posting; read the posting rules.
• 0

### #8 brett14

brett14

GMC Member

• GMC Member
• 1150 posts
• Version:GM8

Posted 25 June 2009 - 05:08 PM

Thanks tepi, that helps alot actually ; Knew it could be done but didn't know how
• 0

### #9 stewrat

stewrat

GMC Member

• GMC Member
• 7 posts

Posted 25 June 2009 - 07:22 PM

Heh. It was my bad. Forgot to change a variable. Works great now! Thanks a whole lot!!!!!!!
• 0

### #10 Tepi

Tepi

GMC Member

• Global Moderators
• 4203 posts
• Version:GM8.1

Posted 25 June 2009 - 11:03 PM

Heh. It was my bad. Forgot to change a variable. Works great now! Thanks a whole lot!!!!!!!

Ah, OK. Thanks for the info (I didn't even get to waste my time, as I didn't get to test it yet).

Thanks tepi, that helps alot actually ; Knew it could be done but didn't know how

You're welcome.

EDIT: Oh, and I will post the mathematical explanation a little later.

EDIT2: Ok, here is it.

The math behind the camera:

The up-vector (xup,yup,zup) is a vector that represents a direction. The direction a vector represents can be thought of as the direction in which a point with the same coordinates appears to be from the origin (0,0,0). E.g. (0,0,1), directly up (in positive z-axis), (1,0,0) in the direction of the positive x-axis, and (0,1,0) in the direction of the positive y-axis. (1,1,1) points exactly 45 degrees up ('up' meaning along z-axis) along the diagonal between x -and y -axes (the line y=x). The opposite direction can always be found by negating all coordinates, and the vector between points (x1,y1,z1) and (x2,y2,z2) will be (x2-x1, y2-y1, z2-z1).

Now the up-vector doesn't exactly define which direction is up. That direction is defined by both the direction vector and the up-vector. (The direction vector is (xto-xfrom, yto-yfrom, zto-zfrom), the vector that represent the camera's direction in space.) Now what the up-vector really does is that it defines in which direction the camera will be tilted towards in its way around the projection axis. So, in fact, the vector directly to left or right from the camera is perpendicular to both, the up-vector and the direction vector. From that info, we can calculate the desired up-vector.

The direction vector is in black, and the vectors directly left and right are in grey.
The input up-vector is the cyan one, and the red one is the physical direction up (I should have named the cyan one up-vector). Now there are infinite amount of up-vectors that yield the same camera set up. These vectors are all in the plane depicted in grey. What I said before, that the left/right vector is perpendicular to the up-vector and the direction vector, is visible here. All up-vectors along that plane will yield the same left/right vector, which also defines the physical up-vector - the orientation of the camera. We will get the exact same up vector as the physical one, though. It's easier that way.

The math behind the code:

Here the grey side vectors should represent vectors on the x-y-plane, not the left/right vectors (my bad).
The projection plane (green), is the plane that's perpendicular to the direction vector. The left/right vectors always belong to this plane, but we don't know those (as well as the physical up-vector, which we are about to get). Well we need two vectors to represent this plane, one arbitrary vector and one that's perpendicular to that (and the direction vector). To ease things up, we'll pick (0,0,1) as the first, and the second one is perpendicular to that, I.E. it's along x-y-plane. It's also perpendicular to the direction vector, which means, we can take the x-y-plane projection of that (xto-xfrom, yto-yfrom, 0), and get the vector that's 2-dimensionally perpendicular. This becomes (yfrom-yto, xto-xfrom), as vectors (a,b ) and (-b,a) are always perpendicular.

The vector (0,0,1) is not needed anymore, as it's not on the projection plane. The vector (xto-xfrom, yto-yfrom, 0), however is. Let's name this v for future reference. The second vector we need to represent the plane is most comfortably perpendicular to v and the direction vector. We have a useful vector operation as cross-product. It will yield a vector that's perpendicular to both the vectors that were 'multiplied' (its length doesn't matter here). So we will take a cross-product out of v and the direction vector (let's denote this as d and the vector coordinates with suffixes x, y and z). This cross-product will become:
(vy*dz-vz*dy, vz*dx-vx*dz, vx*dy-vy*dx) =
((xto-xfrom)*(zto-zfrom), -(yfrom-yto)*(zto-zfrom), (yfrom-yto)*(yto-yfrom)-(xto-xfrom)*(xto-xfrom)) =
((xto-xfrom)*(zto-zfrom), -(yfrom-yto)*(zto-zfrom), -(yto-yfrom)2-(xto-xfrom)2).

Now we have the two vectors, what to do with them? Well we wanted to represent the plane because the desired up-vector is always on it. We can get this vector by treating the plane as if it was any other plane, such as the x-y-plane - the vectors we got are the axes. We know the point in direction (with arbitrary distance, here it can be 1) is got by:
```x = lengthdir_x(1,angle);
y = lengthdir_y(1,angle);```
Well if we were going to represent the x-axis with a vector i=(1,0) and y-axis as the vector j=(0,1), this specific vector would be lengthdir_x(1,angle)*i + lengthdir_y(1,angle)*j. But this doesn't limit to x-y-plane; we use the vectors we found, name them i and j, and calculate the vector. Goal.

GM doesn't use vectors as data, so we need to separate the vector into coordinates. "lengthdir_x(1,angle)" and "lengthdir_x(1,angle)" are scalars (real numbers), so we can deal with the multiplication as a typical scalar times vector case: let a = (ax,ay) and the scalar be s; the multiplication sa will be: (s*ax, s*ay) (basic vector maths; sum (ax,ay)+(bx,by) = (ax+bx, ay+by)). if i = (yfrom-yto, xto-xfrom, 0) and j = ((xto-xfrom)*(zto-zfrom), -(yfrom-yto)*(zto-zfrom), -(yto-yfrom)2-(xto-xfrom)2), the up-vector will be:
( lengthdir_x(1,angle)*(yfrom-yto) + lengthdir_y(1,angle)*(xto-xfrom)*(zto-zfrom),
lengthdir_x(1,angle)*(xto-xfrom) + lengthdir_y(1,angle)*-(yfrom-yto)*(zto-zfrom),
lengthdir_y(1,angle)*(-(yto-yfrom)2-(xto-xfrom)2) )

There is one last twist: in order for the camera to tilt in a perfect circle, the i and j vectors need to be equally sized. The length of vector i is always sqrt((xto-xfrom)2+(yto-yfrom)2), and the length of the direction vector is always: sqrt((xto-xfrom)2+(yto-yfrom)2+(zto-zfrom)2). The length of cross-product is the lengths of both the 'multiplied' vectors multiplied together times sine of the angle between. Well in the cross-product j we had vectors d and v, which are already perpendicular - the sine of the angle between is always 1. Therefore j's length is the same as i's length times d's length, meaning that we need to divide the vector j by d's length.

In the previous code I also divided by i's length but it's totally redundant here. Note that in that code the factors of lengthdir_[x/y](1,angle) are taken inside the first argument, as that can freely be done. However, the biggest difference from that to this is my choise for i and j (previously they were the other way around). This makes the normal state to be the up-vector be perpendicular to (0,0,1) (technically this isn't 'wrong, people just seem to prefer 0-tilting as the (0,0,1) direction). I'll write the code down again and change these variables.

The code, when optimized a little will then end up looking like:
```var xx, yy, zz, dx, dy;
xx = xto - xfrom;
yy = yto - yfrom;
zz = zto - zfrom;
dx = lengthdir_x(1,angle)/sqrt(xx*xx + yy*yy + zz*zz);
dy = lengthdir_y(1,angle);
xup = - dx*xx*zz - dy*yy;
yup = dy*xx - dx*yy*zz;
zup = dx*(xx*xx + yy*yy);```

I hope someone took the time to actually read what I wrote here.

Edited by Tepi, 26 June 2009 - 05:43 PM.

• 0

### #11 stewrat

stewrat

GMC Member

• GMC Member
• 7 posts

Posted 28 June 2009 - 09:06 PM

Wow! Thanks alot! That makes perfect sense. It's really clear now!!! Thanks a ton for taking your time to do this!
stewrat
• 0

### #12 Tepi

Tepi

GMC Member

• Global Moderators
• 4203 posts
• Version:GM8.1

Posted 28 June 2009 - 09:27 PM

Wow! Thanks alot! That makes perfect sense. It's really clear now!!! Thanks a ton for taking your time to do this!
stewrat

You're welcome.

I always get a little carried away when explaining mathematical things.
• 0

### #13 brett14

brett14

GMC Member

• GMC Member
• 1150 posts
• Version:GM8

Posted 28 June 2009 - 10:57 PM

Wow! Thanks alot! That makes perfect sense. It's really clear now!!! Thanks a ton for taking your time to do this!
stewrat

You're welcome.

I always get a little carried away when explaining mathematical things.

trust me, that's a good thing, better over explaining than under (i usually under explain things and get lots of questions)

Edited by brett14, 28 June 2009 - 10:58 PM.

• 0

### #14 fps freak

fps freak

GMC Member

• New Member
• 2 posts
• Version:Unknown

Posted 19 April 2012 - 08:47 AM

Wow! Thanks alot! That makes perfect sense. It's really clear now!!! Thanks a ton for taking your time to do this!
stewrat

You're welcome.

I always get a little carried away when explaining mathematical things. :D

trust me, that's a good thing, better over explaining than under (i usually under explain things and get lots of questions)

Can you Give a example. it isn't working by me.
• 0

### #15 slayer 64

slayer 64

GMC Member

• GMC Member
• 3300 posts
• Version:GM8.1

Posted 23 April 2012 - 12:40 AM

Example i made a while ago. uses quaternions
• 0

#### 0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users