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.
Related
I have this code but the light seems not working correctly, when I render the object it's dark, then when I rotate it, the light source seems to be rotated too. I can't figure out where the problem is. I tried to modify the model for the light but still not working
this is the program:
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 projection = glm::mat4(1.0f);
projection = glm::perspective(glm::radians(45.0f), (float)width / (float)heigh, 0.1f, 100.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, transZ)); //this is for scroll mouse
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -2.0f));
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -5.0f));
glUseProgram(programT);
int lightColorLoc = glGetUniformLocation(programT, "lightColor");
glUniformMatrix4fv(lightColorLoc, 1, GL_FALSE, glm::value_ptr(glm::vec3(1.0f, 0.0f, 0.0f)));
int objectColorLoc = glGetUniformLocation(programT, "objectColor");
glUniformMatrix4fv(objectColorLoc, 1, GL_FALSE, glm::value_ptr(glm::vec3(1.0f, 0.5f, 0.31f)));
glm::vec3 lightPos(2.0f, 4.0f, 5.0f);
int lightPosLoc = glGetUniformLocation(programT, "lightPos");
glUniformMatrix4fv(lightPosLoc, 1, GL_FALSE, glm::value_ptr(lightPos));
int projectionLocLight = glGetUniformLocation(programT, "projection");
glUniformMatrix4fv(projectionLocLight, 1, GL_FALSE, glm::value_ptr(projection));
glm::mat4 modelLight = glm::mat4(1.0f);
int modelLocLight = glGetUniformLocation(programT, "model");
glUniformMatrix4fv(modelLocLight, 1, GL_FALSE, glm::value_ptr(modelLight));
glm::mat4 viewLight = glm::mat4(1.0f);
int viewLocLight = glGetUniformLocation(programT, "view");
glUniformMatrix4fv(viewLocLight, 1, GL_FALSE, glm::value_ptr(viewLight));
int viewLoc = glGetUniformLocation(programT, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
int projectionLoc = glGetUniformLocation(programT, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
model = glm::rotate(model, glm::radians(rotX), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(rotY), glm::vec3(.0f, 1.0f, .0f));
model = glm::rotate(model, glm::radians(rotZ), glm::vec3(.0f, 0.0f, 1.0f));
int modelLoc = glGetUniformLocation(programT, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glGenerateMipmap(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureArray[0]);
glUniform1i(glGetUniformLocation(programT, "ourTexture"), 0);
glBindVertexArray(VAOArray[0]);
glDrawArrays(GL_TRIANGLES, 0, myMeshes.at(0).Indices.size());
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
glfwSetKeyCallback(window, key_callback);
glfwSetScrollCallback(window, scroll_callback);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
}
the following is my vertex shader:
#version 330 core
layout (location = 0) in vec3 RealPos;
layout (location = 1) in vec3 vertex_color;
layout (location = 2) in vec2 vertex_textcoord;
layout (location = 3) in vec3 RealNor;
out vec3 vs_pos;
out vec3 vs_color;
out vec2 vs_text;
out vec3 normal;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
vs_pos = RealPos;
vs_color = vertex_color;
vs_text=vertex_textcoord;
normal=RealNor;
FragPos = vec3(model * vec4(vs_pos, 1.0));
gl_Position = projection * view * model * vec4(vs_pos, 1.0);
}
and the following is the fragment shader:
#version 330 core
in vec2 vs_text;
in vec3 normal;
in vec3 FragPos;
uniform vec3 lightPos;
out vec4 gl_FragColor;
uniform vec3 objectColor;
uniform vec3 lightColor;
uniform sampler2D ourTexture;
void main()
{
vec3 norm = normalize(normal);
vec3 lightDir = normalize(lightPos - FragPos);
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
vec3 result = (ambient + diffuse) * objectColor;
gl_FragColor = texture(ourTexture, vs_text) * vec4(result,1.0);
}
how can I solve the problem?
The light calculations in the fragment shader are done in world space. Therefore, you have to transform the normal vector with the normal matrix from object space to world space:
mat3 normalMatrix = transpose(inverse(mat3(model)));
normal = normalMatrix * RealNor;
FragPos = vec3(model * vec4(vs_pos, 1.0));
See Why is the transposed inverse of the model view matrix used to transform the normal vectors?
and Why transforming normals with the transpose of the inverse of the modelview matrix?
Imagine a spinner and a reading lamp on a table. Your eyes are the camera. The model matrix models the spinning. This causes different sides of the spinner to be illuminated as it rotates. However, the position of the lamp does not change relative to your position.
The relative position of the lamp changes when you change your position (the position of the eyes). This can be modeled by changing the view matrix.
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 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