Multiple rotation problems - c++

Here is my problem. I have to move a torus along a circular trajectory on a bicubic surface.
However the vertical axis of the torus must be aligned with the surface normal at the given point Moreover the torus must face it's circular trajectory.
To manage this i took the normal vector and the Oy vector, made a cross and a dot product to find the angle i need and the axis to rotate around, it works.
To manage the 2nd part, i took the actual coordinates of the torus, the next ones on the circular trajectory, made a vector, and did the same as previously described to found the angle and the axis, it works.
My problem is, i must apply the two rotations simultaneously and i can't find a way to do this. I tryed to Push/Pop Matrix i every possible way but i can't find a way out of this one. So i'm back to this...
glPushMatrix();
glTranslatef(pp -> x, pp ->y , pp ->z);
glRotatef(*angledegree, vecortho -> x, vecortho -> y, vecortho -> z);
glRotatef(*angledegreetang, tang -> x, tang -> y, tang -> z);
tore(0.1, 0.3, 6, 4, 1);
repere(0.6);
glPopMatrix();
Any ideas? Sorry to bother you, it must be simple i think, but i don't see it. The first rotation always bugs the next one, whatever the order.
vecortho is the axis vector computed from the surface normal and Oy.
tang is the vector computed with my trajectory vector and Ox.

Don't think in terms of rotations. Just think in terms of axes.
You want the torus's new Y axis to be translated to a particular new direction (the normal vector), its new Z axis to be translated to a particular new direction (the forward vector) and its X axis you don't care about.
So build the matrix that does this transformation and use it. Your vector class may differ from this example, and my vector math may be rusty as I haven't tested this code:
vector newY = normalVec;
vector newZ = forwardVec;
// We don't really care what X is, but it must be perpendicular to Y and Z. Swap Y and Z here if this ends up mirroring the object.
vector newX = normalize(cross(newY, newZ));
double matrix[16] = {
newX.x, newX.y, newX.z, 0,
newY.x, newY.y, newY.z, 0,
newZ.x, newZ.y, newZ.z, 0,
0, 0, 0, 1,
};
glPushMatrix();
glTranslatef(position of torus);
glMultMatrixd(matrix);
// draw torus
glPopMatrix();

Related

How to rotate model to follow path

I have a spaceship model that I want to move along a circular path. I want the nose of the ship to always point in the direction it is moving in.
Here is the code I have to move it in a circle right now:
glm::mat4 m = glm::mat4(1.0f);
//time
long value_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::
high_resolution_clock::now())
.time_since_epoch())
.count();
//translate
m = glm::translate(m, translate);
m = glm::translate(m, glm::vec3(-50, 0, -20));
m = glm::scale(m, glm::vec3(0.025f, 0.025f, 0.025f));
m = glm::translate(m, glm::vec3(1800, 0, 3000));
float speed = .002;
float x = 100 * cos(value_ms * speed); // + 1800;
float y = 0;
float z = 100 * sin(value_ms * speed); // + 3000;
m = glm::translate(m, glm::vec3(x, y, z));
How would I move it so the nose always points ahead? I tried doing glm::rotate with the rotation axis set as x or y or z but I cannot get it to work properly.
First see Understanding 4x4 homogenous transform matrices as I am using terminology and stuff from there...
Its usual to use a transform matrix of object for its navigation purposes and not the other way around ... So you should have a transform matrix M for your space ship that represents its position and orientation in [GCS] (global coordinate system). On top of that is sometimes multiplied another matrix M0 that align your space ship mesh to the first matrix (you know some meshes are not centered around (0,0,0) nor axis aligned...)
Now when you are moving your object you just do local transformations on the M so moving forward is just translating M origin position by a multiple of forward axis basis vector. The same goes for sliding to sides (just use different basis vector) resulting in that the object is alway aligned to where it supposed to be (in respect to movement). The same goes for turns. So going in circle is just moving forward and turning at constant speeds per time iteration step (timer).
You are doing this backwards first you compute position and orientation and then you are trying to make operations resulting in matrix that would do the same... In such case is much much easier to construct the matrix M instead of creating transformations that will create it... So what you need is:
origin position
3 perpendicular (most likely unit) basis vectors
So the origin is your x,y,z position. 2 basis vectors can be obtained from the circle so forward is tangent (or position-last_position) and vector towards circle center cen be used as (right or left). The 3th vector can be obtained by cross product so let assume:
+X axis is right
+Y axis is up
+Z axis is forward
you got:
r=100.0
a=speed*t
pos = (r*cos(a),0.0,r*sin(a))
center = (0.0,0.0,0.0)
so:
Z = (cos(a-0.5*M_PI),0.0,sin(a-0.5*M_PI))
X = (cos(a),0.0,sin(a))-ceneter
Y = cross(X,Z)
O = pos
normalize:
X /= length(X)
Y /= length(Y)
Z /= length(Z)
So now just feed your X,Y,Z,O to your matrix (depending on the conventions you use like multiplication order, direct/inverse matrix, row-major or column-major matrices ...)
so for example like this:
double M[16]=
{
X[0],X[1],X[2],0.0,
Y[0],Y[1],Y[2],0.0,
Z[0],Z[1],Z[2],0.0,
O[0],O[1],O[2],1.0,
};
or:
double M[16]=
{
X[0],Y[0],Z[0],O[0],
X[1],Y[1],Z[1],O[1],
X[2],Y[2],Z[2],O[2],
0.0 ,0.0 ,0.0 ,1.0,
};
And that is all ... The matrix might be transposed, inverted etc based on the conventions you use. Sorry I do not use GLM but the syntax should be very siilar ... the matrix feeding might be even simpler if rows or columns are loadable by a vector ...

OpenGl draw a cylinder with 2 points glRotated

I want to show draw a cylinder that starts at point a and that points to I think the key is in the first glRotated, but this is my first time working with openGL
a and b are btVector3
glPushMatrix();
glTranslatef(a.x(), a.y(), a.z());
glRotated(0, b.x(), b.y(), b.z());
glutSolidCylinder(.01, .10 ,20,20);
glPopMatrix();
Any suggestions ??
According to glutsolidcylinder(3) - Linux man page:
glutSolidCylinder() draws a shaded cylinder, the center of whose base is at the origin and whose axis is along the positive z axis.
Hence, you have to prepare the transformations respectively:
move the center of cylinder to origin (that's (a + b) / 2)
rotate that axis of cylinder (that's b - a) becomes z-axis.
The usage of glRotatef() seems to be mis-understood, also:
1st value is angle of rotation, in degrees
2nd, 3rd, and 4th value are x, y, z of rotation axis.
This would result in:
// center of cylinder
const btVector3 c = 0.5 * (a + b);
// axis of cylinder
const btVector3 axis = b - a;
// determine angle between axis of cylinder and z-axis
const btVector3 zAxis(0.0, 0.0, 1.0);
const btScalar angle = zAxis.angle(axis);
// determine rotation axis to turn axis of cylinder to z-axis
const btVector3 axisT = zAxis.cross(axis).normalize();
// do transformations
glTranslatef(c.x(), c.y(), c.z());
if (axisT.norm() > 1E-6) { // skip this if axis and z-axis are parallel
const GLfloat radToDeg = 180.0f / 3.141593f;
glRotatef(angle * radToDeg, axisT.x(), axisT.y(), axisT.z());
}
glutSolidCylinder(0.1, axis.length(), 20, 20);
I wrote this code out of mind (using the doc. of btVector3 which I've never used before). Thus, please, take this with a grain of salt. (Debugging might be necessary.)
So, please, keep the following in mind:
The doc. does not mention whether btVector3::angle() returns angle in degree or radians – I assumed radians.
When writing such code, I often accidentally flip things (e.g. rotation into opposite direction). Such things, I usually fix in debugging, and this is probably necessary for the above sample code.
If (b - a) is already along positive or negative z-axis, then (b - a) × (0, 0, 1) will yield a 0-vector. Unfortunately, the doc. of btVector3::normalize() does not mention what happens when applied to a 0-vector. If an exception is thrown in this case, extra checks have to be added, of course.
Your rotate doesn't do anything since you rotate 0 degrees.
You want the axiz z to point towards b.
To do that you need to compute the angle between the z axis (0,0,1) and norm(b - a) (that is arccos(z dot norm(b - a))) and you need to rotate that amount around the cross product between z axis and b - a. Your vector library should have these methods(dot and cross product) already implemented.
norm(x) is the normalized version of x, the one with length 1.

glRotate(angle,x,y,z), what is x,y,z in this case?

I've read the documentation here: http://www.opengl.org/sdk/docs/man2/xhtml/glRotate.xml
It specifies that angle is in degrees. It says that X,Y,Z are vectors. If I say glRotate(2,1,0,0) that says I will rotate 2 degrees about the X axis.
What happens if I say glRotate(2,0.5,0,0) and glRotate(2,0.0174524,0,0)
I don't understand what's really happening in that situation, can someone help explain to me?
Does it rotate as a percentage of the angle?
It will still rotate 2 degrees about the X axis. That page you linked also says the following:
x y z = 1 (if not, the GL will normalize this vector).
Meaning the vector (x,y,z) is a unit vector (of length 1), and if it's not, GL will normalize the vector (dividing it by its length, making it of length 1).
Conclusion: the x,y and z parameters define a vector, of which the direction is the only relevant part, the length will be dealt with by the function. Thus you can safely put in any vector and it will simply rotate about that vector.
It doesn't say that x, y and z are vectors. If you open the page with a MathML-capable browser, you'll see something like
glRotate produces a rotation of angle degrees around the vector (x,y,z).
I.e. x, y, z are components of a single vector. Similarly, it doesn't say "x y z = 1 (if not, the GL will normalize this vector)": instead, it says:
||(x,y,z)||=1 (if not, the GL will normalize this vector).
So, (x,y,z) is the vector, rotation around which the function will produce. If the vector you supply is not normalized, the GL will normalize it, so glRotate(2,0.5,0,0) and glRotate(2,0.0174524,0,0) are equivalent.
glRotate means you can rotate current matrix by a given vector (x, y, z) for angle degrees. so the params x, y, z is only 3 basic params of a vector(line) in 3D space. As you can see, a vector has direction and length, but in this function, length is useless, so whether your vector length is 1 or 100 or 0.2, it doesn't make sense in this function. It's just a direction mark.

AABB of rotated sprite?

Say I have a sprite. Its axis-aligned bounding box (AABB) is easy to find since I know the width and height. Say I rotate it 45 degrees, I don't think the AABB would be big enough to cover it, so I need a new AABB. How can I calculate the bounding rectangle of a rotated rectangle? (given a center point, an angle, and its width and height).
Note that OpenGL does the rotation so I do not have access to the vertex information.
What I'm trying to do is get AABBs so I can do 2D culling for rendering.
Is there possibly a greedy way of finding the AABB that satisfies any angle?
Thanks

			
				
If you want a single box that covers all angles, just take the half-diagonal of your existing box as the radius of a circle. The new box has to contain this circle, so it should be a square with side-length equal to twice the radius (equiv. the diagonal of the original AABB) and with the same center as the original.
In general the object will be rotated around an arbitrary point, so you have to compute the new location of the center and translate this box to the right place.
I don't know if this is the most efficient method, but I would just calculate the new positions of the vertices and based on that data find out the AABB. So for example,
Vertex v0, v1, v2, v3;
// in the local coordinates of the rectangle
// so for example v0 is always 0,0 and width and height define the others
// put some values to v0..v3
glLoadIdentity();
glTranslatef(the position of the rectangle);
glTranslatef(center_point);
glRotatef(angle, 0,0,1);
glTranslatef(-center_point);
GLfloat matrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
v0 = multiply_matrix_by_vector(matrix, v0);
v1 = multiply_matrix_by_vector(matrix, v1);
v2 = multiply_matrix_by_vector(matrix, v2);
v3 = multiply_matrix_by_vector(matrix, v3);
AABB = find_the_minimums_and_maximums(v0, v1, v2, v3);
If you don't know how to multiply a matrix by vector, try googling it.
Also note that since the matrix dimensions are 4x4, the vectors for the vertices also need to be 4-dimensional. You can convert a 2D vector to a 4D vector by adding a third component 0 (zero) and a fourth component 1 (one). After the multiplication has been done, you can convert the resulting 4D vector back to 2D by dividing the x and y components by the fourth component and simply by ignoring the third component because you don't need a third dimension.
Since matrix multiplications might be a quite processor-heavy operation, this approach might be good only, if you don't need to update a lot of AABBs very often.

What is the easiest way to align the Z axis with a vector?

Given a point such as (0, 0, 0) and a vector like (x, y, z). What is the easiest way to align the negative Z-axis centered at (0, 0, 0) to point in the direction of this vector? Examples using OpenGL would be welcome, but not neccessary.
There's lots of different ways to rotate a coordinate-frame to point in a given direction; they'll all leave the z-axis pointed in the direction you want, but with variations in how the x- and y-axes are oriented.
The following gets you the shortest rotation, which may or may not be what you want.
vec3 target_dir = normalise( vector );
float rot_angle = acos( dot_product(target_dir,z_axis) );
if( fabs(rot_angle) > a_very_small_number )
{
vec3 rot_axis = normalise( cross_product(target_dir,z_axis) );
glRotatef( rot_angle, rot_axis.x, rot_axis.y, rot_axis.z );
}
You probably want to have a look at Diana Gruber's article
To answer my own question, the best answer I've come up with is this:
Divide the vector up into "components". The x component is the displacement along the x axis. If we turn to trigonometry, we have that cos(alpha) = x / vector_magnitude. If we compute the RHS then we can derive alpha, which is the amount by which we'd have to rotate around the y axis.
Then the coordinate system can be aligned to the vector by a series of calls to glRotatef()
There are lots of resources out there about rotating your coordinates (or rotating objects, which amounts to the same thing). I learnt a lot from this site, both about how to program in multiple dimensions and especially how to manipulate vectors
The page here has a section "Transformations for moving a vector to the z-axis" that
seems to be what you want, or perhaps the inverse of it.