Reputation: 65
I have some OpenGL code I am trying to use to render a pyramid, but only one source is emitting light (the one on the left.) I want one lamp to emit white light, and another to emit green. I can only get the green lamp to work.
#include <iostream> // cout, cerr
#include <cstdlib> // EXIT_FAILURE
#include <GL/glew.h> // GLEW library
#include <GLFW/glfw3.h> // GLFW library
#define STB_IMAGE_IMPLEMENTATION //Image Header
#include <C:\Users\thead\Documents\School and Studying\Template\OpenGLSample\OpenGLSample\stb_image.h>
#include <C:\Users\thead\Documents\School and Studying\Template\OpenGLSample\OpenGLSample\camera.h> // Camera class
// GLM Math Header inclusions
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std; // Standard namespace
using namespace std; // Standard namespace
/*Shader program Macro*/
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version " core \n" #Source
#endif
// Unnamed namespace
namespace
{
const char* const WINDOW_TITLE = "Tutorial 6.3"; // Macro for window title
// Variables for window width and height
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
// Stores the GL data relative to a given mesh
struct GLMesh
{
GLuint vao; // Handle for the vertex array object
GLuint vbo; // Handle for the vertex buffer object
GLuint nVertices; // Number of indices of the mesh
};
// Main GLFW window
GLFWwindow* gWindow = nullptr;
// Triangle mesh data
GLMesh gMesh;
// Texture
GLuint gTextureId;
glm::vec2 gUVScale(5.0f, 5.0f);
GLint gTexWrapMode = GL_REPEAT;
// Shader programs
GLuint gCubeProgramId;
GLuint gLampProgramId;
// camera
Camera gCamera(glm::vec3(0.0f, 0.0f, 7.0f));
float gLastX = WINDOW_WIDTH / 2.0f;
float gLastY = WINDOW_HEIGHT / 2.0f;
bool gFirstMouse = true;
// timing
float gDeltaTime = 0.0f; // time between current frame and last frame
float gLastFrame = 0.0f;
// Subject position and scale
glm::vec3 gCubePosition(0.0f, 0.0f, 0.0f);
glm::vec3 gCubeScale(2.0f);
// Light color
glm::vec3 gObjectColor(1.f, 0.2f, 0.0f);
glm::vec3 gLightColor[] = {
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(1.0f, 0.0f, 0.0f)
};
// Light position and scale
glm::vec3 gLightPosition[] = {
glm::vec3(-2.5f, 3.5f, 0.0f),
glm::vec3(1.5f, 1.0f, 0.0f)
};
glm::vec3 gLightScale(0.3f);
}
/* User-defined Function prototypes to:
* initialize the program, set the window size,
* redraw graphics on the window when resized,
* and render graphics on the screen
*/
bool UInitialize(int, char*[], GLFWwindow** window);
void UResizeWindow(GLFWwindow* window, int width, int height);
void UProcessInput(GLFWwindow* window);
void UMousePositionCallback(GLFWwindow* window, double xpos, double ypos);
void UMouseScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
void UMouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
void UCreateMesh(GLMesh &mesh);
void UDestroyMesh(GLMesh &mesh);
bool UCreateTexture(const char* filename, GLuint &textureId);
void UDestroyTexture(GLuint textureId);
void URender();
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint &programId);
void UDestroyShaderProgram(GLuint programId);
/* Cube Vertex Shader Source Code*/
const GLchar * cubeVertexShaderSource = GLSL(440,
layout(location = 0) in vec3 position; // VAP position 0 for vertex position data
layout(location = 1) in vec3 normal; // VAP position 1 for normals
layout(location = 2) in vec2 textureCoordinate;
out vec3 vertexNormal; // For outgoing normals to fragment shader
out vec3 vertexFragmentPos; // For outgoing color / pixels to fragment shader
out vec2 vertexTextureCoordinate;
//Uniform / 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); // Transforms vertices into clip coordinates
vertexFragmentPos = vec3(model * vec4(position, 1.0f)); // Gets fragment / pixel position in world space only (exclude view and projection)
vertexNormal = mat3(transpose(inverse(model))) * normal; // get normal vectors in world space only and exclude normal translation properties
vertexTextureCoordinate = textureCoordinate;
}
);
/* Cube Fragment Shader Source Code*/
const GLchar * cubeFragmentShaderSource = GLSL(440,
in vec3 vertexNormal; // For incoming normals
in vec3 vertexFragmentPos; // For incoming fragment position
in vec2 vertexTextureCoordinate;
out vec4 fragmentColor; // For outgoing cube color to the GPU
// Uniform / Global variables for object color, light color, light position, and camera/view position
uniform vec3 objectColor;
uniform vec3 lightColor;
uniform vec3 lightPos;
uniform vec3 viewPosition;
uniform sampler2D uTexture; // Useful when working with multiple textures
uniform vec2 uvScale;
void main()
{
/*Phong lighting model calculations to generate ambient, diffuse, and specular components*/
//Calculate Ambient lighting
float ambientStrength = 0.1f; // Set ambient or global lighting strength
vec3 ambient = ambientStrength * lightColor; // Generate ambient light color
//Calculate Diffuse lighting*/
vec3 norm = normalize(vertexNormal); // Normalize vectors to 1 unit
vec3 lightDirection = normalize(lightPos - vertexFragmentPos); // Calculate distance (light direction) between light source and fragments/pixels on cube
float impact = max(dot(norm, lightDirection), 0.0);// Calculate diffuse impact by generating dot product of normal and light
vec3 diffuse = impact * lightColor; // Generate diffuse light color
//Calculate Specular lighting
float specularIntensity = 0.8f; // Set specular light strength
float highlightSize = 16.0f; // Set specular highlight size
vec3 viewDir = normalize(viewPosition - vertexFragmentPos); // Calculate view direction
vec3 reflectDir = reflect(-lightDirection, norm);// Calculate reflection vector
//Calculate specular component
float specularComponent = pow(max(dot(viewDir, reflectDir), 0.0), highlightSize);
vec3 specular = specularIntensity * specularComponent * lightColor;
// Texture holds the color to be used for all three components
vec4 textureColor = texture(uTexture, vertexTextureCoordinate * uvScale);
// Calculate phong result
vec3 phong = (ambient + diffuse + specular) * textureColor.xyz;
fragmentColor = vec4(phong, 1.0f); // Send lighting results to GPU
}
);
/* Lamp Shader Source Code*/
const GLchar * lampVertexShaderSource = GLSL(440,
layout (location = 0) in vec3 position; // VAP position 0 for vertex position data
//Uniform / 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); } ); // Transforms vertices into clip coordinates
/* Fragment Shader Source Code*/
const GLchar * lampFragmentShaderSource = GLSL(440,
out vec4 fragmentColor; // For outgoing lamp color (smaller cube) to the GPU
void main() {
fragmentColor = vec4(1.0f, 1.0f, 1.0f, 1.0f); // Set color to green (0.0f, 1.0f, 0.0f) with alpha 1.0
}
);
// Images are loaded with Y axis going down, but OpenGL's Y axis goes up, so let's flip it
void flipImageVertically(unsigned char *image, int width, int height, int channels)
{
for (int j = 0; j < height / 2; ++j)
{
int index1 = j * width * channels;
int index2 = (height - 1 - j) * width * channels;
for (int i = width * channels; i > 0; --i)
{
unsigned char tmp = image[index1];
image[index1] = image[index2];
image[index2] = tmp;
++index1;
++index2;
}
}
}
int main(int argc, char* argv[])
{
if (!UInitialize(argc, argv, &gWindow))
return EXIT_FAILURE;
// Create the mesh
UCreateMesh(gMesh); // Calls the function to create the Vertex Buffer Object
// Create the shader programs
if (!UCreateShaderProgram(cubeVertexShaderSource, cubeFragmentShaderSource, gCubeProgramId))
return EXIT_FAILURE;
if (!UCreateShaderProgram(lampVertexShaderSource, lampFragmentShaderSource, gLampProgramId))
return EXIT_FAILURE;
// Load texture
const char * texFilename = "C:/Users/thead/Documents/School and Studying/5-2/BRICKS.png";
if (!UCreateTexture(texFilename, gTextureId))
{
cout << "Failed to load texture " << texFilename << endl;
return EXIT_FAILURE;
}
// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)
glUseProgram(gCubeProgramId);
// We set the texture as texture unit 0
glUniform1i(glGetUniformLocation(gCubeProgramId, "uTexture"), 0);
// Sets the background color of the window to black (it will be implicitely used by glClear)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// render loop
// -----------
while (!glfwWindowShouldClose(gWindow))
{
// per-frame timing
// --------------------
float currentFrame = glfwGetTime();
gDeltaTime = currentFrame - gLastFrame;
gLastFrame = currentFrame;
// input
// -----
UProcessInput(gWindow);
// Render this frame
URender();
glfwPollEvents();
}
// Release mesh data
UDestroyMesh(gMesh);
// Release texture
UDestroyTexture(gTextureId);
// Release shader programs
UDestroyShaderProgram(gCubeProgramId);
UDestroyShaderProgram(gLampProgramId);
exit(EXIT_SUCCESS); // Terminates the program successfully
}
// Initialize GLFW, GLEW, and create a window
bool UInitialize(int argc, char* argv[], GLFWwindow** window)
{
// GLFW: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// GLFW: window creation
// ---------------------
*window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, NULL, NULL);
if (*window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return false;
}
glfwMakeContextCurrent(*window);
glfwSetFramebufferSizeCallback(*window, UResizeWindow);
glfwSetCursorPosCallback(*window, UMousePositionCallback);
glfwSetScrollCallback(*window, UMouseScrollCallback);
glfwSetMouseButtonCallback(*window, UMouseButtonCallback);
// tell GLFW to capture our mouse
glfwSetInputMode(*window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// GLEW: initialize
// ----------------
// Note: if using GLEW version 1.13 or earlier
glewExperimental = GL_TRUE;
GLenum GlewInitResult = glewInit();
if (GLEW_OK != GlewInitResult)
{
std::cerr << glewGetErrorString(GlewInitResult) << std::endl;
return false;
}
// Displays GPU OpenGL version
cout << "INFO: OpenGL Version: " << glGetString(GL_VERSION) << endl;
return true;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
void UProcessInput(GLFWwindow* window)
{
static const float cameraSpeed = 2.5f;
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
gCamera.ProcessKeyboard(FORWARD, gDeltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
gCamera.ProcessKeyboard(BACKWARD, gDeltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
gCamera.ProcessKeyboard(LEFT, gDeltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
gCamera.ProcessKeyboard(RIGHT, gDeltaTime);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
void UResizeWindow(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void UMousePositionCallback(GLFWwindow* window, double xpos, double ypos)
{
if (gFirstMouse)
{
gLastX = xpos;
gLastY = ypos;
gFirstMouse = false;
}
float xoffset = xpos - gLastX;
float yoffset = gLastY - ypos; // reversed since y-coordinates go from bottom to top
gLastX = xpos;
gLastY = ypos;
gCamera.ProcessMouseMovement(xoffset, yoffset);
}
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void UMouseScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
gCamera.ProcessMouseScroll(yoffset);
}
// glfw: handle mouse button events
// --------------------------------
void UMouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
switch (button)
{
case GLFW_MOUSE_BUTTON_LEFT:
{
if (action == GLFW_PRESS)
cout << "Left mouse button pressed" << endl;
else
cout << "Left mouse button released" << endl;
}
break;
case GLFW_MOUSE_BUTTON_MIDDLE:
{
if (action == GLFW_PRESS)
cout << "Middle mouse button pressed" << endl;
else
cout << "Middle mouse button released" << endl;
}
break;
case GLFW_MOUSE_BUTTON_RIGHT:
{
if (action == GLFW_PRESS)
cout << "Right mouse button pressed" << endl;
else
cout << "Right mouse button released" << endl;
}
break;
default:
cout << "Unhandled mouse button event" << endl;
break;
}
}
// Functioned called to render a frame
void URender()
{
// Enable z-depth
glEnable(GL_DEPTH_TEST);
// Clear the frame and z buffers
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Activate the cube VAO (used by cube and lamp)
glBindVertexArray(gMesh.vao);
// CUBE: draw cube(s)
//----------------
// Set the shader to be used
for (unsigned int i = 0; i < 2; i++) {
glUseProgram(gCubeProgramId);
// Model matrix: transformations are applied right-to-left order
glm::mat4 model = glm::translate(gCubePosition) * glm::scale(gCubeScale);
// camera/view transformation
glm::mat4 view = gCamera.GetViewMatrix();
// Creates a perspective projection
glm::mat4 projection = glm::perspective(glm::radians(gCamera.Zoom), (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, 0.1f, 100.0f);
// Retrieves and passes transform matrices to the Shader program
GLint modelLoc = glGetUniformLocation(gCubeProgramId, "model");
GLint viewLoc = glGetUniformLocation(gCubeProgramId, "view");
GLint projLoc = glGetUniformLocation(gCubeProgramId, "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));
// Reference matrix uniforms from the Cube Shader program for the cube color, light color, light position, and camera position
GLint objectColorLoc = glGetUniformLocation(gCubeProgramId, "objectColor");
GLint lightColorLoc = glGetUniformLocation(gCubeProgramId, "lightColor");
GLint lightPositionLoc = glGetUniformLocation(gCubeProgramId, "lightPos");
GLint viewPositionLoc = glGetUniformLocation(gCubeProgramId, "viewPosition");
// Pass color, light, and camera data to the Cube Shader program's corresponding uniforms
glUniform3f(objectColorLoc, gObjectColor.r, gObjectColor.g, gObjectColor.b);
glUniform3f(lightColorLoc, gLightColor[i].r, gLightColor[i].g, gLightColor[i].b);
glUniform3f(lightPositionLoc, gLightPosition[i].x, gLightPosition[i].y, gLightPosition[i].z);
const glm::vec3 cameraPosition = gCamera.Position;
glUniform3f(viewPositionLoc, cameraPosition.x, cameraPosition.y, cameraPosition.z);
GLint UVScaleLoc = glGetUniformLocation(gCubeProgramId, "uvScale");
glUniform2fv(UVScaleLoc, 1, glm::value_ptr(gUVScale));
// bind textures on corresponding texture units
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gTextureId);
// Draws the triangles
glDrawArrays(GL_TRIANGLES, 0, gMesh.nVertices);
// LAMP: draw lamp
//----------------
glUseProgram(gLampProgramId);
//Transform the smaller cube used as a visual que for the light source
model = glm::translate(gLightPosition[i]) * glm::scale(gLightScale);
// Reference matrix uniforms from the Lamp Shader program
modelLoc = glGetUniformLocation(gLampProgramId, "model");
viewLoc = glGetUniformLocation(gLampProgramId, "view");
projLoc = glGetUniformLocation(gLampProgramId, "projection");
// Pass matrix data to the Lamp Shader program's matrix uniforms
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));
glDrawArrays(GL_TRIANGLES, 0, gMesh.nVertices);
}
// Deactivate the Vertex Array Object and shader program
glBindVertexArray(0);
glUseProgram(0);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
glfwSwapBuffers(gWindow); // Flips the the back buffer with the front buffer every frame.
}
// Implements the UCreateMesh function
void UCreateMesh(GLMesh &mesh)
{
// Position, Normal, and Texture Coordinate data
GLfloat verts[] = {
//Positions //Normals //Texture Coordinates
// Base
-0.5f, 0.0f, -0.5f, 0.5f, -1.0f, 0.5f, 0.0f, 0.0f,
0.5f, 0.0f, -0.5f, -0.5f, -1.0f, 0.5f, 1.0f, 0.0f,
0.5f, 0.0f, 0.5f, -0.5f, -1.0f, -0.5f, 1.0f, 1.0f,
0.5f, 0.0f, 0.5f, -0.5f, -1.0f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.0f, 0.5f, 0.5f, -1.0f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.0f, -0.5f, 0.5f, -1.0f, 0.5f, 0.0f, 0.0f,
// Sides
0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f, // apex and side
-0.5f, 0.0f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, // base
0.5f, 0.0f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // base
0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.5f, // apex and side
0.5f, 0.0f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // base
0.5f, 0.0f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // base
0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, // apex and side
0.5f, 0.0f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // base
-0.5f, 0.0f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, // base
0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.5f, 0.5f, // apex and side
-0.5f, 0.0f, 0.5f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // base
-0.5f, 0.0f, -0.5f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // base
};
const GLuint floatsPerVertex = 3;
const GLuint floatsPerNormal = 3;
const GLuint floatsPerUV = 2;
mesh.nVertices = sizeof(verts) / (sizeof(verts[0]) * (floatsPerVertex + floatsPerNormal + floatsPerUV));
glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
glBindVertexArray(mesh.vao);
// Create 2 buffers: first one for the vertex data; second one for the indices
glGenBuffers(1, &mesh.vbo);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo); // Activates the buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU
// Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
GLint stride = sizeof(float) * (floatsPerVertex + floatsPerNormal + floatsPerUV);// The number of floats before each
// Create Vertex Attribute Pointers
glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, floatsPerNormal, GL_FLOAT, GL_FALSE, stride, (void*)(sizeof(float) * floatsPerVertex));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, floatsPerUV, GL_FLOAT, GL_FALSE, stride, (void*)(sizeof(float) * (floatsPerVertex + floatsPerNormal)));
glEnableVertexAttribArray(2);
}
void UDestroyMesh(GLMesh &mesh)
{
glDeleteVertexArrays(1, &mesh.vao);
glDeleteBuffers(1, &mesh.vbo);
}
/*Generate and load the texture*/
bool UCreateTexture(const char* filename, GLuint &textureId)
{
int width, height, channels;
unsigned char *image = stbi_load(filename, &width, &height, &channels, 0);
if (image)
{
flipImageVertically(image, width, height, channels);
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (channels == 3)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
else if (channels == 4)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
else
{
cout << "Not implemented to handle image with " << channels << " channels" << endl;
return false;
}
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(image);
glBindTexture(GL_TEXTURE_2D, 0); // Unbind the texture
return true;
}
// Error loading the image
return false;
}
void UDestroyTexture(GLuint textureId)
{
glGenTextures(1, &textureId);
}
// Implements the UCreateShaders function
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint &programId)
{
// Compilation and linkage error reporting
int success = 0;
char infoLog[512];
// Create a Shader program object.
programId = glCreateProgram();
// Create the vertex and fragment shader objects
GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
// Retrive the shader source
glShaderSource(vertexShaderId, 1, &vtxShaderSource, NULL);
glShaderSource(fragmentShaderId, 1, &fragShaderSource, NULL);
// Compile the vertex shader, and print compilation errors (if any)
glCompileShader(vertexShaderId); // compile the vertex shader
// check for shader compile errors
glGetShaderiv(vertexShaderId, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShaderId, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
return false;
}
glCompileShader(fragmentShaderId); // compile the fragment shader
// check for shader compile errors
glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShaderId, sizeof(infoLog), NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
return false;
}
// Attached compiled shaders to the shader program
glAttachShader(programId, vertexShaderId);
glAttachShader(programId, fragmentShaderId);
glLinkProgram(programId); // links the shader program
// check for linking errors
glGetProgramiv(programId, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(programId, sizeof(infoLog), NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
return false;
}
glUseProgram(programId); // Uses the shader program
return true;
}
void UDestroyShaderProgram(GLuint programId)
{
glDeleteProgram(programId);
}
Specifically, the for loop is supposed to run over both and render the lights, but it seems to be skipping the second source:
for (unsigned int i = 0; i < 2; i++) {
glUseProgram(gCubeProgramId);
// Model matrix: transformations are applied right-to-left order
glm::mat4 model = glm::translate(gCubePosition) * glm::scale(gCubeScale);
// camera/view transformation
glm::mat4 view = gCamera.GetViewMatrix();
// Creates a perspective projection
glm::mat4 projection = glm::perspective(glm::radians(gCamera.Zoom), (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, 0.1f, 100.0f);
// Retrieves and passes transform matrices to the Shader program
GLint modelLoc = glGetUniformLocation(gCubeProgramId, "model");
GLint viewLoc = glGetUniformLocation(gCubeProgramId, "view");
GLint projLoc = glGetUniformLocation(gCubeProgramId, "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));
// Reference matrix uniforms from the Cube Shader program for the cube color, light color, light position, and camera position
GLint objectColorLoc = glGetUniformLocation(gCubeProgramId, "objectColor");
GLint lightColorLoc = glGetUniformLocation(gCubeProgramId, "lightColor");
GLint lightPositionLoc = glGetUniformLocation(gCubeProgramId, "lightPos");
GLint viewPositionLoc = glGetUniformLocation(gCubeProgramId, "viewPosition");
// Pass color, light, and camera data to the Cube Shader program's corresponding uniforms
glUniform3f(objectColorLoc, gObjectColor.r, gObjectColor.g, gObjectColor.b);
glUniform3f(lightColorLoc, gLightColor[i].r, gLightColor[i].g, gLightColor[i].b);
glUniform3f(lightPositionLoc, gLightPosition[i].x, gLightPosition[i].y, gLightPosition[i].z);
const glm::vec3 cameraPosition = gCamera.Position;
glUniform3f(viewPositionLoc, cameraPosition.x, cameraPosition.y, cameraPosition.z);
GLint UVScaleLoc = glGetUniformLocation(gCubeProgramId, "uvScale");
glUniform2fv(UVScaleLoc, 1, glm::value_ptr(gUVScale));
// bind textures on corresponding texture units
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gTextureId);
// Draws the triangles
glDrawArrays(GL_TRIANGLES, 0, gMesh.nVertices);
// LAMP: draw lamp
//----------------
glUseProgram(gLampProgramId);
//Transform the smaller cube used as a visual que for the light source
model = glm::translate(gLightPosition[i]) * glm::scale(gLightScale);
// Reference matrix uniforms from the Lamp Shader program
modelLoc = glGetUniformLocation(gLampProgramId, "model");
viewLoc = glGetUniformLocation(gLampProgramId, "view");
projLoc = glGetUniformLocation(gLampProgramId, "projection");
// Pass matrix data to the Lamp Shader program's matrix uniforms
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));
glDrawArrays(GL_TRIANGLES, 0, gMesh.nVertices);
}
Tried to create a for loop to emit two lights, only the first loop it emitting
Upvotes: 0
Views: 115
Reputation: 535
Your cube shader only has uniform for a single light source. If you want to account for multiple lights you'll need to store multiple light sources position, color, etc...
Here you try to render the cube twice, lit by only one light each time so the first pass is discarded. Instead you should only have one call to glDrawArrays but 2 times (or n times for the general case) calls to glUniform3f, with different locations.
see https://learnopengl.com/Lighting/Multiple-lights for details.
Upvotes: 0