Skip to main content
gamedev.net
🔒 Locked 🎮 Unity

Spaceship Control Problems

Started by KnyghtMare Aug 6, 2006 at 7:03 PM 6 replies 1.7k views
Original Post
KnyghtMare
KnyghtMare
Hello. I am currently exploring making a space ship game with DirectX using C#. My current dilema is how to control the space ship correctly. My aim is to create a mechanism where in order to change the direction the ship is going you have to roll left or right and then pitch to travel in the correct direction. This is how the ship starts: http://jenova.defcon-gaming.com/game/game-start.jpg Then when I roll: http://jenova.defcon-gaming.com/game/game-roll.jpg And when I pitch: http://jenova.defcon-gaming.com/game/game-pitch.jpg And, finally, the combination of the two: http://jenova.defcon-gaming.com/game/game-combined.jpg The white arrow indicates the dirctions the ship should be looking in. My code is as follows: renderDevice.Transform.World = Matrix.Scaling(renderObjects.Scale, renderObjects.Scale, renderObjects.Scale) * Matrix.RotationYawPitchRoll(renderObjects.Yaw, renderObjects.Pitch, renderObjects.Roll) * Matrix.Translation(renderObjects.X, renderObjects.Y, renderObjects.Z); this little bitty is scaling the model being rendered, applying the correct yaw,pitch and roll and moving it to it's correct co-ordinates in world space. Can anybody please suggest the correct matrix math to achive the desired effect?
haphazardlynamed
haphazardlynamed
1 - you really need a Clearer ship model for your illustration, that thing is all gray and I cant tell what direction it is pointed in anyway

2 - that doesnt matter, because your problem is obvious from the description, and the fact that Everyone starting out runs into it.

Separate rotations for X,Y,and Z axis (pitch,yaw,roll) is what we call Euler Angles rotations.
The Order that they are applied Matters - Euler ROtations are Not Commutative.

Really, for a Space game, you shouldn't be representing your Orientation using Euler at all, because no matter what order you do them in, there will always be a funny case.

Your solution depends on how you are reprsenting Ship Orientation, in your Physics (not the graphics model).
Hopefully, the Physics model is Not using Euler reference from the World 0 system; because if it is, we have a much more serious problem...

Ideally, from your Physics engine you already know the Ship Local x,y,z orientation.
From those you can generate a direction Orientation Matrix, which rotates your graphics model to match instantly, rather than separate X,Y,X rotations.
This will need manual matrix generation... lookup the DirectX function for this... i use OpenGl...
More info later...
KnyghtMare
KnyghtMare
Firstly, thankyou for your reply.

I am aware of the problems with using this system of rotating objects and the camera and the fact that it can, and will, lock.

The simple fact is that moving the ship in any other method is currently beyond my level in the 3D game arena.

I have attempted to rotate the object's x, y and z axis seperately in every possible order and got the same results (or some other, expected results) but did not find a solution to my problem this way.

Any farther help or resources you can direct me to would be very much apreciated.

Thankyou.
Bucket_Head
Bucket_Head
Hey, if you feel that something is beyond your ability, that's a good time to start extending your ability.

With this sort of problem, I find it useful to try looking from different angles (so to speak), including looking at simpler versions of the problem. Consider the 2D case -- much simpler, I know, but as we'll see, we can draw some very useful wisdom from it.

As I'm sure you know, you can represent a two-dimensional rotation as a simple number, an angle, typically in radians or degrees, with 0 pointing right and increasing counter-clockwise. You can just as well represent a two-dimensional rotation as a rotated reference frame -- a pair of orthogonal (perpendicular) unit vectors that form a basis. Let's picture these vectors in our minds as arrows pointing out from the origin. You start with a vector pointing along the X axis, with coordinates (1, 0), and another vector pointing along the Y axis, with coordinates (0, 1). If we apply a rotation of 90 degrees, we get a new reference frame, with the first vector rotated to become (0, 1) and the second vector rotated to become (-1, 0). A handy way to visualize this is by taking the thumb and forefinger on your left hand, forming an L, and to tip it counter-clockwise 90 degrees.

Now, as you may know (and if you don't, you can see that it is true with trial and error) the coordinates of the first "x" vector, as it is rotated into a new reference frame by some angle theta, follow a pattern -- the coordinates will be at (cos theta, sin theta). The coordinates of the second "y" vector are like those of the first, but 90 degrees out of phase ahead of the "x" vector -- with coordinates at (-sin theta, cos theta). More information about this phenomenon can be found at http://en.wikipedia.org/wiki/Unit_circle.

Next, take a look at a 2-dimensional rotation matrix:

[cos(theta) -sin(theta)]
[sin(theta) cos(theta)]

Hmmmm...say, aren't those the coordinates of the "x" vector down the first column, and the coordinates of the "y" vector down the second column? By jove, it is!

I'm not going to delve into a full explanation of just how this works, though if you spend about ten minutes thinking about it and tooling around with a pencil and paper (and considering the definitions of sine and cosine, and they shape of their wave patterns and such) you'll hopefully arrive at a fairly intuitive understanding that you can work with.

But in any case, you can do the same thing with vectors in 3-dimensional space. Any arbitrary rotation in 3-D space can be represented as a 3x3 matrix with three mutually orthogonal unit-length vector columns -- and these would be the "x," "y," and "z" vectors, exactly as they are when rotated into place. Very straightforward, isn't it? You could simply maintain one of these matrices to represent ship orientation, and whenever you want to change the ship's orientation, you can simply multiply this matrix by a matrix representing the small rotation change, and the result is the rotated matrix.

A few notes though -- first and foremost, beware of precision errors accruing! Over time, your vectors might wear down and change to non-unit length, or stop being so orthogonal. There are steps you can take to fight against this though -- think about it.

An alternative is to explore the crazy world of quaternions which are much smaller (a mere 4 floats vs the 9 you'd need for a 3-D rotation matrix), which are less prone to precision error wear and tear, and which multiply together much faster than matrices do -- however, they are more difficult to comprehend. Still, if you're interested, you can start by following a similar path to what's outlined above, and begin by exploring the 2-dimensional version of quaternions, called complex vectors or even complex numbers. Even besides all that, many people have utilized quaternions without understanding them at all, simple working with them as a black box, and using them as a drop-in replacement for rotation matrices.

Anyways, more food for thought.
Hai, watashi no chichi no kuruma ga oishikatta desu!...or, in other words, "Yes, my dad's car was delicious!"
KnyghtMare
KnyghtMare
wow, that's alot of text to take in. I read it all and probably missed the meaning of 99% of it :(

I read it last night, sat down with a pen and paper and drew 2-D axis in order to try and solve this issue.

My problem is that I have no idea how this should work in theory and all my trial/error attempts have been complete failure.

For now, let's say the ship is rolled by PI/4 radians. This is 1/8th of a circle.
This leaves the ship facing dead along the z-axis and the top of the ship pointing half way between the x-axis and the y-axis.

Now, to my mind, to pitch on the correct vector should be a simple application of trig.

Opposite = Sin(Theta) x Hypotenuse.
Adjacent = Cos(Theta) x Hypotenuse.

When I attempt to modify pitch and yaw by these values I get an approximately correct movement by the ship starts to veer to the left (towards negative x) and finally the ship ends up facing upwards or close to it (directly along the y axis).

Grr.
haphazardlynamed
haphazardlynamed
Ok then, lets start with some concepts...

First, the concept of multiple coordinate systems.

You already have one obvious coordinate system used to represent the location that your ship is located at. We call this the 'World' or 'Global' coordinate system. It has X,Y,and Z axis directions.

Lets say you start out with your ship at the center of World at 0,0,0 and with it's nose pointed in the +Y direction.
At this time Ship yaw corresponds to the World Z axis, pitch -> X, roll -> Y.

But, what happens if we roll the ship 90*? the nose is still pointed at World +Y axis, but now the top of the ship is pointed at +X, and the side is pointed at -Z.
the previous relationship of yaw->Z, pitch->X, roll->Y is no longer true!
If we try to do a second rotation of the ship in a different direction now, it will mess up.

the solution:
Since the pitch,yaw,roll of the Ship are not guaranteed to always match the World X,Y,Z axis, we Should Not use the World Coordinte System to apply ship rotations; only use it for the ship location coords.

This is where the concept of Multiple coordinate systems arrives.
Introduce a new 'Local' coordinate system, which uses the ship as its center 0,0,0 reference, and uses the ship's front, top, and right sides to designate it's axis. Call them x,y,z -they are defined to Always match the Ship. (notice that these axis are lowercase, while the World was uppercase)

These x,y, and z axis can be seen by someone standing in the World system as 3 vectors that are perpendicular to each other, and they would rotate as a group and point different directions to represent Ship rotation.
In fact, that is one way to store the Local coordinate system; as 3 vectors who's coordinates represent directions in World. (3 vectors is the same as a Matrix BTW)

We already said that the Ship and Local axis are one and the same, so to rotate the ship, what we really want to do is change the directions of the Local x,y,z axis as seen from World.
Here is where we need to step away from OpenGl; in order to rotate our own x,y,z Local vectors permanenetly, we need to do the calculation ourselves.
OpenGL can only rotate the graphics for the video card; it won't give us the results back.
You will need to implement your own Rotation Matrix for Arbitrary Axis.(this is a section itself, time to break some books)

When your Ship rotates around one axis, you will actually use that to generate the arbitrary matrix, then apply it to the other two Local axis to have them change direction. Basically the Ship's Local x,y,z are used to rotate each other; and you replace them with the new rotated versions each time.

So by now we have a set of 3 vectors x,y,z that are spinning around as we rotate the Ship; all you have to do next is attach the Ship Graphics model to them so it matches the orientation, and do whatever position translateion you need within World.
Setting the Ship Graphic to match the Local x,y,z coords can easily be done by using pushing them as a custom matrix into OpenGl (theres a function to do this). But for now I think it might be easier for you to use glLookAt to do it. just have your ship model 'look at' the direction of the Local y, and use Local z as the lookat 'up' direction......


anyhow... thats the overall concept, try to understand the process and idea even though you don't necesarially have to full math yet
since you really do need the 'picture' in your head before you can apply anything...

there's a big grid on the floor (World) and flying around in the air and rotating is a little triple cross shape (Local) and the Ship model is pinned to that cross
KnyghtMare
KnyghtMare
WOW. Why the hell didn't I think of that.

Thankyou for the insight.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.