Laboratorio #11 - OpenGL - Programacion Grafica 2024
Laboratorio #11 - OpenGL - Programacion Grafica 2024
Creamos una nueva carpeta y la nombramos como JSON, dentro de ella creamos un archivo txt y le
ponemos el nombre de json.txt para dentro del mismo copiar el siguiente contenido que se encuentra
en la ruta https://raw.githubusercontent.com/nlohmann/json/develop/include/nlohmann/json.hpp
Después de copiar todo el contenido debemos de cambiar la extensión del archivo de json.txt json.h
Mesh.cpp
#include "Mesh.h"
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, sizeof(Vertex), (void*)0);
VAO.LinkAttrib(VBO, 1, 3, GL_FLOAT, sizeof(Vertex), (void*)(3 * sizeof(float)));
VAO.LinkAttrib(VBO, 2, 3, GL_FLOAT, sizeof(Vertex), (void*)(6 * sizeof(float)));
VAO.LinkAttrib(VBO, 3, 2, GL_FLOAT, 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,
glm::mat4 matrix,
glm::vec3 translation,
glm::quat rotation,
glm::vec3 scale
)
{
// Bind shader to be able to access uniforms
shader.Activate();
VAO.Bind();
// Initialize matrices
glm::mat4 trans = glm::mat4(1.0f);
glm::mat4 rot = glm::mat4(1.0f);
glm::mat4 sca = glm::mat4(1.0f);
Mesh.h
#ifndef MESH_CLASS_H
#define MESH_CLASS_H
#include<string>
#include"VAO.h"
#include"EBO.h"
#include"Camera.h"
#include"Texture.h"
class Mesh
{
public:
std::vector <Vertex> vertices;
std::vector <GLuint> indices;
std::vector <Texture> textures;
// Store VAO in public so it can be used in the Draw function
VAO VAO;
Model.h
#ifndef MODEL_CLASS_H
#define MODEL_CLASS_H
#include<json/json.h>
#include"Mesh.h"
class Model
{
public:
// Loads in a model from a file and stores tha information in 'data', 'JSON', and 'file'
Model(const char* file);
private:
// Variables for easy access
const char* file;
std::vector<unsigned char> data;
json JSON;
Model.cpp
#include"Model.h"
// Combine all the vertex components and also get the indices and textures
std::vector<Vertex> vertices = assembleVertices(positions, normals, texUVs);
std::vector<GLuint> indices = getIndices(JSON["accessors"][indAccInd]);
std::vector<Texture> textures = getTextures();
// Initialize matrices
glm::mat4 trans = glm::mat4(1.0f);
glm::mat4 rot = glm::mat4(1.0f);
glm::mat4 sca = glm::mat4(1.0f);
loadMesh(node["mesh"]);
}
// Check if the node has children, and if it does, apply this function to them with the
matNextNode
if (node.find("children") != node.end())
{
for (unsigned int i = 0; i < node["children"].size(); i++)
traverseNode(node["children"][i], matNextNode);
}
}
// Transform the raw text data into bytes and put them in a vector
std::vector<unsigned char> data(bytesText.begin(), bytesText.end());
return data;
}
// Go over all the bytes in the data at the correct place using the properties from above
unsigned int beginningOfData = byteOffset + accByteOffset;
unsigned int lengthOfData = count * 4 * numPerVert;
for (unsigned int i = beginningOfData; i < beginningOfData + lengthOfData; i)
{
unsigned char bytes[] = { data[i++], data[i++], data[i++], data[i++] };
float value;
std::memcpy(&value, bytes, sizeof(float));
floatVec.push_back(value);
}
return floatVec;
}
// Get indices with regards to their type: unsigned int, unsigned short, or short
unsigned int beginningOfData = byteOffset + accByteOffset;
if (componentType == 5125)
{
for (unsigned int i = beginningOfData; i < byteOffset + accByteOffset + count * 4; i)
{
unsigned char bytes[] = { data[i++], data[i++], data[i++], data[i++] };
unsigned int value;
std::memcpy(&value, bytes, sizeof(unsigned int));
indices.push_back((GLuint)value);
}
}
else if (componentType == 5123)
{
for (unsigned int i = beginningOfData; i < byteOffset + accByteOffset + count * 2; i)
{
unsigned char bytes[] = { data[i++], data[i++] };
unsigned short value;
std::memcpy(&value, bytes, sizeof(unsigned short));
indices.push_back((GLuint)value);
}
}
else if (componentType == 5122)
{
for (unsigned int i = beginningOfData; i < byteOffset + accByteOffset + count * 2; i)
{
unsigned char bytes[] = { data[i++], data[i++] };
short value;
std::memcpy(&value, bytes, sizeof(short));
indices.push_back((GLuint)value);
}
}
return indices;
}
std::vector<Texture> Model::getTextures()
{
std::vector<Texture> textures;
return textures;
}
std::vector<Vertex> Model::assembleVertices
(
std::vector<glm::vec3> positions,
std::vector<glm::vec3> normals,
std::vector<glm::vec2> texUVs
)
{
std::vector<Vertex> vertices;
for (int i = 0; i < positions.size(); i++)
{
vertices.push_back
(
Vertex
{
positions[i],
normals[i],
glm::vec3(1.0f, 1.0f, 1.0f),
texUVs[i]
}
);
}
return vertices;
}
Texture.h
#ifndef TEXTURE_CLASS_H
#define TEXTURE_CLASS_H
#include<glad/glad.h>
#include<stb/stb_image.h>
#include"shaderClass.h"
class Texture
{
public:
GLuint ID;
const char* type;
GLuint unit;
#include"Texture.h"
// 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(image, &widthImg, &heightImg, &numColCh, 0);
// 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);
// Check what type of color channels the texture has and load it accordingly
if (numColCh == 4)
glTexImage2D
(
GL_TEXTURE_2D,
0,
GL_RGBA,
widthImg,
heightImg,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
bytes
);
else if (numColCh == 3)
glTexImage2D
(
GL_TEXTURE_2D,
0,
GL_RGBA,
widthImg,
heightImg,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
bytes
);
else if (numColCh == 1)
glTexImage2D
(
GL_TEXTURE_2D,
0,
GL_RGBA,
widthImg,
heightImg,
0,
GL_RED,
GL_UNSIGNED_BYTE,
bytes
);
else
throw std::invalid_argument("Automatic Texture type recognition failed");
// Generates MipMaps
glGenerateMipmap(GL_TEXTURE_2D);
void Texture::Bind()
{
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, ID);
}
void Texture::Unbind()
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::Delete()
{
glDeleteTextures(1, &ID);
}
default.vert
// Positions/Coordinates
layout (location = 0) in vec3 aPos;
// Normals (not necessarily normalized)
layout (location = 1) in vec3 aNormal;
// Colors
layout (location = 2) in vec3 aColor;
// Texture Coordinates
layout (location = 3) in vec2 aTex;
void main()
{
// calculates current position
crntPos = vec3(model * translation * -rotation * scale * vec4(aPos, 1.0f));
// Assigns the normal from the Vertex Data to "Normal"
Normal = aNormal;
// Assigns the colors from the Vertex Data to "color"
color = aColor;
// Assigns the texture coordinates from the Vertex Data to "texCoord"
texCoord = mat2(0.0, -1.0, 1.0, 0.0) * aTex;
default.frag
// ambient lighting
float ambient = 0.20f;
// diffuse lighting
vec3 normal = normalize(Normal);
vec3 lightDirection = normalize(lightVec);
float diffuse = max(dot(normal, lightDirection), 0.0f);
// specular lighting
float specularLight = 0.50f;
vec3 viewDirection = normalize(camPos - crntPos);
vec3 reflectionDirection = reflect(-lightDirection, normal);
float specAmount = pow(max(dot(viewDirection, reflectionDirection), 0.0f), 16);
float specular = specAmount * specularLight;
vec4 direcLight()
{
// ambient lighting
float ambient = 0.20f;
// diffuse lighting
vec3 normal = normalize(Normal);
vec3 lightDirection = normalize(vec3(1.0f, 1.0f, 0.0f));
float diffuse = max(dot(normal, lightDirection), 0.0f);
// specular lighting
float specularLight = 0.50f;
vec3 viewDirection = normalize(camPos - crntPos);
vec3 reflectionDirection = reflect(-lightDirection, normal);
float specAmount = pow(max(dot(viewDirection, reflectionDirection), 0.0f), 16);
float specular = specAmount * specularLight;
return (texture(diffuse0, texCoord) * (diffuse + ambient) + texture(specular0, texCoord).r *
specular) * lightColor;
}
vec4 spotLight()
{
// controls how big the area that is lit up is
float outerCone = 0.90f;
float innerCone = 0.95f;
// ambient lighting
float ambient = 0.20f;
// diffuse lighting
vec3 normal = normalize(Normal);
vec3 lightDirection = normalize(lightPos - crntPos);
float diffuse = max(dot(normal, lightDirection), 0.0f);
// specular lighting
float specularLight = 0.50f;
vec3 viewDirection = normalize(camPos - crntPos);
vec3 reflectionDirection = reflect(-lightDirection, normal);
float specAmount = pow(max(dot(viewDirection, reflectionDirection), 0.0f), 16);
float specular = specAmount * specularLight;
// calculates the intensity of the crntPos based on its angle to the center of the light cone
float angle = dot(vec3(0.0f, -1.0f, 0.0f), -lightDirection);
float inten = clamp((angle - outerCone) / (innerCone - outerCone), 0.0f, 1.0f);
void main()
{
// outputs final color
FragColor = direcLight();
}
Main.cpp
#include"Model.h"
const unsigned int width = 800;
const unsigned int height = 800;
int main()
{
// Initialize GLFW
glfwInit();
// Create a GLFWwindow object of 800 by 800 pixels, naming it "Importando un Modelo 3D gltf"
GLFWwindow* window = glfwCreateWindow(width, height, " Importando un Modelo 3D gltf ",
NULL, NULL);
// Error check if the window fails to create
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
// Introduce the window into the current context
glfwMakeContextCurrent(window);
shaderProgram.Activate();
glUniform4f(glGetUniformLocation(shaderProgram.ID, "lightColor"), lightColor.x, lightColor.y,
lightColor.z, lightColor.w);
glUniform3f(glGetUniformLocation(shaderProgram.ID, "lightPos"), lightPos.x, lightPos.y,
lightPos.z);
// Load in a model
Model model((parentDir + modelPath).c_str());
// Model model("models/bunny/scene.gltf");
// Draw a model
model.Draw(shaderProgram, camera);