I'm currently working with files that I have no control over, which define 3D cubes with 5 vectors, one for the center position, one for the half-size, and 3 vectors that somehow make up the rotation. I'm struggling with figuring out how to turn these 3 vectors into 3 angles, that I can easily use in my rendering engine.
For example, I might have the following vectors:
Position
X: -655.48, Y: 477.02, Z: -3.30
Size
X: 435.57, Y: 29.79, Z: 138.53
Rotation
X: 0.91, Y: -0.41, Z: 0.00
X: 0.41, Y: 0.91, Z: 0.00
X: 0.00, Y: 0.00, Z: 1.00
With the position and the size (times two) I can easily create a cube, but the rotation is missing. Since I know what the box is supposed to look like, I know that the rotation angles of the cube are supposed to be 0°, 0°, and about -24°, 156°, or 336°, depending on how you rotate it. Unfortunately, I don't know how to turn one into the other.
Figuring out what to even search for to solve this has been challenging, since I don't know what exactly I'm look at. I assume that I have to take these values in some combination and calculate the angles for each axis, possibly using atan2? But I'm out of my depth here.
For another example, here's a cube that doesn't rotate.
X: 1.00, Y: 0.00, Z: 0.00
X: 0.00, Y: 1.00, Z: 0.00
X: 0.00, Y: 0.00, Z: 1.00
I'd appreciate any help in deciphering this.
Update: I realize my explanation about the expected angles was poorly formulated, so here's a quick addendum.
By angles, I mean 3 angles in degree, for rotations around X, Y, and Z. I'm currently testing this in the Unity engine, where I can easily create a box with a given size around a center point, and my specific example was about one such box, that would require the angles X: 0°, Y: 0°, and Z: -24°, for it to appear as I know that it should appear. These values came from me trying to simply put the cube into the rotation I need.
What these rotation values actually represent, by my current understanding, are directions on all 3 axis, which describe the directions the 8 edge points of the cube are in. You could technically create something that isn't a cube, because this format allows for slanted sides, but it's never used that way in the files I'm working with.
Related
I work on a tool to convert old 3d data from a program and convert it into a new format.
The problem i have is, the old program is storring the scale/rotation in a 3x3 matrix and i have no experiance with this kind of stuff.
For testing i have created an object only with scale 0.5 and saved it. It has the matrix
0.5, 0.0, 0.0
0.0, 0.5, 0.0
0.0, 0.0, 0.5
These are the scales for all 3 axis
Then i changed the object to have only rotations xyz of 45 degrees and a scale of 1 and got this matrix
0.5, -0.146447, 0.853553
0.5, 0.853553, -0.146447
-0.707107, 0.5, 0.5
I was able to convert this to the correct angles
Now i come to my showstopper: i changed the object to have a scale of 0.5 and a rotation of 45 degrees. The new matrix somehow combined both values into one matrix:
0.25, -0.0732233, 0.426777
0.25, 0.426777, -0.0732233
-0.353553, 0.25, 0.25
Basically the vales are the half of the secound matrix.
Currently im not able to figure out how to get the scale and the rotation out of this matrix, basically seperate them from each other. So if someone has an idea how this has to be done it world be great.
The determinant of the matrix expresses the factor by which volumes increase. If you're matrix preserves angles, then that determinant must be the third power of the scale factor. Take the cube root and you get the scale factor.
Divide all elements of the matrix by that factor and you should end up with a pure rotation, or mathematically speaking an orthogonal matrix. Wikipedia has a good article on how to convert between that and various other formalisms.
The gyroscope of a device returns values in the following range:
Alpha: 0 - 360 around the Z-axis
Beta: -180 - 180 around the X-axis
Gamma: -90 - 90 around the Y-axis
When I rotate the device around the Y-axis, the value 'flips' at a certain point from -90 to 90.
I know that this is due to the fact that the gyroscope functions like a gimbal, where Alpha is the outer ring, Beta is the middle ring and Gamma is the inner ring.
My question is: how do I measure the rotation JUST around the Y-axis, without the 'flipping' effect?
Is there a mathematical way to process the alpha/beta/gamma values and get more 'useful' values for this case, so that is easier to get the amount of rotation around the X, Y or Z axis?
I'm using the python OpenGL bindings, and trying to only use modern opengl calls. I have a VBO with verticies, and I am trying to render with an orthographic projection matrix passed to the vertex shader.
At present I am calculating my projection matrix with the following values:
from numpy import array
w = float(width)
h = float(height)
n = 0.5
f = 3.0
matrix = array([
[2/w, 0, 0, 0],
[ 0, 2/h, 0, 0],
[ 0, 0, 1/(f-n), -n/(f-n)],
[ 0, 0, 0, 1],
], 'f')
#later
projectionUniform = glGetUniformLocation(shader, 'projectionMatrix')
glUniformMatrix4fv(projectionUniform, 1, GL_FALSE, matrix)
That code I got from here:
Formula for a orthogonal projection matrix?
This seems to work fine, but I would like my Origin to be in the bottom left corner of the screen. Is this a function I can apply over my matrix so everything "just works", or must I translate every object by w/2 h/2 manually?
side note: Will the coordinates match pixel positions with this working correctly?
Because I'm using modern OpenGL techniques, I don't think I should be using gluOrtho2d or GL_PROJECTION calls.
glUniformMatrix4fv(projectionUniform, 1, GL_FALSE, matrix)
Your matrix is stored in row-major ordering. So you should pass GL_TRUE, or you should change your matrix to column-major.
I'm not completely familiar with projections yet, as I've only started OpenGL programming recently, but your current matrix does not translate any points. The diagonal will apply scaling, but the right most column will apply translation. The link Dirk gave gives you a projection matrix that will make your origin (0,0 is what you want, yes?) the bottom-left corner of your screen.
A matrix I've used to do this (each row is actually a column to OpenGL):
OrthoMat = mat4(
vec4(2.0/(screenDim.s - left), 0.0, 0.0, 0.0),
vec4(0.0, 2.0/(screenDim.t - bottom), 0.0, 0.0),
vec4(0.0, 0.0, -1 * (2.0/(zFar - zNear)), 0.0),
vec4(-1.0 * (screenDim.s + left)/(screenDim.s - left), -1.0 * (screenDim.t + bottom)/(screenDim.t - bottom), -1.0 * (zFar + zNear)/(zFar - zNear), 1.0)
);
The screenDim math is effectively the width or height, since left and bottom are both set to 0. zFar and zNear are 1 and -1, respectively (since it's 2D, they're not extremely important).
This matrix takes values in pixels, and the vertex positions need to be in pixels as well. The point (0, 32) will always be at the same position when you resize the screen too.
Hope this helps.
Edit #1: To be clear, the left/bottom/zfar/znear values I stated are the ones I chose to make them. You can change these how you see fit.
You can use a more general projection matrix which additionally uses left,right positions.
See Wikipedia for the definition.
I am working on a visualization for some data and I've run into a snag. I need to draw some ellipses based on data that looks like this:
{
x: 455.53 //the center x coordinate
y: 122.44 //the center y coordinate
e1: .24101 //value from -1 to 1, represents stretching along x when positive, along y when negative
e2: -.44211 //value from -1 to 1, represents stretching along the 45 degree line when positive and 135 when negative
}
Long story short, I have no idea how to do this... it is just for a one time visualization so efficiency isn't a concern. If someone can suggest how to manipulate the e1/e2 to get the foci or major/minor axis and angle of rotation, that'd be super fancy. Thanks!
This form of specifying ellipticity is common in gravitational lensing. These ellipticity numbers are the real and imaginary parts of a complex ellipicity value; see the section Weak Lensing Observables and the expression for ε there.
I can't do proper math notation here because of a policy decision; see this meta question. https://meta.stackexchange.com/questions/4152/adding-support-for-math-notation. Accordingly, I'll simply point out that the magnitude of the vector is a transform of the major-minor axis ratio, and that the angle is half of the inverse tangent of the ratio of the two components.
I have coordinates for 4 vectors defining a quad and another one for it's normal. I am trying to get the rotation of the quad. I get good results for rotation on X and Y just using the normal, but I got stuck getting the Z, since I've used just 1 vector.
Here's my basic test using Processing and toxiclibs(Vec3D and heading methods):
import toxi.geom.*;
Vec3D[] face = {new Vec3D(1.1920928955078125e-07, 0.0, 1.4142135381698608),new Vec3D(-1.4142134189605713, 0.0, 5.3644180297851562e-07),new Vec3D(-2.384185791015625e-07, 0.0, -1.4142135381698608),new Vec3D(1.4142136573791504, 0.0, 0.0),};
Vec3D n = new Vec3D(0.0, 1.0, 0.0);
print("xy: " + degrees(n.headingXY())+"\t");
print("xz: " + degrees(n.headingXZ())+"\t");
print("yz: " + degrees(n.headingYZ())+"\n");
println("angleBetween x: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("angleBetween y: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("angleBetween z: " + degrees(n.angleBetween(Vec3D.X_AXIS)));
println("atan2 x: " + degrees(atan2(n.z,n.y)));
println("atan2 y: " + degrees(atan2(n.z,n.x)));
println("atan2 z: " + degrees(atan2(n.y,n.x)));
And here is the output:
xy: 90.0 xz: 0.0 yz: 90.0
angleBetween x: 90.0
angleBetween y: 90.0
angleBetween z: 90.0
atan2 x: 0.0
atan2 y: 0.0
atan2 z: 90.0
How can I get the rotation(around it's centre/normal) for Z of my quad ?
OK. I am frankly still not really clear on what it is you're looking for, but let me try to clarify the problem and then address my best guess as to what you really want and see if that helps.
As mentioned in the comment thread, a rotation is a transformation that maps one set of stuff (eg, vectors A, B, C...) to a different set of stuff (A', B', C'...). We can fully define this transformation in terms of an angle (call it θ) and an axis of rotation we'll call R.
Note that R is not a vector, it is a line. That means it has a location as well as a direction -- it is anchored somewhere in space -- and so you need either two points or a point and a direction vector to define it. For simplicity we might assume that the anchor point is the origin (0,0,0), since the question talks about the major axes X, Y and Z. In general, however, this need not be the case - if you want to determine rotation about arbitrary lines you will usually need to translate everything first so that the axis passes through the origin. (If all you care about is the orientation of your objects, rather than its position, then you can probably gloss over this issue.)
Given a start position A, end position A' and an axis R, it is conceptually straightforward to determine the angle θ (or an angle θ, since rotation is periodic and there are infinitely many θs that will take A to A'), though it can be a little fiddly for general R. In the simplest case, where R is one of the major axes, you can do something like this (for R = Z):
theta0 = atan2(A.x, A.y);
theta1 = atan2(A_prime.x, A_prime.y);
theta = theta1 - theta0;
In any case, it looks from your code as if you have the tools to do this already -- I'm not familiar with toxiclibs, but I would imagine the Vec3D angleBetween method ought to take you most of the way to the answer you want.
However, that presupposes that you know A, A' and R, and it seems like this is the real sticking point with your question. In the first place, you mention only a single set of points, defining an arbitrary quad. In the second, you talk about the normal as defining the centre of rotation. Both of these indicate that you haven't properly specified the problem.
As I have repeated tediously several times, a rotation is from one thing to another. A single set of quad vertices may define either the first state or the second, but not both (unless θ is 0, in which case the question is trivial). If you want to determine "the rotation of the quad", you need also to say "from an earlier position P" or "to a subsequent position Q", which you have not done.
Given that the particular quad in question is a square, you might think that there's an intuitive other position involved, to wit: with the sides axis-aligned. And we can indeed rather easily determine the angle of rotation required to get to that orientation, if we can assume that the quad is a rectangle:
// A and B are adjacent corners of the square
// B - A is the direction of the edge joining them
// theta is the angle between that side and the X axis
// (rotating by -theta around Z should align the square)
theta = atan2(B.x - A.x, B.y - A.y);
But, you made a point of stating that you might be looking at any arbitrary quad, for which there would be no "natural" base position to compare against. And even in the square case it is frankly not good practice to presume a baseline without explicitly declaring it.
Which brings us back to my original question: what do you mean? If you can actually pin that down properly I suspect you will find the problem itself relatively easy to solve.
EDIT: Based on your comments below, what you really want to do is to find a rotation that aligns your quad with one of the major planes. This is equivalent to rotating the quad's normal to align with the axis perpendicular to that plane: eg, to get the quad parallel to the XY plane, align its normal with the Z axis.
This can notionally be done with a single rotation about some calculated axis, but in practice you will decompose it into two rotations about major axes. The first rotates about the target axis until the vector is in the plane containing that axis and one of the others; then rotate around the third axis to get the normal to its final alignment. A verbal description is inevitably clunky, so let's formalise a bit:
Let's say you have a planar object Q, with vertices {v1, v2, v3, ...} (in your quad case there will be four of these, but it could be any number as long as all the points are coplanar), with unit normal n = (x y z)T. For the sake of explanation, let's arbitrarily assume that we want to align the object with the XY plane, and hence to rotate n to the Z axis -- the process would be essentially the same for XZ/Y or YZ/X.
Rotate around Z to get n into the XZ plane. We can calculate the angle required like this:
theta1 = -atan2(x,y);
However, we only need the sine and cosine to build a rotation matrix, and we can calculate these directly without knowing the angle:
hypoXY = sqrt(x*x + y*y);
c1 = x/hypoXY;
s1 = y/hypoXY;
(Obviously, if hypoXY is 0 this fails, but in that case n is already aligned with Z.)
Our first rotation matrix R1 looks like this:
[ c1 s1 0 ]
[ -s1 c1 0 ]
[ 0 0 1 ]
Next, rotate around Y to get n parallel to Z. Note that the previous rotation has moved x to a new position x' = sqrt(x2 + y2), so we need to account for this in calculating our second angle:
theta2 = -atan2(z, sqrt(x*x + y*y));
Again, we don't actually need theta2. And because we defined n to be a unit vector, our next calculations are easy:
c2 = z;
s2 = hypoXY;
Our second rotation matrix R2 looks like this:
[ c2 0 -s2 ]
[ 0 1 0 ]
[ s2 0 c2 ]
Compose the two together to get R = R2.R1:
[ c2c1 c2s1 -s2 ]
[ -s1 c1 0 ]
[ s2c1 s2s1 c2 ]
If you apply this matrix to n, you should get the normal aligned with the Z axis. (If not, check the signs first -- this is all a bit back of an envelope and I could easily have got some of the directions wrong. I don't have time to code it up and check right now, but will try to give it a go later. I'll also try to look over your sketch code then.)
Once that works, apply the same transformation to all the points in your object Q and it should become parallel to (although likely offset from) the XY plane.
Here is the rotation matrix for the z axis
cos(theta) sin(theta) 0
-sin(theta) cos(theta) 0
0 0 1
your vector
the result is the rotated vector