Calculate camera LookAt position in 3 dimensions (DirectX) - c++

I just started to learn DirectX. Currently I have a cube and a camera which I can move around the cube by sphere.
But now I want to create a feature so I can to turn my camera a bit (left/right/top/bottom). I easily understand how to make it in 2D: I can change X and Y in LookAt function and it's done. How can I do same thing but in 3D? There are 3 dimensions and my camera can take any angle...
I think I need to find a plane perpendicular to the camera vector and deal with it as with 2D. Image
Or I can do it more easy?

The view transformation is a tricky one. Usually, you have model transformations that e.g. move, rotate or scale objects (world transformations).
However, the view transformation is a system transformation. We could imagine it as a model transformation that moves the camera from its position to the origin. Of course, it is easier to look at the inverse view transformation. The one that places the camera at its position.
And that's what we're going to do. Let's say we have a transformation M that positions the camera. The according view transformation is its inverse: V = M^(-1). If you wanted to rotate the camera object, you would just multiply a rotation matrix to the model transformation:
M' = R * M
That would rotate the camera at its position after applying M. The according view transformation is still the inverse. Applying the inverse to M' yields
V' = (M')^(-1)
= (R * M)^(-1)
= M^(-1) * R^(-1)
We see that M^(-1) is the old view transformation. Therefore:
V' = V * R^(-1)
So if you want to rotate the camera, multiply a rotation matrix (with the negative angle) to the right of the current view matrix.
So the workflow would be the following:
At the beginning of the game, set up the view matrix with the LookAt method.
Each time the player rotates the camera, multiply a rotation matrix to the current view matrix. Make sure that the angles are not too big. If you rotate by 10° every frame, you already have 600* after a second at 60 fps.
Whenever you want to reset the camera, use the LookAt method again.
If you want to turn up and down, use XMMatrixRotationX. If you want to turn left and right, use XMMatrixRotationY. XMMatrixRotationZ would result in a roll.

For camera rotations, use the D3DXMatrixLookAtLH method. Your question is about how to calculate the desired 'at' or 'target' of the eye. This Vector3 is calculated using the same trig methods used in 2D, but just with an extra dimension. You'll need a Vector3 for rotation, each component of which will be rotation about that axis. Then use the below method to apply your rotations to your matrix created with the previously mentioned method.
To perform the same thing on objects in your world, use the DirectX method D3DXMatrixRotation(X,Y,Z) depending on your rotation direction. In a properly oriented world, left and right would rotate about the Y axis, up and down would rotate about the X axis, and tilting would be done about the Z axis. This is, of course, for matrix rotations, not Quaternions.
Remember when performing rotation (or any manipulative operation) to remember the order of operations (ISROT):
I dentity
S cale
R otation
O rbit
T ranslation
This way you don't end up having seemingly funky stuff happen. Also consider the D3DXMatrixYawPitchRoll method.

First, you should read this question.
Basically, matrix is a coordinate system that contains x, y, z vectors and position of the system (within coordinates of parent system). So you can tear the matrix apart, modify vectors, and rebuild the matrix again, without using any "LookAt" routines. The important thing, though, is that camera matrix (view transform) is an inverse of object matrix (world transform) if an object was placed instead of camera at this point. However, because camera matrix has special properties (axes are perpendicular and are norlmally unit-length), you can simply transpose it and recalculate "position" part of matrix.
This old function of mine will build camera matrix ("view" transform or D3DTS_VIEW) out of set of vectors. x points right, y points up, z points forward, and pos is a camera position.
typedef D3DXVECTOR3 Vector3;
typedef D3DXMATRIX Matrix;
void vecToCameraMat(Matrix& m, const Vector3& x, const Vector3& y, const Vector3& z, const Vector3& pos){
m._11 = x.x;
m._12 = y.x;
m._13 = z.x;
m._14 = 0;
m._21 = x.y;
m._22 = y.y;
m._23 = z.y;
m._24 = 0;
m._31 = x.z;
m._32 = y.z;
m._33 = z.z;
m._34 = 0;
m._41 = - (pos.x*x.x + pos.y*x.y + pos.z*x.z);//(pos.x*x.x + pos.y*y.x + pos.z*z.x);
m._42 = - (pos.x*y.x + pos.y*y.y + pos.z*y.z);
m._43 = - (pos.x*z.x + pos.y*z.y + pos.z*z.z);
m._44 = 1;
}
deconstruct camera matrix into vectors:
void cameraMatToVec(Vector3& x, Vector3& y, Vector3& z, Vector3& pos, const Matrix& m){
x.x = m._11;
y.x = m._12;
z.x = m._13;
x.y = m._21;
y.y = m._22;
z.y = m._23;
x.z = m._31;
y.z = m._32;
z.z = m._33;
pos.x = -(m._41*x.x + m._42*y.x + m._43*z.x);
pos.y = -(m._41*x.y + m._42*y.y + m._43*z.y);
pos.z = -(m._41*x.z + m._42*y.z + m._43*z.z);
}
And this will construct OBJECT matrix (i.e. "world" transform or D3DTS_WORLD) using similar set of vectors.
void vecToMat(Matrix& m, const Vector3& x, const Vector3& y, const Vector3& z, const Vector3& pos){
m._11 = x.x;
m._12 = x.y;
m._13 = x.z;
m._14 = 0;
m._21 = y.x;
m._22 = y.y;
m._23 = y.z;
m._24 = 0;
m._31 = z.x;
m._32 = z.y;
m._33 = z.z;
m._34 = 0;
m._41 = pos.x;
m._42 = pos.y;
m._43 = pos.z;
m._44 = 1;
}
deconstruct "object" matrix into set of vectors:
void matToVec(Vector3& x, Vector3& y, Vector3& z, Vector3& vpos, const Matrix& m){
x.x = m._11;
x.y = m._12;
x.z = m._13;
y.x = m._21;
y.y = m._22;
y.z = m._23;
z.x = m._31;
z.y = m._32;
z.z = m._33;
vpos.x = m._41;
vpos.y = m._42;
vpos.z = m._43;
}
For camera, x, y and z should have length of 1.0 and should be perpendicular to each other.
Those routines are DirectX-specific and assume that (view) matrices are left-handed.
To move camera to the "right", you need to break matrix into components, add "x" to "pos" and construct it again. If you insist on using "look at", then you'll have to add "x" to both "view position" and "look at position".

Related

Determining rotation matrix about an axis for a given angle

I've been trying to understand matrices and vectors and implemented Rodrigue's rotation formula to determine the rotation matrix about an axis for a given angle. I've got function Transform which calls out to function Rotate.
// initial values of eye ={0,0,7}
//initial values of up={0,1,0}
void Transform(float degrees, vec3& eye, vec3& up) {
vec3 axis = glm::cross(glm::normalize(eye), glm::normalize(up));
glm::normalize(axis);
mat3 resultRotate = rotate(degrees, axis);
eye = eye * resultRotate;
glm::normalize(eye);
up = up * resultRotate;`enter code here`
glm::normalize(up);
}
mat3 rotate(const float degrees, const vec3& axis) {
//Implement Rodrigue's axis-angle rotation formula
float radDegree = glm::radians(degrees);
float cosValue = cosf(radDegree);
float minusCos = 1 - cosValue;
float sinValue = sinf(radDegree);
float cartesianX = axis.x;
float cartesianY = axis.y;
float cartesianZ = axis.z;
mat3 myFinalResult = mat3(cosValue +(cartesianX*cartesianX*minusCos), ((cartesianX*cartesianY*minusCos)-(cartesianZ*sinValue)),((cartesianX*cartesianZ*minusCos)+(cartesianY*sinValue)),
((cartesianX*cartesianY*minusCos)+(cartesianZ*sinValue)), (cosValue+(cartesianY*cartesianY*minusCos)), ((cartesianY*cartesianZ*minusCos) - (cartesianX*sinValue)),
((cartesianX*cartesianZ*minusCos)-(cartesianY*sinValue)), ((cartesianY*cartesianZ*minusCos) + (cartesianX*sinValue)), ((cartesianZ*cartesianZ*minusCos) + cosValue));
return myFinalResult;
}
All the values, resultant rotation matrix and the changed vectors are as expected for +angle of rotation, but wrong for negative angles and from then on, has cascading effect until the all the vectors are re-initialised. Can someone please help me figure out the problem? I cannot use any inbuilt functions like glm::rotate.
I do not use Rodrigues_rotation_formula because it needs to compute a system of equation on runtime and gets very complicated in higher dimensions.
Instead I am using axis aligned incremental rotations along with 4x4 homogenous transform matrices which are really easily portable to higher dimensions like 4D rotors.
Now there are local and global rotations. Local rotations will rotate around your matrix coordiante system local axises and global ones will rotate around world (or main coordinate system)
What you want is create a transform matrix around some point,axis and angle. To do that just:
create a transform matrix A
that has one axis aligned to axis of rotation and origin is center of rotation. To construct such matrix you need 2 perpendicular vectors which are easily obtainable from cross product.
rotate A around its local axis aligned to axis of rotation by angle
by simple multiplication of A by axis aligned incremental rotation R so
A*R;
revert the original transform of A before rotation
by simply multiplying inverse of A to the result so
A*R*Inverse(A);
apply this on matrix M you want to rotate
also by simply multiplying this to M so:
M*=A*R*Inverse(A);
And that is it... Here 3D OBB approximation you can find function :
template <class T> _mat4<T> rotate(_mat4<T> &m,T ang,_vec3<T> p0,_vec3<T> dp)
{
int i;
T c=cos(ang),s=sin(ang);
_vec3<T> x,y,z;
_mat4<T> a,_a,r=mat4(
1, 0, 0, 0,
0, c, s, 0,
0,-s, c, 0,
0, 0, 0, 1);
// basis vectors
x=normalize(dp); // axis of rotation
y=_vec3<T>(1,0,0); // any vector non parallel to x
if (fabs(dot(x,y))>0.75) y=_vec3<T>(0,1,0);
z=cross(x,y); // z is perpendicular to x,y
y=cross(z,x); // y is perpendicular to x,z
y=normalize(y);
z=normalize(z);
// feed the matrix
for (i=0;i<3;i++)
{
a[0][i]= x[i];
a[1][i]= y[i];
a[2][i]= z[i];
a[3][i]=p0[i];
a[i][3]=0;
} a[3][3]=1;
_a=inverse(a);
r=m*a*r*_a;
return r;
};
That does exactly that. Where m is original matrix to transform (and returns the rotated one), ang is signed angle in [rad], p0 is center of rotation and dp is axis of rotation direction vector.
This approach does not have any singularities nor problems to rotate by negative angles ...
If you want to use this with glm or any other GLSL like math just change the templates to what you use so float,vec3,mat4 instead of T,_vec3<T>,mat4<T>.

Rotate object with keys [duplicate]

i am trying to implement functions, where i can rotate/ translate an object in local or global orientation, like in 3D modeling software, using glm. Something like this:
void Rotate(float x, float y, float z, bool localOrientation);
but I dont know how to get it working. Local rotation rotation should just be something like this(?):
m_Orientation *= glm::rotate(x, glm::vec3(1,0,0);
m_Orientation *= glm::rotate(y, glm::vec3(0,1,0);
m_Orientation *= glm::rotate(z, glm::vec3(0,0,1);
// (m_Orientation is glm::mat4)
But how to combine this with local orientation? Actually i need to rotate the rotation matrix in world orientation, right?
I hope you know what i mean with local and global oriented rotation/translation, like it is in 3D modeling programs. In most of them you have a button to switch between local and global.
And how would i calculating the forward/right/up vector then?
normally it should be something like this, right?:
forward = m_Orientation * glm::vec4(0,0,-1,0);
I tried global rotation with this:
m_GlobalOrientation = glm::rotate(m_GlobalRotation.x, glm::vec(1,0,0);
m_GlobalOrientation *= glm::rotate(m_GlobalRotation.y, glm::vec(0,1,0);
m_GlobalOrientation *= glm::rotate(m_GlobalRotation.z, glm::vec(0,0,1);
but then only x rotation is in global orientation, y and z rotation is in local orientation, since it is already rotated around x axis. So I need to rotate all 3 angles at once(?)
Translating local should just be adding translation values to current translation, and local translation should be glm::inverse(m_Orientation) * translationVector right?
Before I come to your question, let me explain some core concepts of matrices.
Assume that we have the following matrix:
wher T is a translation and R is a rotation matrix.
When we use this matrix to transform a vertex (or even mesh), there is one unique result. However, we can get to this result with the help of two interpretations:
Interpretation 1: Evaluate from right to left
If we evaluate the matrix from right to left, all transformations are performed in the global coordinate system. So if we transform a triangle that sits at the origin, we get the following result:
Interpretation 2: Evaluate from left to right
In the other case, all transformations are performed in the local coordinate system:
Of course, we get the same result.
So coming back to your question. If you store the position and orientation of the object as a matrix T. You can rotate this object in its local coordinate system by multiplying a rotation matrix to the right side of the current matrix. And in the global system by multiplying it at the left side. The same applies for translation:
void Rotate(float x, float y, float z, bool localOrientation)
{
auto rotationMatrix = glm::rotate(x, glm::vec3(1,0,0));
rotationMatrix *= glm::rotate(y, glm::vec3(0,1,0));
rotationMatrix *= glm::rotate(z, glm::vec3(0,0,1));
if(localOrientation)
this->T = this->T * rotationMatrix;
else
this->T = rotationMatrix * this->T;
}
The right / forward / up vectors are the column vectors of the matrix T. You can either read them directly or get them by multiplying the matrix with (1, 0, 0, 0) (right), (0, 1, 0, 0) (up), (0, 0, 1, 0) (for/backward) or (0, 0, 0, 1) (position).
If you want to read more about this, take a look at my blog article about matrices in DirectX. But it's for DirectX, which uses transposed matrices. Therefore the matrix order is reversed. Watch out for that when reading the article.

Problems rotating objects using eulers - quaternions

I'm having problems rotating GameObjects in my engine. I'm trying to rotate in 2 ways.
I'm using MathGeoLib to calculate maths in the engine.
First way: Rotates correctly around axis but if I want to rotate back, if I don't do it following the inverse order then rotation doesn't work properly.
e.g:
Rotate X axis 50 degrees, Rotate Y axis 30 degrees -> Rotate Y axis -50 degrees, Rotate X axis -30 degrees. Works.
Rotate X axis 50 degrees, Rotate Y axis 30 degrees -> Rotate X axis -50 degrees, Rotate Y axis -30 degrees. Doesn't.
Code:
void ComponentTransform::SetRotation(float3 euler_rotation)
{
float3 diff = euler_rotation - editor_rotation;
editor_rotation = euler_rotation;
math::Quat mod = math::Quat::FromEulerXYZ(diff.x * DEGTORAD, diff.y * DEGTORAD, diff.z * DEGTORAD);
quat_rotation = quat_rotation * mod;
UpdateMatrix();
}
Second way: Starts rotating good around axis but after rotating some times, then it stops to rotate correctly around axis, but if I rotate it back regardless of the rotation order it works, not like the first way.
Code:
void ComponentTransform::SetRotation(float3 euler_rotation)
{
editor_rotation = euler_rotation;
quat_rotation = math::Quat::FromEulerXYZ(euler_rotation.x * DEGTORAD, euler_rotation.y * DEGTORAD, euler_rotation.z * DEGTORAD);
UpdateMatrix();
}
Rest of code:
#define DEGTORAD 0.0174532925199432957f
void ComponentTransform::UpdateMatrix()
{
if (!this->GetGameObject()->IsParent())
{
//Get parent transform component
ComponentTransform* parent_transform = (ComponentTransform*)this->GetGameObject()->GetParent()->GetComponent(Component::CompTransform);
//Create matrix from position, rotation(quaternion) and scale
transform_matrix = math::float4x4::FromTRS(position, quat_rotation, scale);
//Multiply the object transform by parent transform
transform_matrix = parent_transform->transform_matrix * transform_matrix;
//If object have childs, call this function in childs objects
for (std::list<GameObject*>::iterator it = this->GetGameObject()->childs.begin(); it != this->GetGameObject()->childs.end(); it++)
{
ComponentTransform* child_transform = (ComponentTransform*)(*it)->GetComponent(Component::CompTransform);
child_transform->UpdateMatrix();
}
}
else
{
//Create matrix from position, rotation(quaternion) and scale
transform_matrix = math::float4x4::FromTRS(position, quat_rotation, scale);
//If object have childs, call this function in childs objects
for (std::list<GameObject*>::iterator it = this->GetGameObject()->childs.begin(); it != this->GetGameObject()->childs.end(); it++)
{
ComponentTransform* child_transform = (ComponentTransform*)(*it)->GetComponent(Component::CompTransform);
child_transform->UpdateMatrix();
}
}
}
MathGeoLib:
Quat MUST_USE_RESULT Quat::FromEulerXYZ(float x, float y, float z) { return (Quat::RotateX(x) * Quat::RotateY(y) * Quat::RotateZ(z)).Normalized(); }
Quat MUST_USE_RESULT Quat::RotateX(float angle)
{
return Quat(float3(1,0,0), angle);
}
Quat MUST_USE_RESULT Quat::RotateY(float angle)
{
return Quat(float3(0,1,0), angle);
}
Quat MUST_USE_RESULT Quat::RotateZ(float angle)
{
return Quat(float3(0,0,1), angle);
}
Quat(const float3 &rotationAxis, float rotationAngleRadians) { SetFromAxisAngle(rotationAxis, rotationAngleRadians); }
void Quat::SetFromAxisAngle(const float3 &axis, float angle)
{
assume1(axis.IsNormalized(), axis);
assume1(MATH_NS::IsFinite(angle), angle);
float sinz, cosz;
SinCos(angle*0.5f, sinz, cosz);
x = axis.x * sinz;
y = axis.y * sinz;
z = axis.z * sinz;
w = cosz;
}
Any help?
Thanks.
Using Euler angles and or Quaternions adds some limitations as it creates singularities which if not handled correctly will make silly things. Sadly almost all new 3D games using it wrongly. You can detect those by the well known things like:
sometimes your view get to very different angle that should not be there
object can not rotate anymore in some direction
object start rotating around different axises than it should
view jumps around singularity pole
view is spinning or flipping until you move/turn again (not the one caused by optic mouse error)
I am using cumulative transform matrices instead:
Understanding 4x4 homogenous transform matrices
Read the whole stuff (especially difference between local and global rotations) then in last 3 links you got C++ examples of how to do this (also read all 3 especially the preserving accuracy ...).
The idea is to have matrix representing your object coordinate system. And when ever you rotate (by mouse, keyboard, NAV,AI,...) you rotate the matrix (incrementally). The same goes for movement. This way they are no limitations or singularities. But also this approach has its problems:
lose of accuracy with time (read the preserving accuracy example to deal with this)
no knowledge about the Euler angles (the angles can be computed from the matrix however)
Both are solvable relatively easily.
Now when you are rotating around local axises you need to take into account that with every rotation around some axis you change the other two. So if you want to get to the original state you need to reverse order of rotations because:
rotate around x by 30deg
rotate around y by 40deg
is not the same as:
rotate around y by 40deg
rotate around x by 30deg
With cumulative matrix if you want to get back you can either iteratively drive your ship until it faces desired directions or remember original matrix and compute the rotations needed to be done one axis at a time. Or convert the matrix difference into quaternion and iterate that single rotation...

Quaternion-Based-Camera unwanted roll

I'm trying to implement a quaternion-based camera, but when moving around the X and Y axis, the camera produces an unwanted roll on the Z axis. I want to be able to look around freely on all axis.
I've read other topics about this problem (for example: http://www.flipcode.com/forums/thread/6525 ), but I'm not getting what is meant by "Fix this by continuously rebuilding the rotation matrix by rotating around the WORLD axis, i.e around <1,0,0>, <0,1,0>, <0,0,1>, not your local coordinates, whatever they might be."
//Camera.hpp
glm::quat rotation;
//Camera.cpp
void Camera::rotate(glm::vec3 vec)
{
glm::quat paramQuat = glm::quat(vec);
rotation = paramQuat * rotation;
}
I call the rotate function like this:
cam->rotate(glm::vec3(0, 0.5, 0));
This must have to do with local/world coordinates, right? I'm just not getting it, since I thought quaternions are always based on each other (thus a quaternion can't be in "world" or "local" space?).
Also, should i use more than one quaternion for a camera?
As far as I understand it, and from looking at the code you provided, what they mean is that you shouldn't store and apply the rotation incrementally by applying rotate on the rotation quat all the time, but instead keeping track of two quaternions for each axis (X and Y in world space) and calculating the rotation vector as the product of those.
[edit: some added (pseudo)code]
// Camera.cpp
void Camera::SetRotation(glm::quat value)
{
rotation = value;
}
// controller.cpp --> probably a place where you'd want to translate user input and store your rotational state
xAngle += deltaX;
yAngle += deltaY;
glm::quat rotationX = QuatAxisAngle(X_AXIS, xAngle);
glm::quat rotationY = QuatAxisAngle(Y_AXIS, yAngle);
camera.SetRotation(rotationX * rotationY);

OpenTK/OpenGL local axis rotation

Here is a scenario:
Object is described by:
Position
Scale
Rotation
First I apply model view (camera) from OpenGL, then Translation and Rotation using following matrix:
private Matrix4d AnglesToMatrix(Vector3d angles)
{
Vector3d left = Vector3d.UnitX;
Vector3d up = Vector3d.UnitY;
Vector3d forward = Vector3d.UnitZ;
AnglesToAxes(angles, ref left, ref up, ref forward);
return new Matrix4d(
new Vector4d(left.X, up.X, forward.X, 0),
new Vector4d(left.Y, up.Y, forward.Y, 0),
new Vector4d(left.Z, up.Z, forward.Z, 0),
new Vector4d(0, 0, 0, 1));
}
private void AnglesToAxes(Vector3d angles, ref Vector3d left, ref Vector3d up, ref Vector3d forward)
{
const double DEG2RAD = 0.0174532925;
double sx, sy, sz, cx, cy, cz, theta;
// rotation angle about X-axis (pitch)
theta = angles.X * DEG2RAD;
sx = Math.Sin(theta);
cx = Math.Cos(theta);
// rotation angle about Y-axis (yaw)
theta = angles.Y * DEG2RAD;
sy = Math.Sin(theta);
cy = Math.Cos(theta);
// rotation angle about Z-axis (roll)
theta = angles.Z * DEG2RAD;
sz = Math.Sin(theta);
cz = Math.Cos(theta);
// determine left axis
left.X = cy * cz;
left.Y = sx * sy * cz + cx * sz;
left.Z = -cx * sy * cz + sx * sz;
// determine up axis
up.X = -cy * sz;
up.Y = -sx * sy * sz + cx * cz;
up.Z = cx * sy * sz + sx * cz;
// determine forward axis
forward.X = sy;
forward.Y = -sx * cy;
forward.Z = cx * cy;
}
at, the end I apply scale. All looks great except rotation, which is based on global axis.
How to rotate objects using local axis?
To make question precise. When I rotate object by 45 degree on Y axis then X and Z axis are rotated with it and then applying another rotation use new axis.
To avoid punishment in form of minuses... I read all subjects related to rotation in 3D space, non of them gave me solution. Above code is a result of applying various attempts, but it produces result same as:
GL.Rotate(Rotation.X, Vector3d.UnitX);
GL.Rotate(Rotation.Y, Vector3d.UnitY);
GL.Rotate(Rotation.Z, Vector3d.UnitZ);
EDIT:
As it turned out, our designer had bad expectations about rotations of objects in 3D, but still the problem exist. As for language used, we write this in C#, but if you point me a solution in C or C++ I will handle it :D
We currently use (order can be configured):
GL.Rotate(Rotation.X, Vector3d.UnitX);
GL.Rotate(Rotation.Y, Vector3d.UnitY);
GL.Rotate(Rotation.Z, Vector3d.UnitZ);
But this rotates objects around world axis. What we want is to use local object axis like this assuming we have X-Y-Z axis rotation:
GL.Rotate(Rotation.X, Vector3d.UnitX);
GL.Rotate(Rotation.Y, newYaxis);
GL.Rotate(Rotation.Z, newZaxis);
or assuming we have Y-X-Z axis rotation
GL.Rotate(Rotation.Y, Vector3d.UnitY);
GL.Rotate(Rotation.X, newXaxis);
GL.Rotate(Rotation.Z, newZaxis);
Most efficient way would be to pre calculate rotation matrix, but still I'm wondering how to determine new axis after rotation. (it seams that I have to revisit trigonometry book). If someone have solution which would calculate rotation matrix really fast I would be grateful. For now I will try to use trigonometry calculations in each pass.
I'm not very good with opentk, but for C style opengl this is the difference between pre-multiplication and post-multiplication. Pre-multiplication occurs in world-coordinate space, post-multiplication occurs in local-coordinate space. See http://www.opengl.org/archives/resources/faq/technical/transformations.htm section 9.070.
If you can get a handle to the actual matrices to perform the matrix multiplication, this should work.
Can you say exactly what kind of situation you're envisioning here?
I don't believe your request makes any sense. With any rotation, you can either apply it before another operation (global axis), or after another operation (local axis). Therefore if you want to apply three rotations, one axis rotation must be first, another axis rotation must come second, and another axis must come third.
You're saying you want to apply three rotations, but you want each rotation to occur before the other two. They can't all be first.
If you put more description (images preferred) of what kind of rotation you're trying to achieve maybe we can clear up this misunderstanding, but what you're currently asking does not make sense to me in physical reality.