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.
Related
This question already has an answer here:
light source is not set correctly
(1 answer)
Closed 1 year ago.
I have this picture below that shows the 3D model and the light is not as I expected, I've already tried many ways but I can't figure out how to fix it. my normal vectors are fine
the goemetry:
glGenVertexArrays(1, &VAOArray);
glBindVertexArray(VAOArray);
/* GENERATE THE BUFFERS */
glGenBuffers(1, &bufferArray);
/* SELECT THAT BUFFER TO WORK WITH */
glBindBuffer(GL_ARRAY_BUFFER, bufferArray);
glBufferData(GL_ARRAY_BUFFER, myMeshes.at(j).realPositions.size() * sizeof(float), (GLfloat*)RealPos, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glGenBuffers(1, &normalArray);
glBindBuffer(GL_ARRAY_BUFFER, normalArray);
glBufferData(GL_ARRAY_BUFFER, myMeshes.at(j).realNormals.size()*sizeof(float), (GLfloat*)RealNor, GL_STATIC_DRAW);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(3);
this is my code:
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);
}
vertex shader used for this project:
#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;
FragPos = vec3(model * vec4(vs_pos, 1.0));
mat3 normalMat = mat3(inverse(transpose(model)));
normal = RealNor * normalMat;
gl_Position = projection * view * model * vec4(vs_pos, 1.0);
}
fragment shader used:
#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(abs(dot(norm, lightDir)), 0.0);
vec3 diffuse = diff * lightColor;
vec3 result = (ambient + diffuse) * objectColor;
gl_FragColor = texture(ourTexture, vs_text) * diff;
}
can someone help me to fix this or maybe guide me to solve it?
thanks
It applies that matrix * vector == vector * (matrix)^T
You are calculating normals via normal = RealNor * normalMat;
This is not equal to normalMat * RealNor which results in wrong normals. So kommutate the expression to normalMat * RealNor and see if it fixes the issue.
I am learning OpenGL from http://learnopengl.com and I have a problem with transformation based on this chapter Coordinate Systems...
I want to render something like this Movie but I have something like this Movie2 in 5 seconds its back on the screen. Sorry for many links but I think it's easier to show this by video.
It's my render loop:
const auto projection = glm::perspectiveFov(glm::radians(45.0f), 800.0f, 600.0f, 0.1f, 100.0f);
const auto view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -3.0f));
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
flatColorShader->bind();
flatColorShader->setMat4("u_Projection", projection);
flatColorShader->setMat4("u_View", view);
auto model = glm::mat4(1.0f);
model = glm::rotate(model, static_cast<float>(glfwGetTime()) * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));
flatColorShader->setMat4("u_Model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(vao);
glfwSwapBuffers(window);
glfwPollEvents();
}
Vaertex shader:
#version 460 core
layout (location = 0) in vec3 a_Pos;
layout (location = 1) in vec2 a_TexCoord;
out vec2 v_TexCoord;
uniform mat4 u_Projection;
uniform mat4 u_Model;
uniform mat4 u_View;
void main()
{
v_TexCoord = vec2(a_TexCoord.x, 1.0f - a_TexCoord.y);
gl_Position = u_Projection * u_Model * u_View * vec4(a_Pos, 1.0);
}
And Fragment shader:
#version 460 core
in vec2 v_TexCoord;
out vec4 color;
uniform sampler2D u_Texture;
void main()
{
color = texture(u_Texture, v_TexCoord);
}
I suppose it is a problem with the model matrix, but I don't known what. Can somebody help me with that's problem?
The order of the vertex transformations in the vertex shader is incorrect:
gl_Position = u_Projection * u_Model * u_View * vec4(a_Pos, 1.0);
gl_Position = u_Projection * u_View * u_Model * vec4(a_Pos, 1.0);
The order matters, because matrix multiplications are not commutative.
I am trying to build lighting using this tutorial. However, lighting appears on wrong side of human object and I do not know why.
Normals were created per triangle. Vertices of a triangle basically have the same normal:
glm::vec3 calculateNormal(glm::vec3 vertice_1, glm::vec3 vertice_2, glm::vec3 vertice_3)
{
glm::vec3 vector_1 = vertice_2 - vertice_1;
glm::vec3 vector_2 = vertice_3 - vertice_1;
return glm::normalize(glm::cross(vector_1, vector_2));
}
Here is code for vertex shader:
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 normal;
out vec4 vert_color;
out vec3 Normal;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 transform;
uniform vec4 color;
void main()
{
vert_color = color;
gl_Position = projection * view * model * transform * vec4(pos.x, pos.y, pos.z, 1.0);
FragPos = vec3(model * transform * vec4(pos, 1.0));
Normal = normal;
}
Fragment shader:
#version 330 core
uniform vec3 cameraPos;
uniform vec3 lightPos;
uniform vec3 lightColor;
in vec4 vert_color;
in vec3 FragPos;
in vec3 Normal;
out vec4 frag_color;
void main()
{
float ambientStrength = 0.1;
float specularStrength = 0.5;
vec3 ambient = ambientStrength * lightColor;
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(Normal, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
vec3 viewDir = normalize(cameraPos - FragPos);
vec3 reflectDir = reflect(-lightDir, Normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor;
vec3 result = (ambient + diffuse + specular) * vec3(vert_color.x, vert_color.y, vert_color.z);
frag_color = vec4(result, vert_color.w);
}
Main loop:
wxGLCanvas::SetCurrent(*glContext);
glClearDepth(1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glm::mat4 model, view, projection;
model = glm::translate(model, modelPos); // modelPos is
view = fpsCamera->getViewMatrix();
projection = fpsCamera->getProjectionMatrix(windowWidth, windowHeight);
color = glm::vec4(0.310f, 0.747f, 0.185f, 1.0f);
glm::vec3 lightPos = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 lightColor = glm::vec3(1.0f, 1.0f, 1.0f);
glm::mat4 phantomtTransformation;
phantomtTransformation = glm::rotate(phantomtTransformation, - glm::pi<float>() / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f));
phantomtTransformation = glm::rotate(phantomtTransformation, - glm::pi<float>() , glm::vec3(0.0f, 0.0f, 1.0f));
ShaderProgram shaderProgram;
shaderProgram.loadShaders("Shaders/phantom.vert", "Shaders/phantom.frag");
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
shaderProgram.use();
shaderProgram.setUniform("transform", phantomtTransformation);
shaderProgram.setUniform("model", model);
shaderProgram.setUniform("view", view);
shaderProgram.setUniform("projection", projection);
shaderProgram.setUniform("color", color);
shaderProgram.setUniform("lightColor", lightColor);
shaderProgram.setUniform("lightPos", lightPos);
shaderProgram.setUniform("cameraPos", fpsCamera->getPosition());
glStencilMask(0xFF); // Write to stencil buffer
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 0, 0xFF); // Set any stencil to 0
glStencilFunc(GL_ALWAYS, 1, 0xFF); // Set any stencil to object ID
m_pantomMesh->draw();
glStencilFunc(GL_ALWAYS, 0, 0xFF); // Set any stencil to 0 // no need for testing
glFlush();
wxGLCanvas::SwapBuffers();
View from front of the object:
View from back of the object:
EDIT:
In order to debug I removed object rotation matrix from main loop:
glm::mat4 phantomtTransformation;
phantomtTransformation = glm::rotate(phantomtTransformation, - glm::pi<float>() / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f));
phantomtTransformation = glm::rotate(phantomtTransformation, - glm::pi<float>() , glm::vec3(0.0f, 0.0f, 1.0f));
shaderProgram.setUniform("transform", phantomtTransformation);
and changed line in fragment shader from
frag_color = vec4(result, vert_color.w);
to
frag_color = vec4(Normal, vert_color.w);
in order to visualize Normal values. As a result I noticed that when camera changes position phantom also changes color which means that normal values are also changing.
I think the cause of your problem is that you are not applying your model transformation to your normal vectors. Since you definitely do not want to skew them, you will have to create a special matrix for your normals.
As is explained further down the tutorial that you mentioned, the matrix can be constructed like this
Normal = mat3(transpose(inverse(model))) * aNormal;
in your vertex shader.
However, I highly recommend that you calculate the matrix in your application code instead, since you would calculate it per vertex in the above example.
Since you are using the glm library, it would look like this instead:
glm::mat3 model_normal = glm::mat3(glm::transpose(glm::inverse(model)));
You can then load your new model_normal matrix into the shader as a uniform mat3.
I'm trying to make a little 3D engine for my master degree (and for my skill). I have a problem on the specular reflection. (I'm sorry for the link for the illustration image but I haven't enough reputation yet). All sources is available on my GitHub : DWRenderer
Right here, we're behing the object but the camera is on the front also the light. As we can see, there's a reflection behind the object.
For describe the actual parameters, all the computations are made in world space (normally... with that problem, I've a doubt). I put the camera on position vec3(0, 0, 3) for the test and the light is just a point at vec3(1.2, 1, 2) represent by a cube. I'm using Qt 5.4 and OpenGL 4.1 under Ubuntu with Nvidia drivers.
Here's my vertex shader :
#version 410 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
out vec3 Normal;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat3 normalMatrix;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
FragPos = vec3(model * vec4(position, 1.0f));
Normal = normalMatrix * normal;
}
And my fragment shader:
#version 410 core
out vec4 color;
in vec3 Normal;
in vec3 FragPos;
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
uniform vec3 viewPos;
void main()
{
// Vectors
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
// Ambient
vec3 ambient = material.ambient * light.ambient;
// Diffuse
float diff = clamp(dot(lightDir, norm), 0.0, 1.0);
vec3 diffuse = diff * material.diffuse * light.diffuse;
// Specular - The bug seems only here
float spec = pow(clamp(dot(viewDir, reflectDir), 0.0, 1.0), material.shininess);
vec3 specular = spec * material.specular * light.specular;
vec3 result = (diffuse + specular + ambient);
color = vec4(result, 1.0f);
// For test vectors
//color = vec4(specular, 1.0f);
}
And the code in the gaming loop (paintGL with a time with an interval of 16ms for real-time) for initialize the uniform variable (The position of the camera for the shader is fixed, i can turn around my cube for check the bug. The position of the light is in "initializeGL" and fixed too) :
// Draw cube
m_cubeShader->useShaderProgram();
GLint lightPosLoc = glGetUniformLocation(m_cubeShader->getId(), "light.position");
GLint viewPosLoc = glGetUniformLocation(m_cubeShader->getId(), "viewPos");
GLint matAmbientLoc = glGetUniformLocation(m_cubeShader->getId(), "material.ambient");
GLint matDiffuseLoc = glGetUniformLocation(m_cubeShader->getId(), "material.diffuse");
GLint matSpecularLoc = glGetUniformLocation(m_cubeShader->getId(), "material.specular");
GLint matShineLoc = glGetUniformLocation(m_cubeShader->getId(), "material.shininess");
GLint lightAmbientLoc = glGetUniformLocation(m_cubeShader->getId(), "light.ambient");
GLint lightDiffuseLoc = glGetUniformLocation(m_cubeShader->getId(), "light.diffuse");
GLint lightSpecularLoc = glGetUniformLocation(m_cubeShader->getId(), "light.specular");
glUniform3f(lightAmbientLoc, 0.2f, 0.2f, 0.2f);
glUniform3f(lightDiffuseLoc, 0.5f, 0.5f, 0.5f);
glUniform3f(lightSpecularLoc, 1.0f, 1.0f, 1.0f);
glUniform3f(matAmbientLoc, 1.0f, 0.5f, 0.31f);
glUniform3f(matDiffuseLoc, 1.0f, 0.5f, 0.31f);
glUniform3f(matSpecularLoc, 0.5f, 0.5f, 0.5f);
glUniform1f(matShineLoc, 32.0f);
glUniform3f(viewPosLoc, 0.0f, 0.0f, 3.0f); // For testing a bug - Unresolved
//glUniform3f(viewPosLoc, m_camera->getPosition().x, m_camera->getPosition().y, m_camera->getPosition().z);
glUniform3f(lightPosLoc, m_lightPos.x, m_lightPos.y, m_lightPos.z);
glm::mat4 model;
glm::mat4 view;
glm::mat4 projection;
glm::mat3 normalMatrix;
normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
view = m_camera->getViewMatrix();
projection = glm::perspective(glm::radians(m_camera->getFov()), (GLfloat)m_screenWidth / (GLfloat)m_screenHeight, 0.1f, 100.0f);
GLint normalMatrixLoc = glGetUniformLocation(m_cubeShader->getId(), "normalMatrix");
GLint modelLoc = glGetUniformLocation(m_cubeShader->getId(), "model");
GLint viewLoc = glGetUniformLocation(m_cubeShader->getId(), "view");
GLint projectionLoc = glGetUniformLocation(m_cubeShader->getId(), "projection");
glUniformMatrix3fv(normalMatrixLoc, 1, GL_FALSE, glm::value_ptr(normalMatrix));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(m_cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
// Draw light
m_lightShader->useShaderProgram();
model = glm::mat4();
model = glm::translate(model, m_lightPos);
model = glm::scale(model, glm::vec3(0.2f));
modelLoc = glGetUniformLocation(m_lightShader->getId(), "model");
viewLoc = glGetUniformLocation(m_lightShader->getId(), "view");
projectionLoc = glGetUniformLocation(m_lightShader->getId(), "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(m_lightVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
I've tried to do the computations on view space but it doesn't work. I've tried to modify/normalize/use max() instead of clamp() but after a few hours on the problem. I'm out of any ideas.
You only have diffuse and specular light if the lightDir (direction from fragment to light) is in the direction of norm ( normal vector of fragment ). If they are directed against you can do without diffuse and specular light. In other words, if ther isn't any diffuse light (because diff is 0.0), there isn't any specular light too. Adapt your code like this:
void main()
{
// Vectors
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
// Ambient
vec3 ambient = material.ambient * light.ambient;
vec3 result = ambient;
float dotNvLd = dot( norm, lightDir );
if ( dotNvLd > 0.0 ) // test if normal vector not directed against vector to light position
{
// Diffuse
float diff = min( dotNvLd, 1.0 );
vec3 diffuse = diff * material.diffuse * light.diffuse;
// Specular - The bug seems only here
float spec = pow(clamp(dot(viewDir, reflectDir), 0.0, 1.0), material.shininess);
vec3 specular = spec * material.specular * light.specular;
result = (diffuse + specular + ambient);
}
color = vec4(result, 1.0f);
// For test vectors
//color = vec4(specular, 1.0f);
}
I seem to have broken the shaders in my program, here is their code:
vertex shader
#version 330 core
uniform mat4 camera;
uniform mat4 model;
layout(location = 0) in vec3 vert;
layout(location = 1) in vec3 vertNormal;
out vec3 fragVert;
out vec3 fragNormal;
void main() {
// Pass some variables to the fragment shader
fragNormal = vertNormal;
fragVert = vert;
// Apply all matrix transformations to vert
gl_Position = camera * model * vec4(vert, 1);
}
fragment shader
#version 150 core
uniform mat4 model;
uniform vec3 cameraPosition;
// material settings
uniform float materialShininess;
uniform vec3 materialSpecularColor;
uniform vec3 materialColor;
uniform struct Light {
vec3 position;
vec3 intensities; //a.k.a the color of the light
float attenuation;
float ambientCoefficient;
} light;
in vec3 fragNormal;
in vec3 fragVert;
out vec4 finalColor;
void main() {
vec3 normal = normalize(transpose(inverse(mat3(model))) * fragNormal);
vec3 surfacePos = vec3(model * vec4(fragVert, 1));
vec4 surfaceColor = vec4(materialColor, 1);
vec3 surfaceToLight = normalize(light.position - surfacePos);
vec3 surfaceToCamera = normalize(cameraPosition - surfacePos);
//ambient
vec3 ambient = light.ambientCoefficient * surfaceColor.rgb * light.intensities;
//diffuse
float diffuseCoefficient = max(0.0, dot(normal, surfaceToLight));
vec3 diffuse = diffuseCoefficient * surfaceColor.rgb * light.intensities;
//specular
float specularCoefficient = 0.0;
if(diffuseCoefficient > 0.0)
specularCoefficient = pow(max(0.0, dot(surfaceToCamera, reflect(-surfaceToLight, normal))), materialShininess);
vec3 specular = specularCoefficient * materialSpecularColor * light.intensities;
//attenuation
float distanceToLight = length(light.position - surfacePos);
float attenuation = 1.0 / (1.0 + light.attenuation * pow(distanceToLight, 2));
//linear color (color before gamma correction)
vec3 linearColor = ambient + attenuation*(diffuse + specular);
//final color (after gamma correction)
vec3 gamma = vec3(1.0/2.2);
finalColor = vec4(pow(linearColor, gamma), surfaceColor.a);
}
I have an asset that I am loading from an obj file, then drawing it like such:
void OpenGLView::run()
{
initializeAndSetupWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "PhongBunny");
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
loadBunnyAsset();
AssetInstance bunny1;
bunny1.asset = bunny;
bunny1.position = glm::vec3(2.0f, 2.0f, 2.0f);
bunny1.scale = glm::vec3(1.0f, 1.0f, 1.0f);
do{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
loadUniforms(bunny1);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, bunny.vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, bunny.normalBuffer);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bunny.elementBuffer);
glDrawElements(GL_TRIANGLES, bunny.elementsSize, GL_UNSIGNED_INT, (void*)0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glfwSwapBuffers(window);
glfwPollEvents();
} while (!glfwWindowShouldClose(window));
glfwDestroyWindow(window);
glfwTerminate();
}
with this being the function to load uniforms:
void OpenGLView::loadUniforms(AssetInstance assetInstance)
{
Asset* asset = &assetInstance.asset;
glUseProgram(asset->shaderProgramID);
glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 1000.0f);
glm::mat4 camera = Projection * getViewMatrix();
glm::mat4 model = translate(assetInstance.position) * scale(assetInstance.position);
GLuint cameraID = glGetUniformLocation(asset->shaderProgramID, "camera");
GLuint modelID = glGetUniformLocation(asset->shaderProgramID, "model");
GLuint cameraPositionID = glGetUniformLocation(asset->shaderProgramID, "cameraPosition");
GLuint lightPositionID = glGetUniformLocation(asset->shaderProgramID, "light.position");
GLuint lightIntensitiesID = glGetUniformLocation(asset->shaderProgramID, "light.intensities");
GLuint lightAttenuationID = glGetUniformLocation(asset->shaderProgramID, "light.attenuation");
GLuint lightAmbientCoefficientID = glGetUniformLocation(asset->shaderProgramID, "light.ambientCoefficient");
GLuint materialColorID = glGetUniformLocation(asset->shaderProgramID, "materialColor");
GLuint materialShininessID = glGetUniformLocation(asset->shaderProgramID, "materialShininess");
GLuint materialSpecularColorID = glGetUniformLocation(asset->shaderProgramID, "materialSpecularColor");
glUniformMatrix4fv(cameraID, 1, GL_FALSE, &camera[0][0]);
glUniformMatrix4fv(modelID, 1, GL_FALSE, &model[0][0]);
glUniform3fv(cameraPositionID, 1, &cameraPosition[0]);
glUniform3fv(lightPositionID, 1, &light.position[0]);
glUniform3fv(lightIntensitiesID, 1, &light.intensities[0]);
glUniform1f(lightAttenuationID, light.attenuation);
glUniform1f(lightAmbientCoefficientID, light.ambientCoefficient);
glUniform3fv(materialColorID, 1, &assetInstance.materialColor[0]);
glUniform1f(materialShininessID, assetInstance.materialShininess);
glUniform3fv(materialSpecularColorID, 1, &assetInstance.materialSpecularColor[0]);
}
and some setup being done here:
OpenGLView::OpenGLView()
{
light.position = glm::vec3(0.0f, 7.0f, 3.0f);
light.intensities = glm::vec3(0.3f, 0.3, 0.3f);
light.attenuation = 0.3f;
light.ambientCoefficient = 0.005f;
cameraPosition = glm::vec3(5.0f, 3.0f, 8.0f);
}
For a while I had the bunny1's position set to 0, 0, 0 which caused it to not be drawn at all, I can't figure out why that is? Then when I changed it to 1, 1, 1 it started to draw, but now my key_callback function (which rotates and scales the bunny) stopped working. Also, here are my translate and scale functions:
glm::mat4 OpenGLView::translate(glm::vec3 position)
{
return glm::translate(glm::mat4(), position);
}
glm::mat4 OpenGLView::scale(glm::vec3 size)
{
return glm::scale(glm::mat4(), size);
}
and I can't figure out why changing bunny1.position seems to scale the bunny instead of translating its position?
The reason why your bunny's scale changes when changing bunny1.position is because you scale your bunny by bunny1.position:
glm::mat4 model = translate(assetInstance.position) * scale(assetInstance.position);
That might also be the reason why the bunny disapears when setting it's position to (0,0,0) since you then scale it to 0.