object drawing order in OpenGL - opengl

I created a sphere floating above a ground. The sphere is centered around (0,0,0). I have set up a camera with a twist, elevation, azimuth as well as moving in closer and farther from the sphere. The problem I have is that the sphere is always drawn on top of the ground. For example, if I move the camera below the ground I should see the ground be drawn on top of the sphere but that's not the case. Here are my ground and draw functions.
void init_ground()
{
GLfloat x = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
GLfloat z = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
for(int i=0; i<NUM_GROUND_LINES*2; i += 2)
{
GLfloat x = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(-x, -4.0, z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
z += 1.0;
}
for(int i=NUM_GROUND_LINES*2; i<NUM_GROUND_LINES*4; i += 2)
{
GLfloat z = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(x, -4.0, -z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
x += 1.0;
}
}
glm::vec3 cameraPos = glm::vec3(0.0, 0.0, 3.0);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
void draw()
{
glm::mat4 view;
glm::mat4 projection;
glm::mat4 model;
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
view = glm::rotate(view, glm::radians(GLfloat(twist)), glm::vec3(0.0, 0.0, 1.0));
view = glm::rotate(view, glm::radians(GLfloat(elevation)), glm::vec3(1.0, 0.0, 0.0));
view = glm::rotate(view, glm::radians(GLfloat(azimuth)), glm::vec3(0.0, 0.0, 1.0));
projection = glm::perspective(45.0f, (GLfloat)WIDTH/(GLfloat)HEIGHT, 0.1f, 100.0f);
glUseProgram(program_ground);
GLint ground_proj_loc = glGetUniformLocation(program_ground, "projection");
GLint ground_view_loc = glGetUniformLocation(program_ground, "view");
GLint ground_model_loc = glGetUniformLocation(program_ground, "model");
glUniformMatrix4fv(ground_proj_loc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(ground_view_loc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(ground_model_loc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(vao_ground);
glDrawArrays(GL_LINES, 0, NUM_GROUND_LINES*2*4);
glBindVertexArray(0);
glUseProgram(program_sphere);
GLint sphere_model_loc = glGetUniformLocation(program_sphere, "model");
GLint sphere_view_loc = glGetUniformLocation(program_sphere, "view");
GLint sphere_proj_loc = glGetUniformLocation(program_sphere, "projection");
glUniformMatrix4fv(sphere_view_loc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(sphere_proj_loc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(sphere_model_loc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(vao_sphere);
glDrawArrays(GL_LINE_LOOP, 0, 342);
glBindVertexArray(0);
glfwSwapBuffers(window);
}

To be able to remove hidden superficies, you need to enable the Depth Test.
To do that, first you must ask, at the context creation time, a buffer to store the relative z positional value of a vertex, in relation to the camera. If you are using GLFW library, this creation is done automatically.
The second step is to enable the depth test itself. To do that, you need to call:
glEnable(GL_DEPTH_TEST);
somewhere before you call your draw functions.
And, at last, at every frame draw, you must clear you depth buffer, calling:
glClear(GL_DEPTH_BUFFER_BIT);
but usually it is called as:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
to clear the color buffer as well.

Related

How to create a light source in OpenGL in the form of a cube

I am trying to create a lamp or light source in OpenGL in the form of a cube. My current code renders a cylinder sitting on a plane with textures whenever I run the program. I have defined planePositions and planeRotations and I have used those variables in a for loop to form a cube that will be my shining lamp. But for some reason, a lamp is not rendering at all. Is there a way to incorporate my current plane into the for loop or is there a better way to create a lamp? Here is my code:
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>
// GLM library
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <SOIL2.h>
using namespace std;
int width, height;
const double PI = 3.14159;
const float toRadians = PI / 180.0f;
// Input Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
// Initialize FOV
GLfloat fov = 45.f;
double cameraSpeedPerSecond = 2.5;
// Define Camera Attributes
glm::vec3 cameraPosition;
glm::vec3 target;
glm::vec3 cameraDirection;
glm::vec3 worldUp;
glm::vec3 cameraRight;
glm::vec3 cameraUp;
// Declare target prototype
glm::vec3 getTarget();
// Camera transformation prototype
void TransformCamera();
// Boolean for keys and mouse buttons
bool keys[1024], mouseButtons[3];
// Boolean to check camera transformations
bool isPanning = false, isOrbiting = false;
bool projectionIsPerspective = true;
// Radius, Pitch, and Yaw
GLfloat radius = 3.f, rawYaw = 0.f, rawPitch = 0.f, degYaw, degPitch;
GLfloat deltaTime = 0.f, lastFrame = 0.f;
GLfloat lastX = 400, lastY = 300, xChange, yChange;
bool firstMouseMove = true; // Detect inititial mouse movement
// Light source position
glm::vec3 lightPosition(1.0f, 1.0f, 1.0f);
void initCamera();
void UProcessInput(GLFWwindow* window);
// Draw Primitive(s)
void draw() {
GLenum mode = GL_TRIANGLES;
GLsizei indices = 62;
glDrawElements(mode, indices, GL_UNSIGNED_BYTE, nullptr);
}
// Create and Compile Shaders
static GLuint CompileShader(const string& source, GLuint shaderType) {
// Create Shader Object
GLuint shaderID = glCreateShader(shaderType);
const char* src = source.c_str();
// Attach source code to Shader object
glShaderSource(shaderID, 1, &src, nullptr);
// Compile Shader
glCompileShader(shaderID);
// Return ID of Compiled shader
return shaderID;
}
// Create Program Object
static GLuint CreateShaderProgram(const string& vertexShader, const string& fragmentShader) {
// Compile vertex shader
GLuint vertexShaderComp = CompileShader(vertexShader, GL_VERTEX_SHADER);
// Compile fragment shader
GLuint fragmentShaderComp = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
// Create program object
GLuint shaderProgram = glCreateProgram();
// Attch vertex and fragment shaders to program object
glAttachShader(shaderProgram, vertexShaderComp);
glAttachShader(shaderProgram, fragmentShaderComp);
// Link shaders to create executable
glLinkProgram(shaderProgram);
// Delete compiled vertex and fragment shaders
glDeleteShader(vertexShaderComp);
glDeleteShader(fragmentShaderComp);
// Return Shader Program
return shaderProgram;
}
int main(void) {
width = 640; height = 480;
GLFWwindow* window;
// Initialize the library
if (!glfwInit())
return -1;
// Create a windowed mode window and its OpenGL context
window = glfwCreateWindow(width, height, "Main Window", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwSetScrollCallback(window, scroll_callback);
glfwSetCursorPosCallback(window, cursor_position_callback);
glfwSetKeyCallback(window, key_callback);
// Make the window's context current
glfwMakeContextCurrent(window);
// Initialize GLEW
if (glewInit() != GLEW_OK)
cout << "Error!" << endl;
initCamera();
GLfloat cylinderVertices[] = {
// Base of the cylinder
// Triangle One // Color
// Vertex 0 // Red // UV
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.0,
// Vertex 1 // Green // UV
cos(0 * toRadians), sin(0 * toRadians), 0.0, 0.0, 1.0, 0.0, 1.0, 0.0,
// Vertex 2 // Blue // UV
cos(60 * toRadians), sin(60 * toRadians), 0.0, 0.0, 0.0, 1.0, 1.0, 0.0,
// Part of Triangle Two
// Vertex 3 // Purple // UV
cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, 1.0, 0.0,
// Part of Triangle Three
// Vertex 4 // Green // UV
cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, 1.0, 0.0,
// Part of Triangle Four
// Vertex 5 // Blue // UV
cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
// Part of Triangle Five
// Vertex 6 // Purple // UV
cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, 0.0, 0.0,
// Part of Triangle Six
// Vertex 7 // Green // UV
cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
// Sides of the cylinder
// Part of Triangle Seven
// Vertex 8 // Red // UV
cos(0 * toRadians), sin(0 * toRadians), 2.0, 1.0, 0.0, 0.0, 1.0, 1.0,
// Part of Triangle Eight
// Vertex 9 // Green // UV
cos(60 * toRadians), sin(60 * toRadians), 2.0, 0.0, 1.0, 0.0, 1.0, 1.0,
// Part of Triangle Nine
// Vertex 10 // Blue // UV
cos(120 * toRadians), sin(120 * toRadians), 2.0, 0.0, 0.0, 1.0, 1.0, 1.0,
// Part of Triangle Ten
// Vertex 11 // Purple // UV
cos(180 * toRadians), sin(180 * toRadians), 2.0, 1.0, 0.0, 1.0, 0.0, 1.0,
// Part of Triangle Eleven
// Vertex 12 // Red // UV
cos(240 * toRadians), sin(240 * toRadians), 2.0, 1.0, 0.0, 0.0, 0.0, 1.0,
// Part of Triangle Twelve
// Vertex 13 // Green // UV
cos(300 * toRadians), sin(300 * toRadians), 2.0, 0.0, 1.0, 0.0, 0.0, 1.0
};
// we need two index buffers, one for the plane, one for the cylinder
GLuint cylinderIBO, planeIBO, lampIBO;
// Define element indices
GLubyte cylinderIndices[] = {
// Bottom base
0,1,2,
0,2,3,
0,3,4,
0,4,5,
0,5,6,
0,6,7,
// Sides
1,2,8,
2,9,8,
2,3,9,
3,10,9,
3,4,10,
4,11,10,
5,11,4,
5,12,11,
5,6,12,
6,13,12,
6,1,13,
1,8,13
};
glGenBuffers(1, &cylinderIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // Load indices attributes
GLfloat planeVertices[] = {
// positon attributes (x,y,z)
-2.0f, 2.0f, 0.0f, // plane vertex 0
0.0f, 1.0f, 1.0f, // cyan
0.0f, 0.0, // UV
2.0f, 1.0f, -0.2f, // plane vertex 1
1.0f, 1.0f, 0.0f, // yellow
0.0f, 1.0f, // UV
-3.0f, 0.0f, 0.0f, // plane vertex 2
1.0f, 1.0f, 0.0f, // yellow
1.0f, 0.0, // UV
1.0f, -1.0f, -0.2f, // plane vertex 3
0.0f, 1.0f, 1.0f, // cyan
1.0f, 1.0f // UV
};
// Define element indicesd
GLubyte planeIndices[] = {
0,2,1,
2,3,1
};
// Plane Transforms
glm::vec3 planePositions[] = {
glm::vec3(0.0f, 0.0f, 0.5f),
glm::vec3(0.5f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.0f, -0.5f),
glm::vec3(-0.5f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.5f, 0.0f),
glm::vec3(0.0f, -0.5f, 0.0f)
};
glm::float32 planeRotations[] = {
0.0f, 90.0f, 0.0f, 50.0f, 90.0f, 90.0f
};
glGenBuffers(1, &planeIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // Load indices attributes
GLfloat lampVertices[] = {
-0.5, -0.5, 0.0, // index 0
-0.5, 0.5, 0.0, // index 1
0.5, -0.5, 0.0, // index 2
0.5, 0.5, 0.0 // index 3
};
GLubyte lampIndices[] = {
0, 1, 2,
1, 2, 3
};
glGenBuffers(1, &lampIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lampIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lampIndices), lampIndices, GL_STATIC_DRAW); // Load indices attributes
// Enable Depth Buffer
glEnable(GL_DEPTH_TEST);
// Wireframe mode
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
GLuint cylinderVBO, planeVBO, EBO, lampVBO, lampEBO;
glGenBuffers(1, &cylinderVBO); // Create VBO and returns ID
glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); // Select VBO and activate buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); // Load vertex attributes
glGenBuffers(1, &planeVBO); // Create VBO and returns ID
glBindBuffer(GL_ARRAY_BUFFER, planeVBO); // Select VBO and activate buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); // Load vertex attributes
glGenBuffers(1, &EBO); // Create EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Select EBO
glGenBuffers(1, &lampVBO); // Creat VBO and returns ID
glBindBuffer(GL_ARRAY_BUFFER, lampVBO); // Select VBO and activate buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(lampVertices), lampVertices, GL_STATIC_DRAW); // Load vertex attributes
glGenBuffers(1, &lampEBO); // Create EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lampEBO); // Select EBO
GLuint cylinderVAO, planeVAO, lampVAO;
// generate a bind new VAO for the cylinder
glGenVertexArrays(1, &cylinderVAO);
glBindVertexArray(cylinderVAO);
// specify which buffers the current VAO should use
glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
// generate a bind new VAO for the plane
glGenVertexArrays(1, &planeVAO);
glBindVertexArray(planeVAO);
// specify which buffers the current VAO should use
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
// generate a bind new VAO for the lamp
glGenVertexArrays(1, &lampVAO);
glBindVertexArray(lampVAO);
// specify which buffers the current VAO should use
glBindBuffer(GL_ARRAY_BUFFER, lampVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lampIBO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
glBindVertexArray(cylinderVAO);
glDrawElements(GL_TRIANGLES, 54, GL_UNSIGNED_BYTE, nullptr);
glBindVertexArray(planeVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
glBindVertexArray(lampVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
// Load textures
int crateTexWidth, crateTexHeight, gridTexWidth, gridTexHeight;
unsigned char* crateImage = SOIL_load_image("crate.png", &crateTexWidth, &crateTexHeight, 0, SOIL_LOAD_RGB);
unsigned char* gridImage = SOIL_load_image("grid.png", &gridTexWidth, &gridTexHeight, 0, SOIL_LOAD_RGB);
// Generate Textures
GLuint crateTexture;
glGenTextures(1, &crateTexture);
glBindTexture(GL_TEXTURE_2D, crateTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, crateTexWidth, crateTexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, crateImage);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(crateImage);
glBindTexture(GL_TEXTURE_2D, 0);
GLuint gridTexture;
glGenTextures(1, &gridTexture);
glBindTexture(GL_TEXTURE_2D, gridTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gridTexWidth, gridTexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, gridImage);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(gridImage);
glBindTexture(GL_TEXTURE_2D, 0);
// Vertex shader source code
string vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 vPosition;"
"layout(location = 1) in vec3 aColor;"
"layout(location = 2) in vec2 texCoord;"
"out vec3 oColor;"
"out vec2 oTexCoord;"
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 projection;"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(vPosition.x, vPosition.y, vPosition.z, 1.0);"
"oColor = aColor;"
"oTexCoord = texCoord;"
"}\n";
// Fragment shader source code
string fragmentShaderSource =
"#version 330 core\n"
"in vec3 oColor;"
"in vec2 oTexCoord;"
"out vec4 fragColor;"
"uniform sampler2D myTexture;"
"uniform vec3 objectColor;"
"uniform vec3 lightColor;"
"uniform vec3 lightPos;"
"void main()\n"
"{\n"
"fragColor = texture(myTexture, oTexCoord) * vec4(objectColor * lightColor, 1.0f);"
"}\n";
// Lamp Vertex shader source code
string lampVertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 vPosition;"
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 projection;"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(vPosition.x, vPosition.y, vPosition.z, 1.0);"
"}\n";
// Lamp Fragment shader source code
string lampFragmentShaderSource =
"#version 330 core\n"
"out vec4 fragColor;"
"void main()\n"
"{\n"
"fragColor = vec4(1.0f);"
"}\n";
// Creating Shader Program
GLuint shaderProgram = CreateShaderProgram(vertexShaderSource, fragmentShaderSource);
GLuint lampShaderProgram = CreateShaderProgram(lampVertexShaderSource, lampFragmentShaderSource);
double currentTime = glfwGetTime();
// loop until th euser closes window
while (!glfwWindowShouldClose(window)) {
double newTime = glfwGetTime();
deltaTime = newTime - currentTime;
currentTime = newTime;
// Resize window and graphics simultaneously
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Render here
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
UProcessInput(window);
// Use Shader Program exe and select VAO before drawing
glUseProgram(shaderProgram); // Call Shader per-frame when updating attributes
// Declare identity matrix
glm::mat4 modelMatrix(1.0f);
glm::mat4 viewMatrix(1.0f);
glm::mat4 projectionMatrix(1.0f);
// Initialize transforms
modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f, 0.5f, 0.5f));
// I increased the third argument from -3.0f to -6.0f to make the object smaller
// Moved the cup to the right by increasing the x coordinate
//viewMatrix = glm::translate(viewMatrix, glm::vec3(0.5f, 0.0f, -6.0f));
// I changed up somme of the arguments, so the object would tilt right instead of toward me
//viewMatrix = glm::rotate(viewMatrix, 45.0f * toRadians, glm::vec3(-0.5f, 1.0f, 1.5f));
//
// Transforms the camera: move the camera back (z axis)
viewMatrix = glm::lookAt(cameraPosition, cameraPosition + cameraDirection, worldUp);
if (projectionIsPerspective) {
projectionMatrix = glm::perspective(45.0f * toRadians, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
}
else
projectionMatrix = glm::ortho(-10.f, 10.f, -10.f * ((GLfloat)height / width), 10.f * ((GLfloat)height / width), 0.1f, 100.0f);
// Get matrix's uniform location and set matrix
// Select uniform shader and variable
GLuint modelLoc = glGetUniformLocation(shaderProgram, "model");
GLuint viewLoc = glGetUniformLocation(shaderProgram, "view");
GLuint projectionLoc = glGetUniformLocation(shaderProgram, "projection");
// Get light and object color, and light position location
GLint objectColorLoc = glGetUniformLocation(shaderProgram, "objectColor");
GLint lightColorLoc = glGetUniformLocation(shaderProgram, "lightColor");
GLint lightPosLoc = glGetUniformLocation(shaderProgram, "lightPos");
// Assign Light and Object Colors
glUniform3f(objectColorLoc, 0.46f, 0.36f, 0.25f);
glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f);
// Set light position
glUniform3f(lightColorLoc, lightPosition.x, lightPosition.y, lightPosition.z);
// Pass transform to Shader
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glBindTexture(GL_TEXTURE_2D, crateTexture);
glBindVertexArray(cylinderVAO);
glDrawElements(GL_TRIANGLES, 54, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, gridTexture);
glBindVertexArray(planeVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr); // User-defined VAO must be called before draw
for (GLuint i = 0; i < 4; i++) {
glm::mat4 modelMatrix(1.0f);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));
// Draw primitive(s)
draw();
}
// Unbind Shader exe and VOA after drawing per frame
glBindVertexArray(0); // In case different VAO will be used after
glUseProgram(0); // In case different shader will be used after
glUseProgram(lampShaderProgram);
// Get matrix's uniform location and set matrix
// Select uniform shader and variable
GLuint lampModelLoc = glGetUniformLocation(lampShaderProgram, "model");
GLuint lampViewLoc = glGetUniformLocation(lampShaderProgram, "view");
GLuint lampProjectionLoc = glGetUniformLocation(lampShaderProgram, "projection");
glUniformMatrix4fv(lampViewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(lampProjectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glBindVertexArray(lampVAO); // Calls lamp VAO
// Transform planes to form cube
for (GLuint i = 0; i < 6; i++) {
glm::mat4 modelMatrix;
modelMatrix = glm::translate(modelMatrix, planePositions[i] / glm::vec3(8.,8.,8.) + lightPosition);
modelMatrix = glm::rotate(modelMatrix, planeRotations[i] * toRadians, glm::vec3(0.0f, 1.0f, 0.0f));
modelMatrix = glm::scale(modelMatrix, glm::vec3(.125f, .125f, .125f));
if (i >= 4)
modelMatrix = glm::rotate(modelMatrix, planeRotations[i] * toRadians, glm::vec3(1.0f, 0.0f, 0.0f));
glUniformMatrix4fv(lampModelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));
// Draw primitive(s)
draw();
}
glBindVertexArray(0); // Deactivates vertex array object
glUseProgram(0); // In case different shader will be used after
// Swap front and back buffers
glfwSwapBuffers(window);
// Poll for and process events
glfwPollEvents();
}
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
void UProcessInput(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float cameraSpeed = cameraSpeedPerSecond * deltaTime;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
cameraPosition += cameraSpeed * cameraDirection;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
cameraPosition -= cameraSpeed * cameraDirection;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
cameraPosition -= glm::normalize(glm::cross(cameraDirection, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
cameraPosition += glm::normalize(glm::cross(cameraDirection, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
cameraPosition -= cameraSpeed * cameraUp;
if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
cameraPosition += cameraSpeed * cameraUp;
}
// Define Input Callback functions
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
if (action == GLFW_PRESS)
{
keys[key] = true;
if (key == GLFW_KEY_P) {
projectionIsPerspective = !projectionIsPerspective;
}
}
else if (action == GLFW_RELEASE)
keys[key] = false;
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
cameraSpeedPerSecond += yoffset;
if (cameraSpeedPerSecond < 0) {
cameraSpeedPerSecond = 0;
}
}
double oldXPos = 0;
double oldYPos = 0;
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) {
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
if (state == GLFW_PRESS)
{
float horizontalRotation = (xpos - oldXPos) * 0.01f;
float verticalRotation = (ypos - oldYPos) * -0.01f;
glm::mat4 rotationMat(1);
rotationMat = glm::rotate(rotationMat, horizontalRotation, cameraUp);
rotationMat = glm::rotate(rotationMat, verticalRotation, cameraRight);
cameraDirection = glm::vec3(rotationMat * glm::vec4(cameraDirection, 1.0));
cameraUp = glm::vec3(rotationMat * glm::vec4(cameraUp, 1.0));
cameraRight = glm::vec3(rotationMat * glm::vec4(cameraRight, 1.0));
}
oldXPos = xpos;
oldYPos = ypos;
}
void initCamera() {
cameraPosition = glm::vec3(6.f, 6.f, 6.f);
target = glm::vec3(1.f, 0.f, 0.f);
cameraDirection = glm::normalize(target - cameraPosition);
worldUp = glm::vec3(-1.f, -1.f, 0.f);
cameraRight = glm::normalize(glm::cross(worldUp, cameraDirection));
cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight));
cameraSpeedPerSecond = 2.5;
}

Location of cube in OpenGL

The output of this code is 25 cubs rotating .
The problem that I'm facing is the location of each cubes I don not know how to make them be in one line , Like for example every 5 cubes in one line and so on.
Note : I have added the Positions of cubes.
glm::vec3 cubePositions[] = {
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3(2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3(1.3f, -2.0f, -2.5f),
glm::vec3(1.5f, 2.0f, -2.5f),
glm::vec3(1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
};
while (!glfwWindowShouldClose(mainWindow))
{
glfwPollEvents();
glClearColor(0.0f, 0.1f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Camera transformation
glm::mat4 projection = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
projection = glm::perspective(glm::radians(45.0f), (float)WIDTH / (float)HEIGHT, 0.1f, 100.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
//Get uniform locations
GLint viewlLoc = glGetUniformLocation(ourShader.Program, "view");
glUniformMatrix4fv(viewlLoc, 1, GL_FALSE, glm::value_ptr(view));
GLint projlLoc = glGetUniformLocation(ourShader.Program, "projection");
glUniformMatrix4fv(projlLoc, 1, GL_FALSE, glm::value_ptr(projection));
// Call Shader Program
ourShader.Use();
glBindVertexArray(VAO);
for(unsigned int i = 0; i < 25; i++)
{
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
float angle = 20.0f * i;
angle = glfwGetTime() * 25.0f;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
}
glBindVertexArray(0);
glfwSwapBuffers(mainWindow);
glfwPollEvents();
}
Use glm::translate to add a translation to the model matrix of each individual cube, dependent on the index of the cube. e.g.:
for(unsigned int i = 0; i < 25; i++)
{
float dist = ; // distance between the cubes
float x = (i % 5) * dist;
float y = (i / 5) * dist;
float angle = 20.0f * i;
angle = glfwGetTime() * 25.0f;
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vector3(x, y, 0.0f));
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
}
Note, you've to define the distance (dist) between the cubes.
Note, the concatenation (multiplication *) of matrices is not Commutative.
If you want to rotate the entire block of cubes, then you've to do the translation before the rotation:
model = rotate * translate
Since glm::rotate respectively glm::translate, define a matrix and multiply the input matrix by the new matrix, glm::rotate has to be done before glm::translate:
glm::mat4 model = glm::mat4(1.0f);
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
model = glm::translate(model, glm::vector3(x, y, 0.0f));
You can use the algorithm to calculate the cubePositions:
#include <vector>
std::vector<glm::vec3> cubePositions;
for(unsigned int i = 0; i < 25; i++)
{
float dist = 5.0f; // distance between the cubes
float x = (i % 5) * dist;
float y = (i / 5) * dist;
cubePositions.push_back(glm::vec3(x, y, 0.0f));
}

rotating cubes differently

I have 25 cubes that i want to rotate each one differently this is my code on both x and y axis
i tried using rand() but it kept rotating them weirdly and all of them rotate in the same directions
this is in the game loop
for (unsigned int i = 0; i < 25; i++)
{
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
view = glm::translate(model, glm::vec3(0.0f, 0.0f, -10.0f));
float angle = 20.0f * i;
angle = glfwGetTime() * 20.0f;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.0f, 0.5f));
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
GLint projLoc = glGetUniformLocation(ourShader.Program, "projection");
glUniformMatrix4fv(projLoc, 1, GL_FALSE,
glm::value_ptr(projection));
glDrawArrays(GL_TRIANGLES, 0, 36);
}
Since there is no actual question, I try to give some comments on the posted code
that could explain the unexpected behavior of the resulting program.
The angle variable is initialised, then assigned immediately with a new
value ; only this new value is relevant, then the cubes should all rotate
at the rate of 20 degrees per second. (this is not a problem)
The view matrix is reassigned with a new value for each object! It is
extremely unlikely that this is what you want.
It's like if, while drawing a single frame, you move the camera in front of
each object being drawn ; if you move the camera and the object the same way,
then everything is displayed at the same place in the rendered frame.
(I think this is the main problem)
You should choose once for all the view matrix (as well as the projection
matrix) for the whole frame.
Some other comments, not directly related:
You should retrieve the uniform locations once for all before the loop
(and even at the beginning of the program) since they won't change as long
as you use the same shader program.
The glUniformMatrix4fv() calls for projection and view should
occur once for all before the loop; only the model matrix changes from
one object to another.
That could look like this
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
GLint projLoc = glGetUniformLocation(ourShader.Program, "projection");
glm::mat4 projection = ... already known ...
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glm::mat4 view = glm::mat4(1.0f);
// adjust to the layout of your scene
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -10.0f));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
for(unsigned int i = 0; i < 25; i++)
{
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
// the same rotation rate but a different offset for each object
float angle = 20.0f * i;
angle += std::fmod(glfwGetTime() * 20.0f, 360.0f);
// choose x or y rotation axis
auto axis=(i%2) ? glm::vec3(1.0f, 0.0f, 0.0f) : glm::vec3(0.0f, 1.0f, 0.0f);
model = glm::rotate(model, glm::radians(angle), axis);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
}

Can't get perspective to work with my image

So I'm following LearnOpenGL tutorials for the camera. I am trying to render a cube (definied with the vector of verts) and just circle around the cube to make sure it has rendered properly. I can render the front face of the cube just fine, but as soon as I switch the shader to use MVP nothing renders
void GraphicsProgram::run_program()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
state = RUNNING;
// TODO: Move these into their respective classes
// Hardcoded for some testing
// ----------------------------------------------
const char *vertexShaderPath = "vertex_shader.vs";
const char *fragmentShaderPath = "fragment_shader.fs";
Shader firstShader = Shader(vertexShaderPath, fragmentShaderPath);
std::vector<Vertex> verts;
Vertex v1, v2, v3, v4, v5, v6, v7, v8;
v1.position = { -0.5, -0.5, +0.5 };
v2.position = { +0.5, -0.5, +0.5 };
v3.position = { +0.5, +0.5, +0.5 };
v4.position = { -0.5, +0.5, +0.5 };
v5.position = { +0.5, -0.5, -0.5 };
v6.position = { +0.5, +0.5, -0.5 };
v7.position = { -0.5, +0.5, -0.5 };
v8.position = { -0.5, -0.5, -0.5 };
verts.push_back(v1);
verts.push_back(v2);
verts.push_back(v3);
verts.push_back(v4);
verts.push_back(v5);
verts.push_back(v6);
verts.push_back(v7);
verts.push_back(v8);
std::vector<unsigned int> indicies = {
0, 1, 2, 0, 2, 3, // front
1, 4, 5, 1, 5, 2, // right
4, 7, 6, 4, 6, 7, // back
7, 0, 3, 7, 3, 6, // left
3, 2, 5, 3, 5, 6, // top
7, 4, 1, 7, 1, 0 // bottom
};
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(Vertex), &verts[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(unsigned int), &indicies[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glUseProgram(firstShader.shaderID);
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
firstShader.set_mat4("projection", projection);
while (state == RUNNING) {
currentFrame = (float)SDL_GetTicks() / 1000;
deltaTime = lastFrame - currentFrame;
lastFrame = currentFrame;
process_input();
glUseProgram(firstShader.shaderID);
glm::mat4 view;
float radius = 10.0f;
float camX = sin((float)SDL_GetTicks() / 1000) * radius;
float camZ = cos((float)SDL_GetTicks() / 1000) * radius;
view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
firstShader.set_mat4("view", view);
glBindVertexArray(VAO);
glm::mat4 model;
model = glm::translate(model, glm::vec3(0.0, 0.0, 0.0));
float angle = 0.0;
model = glm::rotate(model, glm::radians(angle), glm::vec3(0,0,0));
firstShader.set_mat4("model", model);
glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0);
SDL_GL_SwapWindow(window);
}
shutdown_program();
}
Vertex struct:
struct Vertex {
glm::vec3 position;
glm::vec3 normal;
glm::vec2 texCoord;
};
Vertex Shader code:
#version 330 core
layout (location = 0) in vec3 aPos;
out vec4 vertexColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() {
gl_Position = projection * view * model * vec4(aPos, 1.0f);
vertexColor = vec4(abs(aPos.x), abs(aPos.y), abs(aPos.z), 1.0);
}
Fragment Shader:
#version 330 core
in vec4 vertexColor;
out vec4 fragColor;
void main() {
fragColor = vertexColor;
}
The vertex shader I used originally just took in the vertex positions.
You have to initialize the matrix variables glm::mat4 model and glm::mat4 view.
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);
....
glm::mat4 view(1.0f);
You missed to set a proper rotation axis in the glm::rotate:
model = glm::rotate(model, glm::radians(angle),
glm::vec3(1.0,0,0)); // e.g. (1, 0, 0) instead of (0, 0, 0)
You have to clear the default farmebuffer before every frame (glClear):
glClearColor(0.0, 0.0, 0.0, 1.0);
while (state == RUNNING)
{
glClear(GL_COLOR_BUFFER_BIT);
.....
You should enable the Depth Test and clear the depth buffer too:
glEnable(GL_DEPTH_TEST);
glClearColor(0.0, 0.0, 0.0, 1.0);
while (state == RUNNING)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
.....

OpenGL: Fish-eyes effect and how to avoid this

I'm trying to model the Solar System and I'm experiencing the Fish-eyes effects.
As you can see from the picture, the sun is at the centre, the Earth is translated 20 units to the x-axis and it doesn't look like a sphere anymore.
In glm::lookAt function, I set the field of view (is this FoVx?, I read from wiki, this is horizontal field of view so I think this is FoVx.) to be 80 degree, aspect ratio is 5.4f / 3.0f (most of application set the aspect ratio to be 4/3 but if I use this ratio, these planets look exactly like an ellipse!).
So how can I solve this problem? As the Earth would be orbiting around the Sun, and it should be always be a sphere at any angle and distance of view. Maybe I haven't completely understand the perspective, view matrix etc. Really need some help.
Here is the code which I used to render the Sun and the Earth:
void renderSun(int i){
glPushMatrix();
glLoadIdentity();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_ID[0]);
glUniform1i(texture_Location, 0);
glm::mat4 Projection = glm::perspective(90.0f, 5.4f / 3.0f, 1.0f, 100.0f);
glm::mat4 View = glm::lookAt(
glm::vec3(0, 30, 1),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
/* Animations */
GLfloat angle = (GLfloat) (i);
//View = glm::translate(View, glm::vec3(-2.0f, 0.0f, 0.0f));
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f));
/* ******* */
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
glDrawElements(GL_TRIANGLES, numsToDraw, GL_UNSIGNED_INT, NULL);
glPopMatrix();
}
void renderEarth(int i){
glPushMatrix();
glLoadIdentity();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_ID[3]);
glUniform1i(texture_Location, 0);
//glm::mat4 Projection = glm::ortho(0.f, 800.f, 0.f, 400.f, -5.f, 5.f );
glm::mat4 Projection = glm::perspective(80.0f, 5.4f / 3.0f, 1.0f, 100.0f);
glm::mat4 View = glm::lookAt(
glm::vec3(0, 30, 2),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
/* Animations */
GLfloat angle = (GLfloat) (i);
View = glm::translate(View, glm::vec3(30.0f, 0.0f, 0.0f));
//View = glm::scale(View, glm::vec3(4.0f, 5.0f, 4.0f));
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f));
/* ******* */
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
glDrawElements(GL_TRIANGLES, numsToDraw, GL_UNSIGNED_INT, NULL);
glPopMatrix();
}