Child rotating around parent axes instead of his own - c++

So, I have a C ++ project which is simulating a car.
My program is working in 2D(only in the XY plane), it feed with odometries data gave by a rosbag, giving him his position in the XYplane depending of the world origin. Everything is fine in 2D.
But when I am in 3D, meaning I can rotate my car around several axes, not only Z anymore.
I realized that my car is rotating around the axes of the "world" axes, when I would like them to turn around my vehicle axes.
In order to test it, I did a dummy code where my vehicle is suppose to do a 90deg rotation one the Z axe and then a 90 deg rotation on Y axe.
I can do to have my vehicle rotating around his own axes ?
How would the math would be ?
In the following the two rotations are done around the world axes.
Here is a piece of my code to illustrate:
void NodeImpl::callback_odometry(motion_common_msg::Odometry input_msg)
{
//Getting Direction3D
//---
frame_id = input_msg.header.frame_id;
stamp = input_msg.header.stamp;
transform_from_odometry.setOrigin(new_position_3D);
tf::Quaternion q;
q.setRPY(0.0, 0.0, 0.0);
transform_from_odometry.setRotation(q);
if(input_msg.pos_x >= 5.0)
{
double cos90 = 0;
double sin90 = 1;
tf::Matrix3x3 Rz90;
tf::Matrix3x3 Ry90;
Rz90.setValue(cos90, - sin90, 0, sin90, cos90, 0, 0, 0, 1);
Ry90.setValue(cos90, 0, sin90, 0, 1, 0, -sin90, 0, cos90);
tf::Quaternion qz90;
tf::Quaternion qy90;
Rz90.getRotation(qz90);
Ry90.getRotation(qy90);
qz90.normalize();
qy90.normalize();
tf::Transform tf_new_rot;
tf_new_rot.setRotation(qz90);
transform_from_odometry.setRotation(qy90);
transform_from_odometry.mult (transform_from_odometry, tf_new_rot);
}
broadcast();
}
void NodeImpl::broadcast()
{
static tf::TransformBroadcaster br;
br.sendTransform(tf::StampedTransform(transform_from_odometry, stamp, frame_id, "ego_vehicle_rear_axis"));
}

I'm not sure which library you are using, so I'll try to give some generic advice on this.
Global vs Local rotations are just a matter of the matrix multiplication order. Let R be the final rotation matrix. When you multiply the X, Y and Z matrices using the following order R=X*Y*Z, then this would give you Global rotations, whereas R=Z*Y*X will give you Local rotations.
The problem with the above is that it limits your freedom for local rotations to the specific order Z-Y-X. For example, if you want to rotate, first on the x-axis, then on the y-axis, and then on the z-axis, the above would work fine. Anything else, is not going to give you the results you want. You would have to change the order of matrix multiplications.
If you want to rotate about an axis, let's say the y-axis, which is local to your object, then, you'd need to know where this axis is. You need to keep a reference of the current axes after each transformation and then, use the Rotation matrix from axis and angle to rotate about your current local y-axis.
/* from the wiki link above */
Mat3 Axis_Matrix(float angle_, const Vec3 &axis_)
{
return Mat3{ cos(angle_)+pow(axis_.x,2)*(1.0-cos(angle_)) , (axis_.x*axis_.y*(1.0-cos(angle_)))-(axis_.z*sin(angle_)) , (axis_.x*axis_.z*(1.0-cos(angle_)))+(axis_.y*sin(angle_)),
(axis_.y*axis_.x*(1.0-cos(angle_)))+(axis_.z*sin(angle_)) , cos(angle_)+pow(axis_.y,2)*(1.0 - cos(angle_)) , (axis_.y*axis_.z*(1.0-cos(angle_)))-(axis_.x*sin(angle_)),
(axis_.z*axis_.x*(1.0-cos(angle_)))-(axis_.y*sin(angle_)) , (axis_.z*axis_.y*(1.0-cos(angle_)))+(axis_.x*sin(angle_)) , cos(angle_)+pow(axis_.z,2)*(1.0 - cos(angle_)) };
}
You can basically create your own structure that does all this:
struct CoordinateSystem
{
Vec3 current_x_axis;
Vec3 current_y_axis;
Vec3 current_z_axis;
Mat3 local;
void setRotationX(float angle_)
{
local *= Axis_Matrix(angle_, current_x_axis);
update();
}
void setRotationY(float angle_)
{
local *= Axis_Matrix(angle_, current_y_axis);
update();
}
void setRotationZ(float angle_)
{
local *= Axis_Matrix(angle_, current_z_axis);
update();
}
void update()
{
current_x_axis = {-1.f, 0.f, 0.f} * local;
current_y_axis = { 0.f, 1.f, 0.f} * local;
current_z_axis = { 0.f, 0.f,-1.f} * local;
}
};
Then you can just say:
setRotationX(45);
setRotationZ(10);
setRotationY(62);
setRotationX(34);
setRotationY(81);
And all the rotations would be local to your object.

Related

How to use rotation matrices to move in direction of a camera opengl

I'm tinkering around with opengl and c++ and so far everything has gone pretty smoothly, using glm/glfw/glew however I've run into a bit of a problem when dealing with using the cameras rotation to rotate a movement vector in the direction of the camera for a fly-by camera effect. i.e.
The program receives W + A as inputs so W subtracts 1 to the z component of a direction vector and A adds 1 to the x component.
This produces a direction vector of {1, 0, -1}
example code might be
if (Keyboard::isKeyDown(Key::W)) {
dir += {0, 0, -1};
}
if (Keyboard::isKeyDown(Key::S)) {
dir += {0, 0, 1};
}
if (Keyboard::isKeyDown(Key::A)) {
dir += {1, 0, 0};
}
if (Keyboard::isKeyDown(Key::D)) {
dir += {-1. 0, 0};
}
Then the output is normalised to produce a constant movement speed no matter which direction, now this works fine if the camera is pointed perfectly in the "forward" direction, i can make this code work by calculating forward and right vectors and using this instead of the unit movement lengths, however i find this code not very ellegant and would like to use some sort of function to rotate the movement vector in the direction of the camera in 3d space so you can look up and fly up, I'm using the rotation vector of the camera to calculate the rotation matrix and using this, how this seems to calculate everything weirdly inverted and moving in the wrong direction but relative to the camera?
So calculated every frame is:
m_rotationMatrix = glm::identity<glm::mat4>();
Maths::rotateMatrix(m_rotationMatrix, m_rotation);
using the rotateMatrix method defined here:
void rotateMatrix(glm::mat4& matrix, const glm::vec3& degrees){
matrix = glm::rotate(matrix, glm::radians(degrees.x), { 1, 0, 0 });
matrix = glm::rotate(matrix, glm::radians(degrees.y), { 0, 1, 0 });
matrix = glm::rotate(matrix, glm::radians(degrees.z), { 0, 0, 1 });
}
then in the movement code it's used like so:
m_camera->translate(m_camera->transformDirection(dir) * deltaTime * movementSpeed);
using the transformDirection method defined in the camera as:
glm::vec3 Camera::transformDirection(glm::vec3 vec){
glm::vec4 inputAsVec4 = glm::vec4(vec.x, vec.y, vec.z, 1.0);
glm::vec4 result = m_rotationMatrix * inputAsVec4;
return { result.x, result.y, result.z };
}
I'm pretty new to OpenGL and relatively new to c++ also, so is there anything I'm missing/doing wrong to cause this behavior?

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...

How to rotate an object according to it's orientation

Similar question for WebGL: Rotate object around world axis .
I need to rotate an object in a way that the user should be able to move it with the mouse, like if he's dragging it. The problem is that glRotatef just rotates the object without taking account of it's orientation. For WebGL the solution was to use quaternions, but I guess that there aren't quaternions in OpenGL.
This is how I achieve a rotation for now:
// rotation 2D GLfloat C-vector, posX, posY GLfloat's
void mouse(int button, int state, int x, int y) {
if(button== GLUT_LEFT_BUTTON) {
if(state== GLUT_DOWN)
{
posX=x;
posY= y;
onEvent= true;
}
else if(state== GLUT_UP)
{
GLfloat dx= x-posX;
GLfloat dy= y-posY;
rotation[0]= -dy/5;
rotation[1]= dx/5;
onEvent= false;
glutPostRedisplay();
}
}
}
Then I handle the rotation in the display function:
glPushMatrix();
glRotatef(rotation[0],1,0,0);
glRotatef(rotation[1],0,1,0);
// Draw the object
glPopMatrix();
It kinda works, but like I said it should like if the user is able to drag the object to rotate it. Instead if for example the object is rotated of 90 degrees around the X axis, when the user drags the mouse horizontally to make it rotate around the Y axis, it rotates in the inverse direction. I need an idea here, how could I do that?
Edit
I tried to use glMultMatrixf, but the object doesn't rotate correctly: it gets scaled instead of rotating, this is the code I've edited in the mouse function:
// Global variables:
// GLfloat xRotationMatrix[4][4];
// GLfloat yRotationMatrix[4][4];
else if(state== GLUT_UP && onEvent)
{
GLfloat dx= (x-posX)/(180.0*5)*2.0*M_PI;
GLfloat dy= (y-posY)/(180.0*5)*2.0*M_PI;
// Computing rotations
double cosX= cos(dx);
double sinX= sin(dy);
double cosY= cos(dy);
double sinY= sin(dy);
// x axis rotation
xRotationMatrix[1][1]+= cosY;
xRotationMatrix[1][2]+=-sinY;
xRotationMatrix[2][2]+= sinY;
xRotationMatrix[2][2]+= cosY;
// y axis rotation
yRotationMatrix[0][0]+= cosX;
yRotationMatrix[0][2]+= sinX;
yRotationMatrix[2][0]+= -sinX;
yRotationMatrix[2][2]+= cosX;
onEvent= false;
glutPostRedisplay();
}
Then in the display function:
glPushMatrix();
glMultMatrixf((const GLfloat*)xRotationMatrix);
glMultMatrixf((const GLfloat*)yRotationMatrix);
glutSolidTeapot(10);
glPopMatrix();
This is the non rotated teapot:
If I drag the mouse horizontally to rotate the teapot around the y axis, instead of the rotation this is what I get:
First of all a bit of algebra.
Let v be a vector, M your current modelview matrix, and R the matrix associated with a glRotate command. Then, if you use glRotate, what you get is:
M * R * v
That means you are rotating around object axes. You want to rotate around the world axes, that is:
R * M * v
See the difference? Unfortunately GL doesn't have a MatrixPreMult function.
In modern OpenGL we don't use the matrix stack anymore, in fact while working with shaders we manually pass the transformation matrices to the GL program. What (most) people do is write/use an external vector algebra library (like Eigen).
One possible (untested) workaround which uses only the old deprecated GL stuffs may be something like this:
void rotate(float dx, float dy)
{
//assuming that GL_MATRIX_MODE is GL_MODELVIEW
float oldMatrix[4][4];
glGetFloatv(GL_MODELVIEW_MATRIX,oldMatrix);
glLoadIdentity();
glRotatef(-dy,1,0,0);
glRotatef(dx,0,1,0);
glMultMatrixf(oldMatrix);
}
And you put this code in your mouse function, not in the draw routine.
You can use this trick by keeping the view matrix in the GL matrix stack, then pushing/popping everytime you have to draw an object. I wouldn't recommend something like that in a large project.
Notice also that if you invert the order of the two glRotate calls in the code above you can get slightly different results, expecially if dx and dy are not small.
This code might be slightly better:
float angle = sqrt(dx*dx+dy*dy)*scalingFactor;
glRotate(angle,-dy,dx,0);

(each call to glTranslate is cumulative on the modelview matrix) what does it mean and how to disable this feature?

Studying the book OpenGL SuperBible fram Addison-Wesley, I read:
each call to glTranslate is cumulative on the modelview matrix
what does it mean?
Does it mean that for example this code:
glTranslatef(2.0,3.0,0);
glTranslatef(4.0,5.0,0);
first moves an object that is on the origin to the point (2,3,0) and then translates it from the (2,3,0) to (2+4,3+5,0+0) = (6,8,0) not from the origin again?
Is this true about glScalef and glRotatef too?
for example this code:
glScalef(2.0,3.0,4.0);
glScalef(3.0,4.0,5.0);
first turn a 1x1x1 cuboid to a 2x3x4 cubic rectangle and then turns this cubic rectangle to a 6x12x20 one?
And at last, Does this code mean that a total 75 degrees rotation around the x-axis?
glRotatef(30.0,1,0,0);
glRotatef(45.0,1,0,0);
the most importantant: Does calling glLoadIdentity() before each call of these functions cancels these feature?
I mean Do you think this code assures that each time translates will be done from the origin? , scale changes will be done from the initial state?
void COpenGLControl::ZoomToFullExtent()
{
float zoom1 = (float)oglWindowWidth/(float)ImageWidth;
float zoom2 = (float)oglWindowHeight/(float)ImageHeight;
m_fZoom = min(zoom1,zoom2);
m_fZoomInverse = 1/m_fZoom;
m_fPosX = 0;
m_fPosY = 0;
OnDraw(NULL);
}
void COpenGLControl::FixedZoomIn()
{
m_fZoom = 2*m_fZoom;
m_fZoomInverse = 1/m_fZoom;
OnDraw(NULL);
}
void COpenGLControl::FixedZoomOut()
{
m_fZoom = 0.5*m_fZoom;
m_fZoomInverse = 1/m_fZoom;
OnDraw(NULL);
}
void COpenGLControl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (WantToPan)
{
if (m_fLastX < 0.0f && m_fLastY < 0.0f)
{
m_fLastX = (float)point.x;
m_fLastY = (float)point.y;
}
diffX = (int)(point.x - m_fLastX);
diffY = (int)(point.y - m_fLastY);
m_fLastX = (float)point.x;
m_fLastY = (float)point.y;
if (nFlags & MK_MBUTTON)
{
m_fPosX += (float)0.2f*m_fZoomInverse*diffX;
m_fPosY += (float)0.2f*m_fZoomInverse*diffY;
}
OnDraw(NULL);
}
CWnd::OnMouseMove(nFlags, point);
}
void COpenGLControl::OnDraw(CDC *pDC)
{
// TODO: Camera controls
wglMakeCurrent(hdc,hrc);
glLoadIdentity();
gluLookAt(0,0,1,0,0,0,0,1,0);
glScalef(m_fZoom,m_fZoom,1.0);
glTranslatef(m_fPosX, m_fPosY, 0.0f);
wglMakeCurrent(NULL, NULL);
}
glTranslate, glScale, glRotate don't act on "objects" (whatever a object is. OpenGL doesn't know what a "object" is, it only knows points, lines and triangles).
In old fixed function OpenGL you have a couple of matrix stacks. A stack is a data structure similar to a list, with two operations push and pop. You can in fact derive it from a list:
stack : list;
void stack::push() {
this->append( copy(this->last_element) );
}
void stack::pop() {
this->drop( this->last_element );
}
Projection and modelview are the most oftenly used ones. There's always one particular matrix stack active for manipulation. glMatrixMode selects which one; think of it as a reference.
stack<mat4x4> modelview;
stack<mat4x4> projection;
stack<mat4x4> *M;
void glMatrixMode(mode) {
switch(mode) {
case GL_MODELVIEW:
M = &modelview; break;
case GL_PROJECTION:
M = &projection; break;
}
}
void glPushMatrix() {
M->push();
}
void glPopMatrix() {
M->pop();
}
The OpenGL fixed function matrix manipulation functions act in place on top element of the active matrix stack (M).
void glLoadIdentity() {
M->last_element = identity_matrix;
}
void glTranslate(x,y,z) {
/* make a translation matrix and R-multiply in place */
mat4x4 T = translate_matrix(x,y,z);
M->last_element = M->last_element * T;
}
void glScale(x,y,z) {
/* make a scaling matrix and R-multiply in place */
mat4x4 S = scaling_matrix(x,y,z);
M->last_element = M->last_element * S;
}
void glRotate(a,x,y,z) {
/* make a rotation matrix and R-multiply in place */
mat4x4 R = rotation_matrix(a,x,y,z);
M->last_element = M->last_element * R;
}
And that's all that's happening behind the curtain when calling those functions.
OpenGl keeps a modelView matrix which multiply the coordinates of your vertices. Every call to translate, rotate, scale etc will multiply this matrix by the right. So if you have:
glLoadIdentity();
glTranslatef(2.0,3.0,0);
glTranslatef(4.0,5.0,0);
The result will be first translating your vertices by 4,5,0 and then by 2,3,0. Internally, this will work as follows:
1. the modelView matrix will be the identity.
2. the current modelView matrix (the identity) will be right multiplied by the translation matrix with values ( 4, 5, 0) for more details see (http://en.wikipedia.org/wiki/Translation_%28geometry%29)
3. the current modelViewmatrix (the one of step 2) will be right multiplied by the second translation matrix.
In your example of scaling:
glScalef(2.0,3.0,4.0);
glScalef(3.0,4.0,5.0);
It will be equivalent to first turn the 1x1x1 cuboid into a 3x4x5 cuboid and then into a 6x12x20.
In the roation case, first rotate 45 degrees and then 30.
To your question about the use of glLoadIdentity(), the modelView matrix will be the identity independently from the previous value of the matrix.
You may also be interested in checking the transformation stack system of opengl.
Pay special attention to OpenGL API functions that include the description: "does ... to the current ...".
OpenGL is a glorified state machine, and things like bound objects and matrices (in legacy OpenGL) retain their state. When you make a call to glTranslatef (...) it multiplies the current matrix (defined by the matrix mode and the top of your matrix stack). Unless you issue glLoadMatrixf (...), glLoadIdentity (...) or modify the matrix stack, glTranslatef (...) will simply accumulate everytime you call it.
glLoadIdentity (...) will replace the current matrix with its identity:
1, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 0
0, 0, 0, 1
If you setup your transform matrices every frame, it is generally required that you do this. Otherwise, all of your transformations will be relative to the previous state (though this is sometimes desired).