How do I rotate my camera around my object? - c++

I want to rotate my camera around the scene and an object which is in the center. I've tried doing it this way:
glm::mat4 view;
float radius = 10.0f;
float camX = sin(SDL_GetTicks()/1000.0f) * radius;
float camZ = cos(SDL_GetTicks()/1000.0f) * radius;
view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(glGetUniformLocation(shader, "viewingMatrix"), 1, false, &view[0][0]);
but my object loads up further away on the screen and the object rotates around the scene, not the camera.
That's my vertex shader:
void main()
{
FragPos = vec3(modelMatrix * vec4(aPos, 1.0));
Normal = mat3(transpose(inverse(modelMatrix))) * aPos;
TexCoord = aTexture;
vec4 transformedPosition = projectionMatrix * viewingMatrix * vec4(FragPos, 1.0f);
gl_Position = transformedPosition;
}
How do I make it such that the camera is the one rotating around in the scene without the object rotating around?
I'm following this tutorial and I'm trying to work out the what happens in the first animation.
https://learnopengl.com/Getting-started/Camera
modelMatrix
glm::mat4 modelMat(1.0f);
modelMat = glm::translate(modelMat, parentEntity.position);
modelMat = glm::rotate(modelMat, parentEntity.rotation.z, glm::vec3(0.0f, 0.0f, 1.0f));
modelMat = glm::rotate(modelMat, parentEntity.rotation.y, glm::vec3(0.0f, 1.0f, 0.0f));
modelMat = glm::rotate(modelMat, parentEntity.rotation.x, glm::vec3(1.0f, 0.0f, 0.0f));
modelMat = glm::scale(modelMat, parentEntity.scale);
int modelMatrixLoc = glGetUniformLocation(shader, "modelMatrix");
glUniformMatrix4fv(modelMatrixLoc, 1, false, &modelMat[0][0]);

The target of the view (2nd parameter of glm::lookAt) should be the center of the object. The position of the object (and the center of the object) is changed by the model matrix (modelMatrix) in the vertex sahder.
You have to add the world position of the object to the 1st and 2nd parameter of glm::lookAt. The position of the object is the translation of the model matrix.
Further the object is to far away from the camera, because the radius is to large.
To solve your issue, the code has to look somehow like this:
glm::mat4 view;
float radius = 2.0f;
float camX = sin(SDL_GetTicks()/1000.0f) * radius;
float camZ = cos(SDL_GetTicks()/1000.0f) * radius;
view = glm::lookAt(
glm::vec3(camX, 0.0f, camZ) + parentEntity.position,
parentEntity.position,
glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(
glGetUniformLocation(shader, "viewingMatrix"), 1, false, glm::value_ptr(view));

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;

Orbiting And Spinning Rotation in OpenGL using GLM

I'm making a solar system in OpenGL and I want the planets to be able to orbit other planets as well as rotate around their own centers.
This is the code I'm currently using to make the planets orbit a specific point:
Model = glm::translate(Model, glm::vec3(-orbit_radius_, 0.0f, 0.0f));
Model = glm::rotate(Model, glm::radians(orbit_speed_) / 100.0f, glm::vec3(0.0f, 1.0f, 0.0f));
Model = glm::translate(Model, glm::vec3(orbit_radius_, 0.0f, 0.0f));
How would I combine this with a transformation that spins the object around itself?
I got it to work by just splitting then transformations and then combining them at the end.
rotate_ = glm::translate(rotate_, glm::vec3(-orbit_radius_, 0.0f, 0.0f));
rotate_ = glm::rotate(rotate_, glm::radians(orbit_speed_) / 100.0f, glm::vec3(0.0f, 1.0f, 0.0f));
rotate_ = glm::translate(rotate_, glm::vec3(orbit_radius_, 0.0f, 0.0f));
spin_ = glm::rotate(spin_, glm::radians(spin_speed_) / 100.0f, glm::vec3(0.0f, 1.0f, 0.0f));
final_ = rotate_ * spin_;
If you want to spinn and rotate an object, the I recommend to create an object which has its center at (0, 0, 0)
The self spinning of the object has to be do first. Then translate and rotate the object:
Model = rotate * translate * spinn
e.g.:
rot_angle += glm::radians(orbit_speed_) / 100.0f;
spin_angle += glm::radians(orbit_speed_) / 100.0f;
glm::vec3 tvec = glm::vec3(orbit_radius_, 0.0f, 0.0f);
glm::vec3 axis = glm::vec3(0.0f, 1.0f, 0.0f)
glm::mat4 translate = glm::translate(glm::mat(1.0f), tvec);
glm::mat4 rotate = glm::rotate(glm::mat(1.0f), rot_angle, axis);
glm::mat4 spin = glm::rotate(glm::mat(1.0f), spin_angle , axis);
Model = rotate * translate * spin;
With this solution rot_angle and spin_angle have to be incremented in every frame by a constant step.
If you don't want to increment the angles, then you have to store 2 matrices, instead of the angles. 1 for the rotation and on for the spin:
mat4 rotate(1.0f);
mat4 spin(1.0f);
glm::vec3 tvec = glm::vec3(-orbit_radius_, 0.0f, 0.0f);
glm::vec3 axis = glm::vec3(0.0f, 1.0f, 0.0f)
float rot_angle = glm::radians(orbit_speed_) / 100.0f;
float spin_angle = glm::radians(spin_speed_) / 100.0f;
rotate = glm::translate(rotate, tvec);
rotate = glm::rotate(rotate, rot_angle, axis );
rotate = glm::translate(rotate, -tvec);
spin = glm::rotate(spin, spin_angle, axis);
Model = rotate * spin;

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.

How to position an object in model / view / world space?

I have a cube which is defined with the centre at 0,0,0 and the edges reaching out to -1/+1 (i.e. the cube has width, height, depth of 2).
I then setup the following matrices:
glm::mat4 modelMat4;
modelMat4 = glm::translate(modelMat4, 0.0f, 0.0f, 200.f);
modelMat4 = glm::scale(modelMat4, 200.0f, 200.0f, 200.0f);
glm::mat4 viewMat4;
viewMat4 = glm::lookAt(glm::vec3(0.0f, 0.0f, zNear),
glm::vec3(0.0f, 0.0f, zFar),
glm::vec3(0.0f, 1.0f, 0.0f));
// initialWidth = window width
// initialHeight = window height
// zNear = 1.0f
// zFar = 1000.0f
glm::mat4 projectionMat4;
projectionMat4 = glm::frustum(-initialWidth / 2.0f, initialWidth / 2.0f, -initialHeight / 2.0f, initialHeight / 2.0f, zNear, zFar);
But the middle of my object appears at the near z-plane (i.e. I can only see the back half of my cube, from the inside).
If I adjust the model transform to be:
glm::translate(modelMat4, 0.0f, 0.0f, 204.f);
Then I can see the front side of my cube as well.
If I change the model transform to be:
glm::translate(modelMat4, 0.0f, 0.0f, 250.f);
Then the cube only rasterises at approx 2x2x2 pixels.
What am I misunderstanding about model, view projection matrices? I was expecting the transform to be linear, but the z-plane disappears between 200 and 250. Even though the planes are defined between 1.0f and 1000.0f.
Edit: My shader code is below:
#version 100
layout(location = 0) in vec3 v_Position;
layout(location = 1) in vec4 v_Colour;
layout(location = 2) uniform mat4 v_ModelMatrix;
layout(location = 3) uniform mat4 v_ViewMatrix;
layout(location = 4) uniform mat4 v_ProjectionMatrix;
out vec4 f_inColour;
void main()
{
gl_Position = v_ProjectionMatrix * v_ViewMatrix * v_ModelMatrix * vec4(v_Position, 1.0);
f_inColour = v_Colour;
}
You didn't show how you are multiplying your matrices, but for what you describe, its seems that it could be doing wrong. Be sure to do in this order:
MVP = projectionMat4 * viewMat4 * modelMat4;
UPDATED
Looking more carefully into your code, it is seeming that you are lacking a multiplication to concanate your transformations:
modelMat4 = glm::translate(modelMat4, 0.0f, 0.0f, 200.f);
modelMat4 *= glm::scale(modelMat4, 200.0f, 200.0f, 200.0f); // <-- here
so, modelMat4 will be the results of a scale and then a translation

Displace cube into origin with OpenGL

I'm drawing a bunch of points inside a 64x64x64 cube and can't figure out how to displace the origin so that rotations are done around the center of the cube.
My vertex data is stored inside a 1D array, going from {(0,0,0), (0,0,1), ..., (63, 63, 63)}.
This is my current code to setup the matrices each frame:
// Set ProjectionMatrix
projectionMatrix = glm::perspective(90.0f, (GLfloat)width / (GLfloat) height,0.1f, 1000.f);
glUniformMatrix4fv(location_projectionMatrix, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
// Set ModelViewMatrix
glm::mat4 identity = glm::mat4(1.0);
glm::mat4 viewTranslate = glm::translate(identity, glm::vec3(0.0f, 0.0f, -translate_z));
glm::mat4 viewRotateX = glm::rotate(viewTranslate, rotate_x, glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 viewRotateY = glm::rotate(viewRotateX, rotate_y, glm::vec3(0.0f, 1.0f, 0.0f));
modelViewMatrix = viewRotateY;
glUniformMatrix4fv(location_modelViewMatrix, 1, GL_FALSE, glm::value_ptr(modelViewMatrix));
I tried to just translate the cube by -32 into the x and y direction, but without success.
Matrix operations are non commutative .It means that doing translation first and then rotation is not the same as doing rotation and then translation.Usually the order is :scale-> rotation -> translation.
So try this instead:
glm::mat4 viewRotateX = glm::rotate(identity, rotate_x, glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 viewRotateY = glm::rotate(viewRotateX, rotate_y, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 viewTranslate = glm::translate(viewRotateY , glm::vec3(0.0f, 0.0f, -translate_z));