I have a question about implementing the arcball in opengl es, using Android Studio.
After calculating the rotation axis, I should reverse the axis through the rendering pipeline back to the object space, so that the rotation could be applied in the object space.
This part would be written like:
obj_rotateAxis = normalize(vec3(inverse(mat3(camera->projMatrix) * mat3(camera->viewMatrix) * mat3(teapot->worldMatrix)) * rotateAxis));
However, I heard that the correct form should be like:
obj_rotateAxis = normalize(vec3(inverse(mat3(camera->viewMatrix) * mat3(teapot->worldMatrix)) * rotateAxis));
where projMatrix is discarded. Why do we not consider the projection matrix when we implement the arcball, although projection transform is done for the object?
As far as I know, you use the arcBall to compute an angle of rotation you will apply to your object. When you want to rotate an object you want to make it rotate from the origin of the world (world matrice) or from the viewpoint (view matrice).
The projection matrice doesn 't represent the actual location of your object. The farest you are located the smaller you will get you don't want the depth to have an effect on your rotation.
So you compute the rotation from the view point or the origin and then you let the projection matrice do its job at render.
Related
Say I have 2 objects, a camera and a cube, both on XZ plane, the cube has some arbitrary rotation, and camera is facing the cube.
now if a transformation R is applied to the camera such that it has a new rotation and position.
I want to move the cube in front of the camera using transformation R1, such that in the view it looks exactly as before R was applied, meaning relative distance, rotation and scale b/w the 2 objects remain same after both R and R1.
Following image gives a gist of the problem.
Assume that there's no scenegraph that we can use.
I've posed the problem mainly in 2D but I'm trying to solve it in 3D, so rotations can have all yaw, pitch and roll, and translations can be anywhere in 3D space.
EDIT:
I forgot to add what I have done so far.
I figured out how to maintain relative distance b/w camera and cube, I can project cube's position to get world to screen point, then unproject the screen point in new camera position to get new world position.
However for rotation, I have tried this
I thought I can apply same rotation as R in R1, this didn't work, it appears to work if rotation happens only in one axis, if rotation happens in more than one axes, it does not work.
I thought I can take delta rotation b/w camera and cube, and simply apply camera's rotation to the cube and then multiply delta rotation, this also didn't work
Let M and V be the model and view matrices before you move the camera, M2 and V2 be the matrices after you move the camera. To be clear: model matrix transforms the coordinates from object local coordinates into world coordinates; a view matrix transforms from world coordinates into clip-space camera coordinates. Consequently V*M*p transforms the position p into clip-space.
For the position on the screen to stay constant, we need V*M*p = V2*M2*p to be true for all p (that's assuming that the FOV doesn't change). Therefore V*M = V2*M2, or
M2 = inverse(V2)*V*M
If you apply the camera transformation on the right (V2 = V*R) then the above expression for M2 can be simplified:
M2 = inverse(R)*M
(that is you apply inverse(R) on the left of the model matrix to compensate).
Alternatively, ask yourself if you really need to keep the object coordinates in the world reference frame. It may be easier to not to apply the view matrix when rendering that object at all; that would effectively keep it relative to the camera at all times without any additional tweaks. That would have better numerical stability too.
I am building a camera class to look arround a scene. At the moment I have 3 cubes just spread arround to have a good impression of what is going on. I have set my scroll button on a mouse to give me translation along z-axis and when I move my mouse left or right I detect this movement and rotate arround y-axis. This is just to see what happens and play arround a bit. So I succeeded in making the camera rotate by rotating the cubes arround the origin but after I rotate by some angle, lets say 90 degrees, and try to translate along z axis to my surprise I find out that my cubes are now going from left to right and not towards me or away from me. So what is going on here? It seems that z axis is rotated also. I guess the same goes for x axis. So it seems that nothing actually moved in regard to the origin, but the whole coordinate system with all the objects was just rotated. Can anyone help me here, what is going on? How coordinate system works in opengl?
You are most likely confusing local and global rotations. Usual cheap remedy is to change(reverse) order of some of your transformation. However doing this blindly is trial&error and can be frustrating. Its better to understand the math first...
Old API OpeGL uses MVP matrix which is:
MVP = Model * View * Projection
Where Model and View are already multiplied together. What you have is most likely the same. Now the problem is that Model is direct matrix, but View is Inverse.
So if you have some transform matrix representing your camera in oder to use it to transform back you need to use its inverse...
MVP = Model * Inverse(Camera) * Projection
Then you can use the same order of transformations for both Model and Camera and also use their geometric properties like basis vectors etc ... then stuff like camera local movements or camera follow are easy. Beware some tutorials use glTranspose instead of real matrix Inverse. That is correct only if the Matrix contains only unit (or equal sized) orthogonal basis vectors without any offset so no scale,skew,offset or projections just rotation and equal scale along all axises !!!
That means when you rotate Model and View in the same way the result is opposite. So in old code there is usual to have something like this:
// view part of matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotate3f(view_c,0,0,1); // ugly euler angles
glRotate3f(view_b,0,1,0); // ugly euler angles
glRotate3f(view_a,1,0,0); // ugly euler angles
glTranslatef(view_pos); // set camera position
// model part of matrix
for (i=0;i<objs;i++)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(obj_pos[i]); // set camera position
glRotate3f(obj_a[i],1,0,0); // ugly euler angles
glRotate3f(obj_b[i],0,1,0); // ugly euler angles
glRotate3f(obj_c[i],0,0,1); // ugly euler angles
//here render obj[i]
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
note the order of transforms is opposite (I just wrote it here in editor so its not tested and can be opposite to native GL notation ... I do not use Euler angles) ... The order must match your convention... To know more about these (including examples) not using useless Euler angles see:
Understanding 4x4 homogenous transform matrices
Here is 4D version of what your 3D camera class should look like (just shrink the matrices to 4x4 and have just 3 rotations instead of 6):
reper4D
pay attention to difference between local lrot_?? and global grot_?? functions. Also note rotations are defined by plane not axis vector as axis vector is just human abstraction that does not really work except 2D and 3D ... planes work from 2D to ND
PS. its a good idea to have the distortions (scale,skew) separated from model and keep transform matrices representing coordinate systems orthonormal. It will ease up a lot of things latter on once you got to do advanced math on them. Resulting in:
MVP = Model * Model_distortion * Inverse(Camera) * Projection
I am using DirectXTK for C++, and am making heavy use of the sprite batch function.
I am trying to develop an isometric rendering engine. I've already gotten the isometric rendering to work properly. Along with offsetting. However I run into one major problem.
I can't for the life of me figure out how to center the camera's center to the world's (0,0) or any other coord.
And after injecting this transformation matrix generated directly from the camera into SpriteBatch.Begin()
Matrix Camera::getTransformMatrix() {
Matrix Transform = Transform.CreateTranslation(Vector3(World_Pos.x, World_Pos.y, 0));
Matrix Rotation = Rotation.CreateRotationZ(0);
Matrix Scale = Scale.CreateScale(ZoomFactor, ZoomFactor, 1);
return Transform * Rotation * Scale;
}
Nothing seems to happen. This is with the Camera's world position set to (0,0) and the sprite's world position set to (0,0).
This is the resulting image.
http://i.imgur.com/Bep7l5a.png
I turned off alpha blending, and sprite offsets for debugging reasons.
Can anyone help me please? Also, if anyone can tell me how to flip the y that would be great as well.
Remember that the default transformation for the screen viewport is still applied if you provide a custom transformation to SpriteBatch. The default transformation makes SpriteBatch work with pixel coordinates starting at the upper-left corner of the screen.
If you want the custom transformation to be used "as is" without concatenating with the final viewport transformation, you can use this special case for the orientation handling:
spriteBatch->SetRotation(DXGI_MODE_ROTATION_UNSPECIFIED);
Be sure to read the wiki.
I found my answer. To those who run into this problem as well. you'll need to compensate for the fact that the view port needs to be translated to center (0,0) to the center of the screen.
That is to say that the matrix you need is...
View * Translation(width * .05, height * .05)
Where View is the inverse matrix of the product of your world scale, world rotation, and world transformation.
Such that the product of the final world transformation matrix F, and view matrix V satisfies...
I=F*V
I is the identity matrix.
I have a generic OpenGL 3D world, centered on (0,0,0) at start. I implemented a standard trackball, based on this code. This implements rotations as small increments/transformations to the current modelview matrix,
// We need to apply the rotation as the last transformation.
// 1. Get the current matrix and save it.
// 2. Set the matrix to the identity matrix (clear it).
// 3. Apply the trackball rotation.
// 4. Pre-multiply it by the saved matrix.
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)objectXform);
glLoadIdentity();
glRotatef(rot_angle, rotAxis.x, rotAxis.y, rotAxis.z);
glMultMatrixf((GLfloat *)objectXform);
This part works perfectly. But then I wantes to implement translations, and I am doing this also as small increments to the modelview matrix,
glTranslatef(-dx, -dy, 0.f);
This also works as expected (no matter how the world is rotated, the translation goes along with the mouse, i.e., the model goes behind the mouse.
The problem comes when I try to rotate after the translation: I want the rotation to be around the world center, but that will not happen after user translations. I tried to store the absolute translation and compensate for it, but obviously it does not work. I did it as folows:
// Translation part, store absolute translation
m_mouseInfo.m_fTotalTranslationX -= dx;
m_mouseInfo.m_fTotalTranslationY -= dy;
glTranslatef(-dx, -dy, 0.f);
...
// Rotation, try to apply the rotation around (0,0,0)
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)objectXform);
glLoadIdentity();
// Try to compensate for the translation and do the rotation aroun (0,0,0) but won't work
glTranslatef(m_mouseInfo.m_fTotalTranslationX, m_mouseInfo.m_fTotalTranslationY, 0.f);
glRotatef(rot_angle, rotAxis.x, rotAxis.y, rotAxis.z);
glTranslatef(-m_mouseInfo.m_fTotalTranslationX, -m_mouseInfo.m_fTotalTranslationY, 0.f);
glMultMatrixf((GLfloat *)objectXform);
How can I store the absolute translation to compensate for it when I apply the rotation and therefore rotate the scene around the origin?
Or, in other words, how can I just rotate the world around the origin when I have cumulative transfromations?
To translate around a point (x,y), first translate by (x,y), then rotate, then translate by -(x,y).
Now, if your world has been transformed by M (some matrix), then the origin of the world before that transformation is located at M^-1 (0,0).
Suppose your world transformation from the original is M, and you want to perform some rotation R, but that rotation should be around the original origin, but the rotation matrix R is expressed in terms rotation around the point (0,0) (as is the style).
Then R' = M R M^-1 will generate a new matrix R' that consists of rotating by R around the original (0,0). Then M' = R' M is the matrix that represents starting with nothing, and then doing M, then doing R around the origin.
If you are doing cumulative transformations on some model, simply keep track of the product of said transformations, along side modifying the scene.
Alternatively, store the original scene, and instead of doing cumulative transformations on it, always apply M to get the current scene.
So I'm trying to do some rotation operations on an image in openGL based on quaternion information, and I'm wondering, is there a way to define the location of my image by a vector (let's say (001)), and then apply the quaternion to that vector to rotate my image around an arbitrary origin? I've been using GLM for all the math work. (Using C++)
Or is there a better way to do this that I haven't figured out yet?
If you want to rotate around a point P = {x, y, z} then you can simply translate by -P, rotate around the origin and then translate back by P.
The order in which the transforms should be applied are:
scale -> translation to point of rotation -> rotation -> translation
So your final matrix should be computed:
glm::mat4 finalTransform = translationMat * rotationMat * translationToPointOfRotationMat * scaleMat;