0% found this document useful (0 votes)
89 views

Laboratorio #11 - OpenGL - Programacion Grafica 2024

Lab 11 de Open GL

Uploaded by

Liz Gutiérrez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
89 views

Laboratorio #11 - OpenGL - Programacion Grafica 2024

Lab 11 de Open GL

Uploaded by

Liz Gutiérrez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 21

Universidad Nacional de Ingeniería

Programa Académico de Ingeniería en Computación

Asignatura: Programación Gráfica


Elaborado por: Danny Chávez
Laboratorio #11: Incorporación un modelo 3D en OpenGL

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"

Mesh::Mesh(std::vector <Vertex>& vertices, std::vector <GLuint>& indices, std::vector <Texture>&


textures)
{
Mesh::vertices = vertices;
Mesh::indices = indices;
Mesh::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, 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();

// 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 < textures.size(); i++)


{
std::string num;
std::string type = textures[i].type;
if (type == "diffuse")
{
num = std::to_string(numDiffuse++);
}
else if (type == "specular")
{
num = std::to_string(numSpecular++);
}
textures[i].texUnit(shader, (type + num).c_str(), i);
textures[i].Bind();
}
// Take care of the camera Matrix
glUniform3f(glGetUniformLocation(shader.ID, "camPos"), camera.Position.x, camera.Position.y,
camera.Position.z);
camera.Matrix(shader, "camMatrix");

// Initialize matrices
glm::mat4 trans = glm::mat4(1.0f);
glm::mat4 rot = glm::mat4(1.0f);
glm::mat4 sca = glm::mat4(1.0f);

// Transform the matrices to their correct form


trans = glm::translate(trans, translation);
rot = glm::mat4_cast(rotation);
sca = glm::scale(sca, scale);

// Push the matrices to the vertex shader


glUniformMatrix4fv(glGetUniformLocation(shader.ID, "translation"), 1, GL_FALSE,
glm::value_ptr(trans));
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "rotation"), 1, GL_FALSE,
glm::value_ptr(rot));
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "scale"), 1, GL_FALSE, glm::value_ptr(sca));
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "model"), 1, GL_FALSE,
glm::value_ptr(matrix));

// Draw the actual mesh


glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
}

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;

// Initializes the mesh


Mesh(std::vector <Vertex>& vertices, std::vector <GLuint>& indices, std::vector <Texture>&
textures);

// Draws the mesh


void Draw
(
Shader& shader,
Camera& camera,
glm::mat4 matrix = glm::mat4(1.0f),
glm::vec3 translation = glm::vec3(0.0f, 0.0f, 0.0f),
glm::quat rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f),
glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f)
);
};
#endif

Model.h

#ifndef MODEL_CLASS_H
#define MODEL_CLASS_H

#include<json/json.h>
#include"Mesh.h"

using json = nlohmann::json;

class Model
{
public:
// Loads in a model from a file and stores tha information in 'data', 'JSON', and 'file'
Model(const char* file);

void Draw(Shader& shader, Camera& camera);

private:
// Variables for easy access
const char* file;
std::vector<unsigned char> data;
json JSON;

// All the meshes and transformations


std::vector<Mesh> meshes;
std::vector<glm::vec3> translationsMeshes;
std::vector<glm::quat> rotationsMeshes;
std::vector<glm::vec3> scalesMeshes;
std::vector<glm::mat4> matricesMeshes;

// Prevents textures from being loaded twice


std::vector<std::string> loadedTexName;
std::vector<Texture> loadedTex;

// Loads a single mesh by its index


void loadMesh(unsigned int indMesh);

// Traverses a node recursively, so it essentially traverses all connected nodes


void traverseNode(unsigned int nextNode, glm::mat4 matrix = glm::mat4(1.0f));

// Gets the binary data from a file


std::vector<unsigned char> getData();
// Interprets the binary data into floats, indices, and textures
std::vector<float> getFloats(json accessor);
std::vector<GLuint> getIndices(json accessor);
std::vector<Texture> getTextures();

// Assembles all the floats into vertices


std::vector<Vertex> assembleVertices
(
std::vector<glm::vec3> positions,
std::vector<glm::vec3> normals,
std::vector<glm::vec2> texUVs
);

// Helps with the assembly from above by grouping floats


std::vector<glm::vec2> groupFloatsVec2(std::vector<float> floatVec);
std::vector<glm::vec3> groupFloatsVec3(std::vector<float> floatVec);
std::vector<glm::vec4> groupFloatsVec4(std::vector<float> floatVec);
};
#endif

Model.cpp

#include"Model.h"

Model::Model(const char* file)


{
// Make a JSON object
std::string text = get_file_contents(file);
JSON = json::parse(text);

// Get the binary data


Model::file = file;
data = getData();

// Traverse all nodes


traverseNode(0);
}

void Model::Draw(Shader& shader, Camera& camera)


{
// Go over all meshes and draw each one
for (unsigned int i = 0; i < meshes.size(); i++)
{
meshes[i].Mesh::Draw(shader, camera, matricesMeshes[i]);
}
}

void Model::loadMesh(unsigned int indMesh)


{
// Get all accessor indices
unsigned int posAccInd = JSON["meshes"][indMesh]["primitives"][0]["attributes"]["POSITION"];
unsigned int normalAccInd = JSON["meshes"][indMesh]["primitives"][0]["attributes"]
["NORMAL"];
unsigned int texAccInd = JSON["meshes"][indMesh]["primitives"][0]["attributes"]
["TEXCOORD_0"];
unsigned int indAccInd = JSON["meshes"][indMesh]["primitives"][0]["indices"];

// Use accessor indices to get all vertices components


std::vector<float> posVec = getFloats(JSON["accessors"][posAccInd]);
std::vector<glm::vec3> positions = groupFloatsVec3(posVec);
std::vector<float> normalVec = getFloats(JSON["accessors"][normalAccInd]);
std::vector<glm::vec3> normals = groupFloatsVec3(normalVec);
std::vector<float> texVec = getFloats(JSON["accessors"][texAccInd]);
std::vector<glm::vec2> texUVs = groupFloatsVec2(texVec);

// 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();

// Combine the vertices, indices, and textures into a mesh


meshes.push_back(Mesh(vertices, indices, textures));
}

void Model::traverseNode(unsigned int nextNode, glm::mat4 matrix)


{
// Current node
json node = JSON["nodes"][nextNode];

// Get translation if it exists


glm::vec3 translation = glm::vec3(0.0f, 0.0f, 0.0f);
if (node.find("translation") != node.end())
{
float transValues[3];
for (unsigned int i = 0; i < node["translation"].size(); i++)
transValues[i] = (node["translation"][i]);
translation = glm::make_vec3(transValues);
}
// Get quaternion if it exists
glm::quat rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
if (node.find("rotation") != node.end())
{
float rotValues[4] =
{
node["rotation"][3],
node["rotation"][0],
node["rotation"][1],
node["rotation"][2]
};
rotation = glm::make_quat(rotValues);
}
// Get scale if it exists
glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f);
if (node.find("scale") != node.end())
{
float scaleValues[3];
for (unsigned int i = 0; i < node["scale"].size(); i++)
scaleValues[i] = (node["scale"][i]);
scale = glm::make_vec3(scaleValues);
}
// Get matrix if it exists
glm::mat4 matNode = glm::mat4(1.0f);
if (node.find("matrix") != node.end())
{
float matValues[16];
for (unsigned int i = 0; i < node["matrix"].size(); i++)
matValues[i] = (node["matrix"][i]);
matNode = glm::make_mat4(matValues);
}

// Initialize matrices
glm::mat4 trans = glm::mat4(1.0f);
glm::mat4 rot = glm::mat4(1.0f);
glm::mat4 sca = glm::mat4(1.0f);

// Use translation, rotation, and scale to change the initialized matrices


trans = glm::translate(trans, translation);
rot = glm::mat4_cast(rotation);
sca = glm::scale(sca, scale);

// Multiply all matrices together


glm::mat4 matNextNode = matrix * matNode * trans * rot * sca;

// Check if the node contains a mesh and if it does load it


if (node.find("mesh") != node.end())
{
translationsMeshes.push_back(translation);
rotationsMeshes.push_back(rotation);
scalesMeshes.push_back(scale);
matricesMeshes.push_back(matNextNode);

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);
}
}

std::vector<unsigned char> Model::getData()


{
// Create a place to store the raw text, and get the uri of the .bin file
std::string bytesText;
std::string uri = JSON["buffers"][0]["uri"];

// Store raw text data into bytesText


std::string fileStr = std::string(file);
std::string fileDirectory = fileStr.substr(0, fileStr.find_last_of('/') + 1);
bytesText = get_file_contents((fileDirectory + uri).c_str());

// Transform the raw text data into bytes and put them in a vector
std::vector<unsigned char> data(bytesText.begin(), bytesText.end());
return data;
}

std::vector<float> Model::getFloats(json accessor)


{
std::vector<float> floatVec;

// Get properties from the accessor


unsigned int buffViewInd = accessor.value("bufferView", 1);
unsigned int count = accessor["count"];
unsigned int accByteOffset = accessor.value("byteOffset", 0);
std::string type = accessor["type"];

// Get properties from the bufferView


json bufferView = JSON["bufferViews"][buffViewInd];
unsigned int byteOffset = bufferView["byteOffset"];

// Interpret the type and store it into numPerVert


unsigned int numPerVert;
if (type == "SCALAR") numPerVert = 1;
else if (type == "VEC2") numPerVert = 2;
else if (type == "VEC3") numPerVert = 3;
else if (type == "VEC4") numPerVert = 4;
else throw std::invalid_argument("Type is invalid (not SCALAR, VEC2, VEC3, or VEC4)");

// 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;
}

std::vector<GLuint> Model::getIndices(json accessor)


{
std::vector<GLuint> indices;

// Get properties from the accessor


unsigned int buffViewInd = accessor.value("bufferView", 0);
unsigned int count = accessor["count"];
unsigned int accByteOffset = accessor.value("byteOffset", 0);
unsigned int componentType = accessor["componentType"];

// Get properties from the bufferView


json bufferView = JSON["bufferViews"][buffViewInd];
unsigned int byteOffset = bufferView["byteOffset"];

// 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;

std::string fileStr = std::string(file);


std::string fileDirectory = fileStr.substr(0, fileStr.find_last_of('/') + 1);

// Go over all images


for (unsigned int i = 0; i < JSON["images"].size(); i++)
{
// uri of current texture
std::string texPath = JSON["images"][i]["uri"];

// Check if the texture has already been loaded


bool skip = false;
for (unsigned int j = 0; j < loadedTexName.size(); j++)
{
if (loadedTexName[j] == texPath)
{
textures.push_back(loadedTex[j]);
skip = true;
break;
}
}

// If the texture has been loaded, skip this


if (!skip)
{
// Load diffuse texture
if (texPath.find("baseColor") != std::string::npos)
{
Texture diffuse = Texture((fileDirectory + texPath).c_str(), "diffuse",
loadedTex.size());
textures.push_back(diffuse);
loadedTex.push_back(diffuse);
loadedTexName.push_back(texPath);
}
// Load specular texture
else if (texPath.find("metallicRoughness") != std::string::npos)
{
Texture specular = Texture((fileDirectory + texPath).c_str(), "specular",
loadedTex.size());
textures.push_back(specular);
loadedTex.push_back(specular);
loadedTexName.push_back(texPath);
}
}
}

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;
}

std::vector<glm::vec2> Model::groupFloatsVec2(std::vector<float> floatVec)


{
std::vector<glm::vec2> vectors;
for (int i = 0; i < floatVec.size(); i)
{
vectors.push_back(glm::vec2(floatVec[i++], floatVec[i++]));
}
return vectors;
}
std::vector<glm::vec3> Model::groupFloatsVec3(std::vector<float> floatVec)
{
std::vector<glm::vec3> vectors;
for (int i = 0; i < floatVec.size(); i)
{
vectors.push_back(glm::vec3(floatVec[i++], floatVec[i++], floatVec[i++]));
}
return vectors;
}
std::vector<glm::vec4> Model::groupFloatsVec4(std::vector<float> floatVec)
{
std::vector<glm::vec4> vectors;
for (int i = 0; i < floatVec.size(); i)
{
vectors.push_back(glm::vec4(floatVec[i++], floatVec[i++], floatVec[i++], floatVec[i++]));
}
return vectors;
}

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;

Texture(const char* image, const char* texType, GLuint slot);

// Assigns a texture unit to a texture


void texUnit(Shader& shader, const char* uniform, GLuint unit);
// Binds a texture
void Bind();
// Unbinds a texture
void Unbind();
// Deletes a texture
void Delete();
};
#endif
Texture.cpp

#include"Texture.h"

Texture::Texture(const char* image, const char* texType, GLuint slot)


{
// Assigns the type of the texture ot the texture object
type = texType;

// 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);

// Generates an OpenGL texture object


glGenTextures(1, &ID);
// Assigns the texture to a Texture Unit
glActiveTexture(GL_TEXTURE0 + slot);
unit = slot;
glBindTexture(GL_TEXTURE_2D, 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);

// Extra lines in case you choose to use GL_CLAMP_TO_BORDER


// float flatColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
// glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, flatColor);

// 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);

// 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);
}

void Texture::texUnit(Shader& shader, const char* uniform, GLuint unit)


{
// Gets the location of the uniform
GLuint texUni = glGetUniformLocation(shader.ID, uniform);
// Shader needs to be activated before changing the value of a uniform
shader.Activate();
// Sets the value of the uniform
glUniform1i(texUni, unit);
}

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

#version 330 core

// 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;

// Outputs the current position for the Fragment Shader


out vec3 crntPos;
// Outputs the normal for the Fragment Shader
out vec3 Normal;
// Outputs the color for the Fragment Shader
out vec3 color;
// Outputs the texture coordinates to the Fragment Shader
out vec2 texCoord;

// Imports the camera matrix


uniform mat4 camMatrix;
// Imports the transformation matrices
uniform mat4 model;
uniform mat4 translation;
uniform mat4 rotation;
uniform mat4 scale;

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;

// Outputs the positions/coordinates of all vertices


gl_Position = camMatrix * vec4(crntPos, 1.0);
}

default.frag

#version 330 core

// Outputs colors in RGBA


out vec4 FragColor;

// Imports the current position from the Vertex Shader


in vec3 crntPos;
// Imports the normal from the Vertex Shader
in vec3 Normal;
// Imports the color from the Vertex Shader
in vec3 color;
// Imports the texture coordinates from the Vertex Shader
in vec2 texCoord;

// Gets the Texture Units from the main function


uniform sampler2D diffuse0;
uniform sampler2D specular0;
// Gets the color of the light from the main function
uniform vec4 lightColor;
// Gets the position of the light from the main function
uniform vec3 lightPos;
// Gets the position of the camera from the main function
uniform vec3 camPos;
vec4 pointLight()
{
// used in two variables so I calculate it here to not have to do it twice
vec3 lightVec = lightPos - crntPos;

// intensity of light with respect to distance


float dist = length(lightVec);
float a = 3.0;
float b = 0.7;
float inten = 1.0f / (a * dist * dist + b * dist + 1.0f);

// 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;

return (texture(diffuse0, texCoord) * (diffuse * inten + ambient) + texture(specular0, texCoord).r


* specular * inten) * lightColor;
}

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);

return (texture(diffuse0, texCoord) * (diffuse * inten + ambient) + texture(specular0, texCoord).r


* specular * inten) * lightColor;
}

void main()
{
// outputs final color
FragColor = direcLight();
}

Main.cpp

//------- Ignore this ----------


#include<filesystem>
namespace fs = std::filesystem;
//------------------------------

#include"Model.h"
const unsigned int width = 800;
const unsigned int height = 800;

int main()
{
// Initialize GLFW
glfwInit();

// Tell GLFW what version of OpenGL we are using


// In this case we are using OpenGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Tell GLFW we are using the CORE profile
// So that means we only have the modern functions
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

// 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);

//Load GLAD so it configures OpenGL


gladLoadGL();
// Specify the viewport of OpenGL in the Window
// In this case the viewport goes from x = 0, y = 0, to x = 800, y = 800
glViewport(0, 0, width, height);

// Generates Shader object using shaders default.vert and default.frag


Shader shaderProgram("default.vert", "default.frag");

// Take care of all the light related things


glm::vec4 lightColor = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
glm::vec3 lightPos = glm::vec3(0.5f, 0.5f, 0.5f);
glm::mat4 lightModel = glm::mat4(1.0f);
lightModel = glm::translate(lightModel, lightPos);

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);

// Enables the Depth Buffer


glEnable(GL_DEPTH_TEST);

// Creates camera object


Camera camera(width, height, glm::vec3(0.0f, 0.0f, 2.0f));

std::string parentDir = (fs::current_path().fs::path::parent_path()).string();


std::string modelPath = "/Resources/TU_DIRECTORIO_AQUI/models/bunny/scene.gltf";

// Load in a model
Model model((parentDir + modelPath).c_str());

// Model model("models/bunny/scene.gltf");

// Main while loop


while (!glfwWindowShouldClose(window))
{
// Specify the color of the background
glClearColor(0.07f, 0.13f, 0.17f, 1.0f);
// Clean the back buffer and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Handles camera inputs


camera.Inputs(window);
// Updates and exports the camera matrix to the Vertex Shader
camera.updateMatrix(45.0f, 0.1f, 100.0f);

// Draw a model
model.Draw(shaderProgram, camera);

// Swap the back buffer with the front buffer


glfwSwapBuffers(window);
// Take care of all GLFW events
glfwPollEvents();
}

// Delete all the objects we've created


shaderProgram.Delete();
// Delete window before ending the program
glfwDestroyWindow(window);
// Terminate GLFW before ending the program
glfwTerminate();
return 0;
}

You might also like