I broke my program...

So I had a program where I displayed a bunny to the screen, then shaded it with Phong shading, and make it rotate/scale with up/down/left/right.

After I finished that I decided to make it so that it was a class that could display multiple objects that were loaded into it. Somehow I have broken the program and I can’t figure out what went wrong.

As of right now it will display the outline of the bunny, but that’s it. The controls don’t work, the shading doesn’t work. Just the bunny outline.

Here is my code:

OpenGLView.h


#pragma once

#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include "glm\glm.hpp"

#include <string>
#include <vector>

class OpenGLView
{
public:
	OpenGLView();
	struct Asset
	{
		GLuint shaderProgramID;
		GLuint vertexArray;
		GLuint vertexBuffer;
		GLuint normalBuffer;
		GLuint elementBuffer;
		GLint elementsSize;

		Asset()
		{
			shaderProgramID = -1;
			vertexArray = -1;
			GLuint vertexBuffer = -1;
			GLuint normalBuffer = -1;
			GLuint elementBuffer = -1;
			GLint elementsSize = -1;
		}
	};

	struct AssetInstance
	{
		Asset asset;
		glm::vec3 position;
		glm::vec3 scale;
		glm::vec3 materialColor;
		glm::vec3 materialSpecularColor;
		GLfloat materialShininess;
	};

	void run();
	bool loadObjSimple(
		std::string path,
		std::vector<glm::vec3>& vertices,
		std::vector<glm::vec3>& normals,
		std::vector<unsigned int>& elements);
	bool initializeAndSetupWindow(GLint windowWidth, GLint windowHeight, std::string windowTitle);
	GLuint loadShaders(const char * vertex_file_path, const char * fragment_file_path);
	void loadBunnyAsset();
	void loadUniforms(AssetInstance asset);
private:
	struct Light
	{
		glm::vec3 position;
		glm::vec3 intensities;
		GLfloat attenuation;
		GLfloat ambientCoefficient;
	} light;
	Asset bunny;
	GLFWwindow * window;
	//glm::mat4 model;
	//glm::mat4 view;
	glm::vec3 cameraPosition;
	void OpenGLView::getKeys(/*GLFWwindow* window, int key, int scancode, int action, int mods*/);
	glm::mat4 translate(glm::vec3 position);
	glm::mat4 scale(glm::vec3 size);
};

OpenGLView.cpp


//Portions of this code have been taken from:
//http://www.opengl-tutorial.org
//http://www.tomdalling.com/blog/modern-opengl/
//Shen Chen's Assignment 1 & 2 tutorial

#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define MIN(x,y) ((x) < (y) ? (x) : (y))

#include <iostream>
#include "glm\gtc\matrix_transform.hpp"
#include "OpenGLView.h"
#include "controls.h"

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define FILE_PATH "bunny.obj"


OpenGLView::OpenGLView()
{
	light.position = glm::vec3(0.0f, 7.0f, 3.0f);
	light.intensities = glm::vec3(0.3f, 0.3, 0.3f);
	light.attenuation = 0.3f;
	light.ambientCoefficient = 0.005f;

	cameraPosition = glm::vec3(5.0f, 3.0f, 8.0f);
}

bool OpenGLView::loadObjSimple(
	std::string path,
	std::vector<glm::vec3>& vertices,
	std::vector<glm::vec3>& normals,
	std::vector<unsigned int>& elements) {
		std::ifstream in(path, std::ios::in);
		if (!in) { std::cerr << "Cannot open " << path << std::endl; return false; }
		std::vector<int> nb_seen;

		std::cout << "Loading .obj file..." << std::endl;
		std::string line;
		while (std::getline(in, line)) {
			if (line.substr(0, 2) == "v ") {
				std::istringstream s(line.substr(2));
				glm::vec3 v; s >> v.x; s >> v.y; s >> v.z;
				vertices.push_back(v);
			}
			else if (line.substr(0, 2) == "f ") {
				std::istringstream s(line.substr(2));
				GLuint a, b, c;
				s >> a; s >> b; s >> c;
				a--; b--; c--;
				elements.push_back(a); elements.push_back(b); elements.push_back(c);
			}
			else if (line[0] == '#') {}
			else {}
		}

		normals.resize(vertices.size(), glm::vec3(0.0, 0.0, 0.0));
		nb_seen.resize(vertices.size(), 0);

		for (unsigned int i = 0; i < elements.size(); i += 3) {
			GLuint ia = elements[i];
			GLuint ib = elements[i + 1];
			GLuint ic = elements[i + 2];


			//compute vertex normal
			if (glm::cross(
				glm::vec3(vertices[ib]) - glm::vec3(vertices[ia]),
				glm::vec3(vertices[ic]) - glm::vec3(vertices[ia])) != glm::vec3(0.0, 0.0, 0.0)) {
					glm::vec3 normal = glm::normalize(glm::cross(
						glm::vec3(vertices[ib]) - glm::vec3(vertices[ia]),
						glm::vec3(vertices[ic]) - glm::vec3(vertices[ia])));
					int v[3];  v[0] = ia;  v[1] = ib;  v[2] = ic;
					for (int j = 0; j < 3; j++) {
						GLuint cur_v = v[j];
						nb_seen[cur_v]++;
						if (nb_seen[cur_v] == 1) {
							normals[cur_v] = normal;
						}
						else {
							normals[cur_v].x = normals[cur_v].x * (1.0 - 1.0 / nb_seen[cur_v]) + normal.x * 1.0 / nb_seen[cur_v];
							normals[cur_v].y = normals[cur_v].y * (1.0 - 1.0 / nb_seen[cur_v]) + normal.y * 1.0 / nb_seen[cur_v];
							normals[cur_v].z = normals[cur_v].z * (1.0 - 1.0 / nb_seen[cur_v]) + normal.z * 1.0 / nb_seen[cur_v];
							normals[cur_v] = glm::normalize(normals[cur_v]);
						}
					}
			}
		}
		std::cout << FILE_PATH << " loaded." << std::endl;
		return true;
}

GLuint OpenGLView::loadShaders(const char * vertex_file_path, const char * fragment_file_path){

	// Create the shaders
	GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
	GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

	// Read the Vertex Shader code from the file
	std::string VertexShaderCode;
	std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
	if (VertexShaderStream.is_open())
	{
		std::string Line = "";
		while (getline(VertexShaderStream, Line))
			VertexShaderCode += "
" + Line;
		VertexShaderStream.close();
	}

	// Read the Fragment Shader code from the file
	std::string FragmentShaderCode;
	std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
	if (FragmentShaderStream.is_open()){
		std::string Line = "";
		while (getline(FragmentShaderStream, Line))
			FragmentShaderCode += "
" + Line;
		FragmentShaderStream.close();
	}

	GLint Result = GL_FALSE;
	int InfoLogLength;

	// Compile Vertex Shader
	printf("Compiling shader : %s
", vertex_file_path);
	char const * VertexSourcePointer = VertexShaderCode.c_str();
	glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
	glCompileShader(VertexShaderID);

	// Check Vertex Shader
	glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	std::vector<char> VertexShaderErrorMessage(InfoLogLength);
	glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
	fprintf(stdout, "%s
", &VertexShaderErrorMessage[0]);

	// Compile Fragment Shader
	printf("Compiling shader : %s
", fragment_file_path);
	char const * FragmentSourcePointer = FragmentShaderCode.c_str();
	glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
	glCompileShader(FragmentShaderID);

	// Check Fragment Shader
	glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
	glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
	fprintf(stdout, "%s
", &FragmentShaderErrorMessage[0]);

	// Link the program
	fprintf(stdout, "Linking program
");
	GLuint ProgramID = glCreateProgram();
	glAttachShader(ProgramID, VertexShaderID);
	glAttachShader(ProgramID, FragmentShaderID);
	glLinkProgram(ProgramID);

	// Check the program
	glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
	glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	std::vector<char> ProgramErrorMessage(MAX(InfoLogLength, int(1)));
	glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
	fprintf(stdout, "%s
", &ProgramErrorMessage[0]);

	glDeleteShader(VertexShaderID);
	glDeleteShader(FragmentShaderID);

	return ProgramID;
}

bool OpenGLView::initializeAndSetupWindow(GLint windowWidth, GLint windowHeight, std::string windowTitle)
{
	if (!glfwInit())
	{
		std::cerr << "Error initializing glfw!" << std::endl;
		return false;
	}

	std::cout << "GLFW initialized!" << std::endl;

	glfwWindowHint(GLFW_SAMPLES, 8);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	window = glfwCreateWindow(windowWidth, windowHeight, "Triangle", nullptr, nullptr);
	if (window == nullptr)
	{
		std::cerr << "Failed to create a window!" << std::endl;
		return nullptr;
	}

	std::cout << "Window created!" << std::endl;

	glfwMakeContextCurrent(window);
	glewExperimental = true;
	if (glewInit() != GLEW_OK)
	{
		std::cerr << "Failed to initialize GLEW!";
		return nullptr;
	}

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);

	std::cout << "GLEW initialized!" << std::endl;

	std::cout << "You are running OpenGL: " << glfwGetVersionString() << std::endl;

	glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
	glfwSetKeyCallback(window, key_callback);

	return true;
}

void OpenGLView::loadBunnyAsset()
{
	std::vector<glm::vec3> vertices, normals;
	std::vector<GLuint> elements;

	loadObjSimple(FILE_PATH, vertices, normals, elements);

	bunny.shaderProgramID = loadShaders("vertexShader.txt", "fragmentShader.txt");

	glGenVertexArrays(1, &bunny.vertexArray);
	glBindVertexArray(bunny.vertexArray);

	glGenBuffers(1, &bunny.vertexBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, bunny.vertexBuffer);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);

	glGenBuffers(1, &bunny.normalBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, bunny.normalBuffer);
	glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW);

	glGenBuffers(1, &bunny.elementBuffer);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bunny.elementBuffer);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements.size() * sizeof(unsigned int), &elements[0], GL_STATIC_DRAW);

	bunny.elementsSize = elements.size();
}

glm::mat4 OpenGLView::translate(glm::vec3 position)
{
	return glm::translate(glm::mat4(), position);
}

glm::mat4 OpenGLView::scale(glm::vec3 size)
{
	return glm::scale(glm::mat4(), size);
}

void OpenGLView::loadUniforms(AssetInstance assetInstance)
{
	Asset* asset = &assetInstance.asset;

	glUseProgram(asset->shaderProgramID);
	glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 1000.0f);
	glm::mat4 camera = Projection * getViewMatrix();
	glm::mat4 model = translate(assetInstance.position) * scale(assetInstance.scale);

	GLuint cameraID = glGetUniformLocation(asset->shaderProgramID, "camera");
	GLuint modelID = glGetUniformLocation(asset->shaderProgramID, "model");
	GLuint cameraPositionID = glGetUniformLocation(asset->shaderProgramID, "cameraPosition");
	GLuint lightPositionID = glGetUniformLocation(asset->shaderProgramID, "light.position");
	GLuint lightIntensitiesID = glGetUniformLocation(asset->shaderProgramID, "light.intensities");
	GLuint lightAttenuationID = glGetUniformLocation(asset->shaderProgramID, "light.attenuation");
	GLuint lightAmbientCoefficientID = glGetUniformLocation(asset->shaderProgramID, "light.ambientCoefficient");
	GLuint materialColorID = glGetUniformLocation(asset->shaderProgramID, "materialColor");
	GLuint materialShininessID = glGetUniformLocation(asset->shaderProgramID, "materialShininess");
	GLuint materialSpecularColorID = glGetUniformLocation(asset->shaderProgramID, "materialSpecularColor");

	glUniformMatrix4fv(cameraID, 1, GL_FALSE, &camera[0][0]);
	glUniformMatrix4fv(modelID, 1, GL_FALSE, &model[0][0]);
	glUniform3fv(cameraPositionID, 1, &cameraPosition[0]);
	glUniform3fv(lightPositionID, 1, &light.position[0]);
	glUniform3fv(lightIntensitiesID, 1, &light.intensities[0]);
	glUniform1f(lightAttenuationID, light.attenuation);
	glUniform1f(lightAmbientCoefficientID, light.ambientCoefficient);
	glUniform3fv(materialColorID, 1, &assetInstance.materialColor[0]);
	glUniform1f(materialShininessID, assetInstance.materialShininess);
	glUniform3fv(materialSpecularColorID, 1, &assetInstance.materialSpecularColor[0]);
}
/*
void OpenGLView::getKeys()
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, GL_TRUE);
	}
	if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
		model = glm::rotate(model, 1.5f, glm::vec3(0, 1, 0));
	}
	if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
		model = glm::rotate(model, -1.5f, glm::vec3(0, 1, 0));
	}
	if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
		model = glm::scale(model, glm::vec3(1.5, 1.5, 1.5));
	}
	if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
		model = glm::scale(model, glm::vec3(0.95, 0.95, 0.95));
	}
}*/


void OpenGLView::run()
{	
	initializeAndSetupWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "PhongBunny");
	glClearColor(1.0f, 1.0f, 0.0f, 1.0f);

	loadBunnyAsset();

	AssetInstance bunny1;
	bunny1.asset = bunny;
	bunny1.position = glm::vec3(0.0f, 0.0f, 0.0f);
	bunny1.scale = glm::vec3(1.0f, 1.0f, 1.0f);


	do{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		loadUniforms(bunny1);

		glEnableVertexAttribArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, bunny.vertexBuffer);
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);

		glEnableVertexAttribArray(1);
		glBindBuffer(GL_ARRAY_BUFFER, bunny.normalBuffer);
		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bunny.elementBuffer);

		glDrawElements(GL_TRIANGLES, bunny.elementsSize, GL_UNSIGNED_INT, (void*)0);

		glDisableVertexAttribArray(0);
		glDisableVertexAttribArray(1);

		glfwSwapBuffers(window);
		glfwPollEvents();
	} while (!glfwWindowShouldClose(window));

	glfwDestroyWindow(window);
	glfwTerminate();
}

my vertex shader:


#version 330 core

uniform mat4 camera;
uniform mat4 model;

layout(location = 0) in vec3 vert;
layout(location = 1) in vec3 vertNormal;

out vec3 fragVert;
out vec3 fragNormal;

void main() {
    // Pass some variables to the fragment shader
    fragNormal = vertNormal;
    fragVert = vert;
    
    // Apply all matrix transformations to vert
    gl_Position = camera * model * vec4(vert, 1);
}

my fragment shader:


#version 150 core

uniform mat4 model;
uniform vec3 cameraPosition;

// material settings
uniform float materialShininess;
uniform vec3 materialSpecularColor;
uniform vec3 materialColor;

uniform struct Light {
   vec3 position;
   vec3 intensities; //a.k.a the color of the light
   float attenuation;
   float ambientCoefficient;
} light;

in vec3 fragNormal;
in vec3 fragVert;

out vec4 finalColor;

void main() {
    vec3 normal = normalize(transpose(inverse(mat3(model))) * fragNormal);
    vec3 surfacePos = vec3(model * vec4(fragVert, 1));
    vec4 surfaceColor = vec4(materialColor, 1);
    vec3 surfaceToLight = normalize(light.position - surfacePos);
    vec3 surfaceToCamera = normalize(cameraPosition - surfacePos);
    
    //ambient
    vec3 ambient = light.ambientCoefficient * surfaceColor.rgb * light.intensities;

    //diffuse
    float diffuseCoefficient = max(0.0, dot(normal, surfaceToLight));
    vec3 diffuse = diffuseCoefficient * surfaceColor.rgb * light.intensities;
    
    //specular
    float specularCoefficient = 0.0;
    if(diffuseCoefficient > 0.0)
        specularCoefficient = pow(max(0.0, dot(surfaceToCamera, reflect(-surfaceToLight, normal))), materialShininess);
    vec3 specular = specularCoefficient * materialSpecularColor * light.intensities;
    
    //attenuation
    float distanceToLight = length(light.position - surfacePos);
    float attenuation = 1.0 / (1.0 + light.attenuation * pow(distanceToLight, 2));

    //linear color (color before gamma correction)
    vec3 linearColor = ambient + attenuation*(diffuse + specular);
    
    //final color (after gamma correction)
    vec3 gamma = vec3(1.0/2.2);
    finalColor = vec4(pow(linearColor, gamma), surfaceColor.a);
}

and finally my controls implementation:


#include "controls.h"

glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 View = glm::lookAt(
	glm::vec3(5, 3, 8),
	glm::vec3(0, 0, 0),
	glm::vec3(0, 1, 0));

glm::mat4 getModelMatrix() {

	return Model;
}
glm::mat4 getViewMatrix() {

	return View;
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, GL_TRUE);
	}
	if (key == GLFW_KEY_LEFT) {
		Model = glm::rotate(Model, 1.5f, glm::vec3(0, 1, 0));
	}
	if (key == GLFW_KEY_RIGHT) {
		Model = glm::rotate(Model, -1.5f, glm::vec3(0, 1, 0));
	}
	if (key == GLFW_KEY_UP) {
		Model = glm::scale(Model, glm::vec3(1.05, 1.05, 1.05));
	}
	if (key == GLFW_KEY_DOWN) {
		Model = glm::scale(Model, glm::vec3(0.95, 0.95, 0.95));
	}
}