Related
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)));
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();
}
}
I want to be able to pan, zoom, and orbit the cube. I would like to know why the cube appears fully zoomed on the screen such that I have to move backwards to view the whole cube. I would also like to change the zooming controls to alt and right mouse button for both zooming and orbiting but I cant get it to work. Any assistance would be appreciated.
/*/header inclusions*/
#include <iostream> // Includes C++ i/o stream
#include <GL/glew.h> // Includes glew header
#include <GL/freeglut.h> // Includes freeglut header
// GLM Math inclusions
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>
using namespace std; // Uses the standard namespace
#define WINDOW_TITLE "Modern OpenGL" // Macro for window title
//Vertex and fragment shader
#ifndef GLSL
#define GLSL(Version, source) "#version " #Version "\n" #source
#endif
// Variables for window width and height
GLint ShaderProgram, WindowWidth = 800, WindowHeight = 600;
GLuint VBO, VAO;
GLfloat cameraSpeed = 0.0005f;
GLchar currentKey;
GLfloat lastMouseX = 400, lastMouseY = 300;
GLfloat mouseXOffset, mouseYOffset, yaw = 0.0f, pitch = 0.0f;
GLfloat sensitivity = 0.5f;
bool mouseDetected = true;
//global vectors declaration
glm::vec3 cameraPosition = glm::vec3(0.0f,0.0f,0.0f);
glm::vec3 CameraUpY = glm::vec3(0.0f,1.0f,0.0f);
glm::vec3 CameraForwardZ = glm::vec3(0.0f,0.0f,-1.0f);
glm::vec3 front;
/* User-defined Function prototypes to:*/
void UResizeWindow(int,int);
void URenderGraphics(void);
void UCreateShader(void);
void UCreateBuffers(void);
void UKeyboard(unsigned char key, int x, int y);
void UKeyReleased(unsigned char key, int x, int y);
void UMouseMove(int x, int y);
/*Vertex shader source code*/
const GLchar * vertexShaderSource = GLSL(330,
layout(location=0) in vec3 position;
layout(location=1) in vec3 color;
out vec3 mobileColor; //declare a vec 4 variable
//Global variables for the transform matrices
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(){
gl_Position = projection * view * model * vec4(position, 1.0f);//transform vertices
mobileColor = color;
}
);
/*Fragment shader program source code*/
const GLchar * fragmentShaderSource = GLSL(330,
in vec3 mobileColor;
out vec4 gpuColor;//out vertex_Color;
void main(){
gpuColor = vec4 (mobileColor, 1.0);
}
);
//main program
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(WindowWidth, WindowHeight);
glutCreateWindow(WINDOW_TITLE);
glutReshapeFunc(UResizeWindow);
glewExperimental = GL_TRUE;
if (glewInit()!= GLEW_OK)
{
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
UCreateShader();
UCreateBuffers();
// Use the Shader program
glUseProgram(ShaderProgram);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color
glutDisplayFunc(URenderGraphics);
glutKeyboardFunc(UKeyboard);
glutKeyboardUpFunc(UKeyReleased);
glutPassiveMotionFunc(UMouseMove);
glutMainLoop();
// Destroys Buffer objects once used
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
return 0;
}
/* Resizes the window*/
void UResizeWindow(int w, int h)
{
WindowWidth = w;
WindowHeight = h;
glViewport(0, 0, WindowWidth, WindowHeight);
}
/* Renders graphics */
void URenderGraphics(void)
{
glEnable(GL_DEPTH_TEST); // Enable z-depth
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clears the screen
glBindVertexArray(VAO); // Activate the Vertex Array Object before rendering and transforming them
//camera movement logic
if(currentKey == 'w')
cameraPosition += cameraSpeed * CameraForwardZ;
if(currentKey == 's')
cameraPosition -= cameraSpeed * CameraForwardZ;
if(currentKey == 'a')
cameraPosition -= glm::normalize(glm::cross(CameraForwardZ, CameraUpY)) * cameraSpeed;
if(currentKey == 'd')
cameraPosition += glm::normalize(glm::cross(CameraForwardZ, CameraUpY)) * cameraSpeed;
CameraForwardZ = front;
// Transforms the object
glm::mat4 model;
model = glm::translate(model, glm::vec3(0.0, 0.0f, 0.0f)); // Place the object at the center of the 7i,p9rA
model = glm::rotate(model, 45.0f, glm::vec3(1.0, 1.0f, 1.0f)); // Rotate the object 45 degrees on the XYZ
model = glm::scale(model, glm::vec3(1.0f, 1.0f, -1.0f)); // Increase the object size by a scale of 2
// Transforms the camera
glm::mat4 view;
view = glm::lookAt(cameraPosition, cameraPosition + CameraForwardZ, CameraUpY); //Moves the world 0.5 units on X and -5 units in Z
// Creates a perspective projection
glm::mat4 projection;
projection = glm::perspective(45.0f, (GLfloat)WindowWidth / (GLfloat)WindowHeight, 0.1f, 100.0f);
// Retrieves and passes transform matrices to the Shader program
GLint modelLoc = glGetUniformLocation(ShaderProgram, "model");
GLint viewLoc = glGetUniformLocation(ShaderProgram, "view");
GLint projLoc = glGetUniformLocation(ShaderProgram, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glutPostRedisplay();
// Draws the triangles
glDrawArrays(GL_TRIANGLES,0, 36);
glBindVertexArray(0); // Deactivate the Vertex Array Object
glutSwapBuffers(); // Flips the the back buffer with the front buffer every frame. Similar to GL FLush
}
/*Creates the Shader program*/
void UCreateShader()
{
// Vertex shader
GLint vertexShader = glCreateShader(GL_VERTEX_SHADER); // Creates the Vertex Shader
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); // Attaches the Vertex Shader to the source code
glCompileShader(vertexShader); // Compiles the Vertex Shader
// Fragment Shader
GLint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); // Creates the Fragment Shader
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);// Attaches the Fragment Shader to the source code
glCompileShader(fragmentShader); // Compiles the Fragment Shader
// Shader program
ShaderProgram = glCreateProgram(); // Creates the Shader program and returns an id
glAttachShader(ShaderProgram, vertexShader); // Attach Vertex Shader to the Shader program
glAttachShader(ShaderProgram, fragmentShader);; // Attach Fragment Shader to the Shader program
glLinkProgram(ShaderProgram); //Link Vertex and Fragment shader, to Shader program
// Delete the Vertex and Fragment shaders once linked
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
/*creates the buffer and array object*/
void UCreateBuffers()
{
//position and color data
GLfloat vertices[] = {
//vertex positions and colors
-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, 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, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 1.0f,
};
//Generate buffer id,
glGenVertexArrays(1, &VAO);
glGenBuffers(1,&VBO);
// Activate the Vertex Array Object before binding and setting any VB0s and Vertex Attribute Pointers.
glBindVertexArray(VAO);
// Activate the VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //Copy vertices to VBO
// Set attribute pointer 0 to hold Position data
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0); // Enables vertex attribute
// Set attribute pointer 1 to hold Color data
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1); // Enables vertex attribute
glBindVertexArray(0); // Deactivates the VAC, which is good practice
}
//implement the UKeyboard function
void UKeyboard(unsigned char key, GLint x, GLint y)
{
switch(key){
case 'w':
currentKey = key;
cout<<"You Pressed W"<<endl;
break;
case 's':
currentKey = key;
cout<<"You Pressed S"<<endl;
break;
case 'a':
currentKey = key;
cout<<"You Pressed A"<<endl;
break;
case 'd':
currentKey = key;
cout<<"You Pressed D"<<endl;
break;
default:
cout<<"Press a key!"<<endl;
}
}
//implement the UKeyReleased function
void UKeyReleased(unsigned char key, GLint x, GLint y)
{
cout<<"Key Released!"<<endl;
currentKey = '0';
}
//implement UMouseMove function
void UMouseMove(int x, int y)
{
if(mouseDetected)
{
lastMouseX = x;
lastMouseY = y;
mouseDetected = false;
}
//get the direction mouse was moved
mouseXOffset = x - lastMouseX;
mouseYOffset = lastMouseY - y;
//update new coordinates
lastMouseX = x;
lastMouseY = y;
//apply sensitivity
mouseXOffset *= sensitivity;
mouseYOffset *= sensitivity;
//accumulate yaw and pitch
yaw += mouseXOffset;
pitch += mouseYOffset;
//maintain 90 degree pitch
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch > -89.0f)
pitch = -89.0f;
//convert mouse coordinates
front.x = cos(glm::radians(pitch)) * cos(glm::radians(yaw));
front.y = sin(glm::radians(pitch));
front.z = cos(glm::radians(pitch)) * sin(glm::radians(yaw));
}
Start at a camera position, which is translated along the positiv z axis (e.g. (0, 0, 10)). front has to be initialized:
glm::vec3 cameraPosition = glm::vec3(0.0f,0.0f,10.0f);
glm::vec3 CameraUpY = glm::vec3(0.0f,1.0f,0.0f);
glm::vec3 CameraForwardZ = glm::vec3(0.0f,0.0f,-1.0f);
glm::vec3 front = glm::vec3(0.0f,0.0f,-1.0f);
You have to initialize the model matrix variable glm::mat4 model.
The glm API documentation refers to The OpenGL Shading Language specification 4.20.
5.4.2 Vector and Matrix Constructors
If there is a single scalar parameter to a vector constructor, it is used to initialize all components of the constructed vector to that scalar’s value. If there is a single scalar parameter to a matrix constructor, it is used to initialize all the components on the matrix’s diagonal, with the remaining components initialized to 0.0.
This means, that an Identity matrix can be initialized by the single parameter 1.0:
glm::mat4 model(1.0f);
The unit of the angles in OpenGL Mathematics is radian rather than degree. (glm::perspective, glm::rotate):
// Transforms the object
glm::mat4 model(1.0f);
model = glm::translate(model, glm::vec3(0.0, 0.0f, 0.0f)); // Place the object at the center of the 7i,p9rA
model = glm::rotate(model, glm::radians(45.0f), glm::vec3(1.0, 1.0f, 1.0f)); // Rotate the object 45 degrees on the XYZ
model = glm::scale(model, glm::vec3(1.0f, 1.0f, -1.0f)); // Increase the object size by a scale of 2
// Transforms the camera
glm::mat4 view = glm::lookAt(cameraPosition, cameraPosition + CameraForwardZ, CameraUpY); //Moves the world 0.5 units on X and -5 units in Z
// Creates a perspective projection
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (GLfloat)WindowWidth / (GLfloat)WindowHeight, 0.1f, 100.0f);
There are some mistakes when front is calculated. pitch < -89.0f rather than pitch > -89.0f. The x axis is sin(glm::radians(yaw)) and the z axis is -cos(glm::radians(yaw)):
//maintain 90 degree pitch
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
//convert mouse coordinates
front.x = cos(glm::radians(pitch)) * sin(glm::radians(yaw));
front.y = sin(glm::radians(pitch));
front.z = cos(glm::radians(pitch)) * -cos(glm::radians(yaw));
Furthermore, the sensitivity seams to be to strong, I recommend to reduce it (e.g. GLfloat sensitivity = 0.05f;).
I have this OpenGL code the draws a cube and pyramid. However, this program rotates the pyramid and cube together. I am tasked with only making the cube itself move not both objects at the same time. I know for this to happen I have to implement shaders for both. I'm not sure how to go about implementing both of the shaders at once. Any tips?
/*
This program demonstrates simple lighting.
A pyramid is lighted by a point light and can be rotated by mouse.
Ying Zhu
Georgia State University
October 2016
*/
// GLEW header
#include <GL/glew.h> // This must appear before freeglut.h
// Freeglut header
#include <GL/freeglut.h>
// GLM header files
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
// #include <glm/gtx/transform2.hpp>
#include <glm/gtc/matrix_access.hpp>
// #include <glm/gtx/projection.hpp>
#include <glm/gtc/matrix_inverse.hpp>
#include <glm/gtc/type_ptr.hpp>
// C++ header files
#include <iostream>
using namespace std;
using namespace glm;
#define BUFFER_OFFSET(offset) ((GLvoid *) offset)
// VBO buffer IDs
GLuint vertexArrayBufferID = 0;
GLuint normalArrayBufferID = 0;
GLuint cubePosition = 0;
GLuint cubeElements = 0;
GLuint program; // shader program ID
// Shader variable IDs
GLint vPos; // vertex attribute: position
GLint normalID; // vertex attribute: normal
GLint mvpMatrixID; // uniform variable: model, view, projection matrix
GLint modelMatrixID; // uniform variable: model, view matrix
GLint normalMatrixID; // uniform variable: normal matrix for transforming normals
GLint lightSourcePositionID; // uniform variable: for lighting calculation
GLint diffuseLightProductID; // uniform variable: for lighting calculation
GLint ambientID;
GLint attenuationAID;
GLint attenuationBID;
GLint attenuationCID;
// Transformation matrices
mat4 projMatrix;
mat4 mvpMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat3 normalMatrix; // Normal matrix for transforming normals
// Light parameters
vec4 lightSourcePosition = vec4(0.0f, 4.0f, 0.0f, 1.0f);
vec4 diffuseMaterial = vec4(0.5f, 0.5f, 0.0f, 1.0f);
vec4 diffuseLightIntensity = vec4(1.0f, 1.0f, 1.0f, 1.0f);
vec4 ambient = vec4(0.2f, 0.2f, 0.2f, 1.0f);
float attenuationA = 1.0f;
float attenuationB = 0.2f;
float attenuationC = 0.0f;
vec4 diffuseLightProduct;
// Camera parameters
vec3 eyePosition = vec3(0.0f, 0.0f, 4.0f);
vec3 lookAtCenter = vec3(0.0f, 0.0f, 0.0f);
vec3 upVector = vec3(0.0f, 1.0f, 0.0f);
float fieldOfView = 30.0f;
float nearPlane = 0.1f;
float farPlane = 1000.0f;
// Mouse controlled rotation angles
float rotateX = 0;
float rotateY = 0;
struct VertexData {
GLfloat vertex[3];
VertexData(GLfloat x, GLfloat y, GLfloat z) {
vertex[0] = x; vertex[1] = y; vertex[2] = z;
}
};
//---------------------------------------------------------------
// Initialize vertex arrays and VBOs
void prepareVBOs() {
// Define a 3D pyramid.
GLfloat vertices[][4] = {
{1.0f, -1.0f, 1.0f, 1.0f}, // face 1
{-1.0f, -1.0f, -1.0f, 1.0f},
{1.0f, -1.0f, -1.0f, 1.0f},
{ 1.0f, -1.0f, -1.0f, 1.0f }, // face 2
{0.0f, 1.0f, 0.0f, 1.0f},
{ 1.0f, -1.0f, 1.0f, 1.0f },
{ 1.0f, -1.0f, 1.0f, 1.0f }, // face 3
{ 0.0f, 1.0f, 0.0f, 1.0f },
{-1.0f, -1.0f, 1.0f, 1.0f},
{ -1.0f, -1.0f, 1.0f, 1.0f }, // face 4
{ 0.0f, 1.0f, 0.0f, 1.0f },
{ -1.0f, -1.0f, -1.0f, 1.0f },
{ 0.0f, 1.0f, 0.0f, 1.0f }, // face 5
{ 1.0f, -1.0f, -1.0f, 1.0f },
{ -1.0f, -1.0f, -1.0f, 1.0f },
{ 1.0f, -1.0f, 1.0f, 1.0f }, // face 6
{ -1.0f, -1.0f, 1.0f, 1.0f },
{ -1.0f, -1.0f, -1.0f, 1.0f }
};
GLfloat normals[][4] = {
{0.0f, -1.0f, 0.0f, 1.0f}, // normal 1
{0.0f, -1.0f, 0.0f, 1.0f },
{0.0f, -1.0f, 0.0f, 1.0f },
{0.8944f, 0.4472f, 0.0f, 1.0f}, // normal 2
{ 0.8944f, 0.4472f, 0.0f, 1.0f },
{ 0.8944f, 0.4472f, 0.0f, 1.0f },
{-0.0f, 0.4472f, 0.8944f, 1.0f}, // normal 3
{ -0.0f, 0.4472f, 0.8944f, 1.0f },
{ -0.0f, 0.4472f, 0.8944f, 1.0f },
{-0.8944f, 0.4472f, 0.0f, 1.0f}, // normal 4
{ -0.8944f, 0.4472f, 0.0f, 1.0f },
{ -0.8944f, 0.4472f, 0.0f, 1.0f },
{0.0f, 0.4472f, -0.8944f, 1.0f}, // normal 5
{ 0.0f, 0.4472f, -0.8944f, 1.0f },
{ 0.0f, 0.4472f, -0.8944f, 1.0f },
{ 0.0f, -1.0f, 0.0f, 1.0f }, // normal 6
{ 0.0f, -1.0f, 0.0f, 1.0f },
{ 0.0f, -1.0f, 0.0f, 1.0f }
};
// Cube positioins
VertexData vertexData[] = {
VertexData(0.0, 0.0, 0.0), /* Index 0 */
VertexData(0.0, 0.0, 1.0), /* Index 1 */
VertexData(0.0, 1.0, 0.0), /* Index 2 */
VertexData(0.0, 1.0, 1.0), /* Index 3 */
VertexData(1.0, 0.0, 0.0), /* Index 4 */
VertexData(1.0, 0.0, 1.0), /* Index 5 */
VertexData(1.0, 1.0, 0.0), /* Index 6 */
VertexData(1.0, 1.0, 1.0), /* Index 7 */
};
// Cube elements
GLubyte indices[] = {
4, 5, 7, // +X face
4, 7, 6,
0, 2, 3, // ‐X face
0, 3, 1,
2, 6, 7, // +Y face
2, 7, 3,
0, 1, 5, // ‐Y face
0, 5, 4,
0, 4, 6, // +Z face
0, 6, 2,
1, 3, 7, // ‐Z face
1, 7, 5
};
// Get an unused buffer object name. Required after OpenGL 3.1.
glGenBuffers(1, &vertexArrayBufferID);
// If it's the first time the buffer object name is used, create that buffer.
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBufferID);
// Allocate memory for the active buffer object.
// 1. Allocate memory on the graphics card for the amount specified by the 2nd parameter.
// 2. Copy the data referenced by the third parameter (a pointer) from the main memory to the
// memory on the graphics card.
// 3. If you want to dynamically load the data, then set the third parameter to be NULL.
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &normalArrayBufferID);
glBindBuffer(GL_ARRAY_BUFFER, normalArrayBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(normals), normals, GL_STATIC_DRAW);
glGenBuffers(1, &cubePosition);
glBindBuffer(GL_ARRAY_BUFFER, cubePosition);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData),
vertexData, GL_STATIC_DRAW);
glGenBuffers(1, &cubeElements);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeElements);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices),
indices, GL_STATIC_DRAW);
}
//---------------------------------------------------------------
// Print out the output of the shader compiler
void printLog(GLuint obj)
{
int infologLength = 0;
char infoLog[1024];
if (glIsShader(obj)) {
glGetShaderInfoLog(obj, 1024, &infologLength, infoLog);
}
else {
glGetProgramInfoLog(obj, 1024, &infologLength, infoLog);
}
if (infologLength > 0) {
cout << infoLog;
}
}
//-------------------------------------------------------------------
void prepareShaders() {
// Vertex shader source code
// A point light source is implemented.
// For simplicity, only the ambient and diffuse components are implemented.
// The lighting is calculated in world space, not in camera space.
const char* vSource = {
"#version 330\n"
"in vec4 vPos;"
"in vec4 normal;"
"uniform mat4x4 mvpMatrix;"
"uniform mat4x4 modelMatrix;"
"uniform mat3x3 normalMatrix;"
"uniform vec4 lightSourcePosition;"
"uniform vec4 diffuseLightProduct;"
"uniform vec4 ambient;"
"uniform float attenuationA;"
"uniform float attenuationB;"
"uniform float attenuationC;"
"out vec4 color;"
"void main() {"
" gl_Position = mvpMatrix * vPos;"
// Transform the vertex position to the world space.
" vec4 transformedVertex = modelMatrix * vPos;"
// Transform the normal vector to the world space.
" vec3 transformedNormal = normalize(normalMatrix * normal.xyz);"
// Light direction
" vec3 lightVector = normalize(transformedVertex.xyz - lightSourcePosition.xyz);"
// Distance between the light source and vertex
" float dist = distance(lightSourcePosition.xyz, transformedVertex.xyz);"
// Attenuation factor
" float attenuation = 1.0f / (attenuationA + (attenuationB * dist) + (attenuationC * dist * dist));"
// Calculate the diffuse component of the lighting equation.
" vec4 diffuse = attenuation * (max(dot(transformedNormal, lightVector), 0.0) * diffuseLightProduct);"
// Combine the ambient component and diffuse component.
" color = ambient + diffuse;"
"}"
};
// Fragment shader source code
const char* fSource = {
"#version 330\n"
"in vec4 color;"
"out vec4 fragColor;"
"void main() {"
" fragColor = color;"
"}"
};
// Declare shader IDs
GLuint vShader, fShader;
// Create empty shader objects
vShader = glCreateShader(GL_VERTEX_SHADER);
fShader = glCreateShader(GL_FRAGMENT_SHADER);
// Attach shader source code the shader objects
glShaderSource(vShader, 1, &vSource, NULL);
glShaderSource(fShader, 1, &fSource, NULL);
// Compile shader objects
glCompileShader(vShader);
printLog(vShader);
glCompileShader(fShader);
printLog(fShader);
// Create an empty shader program object
program = glCreateProgram();
// Attach vertex and fragment shaders to the shader program
glAttachShader(program, vShader);
glAttachShader(program, fShader);
// Link the shader program
glLinkProgram(program);
printLog(program);
}
//---------------------------------------------------------------
// Retrieve the IDs of the shader variables. Later we will
// use these IDs to pass data to the shaders.
void getShaderVariableLocations(GLuint shaderProgram) {
// Retrieve the ID of a vertex attribute, i.e. position
vPos = glGetAttribLocation(shaderProgram, "vPos");
normalID = glGetAttribLocation(shaderProgram, "normal");
mvpMatrixID = glGetUniformLocation(shaderProgram, "mvpMatrix");
modelMatrixID = glGetUniformLocation(shaderProgram, "modelMatrix");
normalMatrixID = glGetUniformLocation(shaderProgram, "normalMatrix");
lightSourcePositionID = glGetUniformLocation(shaderProgram, "lightSourcePosition");
diffuseLightProductID = glGetUniformLocation(shaderProgram, "diffuseLightProduct");
ambientID = glGetUniformLocation(shaderProgram, "ambient");
attenuationAID = glGetUniformLocation(shaderProgram, "attenuationA");
attenuationBID = glGetUniformLocation(shaderProgram, "attenuationB");
attenuationCID = glGetUniformLocation(shaderProgram, "attenuationC");
}
//---------------------------------------------------------------
void setShaderVariables() {
// value_ptr is a glm function
glUniformMatrix4fv(mvpMatrixID, 1, GL_FALSE, value_ptr(mvpMatrix));
glUniformMatrix4fv(modelMatrixID, 1, GL_FALSE, value_ptr(modelMatrix));
glUniformMatrix3fv(normalMatrixID, 1, GL_FALSE, value_ptr(normalMatrix));
glUniform4fv(lightSourcePositionID, 1, value_ptr(lightSourcePosition));
glUniform4fv(diffuseLightProductID, 1, value_ptr(diffuseLightProduct));
glUniform4fv(ambientID, 1, value_ptr(ambient));
glUniform1f(attenuationAID, attenuationA);
glUniform1f(attenuationBID, attenuationB);
glUniform1f(attenuationCID, attenuationC);
}
//---------------------------------------------------------------
// Set lighting related parameters
void setLightingParam() {
diffuseLightProduct = diffuseMaterial * diffuseLightIntensity;
}
//---------------------------------------------------------------
// Build the model matrix. This matrix will transform the 3D object to the proper place.
mat4 buildModelMatrix() {
mat4 rotationXMatrix = rotate(mat4(1.0f), radians(rotateX), vec3(1.0f, 0.0f, 0.0f));
mat4 rotationYMatrix = rotate(mat4(1.0f), radians(rotateY), vec3(0.0f, 1.0f, 0.0f));
mat4 matrix = rotationYMatrix * rotationXMatrix;
return matrix;
}
//---------------------------------------------------------------
void buildMatrices() {
modelMatrix = buildModelMatrix();
mvpMatrix = projMatrix * viewMatrix * modelMatrix;
normalMatrix = column(normalMatrix, 0, vec3(modelMatrix[0][0], modelMatrix[0][1], modelMatrix[0][2]));
normalMatrix = column(normalMatrix, 1, vec3(modelMatrix[1][0], modelMatrix[1][1], modelMatrix[1][2]));
normalMatrix = column(normalMatrix, 2, vec3(modelMatrix[2][0], modelMatrix[2][1], modelMatrix[2][2]));
// Use glm::inverseTranspose() to create a normal matrix, which is used to transform normal vectors.
normalMatrix = inverseTranspose(normalMatrix);
}
//---------------------------------------------------------------
// Handles the display event
void display()
{
// Clear the window with the background color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
buildMatrices();
setShaderVariables();
// Activate the shader program
glUseProgram(program);
// If the buffer object already exists, make that buffer the current active one.
// If the buffer object name is 0, disable buffer objects.
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBufferID);
// Associate the vertex array in the buffer object with the vertex attribute: "position"
glVertexAttribPointer(vPos, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
// Enable the vertex attribute: "position"
glEnableVertexAttribArray(vPos);
glBindBuffer(GL_ARRAY_BUFFER, normalArrayBufferID);
glVertexAttribPointer(normalID, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(normalID);
// Start the shader program. Draw the object. The third parameter is the number of triangles.
glDrawArrays(GL_TRIANGLES, 0, 18);
glBindBuffer(GL_ARRAY_BUFFER, cubePosition);
glVertexAttribPointer(vPos, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(vPos);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeElements);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
// Refresh the window
glutSwapBuffers();
}
//---------------------------------------------------------------
// Handles the reshape event
void reshape(int width, int height)
{
// Specify the width and height of the picture within the window
glViewport(0, 0, width, height);
projMatrix = perspective(fieldOfView, (float)width / (float)height, nearPlane, farPlane);
viewMatrix = lookAt(eyePosition, lookAtCenter, upVector);
}
//---------------------------------------------------------------
// Read mouse motion data and convert them to rotation angles.
void passiveMotion(int x, int y) {
rotateY = (float)x * -0.8f;
rotateX = (float)y * -0.8f;
// Generate a dislay event to force refreshing the window.
glutPostRedisplay();
}
//-----------------------------------------------------------------
void init() {
prepareVBOs();
prepareShaders();
getShaderVariableLocations(program);
setLightingParam();
// Specify the background color
glClearColor(1, 1, 1, 1);
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
//---------------------------------------------------------------
void main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Lighting Demo");
glutReshapeWindow(800, 800);
glewInit();
init();
// Register the display callback function
glutDisplayFunc(display);
// Register the reshape callback function
glutReshapeFunc(reshape);
// Register the passive mouse motion call back function
// This function is called when the mouse moves within the window
// while no mouse buttons are pressed.
glutPassiveMotionFunc(passiveMotion);
// Start the event loop
glutMainLoop();
}
Well, the most obvious culprit here would be setting a single ModelMatrix for both - I can't see any logic in your code to set them independently for each object you're rendering.
Since each object has a different rotation (and presumably, unless you're planning to draw one on top of the other, a different translation), you would want to be generating / loading a different model matrix for each draw call.
You dont need to use different shaders, you just need to use different model matricies. Say you have two objects in you scene something like this:
while (!myWindow(shouldClose))
{
myShader.use();
glBindVertexArray(myVao1);
glDrawArrays(GL_TRIANGLES, 0, x); // Draw pyramid
glBindVertaxArray(myVao2);
glDrawArrays(GL_TRIANGLES, 0, x); // Draw cube
}
Say you want only the second model to rotate on the y axis, you could do something like this:
float rotationDegree = 0;
while (!myWindow(shouldClose))
{
myShader.use();
myShader.setMat4(glm::mat4(1.0f)) // Make sure to set it to normal matrix for the pyrmamid
glBindVertexArray(myVao1);
glDrawArrays(GL_TRIANGLES, 0, x); // Draw pyramid
glBindVertaxArray(myVao2);
glm::mat4 model = glm::mat4(1.0f);
glm::rotate(model, glm::radians(rotationDegree), glm::vec3(0.0f, 1.0f, 0.0f));
rotateionDegree += 0.01;
myShader.setMat4("model", model); // Set you model matrix in your shader.
glDrawArrays(GL_TRIANGLES, 0, x); // Draw cube
}
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));