I have one problem related to rotation of point in 3D-space.
Suppose I have one point with X, Y and Z coordinates.
And now I want to rotate it, by specifying the rotation in one of these three ways:
By user-defined degree
By user-defined axis of rotation
Around (relative to) user-defined point
I found good link over here, but it doesn't address point 3. Can anyone help me solve that?
All rotations will go around the origin. So you translate to the origin, rotate, then translate back.
T = translate from global coordinates to user-coordinates
R = rotate around the origin (like in your link)
(T^-1) = translate back
point X
X_rotated = (T^-1)*R*T*X
If you have multiple points to rotate then multiply the matrices together:
A = (T^-1)*R*T
X_rotated = A*X
Related
I'm making my camera class and it is almost done but now, i've found a problem. I need to convert a xyz rotation to xyz direction.
Currently i'm trying to do this but is doesn't work:
m_direction = glm::rotateX(glm::vec3(0,0,0), m_rotation.x);
m_direction = glm::rotateY(m_direction, m_rotation.y);
m_direction = glm::rotateZ(m_direction, m_rotation.z);
Any rotation applied to the (0,0,0) vector will return this vector again. Think about which direction you want to have your camera looking when no rotations are applied. In a lot of applications, this will be the the negative z-axis, thus the initial vector should be (0,0,-1).
Edit: Assuming that the original direction is going along one of the major axes, the whole calculation can be simplified, since this corresponds to reading the corresponding column of the matrix. (thx to #datenwolf)
I am using a GLM quaternion to represent an orientation for an object.
Basically, I would like to add the ability to extract the angle of an axis from the quat. I don't know if this is what I need to do; but a use for this would be trying to spin the cube on the y axis, to increment the angle I need to get the old angle first, right? So
cube.setOrientation(cube.getAngleOnAxis(0, 1, 0) + 5);
And that should spin the cube by five degrees, right?
The issue I have is implementing the getAngleOnAxis function. Is there a GLM function that can extract the angle?
I'm not certain I've actually thought of the right solution so it would be great if someone with experience can explain this simpler. Thanks!
to increment the angle I need to get the old angle first, right?
No. The whole point of using a quaternion is to not have to do that. You simply multiply a new quaternion into the old one, normalize the result, and that's your new orientation.
I need to create a list of XYZ positions given a starting point and an offset between the positions based on a plane. On just a flat plane this is easy. Let's say the offset I need is to move down 3 then right 2 from position 0,0,0
The output would be:
0,0,0 (starting position)
0,-3,0 (move down 3)
2,-3,0 (then move right 2)
The same goes for a different start position, let's say 5,5,1:
5,5,1 (starting position)
5,2,1 (move down 3)
7,2,1 (then move right 2)
The problem comes when the plane is no longer on this flat grid.
I'm able to calculate the equation of the plane and the normal vector given 3 points.
But now what can I do to create this dataset of XYZ locations given this equation?
I know I can solve for XYZ given two values. Say I know x=1 and y=1, I can solve for Z. But moving down 2 is no longer just y-2. I believe I need to find a linear equation on both the x and y axis to increment the positions and move parallel to the x and y of this new plane, then just solve for Z. I'm not sure how to accomplish this.
The other issue is that I need to calculate the angle, tilt and rotation of this plane in relation to the base plane.
For example:
P1=0,0,0 and P2=1,1,0 the tilt=0deg angle=0deg rotation=45deg.
P1=0,0,0 and P2=0,1,1 the tilt=0deg angle=45deg rotation=0deg.
P1=0,0,0 and P2=1,0,1 the tilt=45deg angle=0deg rotation=0deg.
P1=0,0,0 and P2=1,1,1 the tilt=0deg angle=45deg rotation=45deg.
I've searched for hours on both these problems and I've always come to a stop at the equation of the plane. Manipulating the x,y correctly to follow parallel to the plane, and then taking that information to find these angles. This is a lot of geometry to be solved, and I can't find any further information on how to calculate this list of points, let alone calculating the 3 angles to the base plane.
I would appericate any help or insight on this. Just plain old math or a reference to C++ would be perfect to sheding some light onto this issue I'm facing here.
Thank you,
Matt
You can think of your plane as being defined by a point and a pair of orthonormal basis vectors (which just means two vectors of length 1, 90 degrees from one another). Your most basic plane can be defined as:
p0 = (0, 0, 0) #Origin point
vx = (1, 0, 0) #X basis vector
vy = (0, 1, 0) #Y basis vector
To find point p1 that's offset by dx in the X direction and dy in the Y direction, you use this formula:
p1 = p0 + dx * vx + dy * vy
This formula will always work if your offsets are along the given axes (which it sounds like they are). This is still true if the vectors have been rotated - that's the property you're going to be using.
So to find a point that's been offset along a rotated plane:
Take the default basis vectors (vx and vy, above).
Rotate them until they define the plane you want (you may or may not need to rotate the origin point as well, depending on how the problem is defined).
Apply the formula, and get your answer.
Now there are some quirks when you're doing rotation (Order matters!), but that's the the basic idea, and should be enough to put you on the right track. Good luck!
The Project
I am working on a texture tracking project for mobile. It exclusively tracks planar surfaces so I have been using openCV's cv::FindHomography() to calculate the homography between two frames. That function runs very very slow however and is the primary bottleneck in my pipeline. I decided that an algorithm that can take an initial estimate of the homography would run much faster because my change in homography between frames is very small. Also, my outlier percentage is very small so robust methods are optional. Unfortunately, to my knowledge open CV does not include a homography finder that takes an initial estimate. It does however include solvePnP() which takes the original 3d world coordinates of the scene, the current 2d image coordinates, a camera matrix, distortion parameters, and most importantly an initial estimate. I am trying to replace FindHomography with solvePnP. Since I use only 2d coordinates throughout the pipeline and solvePnP asks for 3d coordinates I am trying to move from 2d->3d->3d_transform->2d_transform. Right now that process runs 6x faster than FindHomography() if it is given a good initial guess but it has issues.
The Problem
Something is wrong with how I am converting. My theory was that since a camera matrix is not required to find a homography it should not be required for this process since I only want the information contained in a homography in the end. I also assumed that since I throw out all z information in the end how I initialize z should not matter. My process is as follows
First I convert all my initial 2d coordinates to 3d by giving them a z pos of 1. I can assume that my original coordinates lie flat in the x-y plane. Then
cv::Mat rot_mat; //3x3 rotation matrix
cv::Mat pnp_rot; //3x1 rotation vector
cv::Mat pnp_tran; //3x1 translation vector
cv::Matx33f camera_matrix(1,0,0,
0,1,0,
0,0,1);
cv::Matx41f dist(0,0,0,0);
cv::solvePnP(original_cord, current_cord, camera_matrix, dist, pnp_rot, pnp_tran,true);
//Rodrigues converts from a rotation vector to a rotation matrix
cv::Rodrigues(pnp_rot, rot_mat);
cv::Matx33f homography(rot_mat(0,0),rot_mat(0,1),pnp_tran(0),
rot_mat(1,0),rot_mat(1,1),pnp_tran(1),
rot_mat(2,0),rot_mat(2,1),pnp_tran(2)+1);
The conversion to a homography here is simple. The first two columns of the homography are from the 3x3 rotation matrix, the last column is the translation vector. The one trick is that homography(2,2) corresponds to scale while pnp_tran(2) corresponds to movement in the z axis. Given that I initialize my z coordinates to 1, scale is z_translation + 1. This process works perfectly for 4 of 6 degrees of freedom. Translation_x, translation_x, scale, and rotation about z all work. Rotation about x and y however display significant error. I believe that this is due to initializing my points at z = 1 but I don't know how to fix it.
The Question
Was my assumption that I can get good results from solvePnP by using a faked camera matrix and initial z coord correct? If so, how should I set up my camera matrix and z coordinates to make x and y rotation work? Also if anyone knows where I could get a homography finding algorithm that takes an initial guess and works only in 2d, or information on techniques for writing my own it would be very helpful. I will most likely be moving in that direction once I get this working.
Update
I built myself a test program which takes a homography, generates a set of coplanar points from that homography, and then runs the points through solvePnP to recover the specified homography. In the process of doing this I realized that I am fundamentally misunderstanding some part of how homographies are constructed. I have been assuming that a homography is constructed as follows.
hom(0,2) = x translation
hom(1,2) = y translation
hom(2,2) = scale, I can divide the entire matrix by this to normalize
the first two columns I assumed were the first two columns of a 3x3 rotation matrix. This essentially amounts to taking a 3x4 transform and throwing away column(2). I have discovered however that this is not true. The test case showing me the error of my ways was trying to make a homography which rotates points some small angle around the y axis.
//rotate by .0175 rad about y axis
rot_mat = (1,0,.0174,
0,1,0,
-.0174,0,1);
//my conversion method to make this a homography gives
homography = (1,0,0,
0,1,0,
-.0174,0,1);
The above homography does not work at all. Take for example a point x,y,1 where x > 58. The result will be x,y,some_negative_number. When I convert from homogeneous coordinates back to cartesian my x and y values will both flip signs.
All that is to say, I now have a much simpler question that I think would let me solve everything. How do I construct a homography that rotates points by some angle around the x and y axis?
Homographies are not simple translation or rotation matrices. The aim is to map straight lines to straight lines rather than to map single points to other points. They take into account perspective matrices to achieve this and are explained here
Hence, homography matrices cannot be easily decomposed, but there are (complicated) ways to do so shown here. This may help you extract rotations and translations out of it.
This should help you better understand a homography, but the rest I am unfamiliar with.
Im trying to do a simple rotation of a cube about the x and y axis:
I want to always rotate the cube over the x axis by an amount x
and rotate the cube over the yaxis by an amount y independent of the x axis rotation
first i naively did :
glRotatef(x,1,0,0);
glRotatef(y,0,1,0);
then
but that first rotates over x then rotates over y
i want to rotate over the y independently of the x access.
I started looking into quaternions, so i tried :
Quaternion Rotation1;
Rotation1.createFromAxisAngle(0,1, 0, globalRotateY);
Rotation1.normalize();
Quaternion Rotation2;
Rotation2.createFromAxisAngle(1,0, 0, globalRotateX);
Rotation2.normalize();
GLfloat Matrix[16];
Quaternion q=Rotation2 * Rotation1;
q.createMatrix(Matrix);
glMultMatrixf(Matrix);
that just does almost exactly what was accomplished doing 2 consecutive glRotates ...so i think im missing a step or 2.
is quaternions the way to go or should i be using something different? AND if quaternions are the way to go what steps can i add to make the cube rotate independently of each axis.
i think someone else has the same issue:
Rotating OpenGL scene in 2 axes
I got this to work correctly using quaternions: Im sure there are other ways, but afeter some reseatch , this worked perfectly for me. I posted a similar version on another forum. http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=280859&#Post280859
first create the quaternion representation of the angles of change x/y
then each frame multiply the changing angles quaternions to an accumulating quaternion , then finally convert that quaternion to matrix form to multiply the current matrix. Here is the main code of the loop:
Quaternion3D Rotation1=Quaternion3DMakeWithAxisAndAngle(Vector3DMake(-1.0f,0,0), DEGREES_TO_RADIANS(globalRotateX));
Quaternion3DNormalize(&Rotation1);
Quaternion3D Rotation2=Quaternion3DMakeWithAxisAndAngle(Vector3DMake(0.0f,-1.0f,0), DEGREES_TO_RADIANS(globalRotateY));
Quaternion3DNormalize(&Rotation2);
Matrix3D Mat;
Matrix3DSetIdentity(Mat);
Quaternion3DMultiply(&QAccum, &Rotation1);
Quaternion3DMultiply(&QAccum, &Rotation2);
Matrix3DSetUsingQuaternion3D(Mat, QAccum);
globalRotateX=0;
globalRotateY=0;
glMultMatrixf(Mat);
then draw cube
It would help a lot if you could give a more detailed explanation of what you are trying to do and how the results you are getting differ from the results you want. But in general using Euler angles for rotation has some problems, as combining rotations can result in unintuitive behavior (and in the worst case losing a degree of freedom.)
Quaternion slerp might be the way to go for you if you can find a single axis and a single angle that represent the rotation you want. But doing successive rotations around the X and Y axis using quaternions won't help you avoid the problems inherent in composing Euler rotations.
The post you link to seems to involve another problem though. The poster seems to have been translating his object and then doing his rotations, when he should have been rotating first and then translating.
It is not clear what you want to achieve. Perhaps you should think about some points and where you want them to rotate to -- e.g. vertex (1,1,1) should map to (0,1,0). Then, from that information, you can calculate the required rotation.
Quaternions are generally used to interpolate between two rotational 'positions'. So step one is identifying your start and end 'positions', which you don't have yet. Once you have that, you use quaternions to interpolate. It doesn't sound like you have any time-varying aspect here.
Your problem is not the gimbal lock. And effectively, there is no reason why your quaternion version would work better than your matrix (glRotate) version because the quaternions you are using are mathematically identical to your rotation matrices.
If what you want is a mouse control, you probably want to check out arcballs.