I am trying to get a sphere to make contact with the floor. The spheres radius is 1.0f - I need to work out how to determine the distance between the sphere and the floor.
The Sphere is placed here
glm::mat4 mv_matrix_sphere =
glm::translate(glm::vec3(-2.0f, y, 0.0f)) *
glm::rotate(-t, glm::vec3(0.0f, 1.0f, 0.0f)) *
glm::rotate(-t, glm::vec3(1.0f, 0.0f, 0.0f)) *
glm::mat4(1.0f);
mySphere.mv_matrix = myGraphics.viewMatrix * mv_matrix_sphere;
mySphere.proj_matrix = myGraphics.proj_matrix;
Where y = 20.0f
The sphere will fall and land on the floor at
myFloor.mv_matrix = myGraphics.viewMatrix *
glm::translate(glm::vec3(0.0f, 0.0f, 0.0f)) *
glm::scale(glm::vec3(1000.0f, 0.001f, 1000.0f)) *
glm::mat4(1.0f);
myFloor.proj_matrix = myGraphics.proj_matrix;
The function I need will work out when the Sphere is 1.0f(radius) from the floor so that it collides with it instead of clipping through.
Related
I'm trying to understand the OpenGL MVP matrices, and as an exercice I'd like to draw a rectangle filling my window, using the matrices. I thought I would easily find a tutorial for that, but all those I found simply seem to put random values in their MVP matrices setup.
Say my rectangle has these coordinates:
GLfloat vertices[] = {
-1.0f, 1.0f, 0.0f, // Top-left
1.0f, 1.0f, 0.0f, // Top-right
1.0f, -1.0f, 0.0f, // Bottom-right
-1.0f, -1.0f, 0.0f, // Bottom-left
};
Here are my 2 triangles:
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
If I draw the rectangle with identity MVP matrices, it fills the screen as expected. Now I want to use a frustum. Here are its settings:
float m_fov = 45.0f;
float m_width = 3840;
float m_height = 2160;
float m_zNear = 0.1f;
float m_zFar = 100.0f;
From this I can compute the width / height of my window at z-near & z-far:
float zNearHeight = tan(m_fov) * m_zNear * 2;
float zNearWidth = zNearHeight * m_width / m_height;
float zFarHeight = tan(m_fov) * m_zFar * 2;
float zFarWidth = zFarHeight * m_width / m_height;
Now I can create my view & projection matrices:
glm::mat4 projectionMatrix = glm::perspective(glm::radians(m_fov), m_width / m_height, m_zNear, m_zFar);
glm::mat4 viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -m_zNear));
I'd now expect this to make my rectangle to fill the window:
glm::mat4 identity = glm::mat4(1.0f);
glm::mat4 rectangleModelMatrix = glm::scale(identity, glm::vec3(zNearWidth, zNearHeight, 1));
But doing so, my rectangle is way too big. What did I miss?
SOLUTION: as #Rabbid76 pointed out, the problem was the computation of my z-near size, which must be:
float m_zNearHeight = tan(glm::radians(m_fov) / 2.0f) * m_zNear * 2.0f;
float m_zNearWidth = m_zNearHeight * m_width / m_height;
Also, I now need to specify my object coordinates in normalized view space ([-0.5, 0.5]) rather than device space ([-1, 1]). Thus my vertices must now be:
GLfloat vertices[] = {
-0.5f, 0.5f, 0.0f, // Top-left
0.5f, 0.5f, 0.0f, // Top-right
0.5f, -0.5f, 0.0f, // Bottom-right
-0.5f, -0.5f, 0.0f, // Bottom-left
};
The projected height, of an object on a plan which is parallel to the xy plane of the view is
h' = h * tan(m_fov / 2) / -z
where h is the height of the object on the plane, -z is the depth and m_fov is the field of view angle.
In your case m_fov is 45° and -z is -0.1 (-m_zNear), thus tan(m_fov / 2) / z is ~4,142.
Since the height of the quad is 2, the projected height of the quad is ~8,282.
To create a quad which fits exactly in the viewport, use a filed of view angle of 90° and a distance to the object of 1, because tan(90° / 2) / 1 is 1. e.g:
float m_fov = 90.0f;
glm::mat4 projectionMatrix = glm::perspective(glm::radians(m_fov), m_width / m_height, m_zNear, m_zFar);
glm::mat4 viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -1.0f));
If tan(m_fov / 2) == -z, then an object with the bottom of -1 and the top of 1 fits into the viewport.
Because of the division by z, the projected size of on object on the viewport decrease linear by the distance to the camera.
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;
I am trying to set up my camera at a bird's eye perspective. By that I mean pointing straight down. This is what I've initialized so far:
glm::vec3 camPosition = glm::vec3(0.0f, 10.0f, 0.0f); // camera's position
glm::vec3 camFront = glm::vec3(0.0f, 0.0f, 0.0f); // where the camera is pointing
glm::vec3 camUp = glm::vec3(0.0f, 0.0f, 1.0f);
I pass this into the glm::lookat function but this is not working at all. Perhaps I haven't understood it that well...
I am trying to set up my camera at a bird's eye perspective.
I recommend to do the following. Define 2 vectors.
Define the up vector of the world. This means the vector, which points form the ground to the sky, in the coordinate system of your world:
glm::vec3 world_up( 0.0f, 0.0f, 1.0f );
Define the direction to the north in the coordinate system of your world:
glm::vec3 world_north( 0.0f, 1.0f, 0.0f );
With this information the vectors of the view coordinates system can be set up.
camPosition is the position of the "bird". A point hight up in the sky:
float height = 10.0f;
glm::vec3 camPosition = world_up * 10.0f;
camTraget it the position where the "bird" is looking at. A point on the ground:
glm::vec3 camTraget = glm::vec3(0.0f, 0.0f, 0.0f);
camUp is perpendicular to the vector from camPosition to camTraget. Since the "bird" looks at the ground it is the flight direction of the bird (e.g. to the north):
glm::vec3 camUp = world_north;
With this vectrs the view matrix can be set up by glm::lookAt():
glm::mat4 view = glm::lookAt( camPosition, camTraget, camUp );
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));
I'm going for just some basic camera control. Move camera up, down, left, right, and rotate around the origin.
If the camera is at y = 0 it works great, but as soon as I move the camera up, the rotation starts to move away from the origin.
I'm not going for fluid movement or anything like that at the moment. Just basics.
Move code:
// increment camX/Y/Z as float
vec3 camPos = vec3(camX, camY, camZ);
viewMatrix = lookAt(camPos, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f));
Rotate Code:
// Increment camY angle as float
float camOrbX = distance(vec3(camX, camY, camZ), vec3(0.0f)) * sin(camRotY);
float camOrbZ = distance(vec3(camX, camY, camZ), vec3(0.0f)) * cos(camRotY);
camX = camOrbX;
camZ = camOrbZ;
vec3 camPos = vec3(camX, camY, camZ);
viewMatrix = lookAt(camPos, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f));