I was drawing 2 cubes on the screen and I realized that my object behaves really weird when I changed the angle in the perspective matrix, here is my code
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programID);
GLuint mvp = glGetUniformLocation(programID, "MVP");
glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 10.0f);
glm::mat4 translate = glm::translate(glm::mat4(1.0f), vec3(-2.0f, 0.0f, -5.0f));
glm::mat4 rotate = glm::rotate(glm::mat4(1.0f), 54.0f, vec3(-1.0f, 0.0f, 0.0f));
glm::mat4 MVP = Projection * translate * rotate;
glUniformMatrix4fv(mvp, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, numOfIndices, GL_UNSIGNED_SHORT, nullptr);
translate = glm::translate(glm::mat4(1.0f), vec3(3.0f, 0.0f, -6.0f));
rotate = glm::rotate(glm::mat4(1.0f), 54.0f, vec3(0.0f, 1.0f, 0.0f));
MVP = Projection * translate * rotate;
glUniformMatrix4fv(mvp, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, numOfIndices, GL_UNSIGNED_SHORT, nullptr);
The 2 cubes share the same projection matrix but different translate and rotation matrix. Here is my shader
#version 430
in layout(location=0) vec3 position;
in layout(location=1) vec3 color;
uniform mat4 MVP;
out vec3 theColor;
void main(){
gl_Position = MVP * vec4(position,1.0f);
theColor = color;
}
the shader just times the MVP matrix by the position vertex. When I ran the code with 45.0f for degree in perspective matrix I got this:
and then when I ran it with 55.0f I got this:
it seems like I got behind the object and looks at them from there, and when I did 50.0f it closed up and I can only see the corner of one of the cube.
Okay I figured it out, glm::perspective takes radian as it's first argument so I should've wrote (3.14f/180.0f) * 45.0f rather than just 45.0f
Related
I need some help trying to move my circle with view matrix. I can position the circle but cant move it. How can i make this happen?
Right now the the bounding rectangle moves but not the circle.
I've tried to center the circle in the rectangle and but this doesnt work.
Any help is appreciated!
#include <glew.h>
#include "circle.h"
Circle::Circle()
{
const std::string vertexShaderSource = R"END(
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>
uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;
void main()
{
gl_Position = projection * view * model * vec4(vertex.xy, 0.0, 1.0);
}
)END";
const std::string fragmentShaderSource = R"END(
#version 330 core
out vec4 color;
uniform vec2 dim;
uniform vec2 pos;
/**
* Convert r, g, b to normalized vec3
*/
vec3 rgb(float r, float g, float b) {
return vec3(r / 255.0, g / 255.0, b / 255.0);
}
/**
* Draw a circle at vec2 `pos` with radius `rad` and
* color `color`.
*/
vec4 circle(vec2 uv, vec2 pos, float rad, vec3 color) {
float d = length(pos - uv) - rad;
float t = clamp(d, 0.0, 1.0);
return vec4(color, 1.0 - t);
}
void main() {
vec2 uv = gl_FragCoord.xy;
float radius = 60;
vec2 center = pos;
// Background layer
vec4 layer1 = vec4(rgb(210.0, 222.0, 228.0), 0.3);
// Circle
vec3 red = rgb(225.0, 95.0, 60.0);
vec4 layer2 = circle(uv, center, radius, red);
// Blend the two
color = mix(layer1, layer2, layer2.a);
}
)END";
shader.Compile(vertexShaderSource.c_str(), fragmentShaderSource.c_str());
// Configure VAO etc..
}
void Circle::Update(float deltaTime, int width, int height)
{
// Activate shader
shader.Activate();
auto camera = Services::Get<RenderService>()->camera;
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view;
if (skipPan == false)
{
view = camera.GetViewMatrix();
}
else
{
view = glm::mat4{1.0f};
}
projection = glm::ortho(0.0f, static_cast<float>(width),
static_cast<float>(height), 0.0f, -1.0f, 1.0f);
model = glm::translate(model, glm::vec3(transform.position.x, transform.position.y, 0.0f));
model = glm::scale(model, glm::vec3(transform.dimension.width, transform.dimension.height, 1.0f));
shader.setMat4("projection", projection);
shader.setMat4("model", model);
shader.setMat4("view", view);
shader.setVec2("dim", glm::vec2{transform.dimension.width, transform.dimension.height});
shader.setVec2("pos", glm::vec2{transform.position.x, transform.position.y});
shader.setVec4("spriteColor", glm::vec4{style.Background.r, style.Background.g, style.Background.b, style.Background.a});
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
This is an issue i've been struggeling with for some time now. This applies to other shapes aswell that renders with SDF and such.
// configure VAO/VBO
const float vertices[] = {
0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f};
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
You say that you're trying to move the circle with the view matrix. You indeed pass that matrix to your vertex shader and use it in the computation of gl_Position. However, your fragment shader calculation is based on gl_FragCoord and doesn't incorporate the view matrix in any way. Remember that gl_FragCoord is the fragment coordinates relative to the framebuffer bottom-left corner (usually), and is therefore not affected by the model/view/projection transformations.
To solve this, you can do any of the following:
Calculate the fragment coordinates of the center of your circle in Circle::Update and pass that to the pos uniform:
glm::vec4 pos = view*glm::vec4{transform.position.x, transform.position.y, 0.0f, 1.0f};
shader.setVec2("pos", pos.xy);
Apply the viewport transformation in the fragment shader -- same as above but done in the shader. This is kinda ugly as you would be applying view but not model because the later is already accounted for in the value of pos. Also it involves more calculations in the fragment shader.
Change your fragment shader to work off texture coordinates instead of gl_FragCoord. If you set fixed texture coordinates at the vertices of the quad, then the interpolated coordinates within the quad will transform correctly with regards to any of the view/model/projection, thus handling scaling or even perspective projections out-of-the-box. This would probably be the neatest solution in your case. (That being said, rasterization based on gl_FragCoord is sometimes necessary to avoid artifacts on the seam between the two triangles of the quad.)
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);
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);
I have sprites in an atlas rendering in OpenGL properly with the code below. My problem comes from trying to add a secondary "texture" to sample so I can do some multitexturing magic. The problem I think it's that the second sprite is also in an atlas and it's being affected by the VAO offsets so I can't really pick the right UVs to get the exact point I need. I've tried adding some calculations to reverse engineer the correct UVs for this sprite inside the other texture (you can see my attempt at the bottom) but this doesn't seem to work. What would be the best approach to do this?
Preparation:
glm::vec4 fRect;
fRect.x = static_cast<float>(iRect.x) / textureWidth;
fRect.y = static_cast<float>(iRect.y) / textureHeight;
fRect.z = (static_cast<float>(iRect.z) / textureWidth) + fRect.x;
fRect.w = (static_cast<float>(iRect.w) / textureHeight) + fRect.y;
// Configure VAO/VBO
GLuint VBO;
GLfloat vertices[] = {
// Pos // Tex
0.0f, 1.0f, fRect.x, fRect.w,
1.0f, 0.0f, fRect.z, fRect.y,
0.0f, 0.0f, fRect.x, fRect.y,
0.0f, 1.0f, fRect.x, fRect.w,
1.0f, 1.0f, fRect.z, fRect.w,
1.0f, 0.0f, fRect.z, fRect.y
};
GLuint VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
Rendering:
// Prepare transformations
glm::mat4 modelMatrix;
modelMatrix = glm::translate(modelMatrix, position);
// modelMatrix = glm::translate(modelMatrix, -glm::vec3(spriteOffset.x, spriteOffset.y, 0.0f));
modelMatrix = glm::rotate(modelMatrix, rotate.x, glm::vec3(1.0f, 0.0f, 0.0f));
// modelMatrix = glm::rotate(modelMatrix, rotate.y, glm::vec3(0.0f, 1.0f, 0.0f));
modelMatrix = glm::rotate(modelMatrix, rotate.z, glm::vec3(0.0f, 0.0f, 1.0f));
modelMatrix = glm::translate(modelMatrix, glm::vec3(-spriteOffset.x, -spriteOffset.y, 0.0f));
modelMatrix = glm::scale(modelMatrix, glm::vec3(size, 1.0f));
//(...)
glUniformMatrix4fv(modelMatrixLocation, 1, false, glm::value_ptr( modelMatrix ) );
glUniformMatrix4fv(viewMatrixLocation, 1, false, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionMatrixLocation, 1, false, glm::value_ptr(projectionMatrix));
ASSERT( !HasOpenGLErrors(), "OpenGL error!" );
glUniform3f(multColorLocation, multColour.x, multColour.y, multColour.z );
glUniform3f(addColorLocation, addColour.x, addColour.y, addColour.z );
ASSERT( !HasOpenGLErrors(), "OpenGL error!" );
// Bind Texture, etc
glDrawArrays(GL_TRIANGLES, 0, 6);
Vertex shader:
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>
out vec2 TexCoords;
uniform mat4 model_matrix, view_matrix, projection_matrix;
void main()
{
TexCoords = vec2(vertex.z, 1.0 - vertex.w);
gl_Position = projection_matrix*view_matrix*model_matrix*vec4(vertex.xyz,1);
}
Fragment shader:
#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D texture;
uniform vec3 multColour;
uniform vec3 addColour;
void main()
{
vec4 minColour = vec4(0.0, 0.0, 0.0, 0.0);
vec4 maxColour = vec4(1.0, 1.0, 1.0, 1.0);
vec4 texColour = texture(texture, TexCoords);
if(texColour.a < 0.01)
discard;
color = clamp(vec4(multColour, 1.0) * texColour + vec4(addColour,0.0), minColour, maxColour);
}
Failed attempt at reading the right UVs in fragment shader:
float normU = (TexCoords.x - currUVs.x) / (currUVs.z - currUVs.x);
float icU = mix(icUVs.x, icUVs.z, normU);
float normV = (TexCoords.y - currUVs.y) / (currUVs.w - currUVs.y);
float icV = mix(icUVs.y, icUVs.w, normV);
vec2 UV = vec2(icU, icV );
vec4 initial = texture(initialColor, UV);
Where currUVs are the values of fRect passed in the VAO above and the icUVs are the UV bounds (min and max values) for the second sprite within the atlas texture.
So far it seems like all sprites that have no offset applied will render properly but if I passed in any kind of spriteOffset into the rendering, then it will render wrong.
How can I solve this? Is there a way of applying the VAO rects in the shaders and then be able to get the second sprite correctly?
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.