OpenGL Rotation Around a Point Using GLM - c++

I've been reading other posts about how to rotate objects around a point in OpenGL by translating the pivot to the origin, rotating, and the translating back. However, I can't seem to get it working. I have a cube and am using glm::perspective and glm::lookAt to generate the projection and view matrices.
glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
// Camera matrix
glm::mat4 View = glm::lookAt(
glm::vec3(0,3.5,-5),
glm::vec3(0,0,0),
glm::vec3(0,1,0)
);
// Model matrix : an identity matrix (model will be at the origin)
glm::mat4 Model = glm::mat4(1.0f);
Then I apply the transformations on the model matrix like this, inside a while loop:
if (glfwGetKeyOnce(window, GLFW_KEY_UP))
{
Model = translate(Model, vec3(1.0f, 0.0f, 0.0f));
Model = rotate(Model, 90.0f, vec3(1.0f, 0.0f, 0.0f));
Model = translate(Model, vec3(-1.0f, 0.0f, 0.0f));
}
mat4 MVP = Projection * View * Model;
And in my vertex shader, I have this:
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
However, this still just rotates the cube around its center. If I get rid of the calls to glm::translate, and instead, translate by adjusting the x positions of the vertices, it works properly. But I don't think that's the correct way to do it. What am I missing here?

if (glfwGetKeyOnce(window, GLFW_KEY_UP))
{
Model = translate(Model, vec3(1.0f, 0.0f, 0.0f));
Model = rotate(Model, 90.0f, vec3(1.0f, 0.0f, 0.0f));
Model = translate(Model, vec3(-1.0f, 0.0f, 0.0f));
}
mat4 MVP = Projection * View * Model;
try to visualize this code with your "thumbs-up hand". The thumb is the x-Axis. At first you lift your hand, then you walk in a circle, at last you lower your hand.
Most likely you wanted to rotate around another axis.
Please bear in Mind there are more modern ways to do rotations like quaternions. This'll spare you loads of operations.

Related

Why is my glm rotate function not properly rotating my camera?

I have been trying to get a camera in my world that can rotate and look around a 3D scene actually working for a very long time now. I don't understand why my camera is behaving so strangely when I rotate it moving back and forth not rotating how it should. I have been stuck on this and would really appreciate it if anyone could let me know what I could correct. Thanks.
::MAIN MATH
glm::mat4 look(1.0f);
glm::mat4 model_view(1.0f);
glm::mat4 look_around(1.0f);
glm::mat4 the_perspective(1.0f);
float leftrightlook;
the_perspective = glm::perspective(glm::radians(45.0f), static_cast<float>(width)/height , -7.1f,
150.0f);
look_around = glm::rotate(glm::mat4(1.0f), (leftrightlook), glm::vec3(0.0f, 1.0f, 0.0f));
glm::vec3 UP(0.0f, 1.0f, 0.0f);
glm::vec3 position(1.0f, 1.0f, 1.0f);
glm::vec3 viewdirection(0.0f, 0.0f, 1.0f);
look = glm::lookAt(position, position + viewdirection, UP);
model_view = look_around * look;
::SHADER MATRIX MULTIPLICATION
gl_Position = vec4(position.x, position.y, position.z, 1.0) * the_perspective * model_view;

Switching from orthogonal to perspective projection

I am trying to add a paralax effect to an existing engine. So far the engine worked with an orthogonal projection. Objects are placed in pixel coordinates on the screen. The problem is that I can not figure out how to replicate the same projection with a perspective projection matrix ect. that I can add a Z coordinate for depth.
I tried various combinations of matrices and z coordinates already and the result was always a black screen.
The matrix I am trying to replace:
glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(1280.0f), static_cast<GLfloat>(720.0f), 0.0f, 0.0f, -100.0f);
The vertex shader:
// Shader code (I tested this while having identity matrices for view and model
#version 330 core
layout (location = 0) in vec2 vertex;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
void main() {
gl_Position = projection * view * model * vec4(vertex.xy, 1.0f, 1.0f);
}
The projection code I thought might work:
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(-640, -310.0f, 0.0f));
model = glm::scale(model, glm::vec3(1.0f / 1280.0f, 1.0f / 720.0f, 1.0f));
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
glm::mat4 projection = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, -100.0f);
Expected Is that a rectangle gets still displayed at similar position (I can correct the details once something works) without having a black screen.
The specification of the Perspective projection matrix is wrong.
glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, -100.0f);
glm::perspective defines a Viewing frustum by an field of view angle along the y axis, an aspect ratio and a distance to the near and the far plane.
So the near and the far plane have to be positive values (> 0) and near has to be less than far:
0 < near < far
e.g.:
glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 100.0f);
The geometry has to be in between the near and the far plane, else it is clipped.
The ration of the size of the projected area and the depth is linear and can be calculated. It depends on the field of view angle:
float fov_y = glm::radians(45.0f);
float ratio_size_depth = tan(fov_y / 2.0f) * 2.0f;
Note, if an object should appear with half the size in the projection on the viewport, the distance from the object to the camera (depth) has to be doubled.
So the corrected model translation matrix and required depth in the shader to have the coordinates match on the plane are as follows:
int width = 1280.0f;
int height = 720.0f;
glm::mat4 model = glm::mat4(1.0f);
model = glm::scale(model, glm::vec3(-1.0f / width, -1.0f / height, 1.0f));
model = glm::translate(model, glm::vec3(-((float)width / 2.0f), -((float)height / 2.0f), 0.0f));
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, 1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
glm::mat4 projection = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 100.0f);
Shader with Z-Value:
#version 330 core
layout (location = 0) in vec2 vertex;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
void main() {
gl_Position = projection * view * model * vec4(vertex.xy, 1.208f, 1.0f);
}
Which will be equivalent tho this orthogonal matrix:
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(this->width), static_cast<GLfloat>(this->height), 0.0f, 0.0f, -100.0f);
The matrices can also be multiplied together to have only one projection matrix you pass to the shader. This will make it easier to have an actual model matrix passed with the mesh ect.

Setting a 4x4 Rotation Matrix using Degrees

I would like to ask what the steps are to setting a 4x4 Rotation Matrix using degrees for all separate X, Y, Z axis.
Illustrations would be much appreciated, thanks!
(C++ implementation preferred)
Assuming a C++ program, if you want a header-only library that will do this for you, you can use the amazing glm:
http://glm.g-truc.net/0.9.6/index.html
And use glm::rotate as such:
glm::mat4 Projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100.f);
glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate));
glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f));
glm::mat4 View = glm::rotate(ViewRotateX, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f));
glm::mat4 MVP = Projection * View * Model;
You can find the implementation on Github if you are interested in writing your own: matrix_transform.inl

How to set up an orthographic view for glsl with glm?

I'm trying to set up an orthographic view matrix using glm and pass it to glsl. this poster has the same problem, I want to be able to render pixels drawn further away from the camera but they are being clipped when they are anything but 1.0 distance.
The MVP matrix is set up like so:
// Setup MVP Matrix
glm::mat4 model = glm::mat4(1.0);
model = glm::translate(model, glm::vec3(sprite->getPositionX(), sprite->getPositionY(), 0.0f));
model = glm::rotate(model, rotation, glm::vec3(0.0f, 0.0f, 1.0f));
model = glm::translate(model, glm::vec3(-sprite->getOffsetX(), -sprite->getOffsetY(), 0.0f));
//model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f)); // Unused for now
glm::mat4 view = glm::lookAt(glm::vec3(0,0,0), glm::vec3(0,0,-1), glm::vec3(0,1,0));
glm::mat4 projection = glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, 1.0f, 1000.0f);
glm::mat4 mvp = projection * view * model;
// Set mpv matrix in shader
GLint mvpLoc = glGetUniformLocation(this->m_shader, "u_mvpMatrix");
glProgramUniformMatrix4fv(this->m_shader, mvpLoc, 1, GL_FALSE, &mvp[0][0]);
I can see the quad being rendered with the translation and rotation applied but when the verticies are anywhere but -1.0f on the z axis they are not drawn when I expect it to draw anything from -1.0 to -1000.0 units away as specified in the call to glm::ortho. Anybody know how this can be achieved?

glm::translate with local space

I want to move a matrix according to it's own space (direction) and not world space.
Specifically I want to move the view matrix/the "camera".
glm::mat4x4 view = glm::lookAt(glm::vec3(1.1f, 1.3f, 1.2f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
view=glm::rotate(view, r, glm::vec3(0,1,0));
view=glm::translate(view, glm::vec3(x,y,z));
The translation is equal disregarding it's rotation, but I'd like to translate according to where the camera is facing, e.g. when the camera is facing the x axis, and I translate z, it should translate along world axis x. How can this be done?
If you want to manipulate the camera position, you should store the camera position and only put it into view space when you need to.
glm::mat4 camera = glm::inverse(glm::lookAt(
glm::vec3(1.1f, 1.3f, 1.2f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)));
camera = glm::rotate(camera, r, glm::vec3(0,1,0));
camera = glm::translate(camera, glm::vec3(x,y,z));
glm::mat4 view = glm::inverse(camera);
It's also possible that doing pre-multiplcation of your view matrix is what you want, but I'm uncertain, since I try to avoid having to deal with pre vs post multiplication as if my life depended on it.
glm::mat4 view = glm::lookAt(
glm::vec3(1.1f, 1.3f, 1.2f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)));
view = glm::rotate(glm::mat4(), r, glm::vec3(0,1,0)) * view;
view = glm::translate(glm::mat4(), glm::vec3(x,y,z)) * view;