Rotating an object with quaternion - opengl

I have a question in regards to using quaternions for the rotation of my graphics object.
I have a Transform class which has the following constructor with default parameters:
Transform(const glm::vec3& pos = glm::vec3(0.0), const glm::quat& rot = glm::quat(1.0, 0.0, 0.0, 0.0),
const glm::vec3& scale = glm::vec3(1.0))
{
m_pos = pos;
m_rot = rot;
m_scale = scale;
}
In my Transform class calculate the MVP as follows:
glm::mat4 Transform::GetModelMatrix() const
{
glm::mat4 translate = glm::translate(glm::mat4(1.0), m_pos);
glm::mat4 rotate = glm::mat4_cast(m_rot);
glm::mat4 scale = glm::scale(glm::mat4(1.0), m_scale);
return translate * rotate * scale;
}
The issue I'm facing is that when I use const glm::quat& rot = glm::quat(1.0, 0.0, 0.0, 0.0) my object appears normal on screen. The following image shows it:
However if I try to use for example const glm::quat& rot = glm::quat(glm::radians(90.0f), 0.0, 1.0, 0.0) (rotating on y axis by 90 degrees) my object appears as if it has been scaled. The following image shows it:
I can't figure out what is causing it to become like this when I try to rotate it. Am I missing something important?
If it's of any relevance, the following is how I calculate my view matrix:
glm::mat4 Camera::GetView() const
{
glm::mat4 view = glm::lookAt(m_pos, m_pos + m_forward, m_up);
return view;
}

AFAIK you can init a glm::quat using:
glm::vec3 angles(degToRad(rotx), degToRad(roty), degToRad(rotz));
glm::quat rotation(angles);
Where rotx, roty, rotz are the rotation angles around x, y and z axis and degToRad converts angles to radians. Therefore for your case:
glm::vec3 angles(degToRad(0), degToRad(90), degToRad(0));
glm::quat rotation(angles);
Regards

Related

Rotating a 3D cube using opengl glm

I create a cube like normal using 8 vertex points that outline a cube and use indices to draw each individual triangle. However, when I create my camera matrix and rotate it using the lookat function with glm it rotates the entire screen positions not world positions.
glm::mat4 Projection = glm::mat4(1);
Projection = glm::perspective(glm::radians(60.0f), (float)window_width / (float)window_hight, 0.1f, 100.0f);
const float radius = 10.0f;
float camX = sin(glfwGetTime()) * radius;
float camZ = cos(glfwGetTime()) * radius;
glm::mat4 View = glm::mat4(1);
View = glm::lookAt(
glm::vec3(camX, 0, camZ),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
glm::mat4 Model = glm::mat4(1);
glm::mat4 mvp = Projection * View * Model;
Then in glsl:
uniform mat4 camera_mat4
void main()
{
vec4 pos = vec4(vertexPosition_modelspace, 1.0) * camera_mat4;
gl_Position.xyzw = pos;
}
Example: GLM rotating screen coordinates not cube

scaling is moving the object

Video Link for the issue.
https://www.youtube.com/watch?v=iqX1RPo4NDE&feature=youtu.be
This is what i want to attain.
https://www.youtube.com/watch?v=bWwYV0VhXqs
Here after scaling the object i can move pivot independently , position of the pivot does not affect the position of the object.
These are my matrices.
when i move the pivot point to one unit in x and if the scaling is set to 1 than everthing works fine.
the pivot point has moved to one unit and the cube has stayed in its position.
But when i first scale the object to 0.5 and than move the pivot point than the cube follows the pivot point , which should not be he case as i am only moving pivot point.
Please help me with this , how can i keep the cube in position.
Though i am moving the axis not the cube so the cube should stay in original position.
glm::mat4x4 Container::GetPositionMatrix()
{
// posx is the x position of the object.
// posy is the y position of the object.
// posz is the y position of the object.
glm::mat4 TransformationPosition = glm::translate(glm::mat4x4(1.0),
glm::vec3(posx, posy, posz ));
return TransformationPosition;
}
glm::mat4x4 Container::GetRotationMatrix()
{
// posx is the x positon of the object
// pivotx is the x position on the pivot point
// rotx is the x rotation of the object
glm::vec3 pivotVector(posx - pivotx, posy - pivoty, posz - pivotz);
glm::mat4 TransPivot = glm::translate(glm::mat4x4(1.0f), pivotVector);
glm::mat4 TransPivotInverse = glm::translate(glm::mat4x4(1.0f),
glm::vec3( -pivotVector.x , -pivotVector.y , -pivotVector.z));
glm::mat4 TransformationRotation(1.0);
TransformationRotation = glm::rotate(TransformationRotation,
glm::radians(rotx), glm::vec3(1.0, 0.0, 0.0));
TransformationRotation = glm::rotate(TransformationRotation,
glm::radians(roty), glm::vec3(0.0, 1.0, 0.0));
TransformationRotation = glm::rotate(TransformationRotation,
glm::radians(rotz ), glm::vec3(0.0, 0.0, 1.0));
return TransPivotInverse * TransformationRotation * TransPivot;
}
glm::mat4x4 Container::GetScalingMatrix()
{
// posx is the x positon of the object
// pivotx is the x position on the pivot point
// scax is the x scaling of the object
glm::vec3 pivotVector(posx - pivotx, posy - pivoty, posz - pivotz);
glm::mat4 TransPivot = glm::translate(glm::mat4x4(1.0f), pivotVector);
glm::mat4 TransPivotInverse = glm::translate(glm::mat4x4(1.0f),
glm::vec3(-pivotVector.x, -pivotVector.y, -pivotVector.z));
glm::mat4 TransformationScale = glm::scale(glm::mat4x4(1.0 ),
glm::vec3(scax, scay, scaz));
return TransPivotInverse * TransformationScale * TransPivot;
}
final matrix for the Object position.
TransformationPosition * TransformationRotation * TransformationScaling
This is my final matrix for the pivot point
PivotPointPosition = MatrixContainerPosition * MatrixPivotPointPosition *
MatrixRotationContainer * MatrixScaleContainer
The object should be orientated and located as follows:
The reference point (pivotx, pivoty, pivotz) is a point in object space.
The object has to be scaled (scax, scay, scaz) and rotated (rotx, roty, rotz) relative to the reference point (pivotx, pivoty, pivotz).
The point (posx, posy, posz) defines the position of the object in the scene, where the reference point has finally to be placed.
Do the following steps:
Scale the object to the desired size, with respect to the reference point:
glm::mat4 GetScalingMatrix()
{
glm::vec3 refVector(pivotx, pivoty, pivotz);
glm::mat4 TransRefToOrigin = glm::translate(glm::mat4(1.0f), -refVector);
glm::mat4 TransRefFromOrigin = glm::translate(glm::mat4(1.0f), refVector);
glm::vec3 scale = glm::vec3(scax, scay, scaz);
glm::mat4 TransformationScale = glm::scale(glm::mat4(1.0), scale);
return TransRefFromOrigin * TransformationScale * TransRefToOrigin;
}
Rotate the scaled object around the pivot, like in the answer to one of your previous questions (How to use Pivot Point in Transformations):
glm::mat4 GetRotationMatrix()
{
glm::vec3 pivotVector(pivotx, pivoty, pivotz);
glm::mat4 TransPivotToOrigin = glm::translate(glm::mat4(1.0f), -pivotVector);
glm::mat4 TransPivotFromOrigin = glm::translate(glm::mat4(1.0f), pivotVector);
glm::mat4 TransformationRotation(1.0);
TransformationRotation = glm::rotate(TransformationRotation,
glm::radians(rotx), glm::vec3(1.0, 0.0, 0.0));
TransformationRotation = glm::rotate(TransformationRotation,
glm::radians(roty), glm::vec3(0.0, 1.0, 0.0));
TransformationRotation = glm::rotate(TransformationRotation,
glm::radians(rotz), glm::vec3(0.0, 0.0, 1.0));
return TransPivotFromOrigin * TransformationRotation * TransPivotToOrigin;
}
Move the scaled and rotated object to its final position (posx, posy, posz).
glm::mat4 GetPositionMatrix()
{
glm::vec3 trans = glm::vec3(posx-pivotx, posy-pivoty, posz-pivotz);
glm::mat4 TransformationPosition = glm::translate(glm::mat4(1.0), trans);
return TransformationPosition;
}
The order matters:
glm::mat4 model = GetPositionMatrix() * GetRotationMatrix() * GetScalingMatrix();
All this can be simplified:
// translate "pivot" to origin
glm::mat4 ref2originM = glm::translate(glm::mat4(1.0f), -glm::vec3(pivotx, pivoty, pivotz));
// scale
glm::mat4 scaleM = glm::scale(glm::mat4(1.0), glm::vec3(scax, scay, scaz));
// rotate
glm::mat4 rotationM(1.0);
rotationM = glm::rotate(rotationM, glm::radians(rotx), glm::vec3(1.0, 0.0, 0.0));
rotationM = glm::rotate(rotationM, glm::radians(roty), glm::vec3(0.0, 1.0, 0.0));
rotationM = glm::rotate(rotationM, glm::radians(rotz), glm::vec3(0.0, 0.0, 1.0));
// translate to "pos"
glm::mat4 origin2posM = glm::translate(glm::mat4(1.0), glm::vec3(posx, posy, posz));
// concatenate matrices
glm::mat4 model = origin2posM * rotationM * scaleM * ref2originM;

Rotate a camera around a axis?

How can I rotate a camera in a axis? What matrix I have to multiply?
I am using glm::lookAt to construct the viewMatrix, but I tried to multiply it by a rotation matrix and nothing happened.
glm::mat4 GetViewMatrix()
{
return glm::lookAt(this->Position, this->Position + this->Front, glm::vec3(0.0f, 5.0f, 0.0f));
}
glm::mat4 ProjectionMatrix = glm::perspective(actual_camera->Zoom, (float)g_nWidth / (float)g_nHeight, 0.1f, 1000.0f);
glm::mat4 ViewMatrix = actual_camera->GetViewMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
Rotate the front and up vectors of your camera using glm::rotate:
glm::mat4 GetViewMatrix()
{
auto front = glm::rotate(this->Front, angle, axis);
auto up = glm::rotate(glm::vec3(0, 1, 0), angle, axis);
return glm::lookAt(this->Position, this->Position + front, up);
}
Alternatively, you can add a multiplication with your rotation matrix to your MVP construction:
glm::mat4 MVP = ProjectionMatrix * glm::transpose(Rotation) * ViewMatrix * ModelMatrix;
It is important that the rotation happens after the view matrix, so all objects will be rotated relative to the camera's position. Furthermore, you have to use transpose(Rotation) (the inverse of a rotation matrix is its transpose), since rotating the camera clockwise for example, is equivalent to rotating all objects counter-clockwise.

Camera movement around a sphere

I am trying to convert moving around the xz plane to movement around a sphere. Originally, I had my camera moving forward at a constant speed at a constant height on the y axis. The user can move left/right by adjusting the yaw, however they can not move up/down or roll. Here is how I accomplished that:
float turnRate = 1.0;
float stepDist = 0.1;
if (keys['d']) {
yaw += M_PI * (turnRate / 180.0);
}
if (keys['a']) {
yaw += M_PI * (-turnRate / 180.0);
}
position.x += stepDist * sinf(yaw);
position.z += stepDist * cosf(yaw + M_PI);
...
glm::mat4 P = glm::rotate(pitch, glm::vec3(-1.0, 0.0, 0.0));
glm::mat4 Y = glm::rotate(yaw, glm::vec3(0.0, -1.0, 0.0));
glm::mat4 T = glm::translate(position);
glm::mat4 C = T * Y * P;
This worked well for me. Now what I am trying to achieve is instead of moving across the xz plane, I would like to move across the surface of a sphere. I still want to be moving forward at a constant speed at a constant radius from the center of the sphere with only allowing adjustment of the yaw. This is what I have currently:
float turnRate = 1.0;
float stepDist = 0.01;
step += stepDist;
if (keys['d']) {
yaw += M_PI * (turnRate / 180.0);
}
if (keys['a']) {
yaw += M_PI * (-turnRate / 180.0);
}
pitch = M_PI / 8.0; // angle the camera down towards the sphere a bit
glm::vec3 f = glm::vec3(sinf(yaw), 0.0, cosf(yaw + M_PI));
glm::vec3 up = glm::vec3(0.0, 1.0, 0.0);
glm::vec3 forward = glm::normalize(f);
right = glm::cross(up, forward);
float sphereRadius = 50.0;
float camRadius = sphereRadius + 8.0;
radius = glm::vec3(0.0, camRadius, 0.0);
...
glm::mat4 P = glm::rotate(pitch, glm::vec3(-1.0, 0.0, 0.0));
glm::mat4 Y = glm::rotate(yaw, glm::vec3(0.0, -1.0, 0.0));
glm::mat4 T = glm::translate(radius);
glm::mat4 S = glm::rotate(step, right);
glm::mat4 C = S * T * Y * P;
This works when the camera is simply moving forward. However, the problem is that when the yaw is changing (the user is turning right/left) and the step gets to certain values the sphere will start rotating in the wrong direction underneath the camera. It is not an instant switch. It seems to be reversed when step is between increments of PI to 2PI (i.e. it is reversed between pi and 2pi, 3pi and 4pi, etc..).
Any ideas on how I might fix this or what I am doing wrong?
UPDATE:
Here is a similar example of what I am trying to achieve:
http://www.youtube.com/watch?v=izVtTcq_his&t=0m23s
Except I want to be able to rotate the camera at smaller intervals than 90 degrees. If anyone has any links to example code/tutorials of how to achieve this I would really appreciate it.

Can't properly produce a ViewProjection matrix

I have a camera class that uses the DirectXMath API:
__declspec(align(16)) class Camera
{
public:
XMVECTOR Translation;
XMMATRIX Rotation;
XMVECTOR Scale;
XMMATRIX Transform;
XMFLOAT3 RotAngles;
XMMATRIX ProjectionMatrix;
float Width;
float Height;
float NearZ;
float FarZ;
float AspectRatio;
float FieldOfView;
Camera()
{
Translation = XMVectorZero();
Rotation = XMMatrixIdentity();
Scale = XMVectorSplatOne();
Transform = XMMatrixIdentity();
Width = 800;
Height = 600;
NearZ = 0.1f;
FarZ = 100.0f;
AspectRatio = 800 / 600;
FieldOfView = (XM_PIDIV4);
ProjectionMatrix = XMMatrixPerspectiveFovLH(FieldOfView, AspectRatio, NearZ, FarZ);
}
void Update()
{
Rotation = XMMatrixRotationRollPitchYaw(RotAngles.x, RotAngles.y, RotAngles.z);
XMMATRIX scaleM = XMMatrixScalingFromVector(Scale);
XMMATRIX translationM = XMMatrixTranslationFromVector(Translation);
Transform = scaleM * Rotation * translationM;
}
XMMATRIX GetViewMatrix()
{
XMVECTOR Eye;
XMVECTOR At;
XMVECTOR Up;
Eye = Translation;
At = Translation + Transform.r[2];
Up = Transform.r[1];
return(XMMatrixLookAtLH(Eye, At, Up));
}
XMMATRIX GetViewProjectionMatrix()
{
return(XMMatrixTranspose(GetViewMatrix() * ProjectionMatrix));
}
};
When I store the result of GetViewProjectionMatrix() in a XMFLOAT4X4 and update it to the constant buffer, the geometry gets torn apart or doesn't show up at all when I move/rotate the camera with the keyboard.I have isolated the camera to be issue with the deforming/disappearing geometry, but I have no idea what the problem is.I mean the projection matrix can't be wrong, it's just 1 function call, so it's most likely the view matrix.Could someone tell me where the issue is?I tried different combinations of multiplication orders/transposing both/transposing only one/anything.It never works properly.
In case anyone sees this question again:
It seems that OP did not transpose to ViewProjection matrix they generated. Note that DirectXMath works in row-major order while HLSL defaults to column-major. As per the documentation at - https://msdn.microsoft.com/en-us/library/windows/desktop/bb509634(v=vs.85).aspx