Page 1 of 1

How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Thu Aug 01, 2024 5:28 pm
by SomeGuyWithAComputer
I'm making a spaceship game. I'm using irrlicht for the graphics and reactphysics3d for the physics engine. In this game, the ships have "flight assist" which need to be able to hold yaw, pitch and/or roll angular velocities to a target.

The problem I'm running into is there doesn't seem to be any possible way to get these values. Reactphysics3d has a getAngularVelocity() function which does work, the only problem is that it can only give me the absolute angular velocity. This is entirely unsuitable for this application because there is no way to get pitch angular velocity, roll angular velocity and yaw angular velocity separately. I guess what I need is a way to get relative angular velocity. Relative to the "front?" of the ship. i.e. pitching forward should be possible to be measured using a single number regardless of what yaw or roll orientation the ship is in. Both irrlicht and reactphysics3d have quaternion data types. I have not yet figured out how to or if its possible to get relative angular velocities from them yet. For what it's worth, the irrlicht quaternion seems to be a little more feature complete however even after days of trial and error I haven't got anywhere with this.

Any ideas? How can I get pitch angular velocity, roll angular velocity, and yaw angular velocity relative to the spaceship object using nothing but what's in the c++ standard library, irrlicht and the getAngularVelocity function in reactphysics3d?

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Thu Aug 01, 2024 6:51 pm
by CuteAlien
Not quite sure if it makes sense - rotations are not independent - even if you only use pitch and yaw you can start rolling. What you have in the end is a rotation around a single axis with a certain speed. But you don't know how you got there.

Anyway - if you still kinda want to know how that is in your local system (it makes a bit sense to me), maybe this Unity thread I found helps: https://discussions.unity.com/t/how-to- ... ocity/3582 but I've not digged too deep in the answers. Would have to experiment to figure out if those answers work. My own guess would have been that maybe velocities are kinda similar to direction vectors so using tranformVector with the unscaled absolute transformation might work. But I'm really not so good with physics, so that could be completely wrong :-(

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Thu Aug 01, 2024 8:02 pm
by SomeGuyWithAComputer
An idea I got while brainstorming is make 3 "virtual" angularVelocity sensors that are attached to the ship's scene node. One faces forward, one faces upward and one faces to a side. They then keep track of their current rotation along with whatever their rotation value in the last frame was so that they can each return an angular velocity vector, hopefully each sensor will return different ones. It would have to be implemented via irrlicht and i'm not entirely sure what problems I'll run into trying to manually calculate angular velocity that way.

If that works, it might be possible to somehow use that to get the information I need if I brute force trial and error all the quaternion functions. Although I don't understand the math behind it. Similar approaches to this have worked in other games I've made mods for but it's usually a lot easier to get relative values and stuff in game modding. Stormworks is one such example. It's hard to get relative rotations (or whatever you call this type of rotation data im trying to get) in custom stormworks lua scripts but not this hard.

I just need some way of relaying to the autopilot pids how fast the ship is rotating in every direction so that it knows what control movements to assert in order to bring the ship's rotation to a stop. I thought at first maybe I was thinking about it wrong and trying to reinvent the wheel but I guess it's a really advanced difficult theoretical math problem after all. Maybe I'll try to track down a mathematics or physics professor and ask them about this.

Maybe I'm not asking the right questions. Maybe - what if I only wanted to get the angular velocity of the ship's y axis? Meaning that no matter what orientation the ship is in, whatever yaw rotational movement is happening could be expressed by 1 single number and not a vector of 3 numbers. Leftward rotation would always be a negative number and rightward rotation would always a positive number. I know that's a possible thing to figure out but I don't know how to get that data with what I have to work with. I bet if I knew the answer to that question I could find some way to apply it to the other angular velocities I want to measure.

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Thu Aug 01, 2024 9:29 pm
by CuteAlien
Yeah, not sure myself. Bit complicated as you get the values from the physics engine so you probably only have the matrices (otherwise you _know_ your rotation changes as you have to set them). So if you only have the final matrices (not sure if that' true? Depends on physics engine) I guess you could get the relative one for the last frame by multiplying the latest transformation matrix by the inverse of the previous matrix. And from that result you can get the euler angles and those would be pitch, yaw, roll you did in the last frame relative to your current orientation. This gives you an answer... the problem is - it won't always be the optimal one. Like you might get eulers which add 2 unnecesary 180° rotation because those end up with the exact same result. As mentioned above - the problem with rotations is that there is more than one way to rotate things and end up with identical end position - there isn't just a single solution like with positions. Example: yaw by 180° will give the exact same result as roll 180° + pitch 180°. You can't tell afterwards which one was used unless your physics engine gives you that information (which getAngularVelocity probably does).

If you know your rotations are never above 180° in a single frame then maybe there is a better solution, but I don't see it. Quaternion slerp will give you the shortest rotation path between 2 quaternions for every position in between. But the result is again only an absolute rotation. So this doesn't solve your problem.

Starting with the getAngularVelocity you got already didn't sound so bad to me. Maybe just give my stupid idea from above a shot. Use the transformation matrix you got and then use the rotateVect function of Irrlicht matrix with that getAngularVelocity. As long as no scaling is involved (or scaling is at least uniform in all directions) this maybe work. Or is totally wrong... I'm really not sure as it's rotations around an axis and not directions... still trying to wrap my head around that.

Edit: pretty sure by now this is wrong because getAngularVelocity is less like a vector but more like a rotation matrix as it describes 3 rotations - which is just the same thing an inner 3x3 matrix does.

To get further confused you can always ask ChatGPT - it tends to have it's own wrong answers for such questions. And sometimes those push you in the right direction ;-)

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Fri Aug 02, 2024 1:08 am
by SomeGuyWithAComputer
Would it be possible to convert that getAngularVelocity() vector into a form that would actually work with rotateVect()? Your idea is the most correct sounding thing I've heard all day. How do I convert it to a 3x3 matrix? I believe (but haven't proven) that the units from getAngularVelocity() are in radians/second.

I'm going to guess its:
x 0 0
0 y 0
0 0 z

but even if that's correct i'd have to find a way to convert it to a vector and I highly doubt it's just (x, y, z)

note that I also have these useful functions I found on an irrlicht forum post from a long time ago:

Code: Select all

irr::core::vector3df rotateAxesXYZToEuler(const irr::core::vector3df &oldRotation, const irr::core::vector3df &rotationAngles, bool useLocalAxes)
{
	irr::core::matrix4 transformation;
	transformation.setRotationDegrees(oldRotation);
	irr::core::vector3df axisX(1, 0, 0), axisY(0, 1, 0), axisZ(0, 0, 1);
	irr::core::matrix4 matRotX, matRotY, matRotZ;

	if (useLocalAxes)
	{
		transformation.rotateVect(axisX);
		transformation.rotateVect(axisY);
		transformation.rotateVect(axisZ);
	}

	matRotX.setRotationAxisRadians(rotationAngles.X * irr::core::DEGTORAD, axisX);
	matRotY.setRotationAxisRadians(rotationAngles.Y * irr::core::DEGTORAD, axisY);
	matRotZ.setRotationAxisRadians(rotationAngles.Z * irr::core::DEGTORAD, axisZ);

	irr::core::matrix4 newTransform = matRotX * matRotY * matRotZ * transformation;
	return newTransform.getRotationDegrees();
}

irr::core::quaternion getRelativeRotation(const irr::core::vector3df &oldRotationEulerDeg, const irr::core::vector3df &newRotationEulerDeg)
{
	irr::core::quaternion q1(oldRotationEulerDeg * irr::core::DEGTORAD);
	irr::core::quaternion q2(newRotationEulerDeg * irr::core::DEGTORAD);
	irr::core::quaternion qRel(q2 * q1.makeInverse());
	return qRel;
}

irr::core::vector3df applyRelativeRotation(const irr::core::vector3df &oldRotationEulerDeg, const irr::core::quaternion &relativeRotation)
{
	// Add relative rotation
	irr::core::quaternion qt(oldRotationEulerDeg * irr::core::DEGTORAD);
	irr::core::quaternion qt2(relativeRotation * qt);

	irr::core::vector3df rotateTarget;
	qt2.toEuler(rotateTarget);
	rotateTarget *= irr::core::RADTODEG;
	return rotateTarget;
}
rotateAxesXYZToEuler() seems to solve certain rotation problems when used correctly. I haven't found a use for the other 2.

An example of an angular velocity is x=0.493692, y=0.000000, z=0.000000. Eyeballing rotations as it updates does appear to be in radians per second. Using the irrlicht vector and quaternion stuff seems to be the way to go just because there are more functions available. reactphysics3d is really only helping in this context by being the only way to get the angular velocity.
Quaternion slerp will give you the shortest rotation path between 2 quaternions for every position in between. But the result is again only an absolute rotation. So this doesn't solve your problem.
I haven't tried it yet but maybe supplying an upward or sideways vector relative to the ship along with the absolute rotation for the second variable might do.. something.

Edit: I found the irrlicht rotationToDirection() function. Making a directionToRotation() function might be possible.. not sure if it works that way.

Code: Select all

vector3d<T> rotationToDirection(const vector3d<T> & forwards = vector3d<T>(0, 0, 1)) const
		{
			const f64 cr = cos( core::DEGTORAD64 * X );
			const f64 sr = sin( core::DEGTORAD64 * X );
			const f64 cp = cos( core::DEGTORAD64 * Y );
			const f64 sp = sin( core::DEGTORAD64 * Y );
			const f64 cy = cos( core::DEGTORAD64 * Z );
			const f64 sy = sin( core::DEGTORAD64 * Z );

			const f64 srsp = sr*sp;
			const f64 crsp = cr*sp;

			const f64 pseudoMatrix[] = {
				( cp*cy ), ( cp*sy ), ( -sp ),
				( srsp*cy-cr*sy ), ( srsp*sy+cr*cy ), ( sr*cp ),
				( crsp*cy+sr*sy ), ( crsp*sy-sr*cy ), ( cr*cp )};

			return vector3d<T>(
				(T)(forwards.X * pseudoMatrix[0] +
					forwards.Y * pseudoMatrix[3] +
					forwards.Z * pseudoMatrix[6]),
				(T)(forwards.X * pseudoMatrix[1] +
					forwards.Y * pseudoMatrix[4] +
					forwards.Z * pseudoMatrix[7]),
				(T)(forwards.X * pseudoMatrix[2] +
					forwards.Y * pseudoMatrix[5] +
					forwards.Z * pseudoMatrix[8]));
		}

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Fri Aug 02, 2024 11:10 am
by CuteAlien
If getAngularVelocity is in radians you can use setRotationRadians in the Irrlicht matrix. Your guess wasn't correct in this case. You can kinda think of as those 3 rows in the inner 3x3 matrix as the directions of the x,y,z axes (so for example could be the front, up, right directions your ship has after a rotation). Default for inner 3x3 is (1,0,0, 0,1,0, 0,0,1). So your value would only scale those axes (thereby scaling your objects along those axes). If you ever watched the Futurama episode with the universe in a box ... your matrix is that box ;-)

Those functions you posted are old functions I wrote, I guess I'd have to go over them again (I learned a bit more since then), but might be fine to use if you want to rotate things around local axes.

But if I understood you need the other way round - from a given rotation you want to find out how you got there. Or what that global rotation means in a local coordinate sytem. And your worst problem - you need that back in euler angles (or radians which are the same just multplied by PI/180). And that is my problem - I can't wrap my head around what it means to transform such a rotation. Going over matrix will only make it worse - because there are different euler rotations which create the exact same matrix - so at that step you lose the information you need. The matrix only describes the final result - the directions of your new coordinate system. In most cases that's fine - but in your case it means you don't know anymore which rotations were used to get from the old matrix to the new one. Simple example: Your space-ship might have turned 1° since last frame - for a matrix this is identical to having turned -359° but for your display that is probably not the same (depends on your display - but usuallly that one is 2-dimensional and not using circles). And as mentioned earlier - it's not even just the 1° and -359° are the same - but you can also get to the same direction by using rotations around the other 2 axes, so the matrix doesn't even know anymore around which axis your had rotated.

But... googling a bit more around. I found another thread which says my original stupid idea would actually work: https://discourse.panda3d.org/t/local-a ... llet/13169
I thought it's wrong but maybe give it a shot. So ISceneNode::getAbsoluteTransformation().rotateVect(physicsObject.getAngularVelocity()). And need updateAbsoluteTransformation first (if you have parent-child relations in Irrlicht scene, if you don't you can just work with getRelativeTransformation which doesn't need any updates). Or you don't need Irrlicht at all as the physic engine likely has that tranformation anyway as well.

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Sun Aug 04, 2024 5:55 pm
by SomeGuyWithAComputer
ok well i'm still working on it. getAbsoluteTransformation().rotateVect(physicsObject.getAngularVelocity()) doesn't quite work but it works certain edge cases. It's hard to test it and find exactly where it goes wrong because I also don't have a way to derive relative velocity which means no linear flight assist. Maybe if I fix this seemingly easier problem first I'll accidentally discover the fix for this other problem along the way.

I have the ability to get absolute velocity from the physics engine. How can I use that and the irrlicht node rotation to somehow derive the relative velocity of the ship? I've tried this for the x direction but it's not working.

Code: Select all

double relVelX = vx*tan(ry/rx)+vy*tan(rz/rx)+vz*tan(ry/rz);
I've tried this for the x relative direction of the ship. rx,ry,rz are the irrlicht node rotations and vx, vy and vz are the reactphysics3d absolute velocities. I usually end up doing this approach in 2d vector related things but I can't quite figure it out for 3d. Maybe using matrix functions is better.

I'm trying to get relative velocity like this with a 4x4 matrix but it doesn't ever output anything besides 0,0,0.

Code: Select all

core::vector3df shipRotation = m_node->getRotation();//the ISceneNode which contains the ship's rotation
core::matrix4 m4 = core::matrix4();
m4.setRotationDegrees(shipRotation);
core::vector3df relVel;
m4.transformVect(relVel);//relVel should now contain the ship's relative velocity.
Edit: chaning it to m4.transformVect(relVel, absoluteLinearVelocity) outputs numbers into relVel. Upon initial inspection, it's not producing the correct output but as for whether it's completely wrong or theres just signs or axises that are swapped, I haven't determined that yet.

Edit 2: nope, it's not even close.

I found this code that might work but haven't yet figured out how or if its possible to get the "angle" input.

Code: Select all

double c = cos(angle);
    double s = sin(angle);
    double length = sqrt(rx*rx + ry*ry + rz*rz);
    rx /= length;
    ry /= length;
    rz /= length;
    double rotationMatrix[3][3] = {
    { c + rx*rx*(1-c), rx*ry*(1-c) - rz*s, rx*rz*(1-c) + ry*s },
    { ry*rx*(1-c) + rz*s, c + ry*ry*(1-c), ry*rz*(1-c) - rx*s },
    { rz*rx*(1-c) - ry*s, rz*ry*(1-c) + rx*s, c + rz*rz*(1-c) } };
    double newVx = rotationMatrix[0][0]*vx + rotationMatrix[0][1]*vy + rotationMatrix[0][2]*vz;
    double newVy = rotationMatrix[1][0]*vx + rotationMatrix[1][1]*vy + rotationMatrix[1][2]*vz;
    double newVz = rotationMatrix[2][0]*vx + rotationMatrix[2][1]*vy + rotationMatrix[2][2]*vz;
I got it from here: https://www.quora.com/How-do-I-implemen ... f-rotation

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Sun Aug 04, 2024 11:26 pm
by CuteAlien
relVel without parameters is initialized to 0. Transformation use multiplications so 0 stays 0.

I do not know what you mean with relative velocity. Do we still talk about angular velocity? Or do you mean real velocity (ship speed) now?
Try initializing relVel with your velocity then instead of 0.

Also be careful if your speed is really given along the ship axis (matrices don't know where the "front" is as you can model your ship any way you want, there's no image recognition searching for the ship nose). So basically - when you start flying (without any rotation) check which axis that gives you. Then check flying upwards and right just to be sure.

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Mon Aug 26, 2024 9:54 pm
by SomeGuyWithAComputer
Something occurred to me the other day. If it's not really possible to get the relative angular velocity of an object in physical space because math can't work that way, how does the gyroscope on my phone work? It can handle orientation relative to wherever "flat" is in x,y,z angles as well as providing radians / second relative to the phone (i.e. the x axis is always forward/back instead of some impossible to work with combination of other angles). I can yaw, pitch and roll the phone all at the same time and the rads/sec output seems to be pretty sensible unlike anything i've been able to come up with in irrlicht. There is an app called "sensors multitool" for android that can show this data. On my phone this data is returned by the onboard LSM6DSR gyroscope, they sell them on mouser.

Surely there is some way to get relative angular velocity in 3d space. If it really and truly can't be done mathematically, maybe I can emulate a gyroscope? I don't know how those work but I think it has something having to do with an up vector.

This just can't work without being able to find what the relative angular velocity of the ship is. Go play No Man's Sky or Starfield for example. If you move the cursor to the center while piloting a ship, the ship stops rotating even if it was rotating pretty fast before. I'm trying to replicate that. Without this, the best I can do is apply force in the direction the controls are pointing which doesn't make for good controls. It's like playing kerbal space program with SAS off, it doesn't work.

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Tue Aug 27, 2024 9:38 am
by CuteAlien
I don't say it can't be done. I say you can't get it just from comparing 2 matrices. But you need the info about the path taken. It's the same in 2d - if you walk around in your city and I record 2 points in time where you have been I still won't be able to tell how fast you walked. Not unless I also know the _path_ you have taken. It's possible to calculate the shortest path and sometimes that will be fine. But that's not necessarily the path you took.

Matrices are descriptions of where you are and where you look at. They don't tell you anything how you got from one to the other.

It's probably possible to get something like an "optimal rotation" to get from one state to the other. But that sounds like the wrong approach to me.
Because with physicsObject.getAngularVelocity() you have likely the info you want. That's the one you have to transform in some way. If the solution I posted above doesn't work... try to figure out the right one. Maybe ChatGPT can help. Or ask in stackoverflow or so.

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Sat Sep 07, 2024 1:39 pm
by WizardofChaos
SomeGuyWithAComputer wrote: Mon Aug 26, 2024 9:54 pm This just can't work without being able to find what the relative angular velocity of the ship is. Go play No Man's Sky or Starfield for example. If you move the cursor to the center while piloting a ship, the ship stops rotating even if it was rotating pretty fast before. I'm trying to replicate that. Without this, the best I can do is apply force in the direction the controls are pointing which doesn't make for good controls. It's like playing kerbal space program with SAS off, it doesn't work.
Hey, I recently released Extermination Shock, spaceflight game using Irrlicht. The code for that project is available here. (Incidentally, CuteAlien, this might be a good resource for other people?)

What you are looking for is local directions versus global. The way you can do local directions like that in Irrlicht is a pretty quick one-liner:

Code: Select all

vector3df getNodeForward(ISceneNode* node)
{
	return node->getAbsoluteTransformation().getRotationDegrees().rotationToDirection(vector3df(0, 0, 1));
}

vector3df getNodeBackward(ISceneNode* node)
{
	return -getNodeForward(node);
}
This applies to pitch, yaw, and roll as well. Once you have these local directions, you can apply a thrust on these vectors and move however you like.

No idea what physics engine you're using, but I used Bullet3, and the code for that looked something like this:

Code: Select all

btVector3 getRigidBodyForward(btRigidBody* body)
{
	btVector3 forward(0, 0, 1);
	btQuaternion transRot = body->getCenterOfMassTransform().getRotation();
	return forward.rotate(transRot.getAxis(), transRot.getAngle());
}
btVector3 getRigidBodyBackward(btRigidBody* body)
{
	return -getRigidBodyForward(body);
}
In this case, it does pretty similar to what Irrlicht does, except it grabs the quaternion that represents the current orientation and then rotates the vector around the axis and angle from that quaternion. This style should be available in pretty much every physics engine. What are you using?

With respect to having a "dead zone" at the center of your screen for a mouse (i.e. what you mentioned about NMS), it'd be best to have a function that thrusts in the opposite direction of the current angular velocity until it's as close to zero as makes no nevermind. With my game the middle chunk of the screen ignores directional input so that you can drive straight.

Re: How do I get "relative" angular velocity so that I can control pitch, roll and yaw angular velocity on a space ship?

Posted: Sun Sep 08, 2024 10:27 pm
by SomeGuyWithAComputer
I'm using Reactphysics3d. It's ok, but I try to use irrlicht for rotations when possible because it has more stuff. In my experimentation, the absolute angular velocity reactphysics3d returns is less usable than calculating angular velocity by keeping track of irrlicht node angles. Iirc I tried rotating vectors with the physics engine already but i've been stuck on this one for so long I don't even remember anymore or have any code, so I'll try that route next time I attempt to get this to work..

I've decided that i'm going to try to solve some of my other unsolved rotation problems before coming back to this. Maybe some of the things I figure out along the way will end up being part of the solution to whatever is going on here. I had to take so much math in college I thought i'd never get stuck on math again, but this is insane. I guess I'm going to have to make a really serious effort to learn higher rotational angle math. Know of any good books?