Angles between two spaceships (think Wing Commander) [ALMOST got it]

Started by
33 comments, last by Zakwayda 13 years, 5 months ago
Hi,

I forgot to add something -

You can update the direction vector rather easily, as you can rotate it by
any angle you wish using a matrix, or build it from a set of 2 angles (convert from spherical coordinates).

This solution is simple. It doesn't really have the generality of a quaternion
or orientation matrix. It doesn't really need to be integrated using a numerical
integrator such as Euler's or RK4.

Simple to visualize, simple to manipulate and update and good for your purpose, I believe.
-----------------------------He moves in space with minimum waste and maximum joyGalactic Conflict demo reel -http://www.youtube.com/watch?v=hh8z5jdpfXY
Advertisement
Hi,

I forgot to add something -

You can update the direction vector rather easily, as you can rotate it by
any angle you wish using a matrix, or build it from a set of 2 angles (convert from spherical coordinates).

This solution is simple. It doesn't really have the generality of a quaternion
or orientation matrix. It doesn't really need to be integrated using a numerical
integrator such as Euler's or RK4.

Simple to visualize, simple to manipulate and update and good for your purpose, I believe.
-----------------------------He moves in space with minimum waste and maximum joyGalactic Conflict demo reel -http://www.youtube.com/watch?v=hh8z5jdpfXY
Hi,

I forgot to add something -

You can update the direction vector rather easily, as you can rotate it by
any angle you wish using a matrix, or build it from a set of 2 angles (convert from spherical coordinates).

This solution is simple. It doesn't really have the generality of a quaternion
or orientation matrix. It doesn't really need to be integrated using a numerical
integrator such as Euler's or RK4.

Simple to visualize, simple to manipulate and update and good for your purpose, I believe.
-----------------------------He moves in space with minimum waste and maximum joyGalactic Conflict demo reel -http://www.youtube.com/watch?v=hh8z5jdpfXY
Okay, interesting. So let me, before I blindly rewrite my code, make sure I understood you correctly there. Let's also leave the roll out just for a second, I do need it in the end but I want to simplify this as much as possible first.

You suggest I simply store a direction vector for each object, basically a "forward axis" or a "normal" if you want. You say that:

Quote:Original post by voguemaster
2. If every ship has a direction vector, finding the relative vector between
them is trivial.


Now this is what I'd like clarification on - how would I go about getting that relative vector between two direction vectors and then extracting pitch/yaw from these (the latter one I'm confident I can pull off myself with some basic research, the first one stumbles me).

Thanks a ton for the help so far. I really hope I can get this working.
Ok,

If I understand your problem correctly, the player's eye point (the camera) is basically in the cockpit, right ? Just like in X-Wing (although that game had an outside view, it was a chase camera so its not that much different).

So, the relative angle between the player's ship and the enemy will determine which frame you're using, right ?

So, given the system I suggested, finding the relative angle between them is done by finding the relative vector (which is just substraction) and then converting to angles.

Once you have the angles (spherical coordinates, remember that), you basically divide each with the factor I mentions earlier (36 possible directions for example means a factor of 10), in order to get the index into the array.

Since your array is a 2D array, you have two indices from the two angles.

You just need to build the array in a convention that matches the result of the calculation.
-----------------------------He moves in space with minimum waste and maximum joyGalactic Conflict demo reel -http://www.youtube.com/watch?v=hh8z5jdpfXY
You're absolutely right. Your solution sounds extremely easy. I just gave it a try but the end result is still rather random-looking. From time to time it'll actually look right but then I move the camera some more and it just throws the enemy ship around, turn it full 180 degrees or something. That's certainly not all that's wrong though, from some angles it has yaw and pitch mixed up (moving the camera left makes the ship angle go lower vertically for example), while from other angles the directions are correct.

This is my code, as always, right before rendering an enemy ship when determining which textures from the 2D array of textures to use, ie. which pre-rendered angle perspective:

// calculating the relative vector, I did try flipping this as well// direction is the forward vector of this particular enemy shipD3DXVECTOR3 v_rel = direction - camera.forward_axis;// extracting yaw and pitch (in radians) from that relative vectorfloat yaw = atan2f ( v_rel.x, v_rel.y );float pitch =  atan2f ( v_rel.z, sqrtf ( ( v_rel.x * v_rel.x ) + ( v_rel.y * v_rel.y ) ) );// converting so that we now have yaw and pitch values from ranges 0-32 and 0-17 respectively (instead of 0-360)yaw = ( ( D3DXToDegree ( yaw ) + 180.0f ) / 360.0f ) * 32.0f;pitch = ( ( D3DXToDegree ( pitch ) + 180.0f ) / 360.0f ) * 17.0f;// determining the texture from the 2D array to use based on yaw and pitchsprite_slot = ( int ) ( pitch - 1 ) * 32 + ( int ) yaw;


Am I still doing something wrong? Or is this definitely right and the error has to be in my direction vectors for camera and ship (I'm very, very sure these are correct tho).

Thanks a TON for your help, rating++!

I *hope* I can get this to work, would be soooo important for this project of mine. :D
Hi,

A few things to consider with this calculation I'm not sure you're aware of:

1. If you're using the CRT version of the atan2 function (atan2f) which I think you are, then the Y component is the first argument to the function, not X.

2. The result given by atan2f returns the arc-tangent but the signs determine the quadrant. For simplicity's sake, if I draw from my own example then:

I have 24 frames in my sprite "sheet", indices are [0..23]
I have a direction vector (x,y).
I convert it with atan2(y,x). Note that if y>0, the angle will be positive. If y<0, the angle will be negative. Now, I worked with a convention that angle 0 is aligned with the positive X-axis, while 180 is negative X-axis (basically the unit circle).
This means that I had to negate the Y component before passing it to atan2, otherwise I'm not working in the convention of the function.

Now, since the angle can turn out negative, I did something simple like this to revert back to my convention:

angle = (angle >= 0) ? angle : angle+360;

(this was done is fixed point but that's the basic idea).

Once I had the angle in "my" convention, it was trivial.


So the moral is -

1. Check your signs.
2. Check the calculation with simple inputs. For example, player's direction is 0,0,1 or something simple and the enemy's direction something like 1,1,1.
Try various inputs to make sure you're going through the calculation properly.
-----------------------------He moves in space with minimum waste and maximum joyGalactic Conflict demo reel -http://www.youtube.com/watch?v=hh8z5jdpfXY
Okay, makes sense. I did follow your sign-checking advice and flipped the parameters for atan2f to follow the y/x order. That didn't change anything from tho looks of it though. I also realized that, since the result wasn't just wrong in one sense (ie. right frames but in the wrong orientation or whatever) but rather totally unpredictable, I'd go ahead and hard-code direction vectors to check the math.

What do you know, there is a problem somewhere. I want to get only yaw to work first, so the pitch is hard-coded to be 180 (ie. neutral to the camera).

D3DXVECTOR3 t1 ( 0.0f, 0.0f, -1.0f ), t2 ( 0.0f, 0.0f, 1.0f );D3DXVECTOR3 v_rel = t1 - t2;float yaw = atan2f ( -v_rel.y, v_rel.x );float pitch = 180.0f;yaw = D3DXToDegree ( yaw );yaw = ( yaw >= 0.0f ) ? yaw : yaw + 360.0f;	// DEBUG OUTPUT OF YAW AND PITCH HEREyaw = ( yaw / 360.0f ) * 32.0f;pitch = ( pitch / 360.0f ) * 17.0f;sprite_slot = ( int ) ( pitch - 1.0f ) * 32 + ( int ) yaw;


These are the different yaw values I get for hard-coded direction vectors:

t2       yaw-1/0/0   01/0/0    1800/0/-1   00/0/1    0(t1 is 0/0/-1 throughout)


Clearly, there is something very wrong here. I'm absolutely out of ideas - can this be a problem of signs anymore even? If so, what am I doing wrong?

Thanks again.
That output looks correct to me for the given input. It's not immediately clear to me though how your algorithm is intended to work, so I can't offer much beyond that in the way of specific comments.

I don't have a lot of experience with games that use this particular technique, but it seems to me that if all the ships involved are capable of full 6DOF motion, a lot of sprites would be required in order to represent all the possible relative orientations suitably. Did other games that used this technique impose some additional constraints to cut down on the number of sprites required?

If you really do need to represent all possible relative orientations (quantized, of course), then it seems a quaternion-based solution (as discussed previously) might be more suitable. The relative orientation between the viewer and the object in question can easily be computed, at which point it becomes a matter of choosing the sprite that most closely matches the resulting orientation quaternion. I imagine you can do better than a brute-force search for this; although I only skimmed the post, it seems something like what Emergent was describing might be appropriate.

This is probably similar to what Emergent was talking about, but you can 'compress' a quaternion into 3-d vector form by negating it if the value of w is negative, and then dropping the w component. This leaves you with a 3-d vector with length in the range [0, 1].

You can think of this vector as a vector (i.e. with direction and length), or as a point that falls somewhere in the unit sphere. Conceptually, we want to discretize the interior of a unit sphere and assign a sprite to each 'cell'.

One way to approach this might be to break it into two steps. First, if the input vector does not represent identity (or close to it), intersect a ray with direction parallel to the input vector with the surface of the sphere, and identify the 'cell' in which the intersection point falls. This requires discretizing the surface of the sphere somehow, but we'll set that problem aside for now.

Each cell on the sphere surface corresponds to a subset of the set of sprites; a specific sprite from this subset is then chosen based on the length of the vector.

Another approach might be simply to use a 3-d grid of cells. Finding the cell corresponding to the input orientation would then be O(1), so there would be no concerns with respect to performance.

This is all speculative of course, and I may be overlooking something or other, but given the problem description, what I'd probably try first would be:

- Use a regular 3-d grid (subdivision of the unit cube) to represent the possible orientations, with those cells that fall within the unit circle corresponding to orientations in compressed quaternion form.
- Generate the sprite for each cell procedurally somehow (presumably you're using a modeling program of some sort to generate the sprites).
- To render the correct sprite, compute the relative orientation between the viewer and the object in question in quaternion form, compress the quaternion, and then find the cell in the 'sprite grid' in which the resulting point falls.

Again though, all completely speculative.
Thanks first of all. Let me go through your post step-by-step...

Quote:Original post by jyk
That output looks correct to me for the given input. It's not immediately clear to me though how your algorithm is intended to work, so I can't offer much beyond that in the way of specific comments.


I'm trying to follow voguemaster's advice - leaving roll out of the equation for the moment - and extracting pitch and yaw angles from a vector. In the latest code segment I posted, I also left the pitch calculation out so I was really expecting to get yaw values between 0-360 from the vector. In a game like Wolfenstein you'd do the same to draw sprites that aren't billboards. With my camera direction being fixed for the moment at 0/0/-1 I'd have expected a yaw of 0 for 0/0/-1 enemy ship direction, 90 for 1/0/0, 180 for 0/0/1 and 270 for -1/0/0. Or something similar.

Quote:Original post by jyk
I don't have a lot of experience with games that use this particular technique, but it seems to me that if all the ships involved are capable of full 6DOF motion, a lot of sprites would be required in order to represent all the possible relative orientations suitably. Did other games that used this technique impose some additional constraints to cut down on the number of sprites required?


Well, other ships don't need full 6DOF if it isn't possible (without rendering a buttload of additional frames) - just 6DOF for the camera would be fine. So far I have 32x17 (ie. 544) frames per ship for every angle (32 yaws and 17 pitches - 17 so that there is a neutral pitch in the middle). Obviously it would not be an option to add, say, 24 roll angles in there. It already takes a while to load 544 textures per ship class into RAM.

My plan was to do it without roll first and then hoping I could figure a way out where I rotate the actual Direct3D billboard quad that I use to render a ship. Then also shift the texture index somehow as well of course.

FOR REFERENCE: I'm actually willing to leave roll completely out of the picture. I'd be satisfied if I got the right frame for any yaw/pitch combination only.

In regards to the rest of your post, jyk, that was sort of what I was afraid of. Do you think, with the additional information I gave above and no roll, it would be possible to pull this off as voguemaster suggested.

This topic is closed to new replies.

Advertisement