# Help: Rotating Around Projection Axis

### #1

Posted 24 June 2009 - 06:14 PM

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.

Thanks for taking your time to answer.

stewrat

### #2

Posted 24 June 2009 - 06:36 PM

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:59 PM.**

### #3

Posted 24 June 2009 - 11:19 PM

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!

### #4

Posted 24 June 2009 - 11:28 PM

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?

### #5

Posted 24 June 2009 - 11:37 PM

### #6

Posted 24 June 2009 - 11:42 PM

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 - 01:03 AM.**

### #7

Posted 25 June 2009 - 12:26 PM

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

### #8

Posted 25 June 2009 - 05:22 PM

P3DC V6.00 | Editor14 | Large 3D Terrain

GML programmer since 2005, C/C++ programmer since 2009, Java programmer since 2012

### #9

Posted 25 June 2009 - 07:36 PM

### #10

Posted 25 June 2009 - 11:17 PM

Ah, OK. Thanks for the info (I didn't even get to waste my time, as I didn't get to test it yet).Heh. It was my bad. Forgot to change a variable. Works great now! Thanks a whole lot!!!!!!!

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

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 s

**a**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:57 PM.**

### #11

Posted 28 June 2009 - 09:20 PM

stewrat

### #12

Posted 28 June 2009 - 09:41 PM

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

stewrat

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

### #13

Posted 28 June 2009 - 11:11 PM

trust me, that's a good thing, better over explaining than under (i usually under explain things and get lots of questions)You're welcome.Wow! Thanks alot! That makes perfect sense. It's really clear now!!! Thanks a ton for taking your time to do this!

stewrat

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

**Edited by brett14, 28 June 2009 - 11:12 PM.**

P3DC V6.00 | Editor14 | Large 3D Terrain

GML programmer since 2005, C/C++ programmer since 2009, Java programmer since 2012

### #14

Posted 19 April 2012 - 09:01 AM

trust me, that's a good thing, better over explaining than under (i usually under explain things and get lots of questions)You're welcome.Wow! Thanks alot! That makes perfect sense. It's really clear now!!! Thanks a ton for taking your time to do this!

stewrat

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

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