Calculating modelview matrix for 2D camera using Eigen - math

I'm trying to calculate modelview matrix of my 2D camera but I can't get the formula right. I use the Affine3f transform class so the matrix is compatible with OpenGL. This is closest that I did get by trial and error. This code rotates and scales the camera ok, but if I apply translation and rotation at same time the camera movement gets messed up: camera moves in rotated fashion, which is not what I want. (And this probaly due to fact I first apply the rotation matrix and then translation)
Eigen::Affine3f modelview;
modelview.setIdentity();
modelview.translate(Eigen::Vector3f(camera_offset_x, camera_offset_y, 0.0f));
modelview.scale(Eigen::Vector3f(camera_zoom_x, camera_zoom_y, 0.0f));
modelview.rotate(Eigen::AngleAxisf(camera_angle, Eigen::Vector3f::UnitZ()));
modelview.translate(Eigen::Vector3f(camera_x, camera_y, 0.0f));
[loadmatrix_to_gl]
What I want is that camera would rotate and scale around offset position in screenspace {(0,0) is middle of the screen in this case} and then be positioned along the global xy-axes in worldspace {(0,0) is also initialy at middle of the screen} to the final position. How would I do this?
Note that I have set up also an orthographic projection matrix, which may affect this problem.

If you want a 2D image, rendered in the XY plane with OpenGL, to (1) rotate counter-clockwise by a around point P, (2) scale by S, and then (3) translate so that pixels at C (in the newly scaled and rotated image) are at the origin, you would use this transformation:
translate by -P (this moves the pixels at P to the origin)
rotate by a
translate by P (this moves the origin back to where it was)
scale by S (if you did this earlier, your rotation would be messed up)
translate by -C
If the 2D image we being rendered at the origin, you'd also need to end by translate by some value along the negative z axis to be able to see it.
Normally, you'd just do this with OpenGL basics (glTranslatef, glScalef, glRotatef, etc.). And you would do them in the reverse order that I've listed them. Since you want to use glLoadMatrix, you'd do things in the order I described with Eigen. It's important to remember that OpenGL is expecting a Column Major matrix (but that seems to be the default for Eigen; so that's probably not a problem).

JCooper did great explaining the steps to construct the initial matrix.
However I eventually solved the problem bit differently. There was few additional things and steps that were not obvious for me at the time. See JCooper answer's comments. First is to realize all matrix operations are relative.
Thus if you want to position or move the camera with absolute xy-axes, you must first decompose the matrix to extract its absolute position with unchanged axes. Then you translate the matrix by the difference of the old and new position.
Here is way to do this with Eigen:
First compute Affine2f matrix cmat scalar determinant D. With Eigen this is done with D = cmat.linear().determinant();. Next compute 'reverse' matrix matrev of the current rotation+scale matrix R using the D. matrev = (RS.array() / (1.0f / determ)).matrix()); where RS is cmat.matrix().topLeftCorner(2,2)
The absolute camera position P is then given by P = invmat * -C where C is cmat.matrix().col(2).head<2>()
Now we can reposition the camera anywhere along the absolute axes and keeping the rotation+scaling same: V = RS * (T - P) where RS is same as before, T is the new position vec and P is the decomposed position vec.
The cmat then simply translated by V to move the camera: cmat.pretranslate(V)

Related

Calculating camera matrix, given position, angle and FOV

I've recently been venturing into conversion of 3D points in space to a 2D pixel position on a screen, and almost every single answer I've found has been something like "do X with your world-to-camera matrix, and multiply by your viewport height to get it in pixels".
Now, that's all fine and good, but oftentimes these questions were about programming for video game engines, where a function to get a camera's view matrix is often built into a library and called on-command. But in my case, I can't do that - I need to know how to, given an FOV (say, 78 degrees) and a position and angle (of the format pitch = x, yaw = y, roll = z) it's facing, calculate the view matrix of a virtual camera.
Does anybody know what I need to do? I'm working with Lua (with built-in userdata for things like 3D vectors, angles, and 4x4 matrices exposed via the C interface), if that helps.
I am using gluPerspective
where:
fovw,fovh // are FOV in width and height of screen angles [rad]
zn,zf // are znear,zfar distances from focal point of camera
When using FOVy notation from OpenGL then:
aspect = width/height
fovh = FOVy
fovw = FOVx = FOVy*aspect
so just feed your 4x4 matrix with the values in order defined by notations you use (column or row major order).
I got the feeling you are doing SW render on your own so Do not forget to do the perspective divide!. Also take a look at the matrix link above and also at:
3D graphic pipeline

OpenGL : equation of the line going through a point defined by a 4x4 matrix ? (camera for example)

I would like to know what is the set of 3 equations (in the world coordinates) of the line going through my camera (perpendicular to the camera screen). The position and rotation of my camera in the world coordinates being defined by a 4x4 matrix.
Any idea?
parametric line is simple just extract the Z axis direction vector and origin point O from the direct camera matrix (see the link below on how to do it). Then any point P on your line is defined as:
P(t) = O + t*Z
where t is your parameter. The camera view direction is usually -Z for OpenGL perspective in such case:
t = (-inf,0>
Depending on your projection you might want to use:
t = <-z_far,-z_near>
The problem is there are many combinations of conventions. So you need to know if you have row major or column major order of your matrix (so you know if the direction vectors and origins are in rows or columns). Also camera matrix in gfx is usually inverse one so you need to invert it first. For more info about this see:
Understanding 4x4 homogenous transform matrices

Align IMU orientations and then get relative rotations

I am using two IMUs of the same type (BHI160, i.e. orientation is relative to the north and on alignment with north, the IMU's local y-axis points into the north direction) on two objects, let's say pens, with the added difficulty that if I place the two objects in parallel, both IMUs' z-axes point upwards, but one IMU is rotated 180° around the z-axis relative to the other.
Now, if I understand the math here correctly, the quaternion data I receive from an IMU is the half-angle-rotation relative to the north direction, so that q * north_dir * q_inv = IMU_y_axis (with north_dir and IMU_y_axis being 3D vectors in global space, or pure quaternions for the sake of this computation).
Due to the rotation of the IMUs, I would assume that when both pens are pointing in the same direction, I should be able to compute the second pen's orientation as q_2 = q_rot_z * q_1, where q_rot_z equals a 90° rotation around the z-axis -- following the intuition that if I point both pens towards the north, I would obtain the global direction of pen 2's y-axis (i.e. pen 1's y-axis rotated around the z-axis by 180°) by computing q_rot_z * north_dir * q_rot_z_inv
Is it thus correct that if I want to know the relative rotation of the pen tips (say, the rotation I need to go from the first pen's tip to the tip of the second one), I need to compute q_r = q_2 * q_rot_z_inv * q_1_inv in order to get from tip 1 to tip 2 by computing q_r * q_1? Or does the "prior" rotation around the z-axis not matter in this case and I only need to compute q_r = q_2 * q_1_inv as usual?
Edit:
this is basically an extension of this question, but I would like to know if the same answer also applies in my case or whether the known relative IMU rotation would in my case need to be included as well
Let's go through this step by step. You have a global coordinate system G, which is aligned to the north direction. It does not really matter how it is aligned or if it is aligned at all.
Then we have to IMUs with their respective coordinate systems I1 and I2. The coordinate systems are given as the rotation from the global system to the local systems. In the following, we will use the notation R[G->I1] for that. This represents a rotation from G to I1. If you transform any vector in G with this rotation, you will get the same vector in I1 expressed in the coordinate system G. Let's denote the transformation of a vector v with transform T by T ° v. The following figure illustrates this:
In this figure, I have added a translation to the transform (which quaternions can of course not represent). This is just meant to make the point clearer. So, we have a vector v. The same vector can lie in either coordinate system G or I. And the transformed vector R[G->I] ° v represents the v of I in the coordinate system of G. Please make sure that this is actually the rotation that you get from the IMUs. It is also possible that you get the inverse transform (this would be the system transform view, whereas we use the model transform view). This changes little in the following derivations. Therefore, I will stick to this first assumption. If you need the inverse, just adjust the formulas accordingly.
As you already know, the operation R ° v can be done by turning v into a pure quaternion, calculating R * v * conjugate(R), and turning it into a vector again (or work with pure quaternions throughout the process).
Now the pens come into play. The pen has an intrinsic coordinate system, which you can define arbitrarily. From your descriptions, it seems as if you want to define it such that the pen's local y-axis points towards the tip. So, we have an additional coordinate system per pen with the according rotation R[I1->P1] and R[I2->P2]. We can concatenate the rotations to find the global orientations (* is quaternion multiplication):
R[G->P1] = R[G->I1] * R[I1->P1]
R[G->P2] = R[G->I2] * R[I2->P2]
In the way that you defined the pen's local coordinate system, we know that R[I1->P1] is the identity (the local coordinate system is aligned with the IMU) and that R[I2->P2] is a rotation of 180° about the z-axis. So, this simplifies to:
R[G->P1] = R[G->I1]
R[G->P2] = R[G->I2] * RotateZ(180°)
Note that the z-rotation is performed in the local coordinate system of the IMU (it is multiplied at the right side). I don't know why you think that it should be 90°. It is really a rotation of 180°.
If you want to find the relative rotation between the tips, you first need to define in which coordinate system the rotation should be expressed. Let's say we want to express the rotation in the coordinate system of P1. Then, what you want to find is a rotation R[P1->P2], such that
R[G->P1] * R[P1->P2] = R[G->P2]
This solves to
R[P1->P2] = conjugate(R[G->P1]) * R[G->P2]
If you plug the above definitions in, you would get:
R[P1->P2] = conjugate(R[G->I1]) * R[G->I2] * RotateZ(180°)
And that's it.
It is pretty likely that you want something slightly different. That's why I explained it in such detail, so you will be able to modify the calculations accordingly.

How to get new camera direction vector when moving an arbitrary relative angle

I am implementing a camera class and am getting stuck with some things
Let's suppose the camera is at Point (0,0,0) looking at a certain direction with its corresponding UP and RIGHT vectors.
I have a joystick control which allows you to go forward-backwards, or change orientation by moving (left-right) or (up-down), according to the above mentioned vectors.
How can I know, given the 3 vectors, which is the resulting direction vector if for instance I want to move N degrees right??
If you are talking about rotating your camera, here is how it is done: every rotation is a matrix that transforms coordinates, so all you have to do is to calculate the matrix of your rotation and then apply it to Dir, Up and Right vectors of your camera to get new ones after rotation is done.
Here is a little reading about rotation matrices (read the section of 3D rotations):
http://mathworld.wolfram.com/RotationMatrix.html

Trying to find the relative transformation between to two positions - XNA

I have written a simple AR program in XNA and I am now trying to find the relative transformation between my 2 markers.
I have located my markers relative to my camera and have extracted out translation and rotation matrixes for the markers.
What I am trying to do is to find out the relative translation to get to marker 2 from marker 1. For instance if marker 1 and marker 2 were lying on the same Z plane the Z translation component would be 0mm.
The image below is the application working for 2 positions on the same plane:
I assumed that by simply multiplying the matrix of the 2nd marker by the inverse of the 1st marker I can get the translation. However I am getting completely wrong results.
The code I am running is as follows:
posit.EstimatePose(points, out matrix, out trans);
float yaw, pitch, roll;
matrix.ExtractYawPitchRoll(out yaw, out pitch, out roll);
Matrix rotation =
Matrix.CreateFromYawPitchRoll(-yaw, -pitch, roll);
Matrix translation =
Matrix.CreateTranslation(new Vector3(trans.X, trans.Y, -trans.Z));
Matrix complete = rotation * translation;
List<Matrix> all = new List<Matrix>();
all.Add(rotation);
all.Add(translation);
all.Add(complete);
matrixes.Add(all);
}
Matrix res = Matrix.Invert(matrixes[0][2]) * matrixes[1][2];
Vector3 scaleR;
Vector3 translationR;
Quaternion rotationR;
res.Decompose(out scaleR, out rotationR, out translationR);
The result:
TranslationR : {X:-103.4285 Y:-104.1754 Z:104.9243}
I have overlaid 3D axes onto the image as shown above using XNA so I assume the rotation and translation relative to the camera has been worked out correctly.
It seems like I am doing something wrong along the way to calculate the translation. I would definitely not expect the Z to equal 104mm. I was expecting something along the lines of:
{X:0 Y:150 Z:0}
I've done something similar to this before, however it was using 3x3 matrices in a 2D environment (with X,Y Translate, Rotate, Skew). Are the matrices in question 4x4?
Yes you are right, to find the matrix to transform object A with matrix M1 to object B with matrix M2 you can compute M1' * M2 (where M1' is the inverse).
The problem you may be running into is that a Matrix is composed of rotation, translation, scale and other transformations (e.g. skew/perspective). Decomposing the matrix into its component parts often yields a non-deterministic answer. Its like Quadratic equations, there is more than one solution.
Another issue may be that Matrix operations are not commutative and you are simply performing them the wrong way around. If you perform M1' * M2 and M2 * M1' you will get different results.
Please give it a try (switching the matrix order). Also I'd be looking up the matrix decomposition function you used - what value of Rotation & Scaling are you getting at the output? Are your objects rotated or scaled? If not then you should get zero. Note that it is possible to have more than one solution of rotation + translation to get the same end result and the decomposition function doesn't know which it is you are looking for.
To extract just the translation component, you can use the methods form this page:
vt = (M14, M24, M34)T
What do you get when you try that?
What I am trying to do is to find out the relative translation to get
to marker 2 from marker 1.
Vector3 relativeTranslation = Marker2Matrix.Translation - marker1Matrix.Translation;
My answer seems overly simplistic so maybe I'm not grasping your question completely, but it will create a vector that when added to Marker1's location (translation), will get you to Marker 2's location.

Resources