OpenGL – Severe distortions even with correct matrices - c++

My simple OpenGL program is displaying a very severely distorted shape. I'm using GLM for matrix math. I compared the modelView matrix and the projection matrix values to another program that it displaying the values correctly. Yet, it is still distorted. What could be the cause? Here is the matrix code:
modelViewMatrix = glm::lookAt(glm::vec3(3.0f, 5.0f, 7.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
projectionMatrix = glm::perspective(glm::radians(45.0f), (float)height/(float)width, 0.01f, 100.0f);
And here is the vertex shader code:
#version 300 es
in mediump vec3 vertexPosition;
uniform mediump mat4 modelViewMatrix;
uniform mediump mat4 projectionMatrix;
out vec3 finalPosition;
void main(void) {
gl_Position = projectionMatrix * modelViewMatrix * vec4(vertexPosition, 1.0);
}
Here are screenshots of an (unlit) cuboid:
Note that the correct image is the black one. They are both using the exact same shader and the same model view and projection matrix numbers. Why is this happening?

I believe the aspect ratio is being calculated incorrectly - it should be width / height.
You currently have:
projectionMatrix = glm::perspective(glm::radians(45.0f),
(float)height/(float)width, 0.01f, 100.0f);
Try replacing this with:
projectionMatrix = glm::perspective(glm::radians(45.0f),
(float)width/(float)height, 0.01f, 100.0f);

I solved the question by changing the glViewport parameters. Apparently the view transformation was done incorrectly.

Related

OpenGL sprite rotation to camera

I am using OpenGL 3.3. It is necessary to make the sprite always look at the camera.
In most cases, the code is from the learnOpenGL lessons, I rework it to fit my needs. I tried in different ways, but so far I have not managed to do something that works adequately.
The projection is perspective.
glm::mat4 projection = glm::perspective(glm::radians(fov), (float)width_ / (float)height_, 0.1f, 30.0f);
I draw the sprite like this.
void SpriteRenderer3D::DrawSprite(const Texture2D& texture, glm::vec3 position, glm::vec3 camera_pos, glm::vec3 size, float rotate, glm::vec3 color) {
// activate shader
shader.Use();
// create transformations
glm::mat4 model = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix first
model = glm::translate(model, glm::vec3(position)); // first translate (transformations are: scale happens first, then rotation, and then final translation happens; reversed order)
model = glm::translate(model, glm::vec3(0.5f * size.x, 0.5f * size.y, 0.5f * size.z)); // move origin of rotation to center of quad
model = glm::rotate(model, glm::radians(rotate), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::translate(model, glm::vec3(-0.5f * size.x, -0.5f * size.y, -0.5f * size.z)); // move origin back
model = glm::scale(model, glm::vec3(size)); // last scale
this->shader.SetMatrix4("model", model);
// render textured quad
this->shader.SetVector3f("spriteColor", color);
glActiveTexture(GL_TEXTURE0);
texture.Bind();
}
I use this Vshader.
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
TexCoords = vec2(aTexCoord.x, aTexCoord.y);
}
The view matrix is ​​considered this way when you move the camera.
glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
ResourceManager::GetShader("sprite3d").SetMatrix4("view", view);

shape distortion when rotating model matrix

I'm attempting to rotate a shape using the glm library in conjunction with openGL. Unfortunately, when I attempt to rotate the shape using glm::rotate(), my shape's dimensions become stretched. Alongside this, the shape rotates around a seemingly random point. Everything is 2 dimensional.
Vertex Shader Code:
#version 330 core
layout(location = 0) in vec2 pos;
uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;
void main()
{
gl_Position = projection * view * model * vec4(pos.x, pos.y, 1.0f, 1.0f);
}
Model Matrix Code:
m_angle = angle;
m_modelMatrix = glm::rotate(glm::mat4(1.0f), glm::radians((float)m_angle), glm::vec3(0, 0, 1));
Projection and View Matrices Code:
glm::mat4 proj = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
proj = glm::perspective(glm::radians(53.f), 1.f, 0.1f, 100.f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
The issue is caused because the projection matrix doesn't take care of the aspect ration of the viewport. In your code the aspect parameter is 1.0:
proj = glm::perspective(glm::radians(53.f), 1.f, 0.1f, 100.f);
The aspect parameter has to to be the ratio of the width and height of the viewprot respectively window:
float aspect = (float)window_width/(float)window_height;
proj = glm::perspective(glm::radians(53.f), aspect, 0.1f, 100.f);

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.

When I rotate model-view matrix should my light position preserve and only the model will rotate?

Here is my code snippet how I rotate the model-view matrix:
mat4 modelViewMatrix;
vec3 eyePosition = vec3(0, 0, 6);
vec3 centerPosition = vec3(0, 0, 0);
vec3 upVector = vec3(0, 1, 0);
modelViewMatrix = glm::lookAt(eyePosition, centerPosition, upVector);
vec3 axis = vec3(0, 1, 0);
modelViewMatrix = glm::rotate(modelViewMatrix, rotation, axis);
As much as I know model-view matrix is the transformation matrix that is responsible for going from model coordinate from to eye/camera coordinate frame.
So if I have two uniforms such as:
vec4 lightPosition = vec4(15.0f, 0.0f, 0.0f, 1.0f);
vec3 lightIntensity = vec3(1.0f, 0.0f, 0.0f);
that I use to calculate ADS Phong shading using GLSL my model should rotate but the light should stay at the same position, right?
Sorry the code is not compile-able, but I am asking about general concept and hope this gives you enough info to be able to advice me. Thanks!

Setting up a MVP Matrix in OpenGL

i'm trying to learn the basics of OpenGL, but i have a Problem with setting up the transformation matrices. I made the model, view and projection matrices, but i have a problem sending them to my vertex shader.
Here is the code:
//Set up MVP
glm::mat4 model = glm::mat4();
GLint uniModel = glGetUniformLocation(program, "model");
glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model));
glm::mat4 view = glm::lookAt(
glm::vec3(2.5f, 2.5f, 2.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f));
GLint uniView = glGetUniformLocation(program, "view");
glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(view));
glm::mat4 proj = glm::perspective(45.0f, 800.0f / 600.0f, 1.0f, 10.0f);
GLint uniProj = glGetUniformLocation(program, "proj");
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
and the shader:
layout (location = 0) in vec3 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;
void main() {
gl_Position = proj * view * model * vec4(position, 1.0);
}
I think i did something wrong with setting up the uniforms, because it doesn't draw anything, even if i set model, view and proj to the identity. Could be i just mistyped something, but i really can't find the problem.
Edit: Solved it, the problem was that i forgot to use glUseProgram() first.
The first thing to do is check all possible return codes, verify your shader program has compiled and linked correctly, and make sure your uniforms are valid, which means the location value is >= 0.
A binary search with glGetError() can also be very useful in these instances when you don't know where it's going wrong.
After compiling the shaders, make sure you check glGetProgram(GL_LINK_STATUS,...). And finally, you must call glUseProgram() to activate the shader.
As #Vallentin suggests, it is much more efficient to pass in your precalculated MVP matrix, since it will not change between the app and the shader. This simplifies your code somewhat, to something like this for your application code:
// Set up MVP matrices
glm::mat4 model = glm::mat4();
glm::mat4 view = glm::lookAt(
glm::vec3(2.5f, 2.5f, 2.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 proj = glm::perspective(45.0f, 800.0f / 600.0f, 1.0f, 10.0f);
glm::mat4 mvp = proj * view * model;
glUseProgram(prog);
GLint uniMvp = glGetUniformLocation(program, "mvp");
glUniformMatrix4fv(uniMvp, 1, GL_FALSE, glm::value_ptr(mvp));
and then the GLSL:
// Shader code
layout (location = 0) in vec3 position;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(position, 1.0);
}
Also, you could cache the uniform locations, since they won't change once compiled. This will save a small amount per frame, rather than querying them for every redraw.