I'm learning how to code graphics with OpenGL. So far I have created IndexBuffer, VertexBuffer, VertexArray, Camera, Texture and Shader. Now I'm trying to make a Mesh class with vertices, indices and textures. But when I call the "Draw(Shader& shader, Camera& camera)" function it doesn't show anything. All the vertices, indices and textures are passed in correctly (I've already checked this).
Here is my code for Mesh class
#pragma once
#include <vector>
#include"VAO.h"
#include"EBO.h"
#include"Camera.h"
#include"Texture.h"
class Mesh
{
public:
Mesh(std::vector <Vertex>& vertices, std::vector <GLuint>& indices, std::vector <Texture>& textures);
void Draw(Shader& shader, Camera& camera);
private:
std::vector <Vertex> m_Vertices;
std::vector <unsigned int> m_Indices;
std::vector <Texture> m_Textures;
VAO VAO;
};
---------------------------------------------
#include "Mesh.h"
#include <iostream>
Mesh::Mesh(std::vector<Vertex>& vertices, std::vector<GLuint>& indices, std::vector<Texture>& textures)
: m_Vertices(vertices), m_Indices(indices), m_Textures(textures)
{
VAO.Bind();
// Generates Vertex Buffer Object and links it to vertices
VBO VBO(vertices);
// Generates Element Buffer Object and links it to indices
EBO EBO(indices);
// Links VBO attributes such as coordinates and colors to VAO
VAO.LinkAttrib(VBO, 0, 3, GL_FLOAT, false, sizeof(Vertex), (void*)0);
VAO.LinkAttrib(VBO, 1, 3, GL_FLOAT, false, sizeof(Vertex), (void*)(3 * sizeof(float)));
VAO.LinkAttrib(VBO, 2, 3, GL_FLOAT, false, sizeof(Vertex), (void*)(6 * sizeof(float)));
VAO.LinkAttrib(VBO, 3, 2, GL_FLOAT, false, sizeof(Vertex), (void*)(9 * sizeof(float)));
// Unbind all to prevent accidentally modifying them
VAO.Unbind();
VBO.Unbind();
EBO.Unbind();
}
void Mesh::Draw(Shader& shader, Camera& camera)
{
// Bind shader to be able to access uniforms
shader.Use();
VAO.Bind();
// Keep track of how many of each type of textures we have
unsigned int numDiffuse = 0;
unsigned int numSpecular = 0;
for (unsigned int i = 0; i < m_Textures.size(); i++)
{
std::string num;
std::string type = m_Textures[i].GetType();
if (type == "diffuse")
{
num = std::to_string(numDiffuse++);
}
else if (type == "specular")
{
num = std::to_string(numSpecular++);
}
m_Textures[i].SetUniform(shader, (type + num).c_str(), i);
m_Textures[i].Bind();
}
// Take care of the camera Matrix
shader.SetUniform3f("camPos", camera.GetCameraPosition().x, camera.GetCameraPosition().y, camera.GetCameraPosition().z);
camera.SetMatrix(shader, "camMatrix");
// Draw the actual mesh
glDrawElements(GL_TRIANGLES, m_Indices.size(), GL_UNSIGNED_INT, 0);
}
My texture class:
#pragma once
#include <string>
#include "Shader.h"
class Texture
{
public:
Texture(const std::string& filepath, const std::string& texType, unsigned int slot, unsigned int format, unsigned int pixelType);
~Texture();
void SetUniform(const Shader& shader, const std::string& name, unsigned int unit) const;
void Bind() const;
void Unbind() const;
inline unsigned int GetID() const { return m_ID; }
inline std::string GetType() const { return m_Type; }
private:
unsigned int m_ID;
std::string m_Type;
unsigned int m_Unit;
};
#include "Texture.h"
#include <GL/glew.h>
#include "stb_image.h"
Texture::Texture(const std::string& filepath, const std::string& texType, unsigned int slot, unsigned int format, unsigned int pixelType)
: m_Type(texType), m_Unit(slot)
{
// Stores the width, height, and the number of color channels of the image
int widthImg, heightImg, numColCh;
// Flips the image so it appears right side up
stbi_set_flip_vertically_on_load(true);
// Reads the image from a file and stores it in bytes
unsigned char* bytes = stbi_load(filepath.c_str(), &widthImg, &heightImg, &numColCh, 0);
// Generates an OpenGL texture object
glGenTextures(1, &m_ID);
// Assigns the texture to a Texture Unit
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, m_ID);
// Configures the type of algorithm that is used to make the image smaller or bigger
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Configures the way the texture repeats (if it does at all)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Assigns the image to the OpenGL Texture object
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, widthImg, heightImg, 0, format, pixelType, bytes);
// Generates MipMaps
glGenerateMipmap(GL_TEXTURE_2D);
// Deletes the image data as it is already in the OpenGL Texture object
stbi_image_free(bytes);
// Unbinds the OpenGL Texture object so that it can't accidentally be modified
glBindTexture(GL_TEXTURE_2D, 0);
}
Texture::~Texture()
{
glDeleteTextures(1, &m_ID);
}
void Texture::SetUniform(const Shader& shader, const std::string& name, unsigned int unit) const
{
shader.Use();
shader.SetUniform1i(name, unit);
}
void Texture::Bind() const
{
glActiveTexture(GL_TEXTURE0 + m_Unit);
glBindTexture(GL_TEXTURE_2D, m_ID);
}
void Texture::Unbind() const
{
glBindTexture(GL_TEXTURE_2D, 0);
}
And, finally, my shader code
#pragma once
#include <string>
#include <glm/glm.hpp>
std::string readFileContents(const std::string& filepath);
class Shader
{
public:
Shader(const std::string& vertexPath, const std::string& fragmentPath);
~Shader();
void SetUniform1f(const std::string& name, float v0) const;
void SetUniform2f(const std::string& name, float v0, float v1) const;
void SetUniform3f(const std::string& name, float v0, float v1, float v2) const;
void SetUniform4f(const std::string& name, float v0, float v1, float v2, float v3) const;
void SetUniform1i(const std::string& name, int v0) const;
void SetUniformMatrix4f(const std::string& name, const glm::mat4& v0) const;
void Use() const;
inline unsigned int GetID() const { return m_ID; }
private:
unsigned int m_ID;
};
#include "Shader.h"
#include <GL/glew.h>
#include <glm/gtc/type_ptr.hpp>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
std::string readFileContents(const std::string& filepath)
{
std::string contents;
std::ifstream in(filepath, std::ios::binary);
if (in)
{
std::stringstream sstr;
sstr << in.rdbuf();
contents = sstr.str();
in.close();
}
return contents;
}
static unsigned int CompileShader(const std::string& shaderPath, unsigned int shaderType)
{
unsigned int shader = glCreateShader(shaderType);
std::string shaderCode = readFileContents(shaderPath);
const char* shaderSource = shaderCode.c_str();
glShaderSource(shader, 1, &shaderSource, NULL);
glCompileShader(shader);
int result;
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
int infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
std::vector<char> errorMessage((long long)infoLogLength + 1);
glGetShaderInfoLog(shader, infoLogLength, NULL, errorMessage.data());
std::cout << errorMessage.data() << std::endl;
}
return shader;
}
Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath)
{
unsigned int vertexShader = CompileShader(vertexPath, GL_VERTEX_SHADER);
unsigned int fragmentShader = CompileShader(fragmentPath, GL_FRAGMENT_SHADER);
m_ID = glCreateProgram();
glAttachShader(m_ID, vertexShader);
glAttachShader(m_ID, fragmentShader);
glLinkProgram(m_ID);
int result;
glGetProgramiv(m_ID, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
int infoLogLength;
glGetProgramiv(m_ID, GL_INFO_LOG_LENGTH, &infoLogLength);
std::vector<char> errorMessage((long long)infoLogLength + 1);
glGetProgramInfoLog(m_ID, infoLogLength, NULL, errorMessage.data());
std::cout << errorMessage.data() << std::endl;
}
glDetachShader(m_ID, vertexShader);
glDetachShader(m_ID, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
Shader::~Shader()
{
glDeleteProgram(m_ID);
}
void Shader::SetUniform1f(const std::string& name, float v0) const
{
unsigned int location = glGetUniformLocation(m_ID, name.c_str());
glUniform1f(location, v0);
}
void Shader::SetUniform2f(const std::string& name, float v0, float v1) const
{
unsigned int location = glGetUniformLocation(m_ID, name.c_str());
glUniform2f(location, v0, v1);
}
void Shader::SetUniform3f(const std::string& name, float v0, float v1, float v2) const
{
unsigned int location = glGetUniformLocation(m_ID, name.c_str());
glUniform3f(location, v0, v1, v2);
}
void Shader::SetUniform4f(const std::string& name, float v0, float v1, float v2, float v3) const
{
unsigned int location = glGetUniformLocation(m_ID, name.c_str());
glUniform4f(location, v0, v1, v2, v3);
}
void Shader::SetUniform1i(const std::string& name, int v0) const
{
unsigned int location = glGetUniformLocation(m_ID, name.c_str());
glUniform1i(location, v0);
}
void Shader::SetUniformMatrix4f(const std::string& name, const glm::mat4& v0) const
{
unsigned int location = glGetUniformLocation(m_ID, name.c_str());
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(v0));
}
void Shader::Use() const
{
glUseProgram(m_ID);
}
ALso, every "Bind()" function is like "glBindX(ENUM, m_ID);" and every "Unbind()" is like "glBindX(ENUM, 0);"