My GLSL Diffuse Shader is not working properly. How can I fix it? - opengl

I'm trying to create a GLSL diffuse shader, but I'm getting a problem, some faces looks like they become transparent and the back faces are shown in front, it's really confusing and I wonder how to fix this problem.
I guess that the problem is with the direction of the normals, but I'm not sure.
This is my .frag shader code:
#version 330
in vec3 FragPos;
in vec3 Normals;
in vec2 TexCoord;
uniform vec4 AlbedoColor;
out vec4 FragColor;
const int numLights = 1;
uniform vec3 lightPositions[numLights];
uniform vec3 lightColors[numLights];
uniform vec3 viewPos;
uniform vec3 diffuse;
void main()
{
// Perform lighting calculations here
vec3 result = vec3(0);
for (int i = 0; i \< numLights; i++) {
// Diffuse
vec3 norm = normalize(Normals);
vec3 lightDir = normalize(lightPositionsi - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColors[i];
result += diffuse;
}
result = result * AlbedoColor.rgb;
FragColor = vec4(result,1.0);
}
If the problem is with the normals, here's the code that generates the mesh:
new Vertex(-0.5f, -0.5f, -0.5f, new Vector3(-1.0f, -1.0f, -1.0f), new Vector2(0.0f, 0.0f)), // bottom-left-back
new Vertex(-0.5f, 0.5f, -0.5f, new Vector3(-1.0f, 1.0f, -1.0f), new Vector2(0.0f, 1.0f)), // top-left-back
new Vertex( 0.5f, 0.5f, -0.5f, new Vector3( 1.0f, 1.0f, -1.0f), new Vector2(1.0f, 1.0f)), // top-right-back
new Vertex( 0.5f, -0.5f, -0.5f, new Vector3( 1.0f, -1.0f, -1.0f), new Vector2(1.0f, 0.0f)), // bottom-right-back
new Vertex(-0.5f, -0.5f, 0.5f, new Vector3(-1.0f, -1.0f, 1.0f), new Vector2(0.0f, 0.0f)), // bottom-left-front
new Vertex(-0.5f, 0.5f, 0.5f, new Vector3(-1.0f, 1.0f, 1.0f), new Vector2(0.0f, 1.0f)), // top-left-front
new Vertex( 0.5f, 0.5f, 0.5f, new Vector3( 1.0f, 1.0f, 1.0f), new Vector2(1.0f, 1.0f)), // top-right-front
new Vertex( 0.5f, -0.5f, 0.5f, new Vector3( 1.0f, -1.0f, 1.0f), new Vector2(1.0f, 0.0f)) // bottom-right-front
Note that the Normals direction is the second paramether. The vertex position is the first, and the third paramether is the location of the texture (it's not in use for now).
Here's some screenshots of what the current result is right now:
(https://i.stack.imgur.com/y3KwI.png)
(https://i.stack.imgur.com/nvCfW.png)

The problem was that I did not enable the Depth Test.
In case someone is also with this problem, if you're using OpenGL in C#, you can do "GL.Enable(EnableCap.DepthTest);" And it's going to work fine.
Thank you #user253751 for fixing my problem!

Related

Got weird lighting result based on Phong model after learning LearnOpenGL chapter 13

First incorrect result
Hello guys, I've been studying OpenGL on learnopengl.com and I found the result weird when I finished learning the basic lighting chapter. The result is I found specular light on the corner of the cube surface where the light could not reach. The strange result is shown in pictures below:
Even if the camera is hidden behind the cube from the light, the strange specular light still remains:
My vertex shader is:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec3 FragPos;
out vec3 Normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat3 normalMatrix;
void main()
{
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = normalMatrix * aNormal;
// Normal = aNormal;
gl_Position = projection * view * vec4(FragPos, 1.0);
}
My fragment shader is (the same as the official code provided by LearnOpenGL):
#version 330 core
out vec4 FragColor;
in vec3 Normal;
in vec3 FragPos;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;
uniform vec3 objectColor;
void main()
{
// ambient
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
// specular
float specularStrength = 0.5;
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor;
vec3 result = (ambient + diffuse + specular) * objectColor;
FragColor = vec4(result, 1.0);
}
My source file is:
#include"glm/glm.hpp"
#include"glm/gtc/matrix_transform.hpp"
#include"glm/gtc/type_ptr.hpp"
#include<iostream>
#include"LearnOpenGL/camera.h"
#include "LearnOpenGL/stb_image.h"
#include "glad/glad.h"
#include <GLFW/glfw3.h>
#include"LearnOpenGL/shader_m.h"
#include <cmath>
#define STB_IMAGE_IMPLEMENTATION
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void processInput(GLFWwindow *window);
void mouse_callback(GLFWwindow *window, double xpos, double ypos);
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// camera attributes
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;
float fov = 45.0f;
// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f; // time of last frame
// lighting
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
int main() {
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw window creation
// --------------------
GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// cursor
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
// shader declaration
Shader ourShader("../src/shaders/shader.vs", "../src/shaders/shader.fs");
Shader lightingShader("../src/shaders/lightsource_shader.vs", "../src/shaders/lightsource_shader.fs");
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
};
// first, configure the cube's VAO (and VBO)
unsigned int VBO, cubeVAO;
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(cubeVAO);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *) 0);
glEnableVertexAttribArray(0);
// normal attribute
glVertexAttribPointer(1,3,GL_FLOAT, GL_FALSE, 6*sizeof(float),(void*)0);
glEnableVertexAttribArray(1);
//second, configure the light's VAO (VBO stays the same; the vertices are the same for the light object which is also a 3D cube)
unsigned int lightCubeVAO;
glGenVertexArrays(1, &lightCubeVAO);
glBindVertexArray(lightCubeVAO);
// we only need to bind to the VBo (to link it with glVertexAtrribPointer), no need to fill it; the VBO's data already contains all we need (it's already bound, but we do it again for educational purposes)
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *) 0);
glEnableVertexAttribArray(0);
glEnable(GL_DEPTH_TEST);
// render loop
// -----------
while (!glfwWindowShouldClose(window)) {
// per-frame time logic
// --------------------
float currentFrame = static_cast<float>(glfwGetTime());
deltaTime = glfwGetTime() - lastFrame;
lastFrame = glfwGetTime();
// input
// -----
processInput(window);
// render
// ------
// firstly clear the screen
glClearColor(0.1f, 0.1f, 0.1f, 0.1f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// activate shader
ourShader.use();
ourShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
ourShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
ourShader.setVec3("lightPos", lightPos);
ourShader.setVec3("viewPos", camera.Position);
// view/projection transformations
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float) SCR_WIDTH / (float) SCR_HEIGHT, 0.1f,100.0f);
glm::mat4 view = camera.GetViewMatrix();
ourShader.setMat4("projection", projection);
ourShader.setMat4("view", view);
// model transformation (aka world transformation)
glm::mat4 model = glm::mat4(1.0f);
ourShader.setMat4("model", model);
glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(model)));
// glm::mat3 normal_matrix = glm::mat3(glm::transpose(glm::inverse(model)));
ourShader.setMat3("normalMatrix", normal_matrix);
// render the cube
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
// also draw the lamp object
lightingShader.use();
lightingShader.setMat4("projection", projection);
lightingShader.setMat4("view", view);
model = glm::mat4(1.0f);
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.1f));
lightingShader.setMat4("model", model);
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &cubeVAO);
glDeleteVertexArrays(1, &lightCubeVAO);
glDeleteBuffers(1, &VBO);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow *window, int width, int height) {
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
void mouse_callback(GLFWwindow *window, double xpos, double ypos) {
if (firstMouse) {
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed: y ranges from bottom to top
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
std::cout<<"cameraPos"<<camera.Position.x<<","<<camera.Position.y<<","<<camera.Position.z<<std::endl;
}
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) {
camera.ProcessMouseScroll(static_cast<float>(yoffset));
}
Other solutions I tried but didn't work
Furthermore, if I just use the specular result to generate the FragColor, the result would be like this:
in this case, my fragment shader is:
#version 330 core
out vec4 FragColor;
in vec3 Normal;
in vec3 FragPos;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;
uniform vec3 objectColor;
void main()
{
// ambient
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
// specular
float specularStrength = 0.5;
vec3 viewDir = normalize(viewPos - FragPos);
float NdotL = dot(norm, lightDir);
vec3 specular = vec3(0.0);
if(NdotL > 0.0)
{
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
specular = specularStrength * spec * lightColor;
}
vec3 result = (ambient + diffuse + specular) * objectColor;
FragColor = vec4(result, 1.0);
}
The code above is inspired by the solution on OpenGL Phong lighting: specular highlight is wrong, but this solution turned out the above result.
You didn't set the offset for the normal vector attribute. The offset of the normal vector is 3*sizeof(float)
glVertexAttribPointer(1,3,GL_FLOAT, GL_FALSE, 6*sizeof(float),(void*)0);
glVertexAttribPointer(1,3,GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));

OpenGL - How to properly add lighting to a scene using the Blinn-Phong shading model?

Recently, I have been trying to add lighting to a simple OpenGL scene using the Blinn-Phong shading model as described in this website.
I tried to follow the tutorial as closely as possible. However, the lighting seems off, especially on the side faces of the cube as the light source begins to move across the front.
I believe it would have something to do with the positions of the Normals not being in the right place due to rotation on the model matrix or having done something wrong in the lighting shader, however, I am not sure whether either of those is really the cause.
Here is the source code, by the way:
#include <glad/glad.h>
#include <SFML/Graphics.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <cstdlib>
#include <cmath>
// Vertex shader for the light source cube
const std::string source_vert_shader = R"(
#version 330 core
layout (location = 0) in vec3 vertPos;
uniform mat4 proj, view, model;
void main() {
gl_Position = proj * view * model * vec4(vertPos, 1);
}
)";
// Fragment shader for the light source cube
const std::string source_frag_shader = R"(
#version 330 core
out vec4 FragColor;
void main() {
FragColor = vec4(1);
}
)";
// Vertex shader for the cube
const std::string cube_vert_shader = R"(
#version 330 core
layout (location = 0) in vec3 vertPos;
layout (location = 1) in vec3 vertNorm;
uniform mat4 proj, view, model;
out vec3 fragPos;
out vec3 interNorm;
void main() {
fragPos = vec3(model * vec4(vertPos, 1));
gl_Position = proj * view * vec4(fragPos, 1);
interNorm = mat3(transpose(inverse(model))) * vertNorm;
}
)";
// Fragment shader for the cube
const std::string cube_frag_shader = R"(
#version 330 core
in vec3 fragPos;
in vec3 interNorm;
out vec4 FragColor;
uniform vec3 viewPos;
uniform vec3 lightPos;
uniform vec3 objectColor;
const float pi = 3.14159265;
const float shininess = 16;
void main() {
vec3 normal = normalize(interNorm);
vec3 lightDir = normalize(lightPos - fragPos);
float dist = length(lightPos - fragPos);
float attenuation = 1 / (dist * dist);
// Ambient light effect
const float ambientStrength = 0.05;
vec3 ambient = ambientStrength * objectColor;
// Diffuse light effect
float diff = max(dot(normal, lightDir), 0);
vec3 diffuse = attenuation * diff * objectColor;
// Specular light effect
vec3 specular = vec3(0);
if (diff != 0) {
const float energy_conservation = (8 + shininess) / (8 * pi);
vec3 viewDir = normalize(viewPos - fragPos);
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = energy_conservation * pow(max(dot(normal, halfwayDir), 0), shininess);
specular = attenuation * spec * vec3(0.3);
}
const float gamma = 2.2;
// Apply the different lighting techniques of the Phong shading model and finally apply gamma correction
FragColor = vec4(pow(ambient + diffuse + specular, vec3(1 / gamma)), 1);
}
)";
int main() {
// Initialize the window
sf::RenderWindow window(
sf::VideoMode(1365, 768), "Lighting", sf::Style::Default,
sf::ContextSettings(24, 8, 4, 3, 3, sf::ContextSettings::Core, true));
// Initialize OpenGL functions
gladLoadGLLoader(reinterpret_cast<GLADloadproc>(sf::Context::getFunction));
// Specify the viewport of the scene
glViewport(0, 0, window.getSize().x, window.getSize().y);
// Enable depth testing
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Enable blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Load the shaders into the application
sf::Shader shader, source_shader;
(void)shader.loadFromMemory(cube_vert_shader, cube_frag_shader);
(void)source_shader.loadFromMemory(source_vert_shader, source_frag_shader);
// Define the vertices of the cube and the light source cube
float vertices[] = {
// Vertices Normals
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
};
// Attach the vertices in the vertices array to the VAO and the VBO
GLuint vao, vbo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void*>(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// The same VBO can be used to render the light source cube
GLuint source_vao;
glGenVertexArrays(1, &source_vao);
glBindVertexArray(source_vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(0);
// Projection matrix
auto proj = glm::perspective(glm::radians(45.0f), static_cast<GLfloat>(window.getSize().x) / window.getSize().y, 0.1f, 100.0f);
glm::vec3 view_pos(0.0f, 0.0f, -5.0f);
// View/camera matrix
glm::mat4 view(1.0f);
view = glm::translate(view, view_pos);
view = glm::rotate(view, glm::radians(45.0f), glm::vec3(1.0f, 1.0f, 1.0f));
// Model matrix
glm::mat4 model(1.0f);
//model = glm::rotate(model, glm::radians(45.0f), glm::vec3(1.0f, 1.0f, 0.0f));
// For the cube in the center
shader.setUniform("proj", sf::Glsl::Mat4(glm::value_ptr(proj)));
shader.setUniform("view", sf::Glsl::Mat4(glm::value_ptr(view)));
shader.setUniform("model", sf::Glsl::Mat4(glm::value_ptr(model)));
shader.setUniform("viewPos", sf::Glsl::Vec3(view_pos.x, view_pos.y, view_pos.z));
shader.setUniform("objectColor", sf::Glsl::Vec3(1.0f, 0.3f, 1.0f));
// For the light source cube
source_shader.setUniform("proj", sf::Glsl::Mat4(glm::value_ptr(proj)));
source_shader.setUniform("view", sf::Glsl::Mat4(glm::value_ptr(view)));
sf::Clock clock;
sf::Event evt{};
while (window.isOpen()) {
while (window.pollEvent(evt)) {
if (evt.type == sf::Event::Closed) {
// When window is closed, destroy the VAO and the VBO
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
window.close();
}
if (evt.type == sf::Event::Resized)
// Update the viewport as the window is resized
glViewport(0, 0, evt.size.width, evt.size.height);
}
// Clear the screen with a color
glClearColor(0.8f, 0.2f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Calculate an angular factor based on the elapsed time
auto const angular_factor = glm::radians(45.0f) * clock.getElapsedTime().asSeconds();
sf::Shader::bind(&shader);
// Makes the light source move in circles around the cube in the center
glm::vec3 light_pos(
6.0f * std::sin(angular_factor),
0.0f,
6.0f * std::cos(angular_factor)
);
shader.setUniform("lightPos", sf::Glsl::Vec3(light_pos.x, light_pos.y, light_pos.z));
// Draw the cube
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 36);
sf::Shader::bind(&source_shader);
model = glm::identity<glm::mat4>();
model = glm::scale(model, glm::vec3(0.3f, 0.3f, 0.3f));
model = glm::translate(model, light_pos);
source_shader.setUniform("model", sf::Glsl::Mat4(glm::value_ptr(model)));
// Draw the light source cube
glBindVertexArray(source_vao);
glDrawArrays(GL_TRIANGLES, 0, 36);
sf::Shader::bind(nullptr);
// Swap the window's buffers
window.display();
}
}

OpenGL Phong lighting: specular highlight is wrong

There seems to be an odd problem with my Phong lighting shader in OpenGL. The specular highlight appears on the wrong side of the object.
The problem at hand:
As you can see, the specular highlight appears on the opposite side of the cube (and also appears in the corners of the perpendicular edges of the cube, from the light's perspective. It should only appear on the side closest to the light.
The cube's vertices:
float cubeVertices[] = {
// positions // normals // texture coords
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
The vertex shader:
#version 330 core
layout (location = 0) in vec3 vPos;
layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec2 vTexCoords;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
FragPos = vec3(model * vec4(vPos, 1.0));
Normal = mat3(transpose(inverse(model))) * vNormal;
TexCoords = vTexCoords;
gl_Position = projection * view * vec4(FragPos, 1.0);
}
The fragment shader:
#version 330 core
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform sampler2D diffuseMap;
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light lights[8];
uniform int numLights;
vec3 calculateAmbient(vec3 fragPos, vec3 materialAmbient)
{
vec3 ambient = vec3(0.0);
for (int i = 0; i < numLights && i < 8; i++)
{
ambient += lights[i].ambient * materialAmbient;
}
return ambient * 0.5;
}
vec3 calculateDiffuse(vec3 fragPos, vec3 normal, vec3 materialDiffuse)
{
vec3 diffuse = vec3(0.0);
for (int i = 0; i < numLights && i < 8; i++)
{
vec3 lightDir = normalize(lights[i].position - fragPos);
float diff = max(dot(normal, lightDir), 0.0);
diffuse += lights[i].diffuse * (diff * materialDiffuse);
}
return diffuse;
}
vec3 calculateSpecular(vec3 fragPos, vec3 normal, vec3 viewDir, vec3 materialSpecular, float shininess)
{
vec3 specular = vec3(0.0);
for (int i = 0; i < numLights && i < 8; i++)
{
vec3 lightDir = normalize(lights[i].position - fragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0f * shininess);
specular += lights[i].specular * (spec * materialSpecular);
}
return specular;
}
void main()
{
vec4 tex = texture(diffuseMap, TexCoords);
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
vec3 ambient = calculateAmbient(FragPos, material.ambient);
vec3 diffuse = calculateDiffuse(FragPos, norm, material.diffuse);
vec3 specular = calculateSpecular(FragPos, norm, viewDir, material.specular, material.shininess);
vec3 result = (ambient + diffuse + specular) * tex.rgb;
FragColor = vec4(result, 1.0);
}
The specular highlight appears also on the faces which are back side facing to the light source, because relfect actually computes:
refelct(I, N) = I - 2.0 * dot(N, I) * N
On back faces the normal vector points away from the light source, but refelct(I, N) == refelct(I, -N), because:
I - 2.0 * dot(N, I) * N == I - 2.0 * dot(-N, I) * -N
In the Phong reflection model, the specular hightlight is only add, if the diffuse light is > 0. e.g:
for (int i = 0; i < numLights && i < 8; i++)
{
vec3 lightDir = normalize(lights[i].position - fragPos);
float NdotL = dot(normal, lightDir);
if (NdotL > 0.0)
{
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0f * shininess);
specular += lights[i].specular * (spec * materialSpecular);
}
}

Change camera position and direction in OpenGL?

I have a code (game) with a fixed camera in an ortho projection. It runs smoothly until I change the camera position from (0,0,1) to (0,0,-1).
In a nutshell, I have 2 textures:
{ //texture 1
960.0f, 0.0f, -5.0f, 0.0f, 0.0f,
960.0f, 1080.0f, -5.0f, 1.0f, 0.0f,
1920.0f, 0.0f, -5.0f, 0.0f, 1.0f,
1920.0f, 1080.0f, -5.0f, 1.0f, 1.0f
}
{ // texture 2
1290.0f, 390.0f, -7.0f, 0.0f, 0.0f,
1290.0f, 690.0f, -7.0f, 1.0f, 0.0f,
1590.0f, 390.0f, -7.0f, 0.0f, 1.0f,
1590.0f, 690.0f, -7.0f, 1.0f, 1.0f
}
the transformation matrices:
view = glm::lookAt
(
glm::vec3( 0.0f, 0.0f, 1.0f ),
glm::vec3( 0.0f, 0.0f, 0.0f ),
glm::vec3( 0.0f, 1.0f, 0.0f )
);
projection = glm::ortho
(
0.0f,
1920.0f,
0.0f,
1080.0f,
1.0f, // zNear
10.0f // zFar
);
the vertex shader:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4( aPos, 1.0 );
TexCoord = vec2( aTexCoord.x, aTexCoord.y );
}
If I run this code, it properly displays both textures, does depth testing,...
However, if I change the camera position to (0, 0, -1) and textures' Z-coordinate to their inverse +5 and +7, and keep the same direction (0, 0, 0), no texture is displayed (rendered). Shouldn't it display the same as before the changes ?
The issue is related to the orthographic projection matrix, because it is not centered. When the z axis of the view is inverted, then the x axis is inverted, too. Note the Right-hand rule has to be still fulfilled and the x.axis is the cross product of the y-axis and z-axis.
When the geometry is at z-5and the view and projection matrix is as follows
view = glm::lookAt(
glm::vec3(0.0f, 0.0f, 1.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f);
projection = glm::ortho(0.0f, 1920.0f, 0.0f, 1080.0f, 1.0f, 10.0f);
then the object is projected to the viewport:
But if you switch the z position of the geometry and the view, then you get the following situation:
view = glm::lookAt(
glm::vec3(0.0f, 0.0f, -1.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f);
then the object is beside the viewport:
Shift the the orthographic projection along the X-axis, to solve your issue:
projection = glm::ortho(-1920.0f, 0.0f, 0.0f, 1080.0f, 1.0f, 10.0f);

Rendering two overlapping 2D objects with 2 shaders

I want to render two triangles in blue and a "windmill" in red. To do this I have created 2 shaders, which are the same except for the color. The two triangles are a lot bigger than the "windmill". The problem I'm facing is that if I switch between shaders, ONLY the last object will be rendered. If I switch to using only 1 shader, both objects will be drawn, but I can barely see the "windmill" because of the same color. So my question is how to draw both objects with two shaders? (I know I can just pass a color to the fragment shader, but I don't want to do that).
Render loop:
GLint index, index2;
index = glGetUniformLocation(shaders[LINE], "projectionMatrix");
index2 = glGetUniformLocation(shaders[TRIANGLE], "projectionMatrix");
glUniformMatrix3fv(index, 1, true, value_ptr(projectionMatrix));
glUniformMatrix3fv(index2, 1, true, value_ptr(projectionMatrix));
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaders[TRIANGLE]);
glBindVertexArray(vaos[TRIANGLE]);
glDrawArrays(GL_TRIANGLES, 0, tbufindex/sizeof(glm::vec3));
glUseProgram(shaders[LINE]); // If I comment out this line both objects will be drawn
glBindVertexArray(vaos[LINE]);
glDrawArrays(GL_LINE_STRIP, 0, sizeof(vertices_position)/sizeof(glm::vec3));
Line/Triangle.vert:
#version 450
layout (location = 0) in vec3 vPosition;
uniform mat3 projectionMatrix;
void main()
{
vec3 tmp = projectionMatrix*vPosition;
gl_Position = vec4(tmp, 1.0f);
}
Line/triangle.frag:
#version 450
in vec4 gl_FragCoord;
out vec4 fColor;
void main()
{
fColor = vec4(0.0, 0.0, 1.0, 1.0);
}
Also note that I don't have GL_DEPTH_TEST enabled, I'm using 2D coordinates.
Edit positions:
triangles[2] = { { vec3(-0.90f, -0.90f, 1.0f), vec3(0.85f, -0.90f, 1.0f), vec3(-0.90f, 0.85f, 1.0f) },
{ vec3(0.90f, -0.85f, 1.0f), vec3(0.90f, 0.90f, 1.0f), vec3(-0.85f, 0.90f, 1.0f) } };
lines[39] = {
0.0f, 0.0f, 1.0f,
0.5f, 0.0f, 1.0f,
0.5f, 0.5f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.5f, 1.0f,
-0.5f, 0.5f, 1.0f,
0.0f, 0.0f, 1.0f,
-0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, -0.5f, 1.0f,
0.5f, -0.5f, 1.0f,
0.0f, 0.0f, 1.0f
};
glUniform..() must be called after binding the program (source). So the following should work:
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaders[TRIANGLE]);
glUniformMatrix3fv(index2, 1, true, value_ptr(projectionMatrix));
glBindVertexArray(vaos[TRIANGLE]);
glDrawArrays(GL_TRIANGLES, 0, tbufindex/sizeof(glm::vec3));
glUseProgram(shaders[LINE]); // If I comment out this line both objects will be drawn
glUniformMatrix3fv(index, 1, true, value_ptr(projectionMatrix));
glBindVertexArray(vaos[LINE]);
glDrawArrays(GL_LINE_STRIP, 0, sizeof(vertices_position)/sizeof(glm::vec3));