diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..000c6b3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +*.obj filter=lfs diff=lfs merge=lfs -text +*.mtl filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore index f38fb1c..912c4dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ lib/ build/ +.vscode diff --git a/Makefile b/Makefile index 683dab4..c30bb45 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = g++ -CFLAGS = -std=c++17 -O2 -LDFLAGS = -lglfw3 -lGL -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi +CFLAGS = -std=c++17 -O2 -g +LDFLAGS = -lglfw3 -lGL -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi -lz -lassimp OUT_NAME = LearnOpenGL build: src/*.cpp src/*.h @@ -9,4 +9,4 @@ build: src/*.cpp src/*.h run: build build/$(OUT_NAME) - ./build/$(OUT_NAME) \ No newline at end of file + ./build/$(OUT_NAME) diff --git a/Models/ao.jpg b/Models/ao.jpg new file mode 100644 index 0000000..0b28edb --- /dev/null +++ b/Models/ao.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7b0855da6e4f621546b5bbf8a41bc0963a898c44ccce578c89e6bf929cdcfd7 +size 1895126 diff --git a/Models/backpack.mtl b/Models/backpack.mtl new file mode 100644 index 0000000..868905e --- /dev/null +++ b/Models/backpack.mtl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9aaffb7ce3f968c01c3ab0e2de60fa38dff9695993c79d082c2e0a10c115cb5 +size 278 diff --git a/Models/backpack.obj b/Models/backpack.obj new file mode 100644 index 0000000..9c18219 --- /dev/null +++ b/Models/backpack.obj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d3253f4032314c72353b79cbe589ec5751f50c294668cfd55fe70988e1d64ea +size 6998040 diff --git a/Models/diffuse.jpg b/Models/diffuse.jpg new file mode 100644 index 0000000..cc28b9f --- /dev/null +++ b/Models/diffuse.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbac15f06974d2ff27ea3aa3c4c555025b4d90bef533a23bd6c89630efc8f582 +size 6108855 diff --git a/Models/normal.png b/Models/normal.png new file mode 100644 index 0000000..3a8a103 Binary files /dev/null and b/Models/normal.png differ diff --git a/Models/roughness.jpg b/Models/roughness.jpg new file mode 100644 index 0000000..2668d92 --- /dev/null +++ b/Models/roughness.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e6d31f76cd1cc19694c99f4c2d05dc75baf5f09580439ddf5f3cb934779df08 +size 4388250 diff --git a/Models/source_attribution.txt b/Models/source_attribution.txt new file mode 100644 index 0000000..31bb948 --- /dev/null +++ b/Models/source_attribution.txt @@ -0,0 +1,3 @@ +Model by Berk Gedik, from: https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36 + +Modified material assignment (Joey de Vries) for easier load in OpenGL model loading chapter, and renamed albedo to diffuse and metallic to specular to match non-PBR lighting setup. \ No newline at end of file diff --git a/Models/specular.jpg b/Models/specular.jpg new file mode 100644 index 0000000..08395c7 --- /dev/null +++ b/Models/specular.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfc3fac4a52b709caa998aec8699ae2421f59ae8c353c7e05779cd93cff8153b +size 6722296 diff --git a/Textures/container.jpg b/Textures/container.jpg index d07bee4..f04776f 100644 Binary files a/Textures/container.jpg and b/Textures/container.jpg differ diff --git a/Textures/wall.jpg b/Textures/wall.jpg index 4963198..2f81ab7 100644 Binary files a/Textures/wall.jpg and b/Textures/wall.jpg differ diff --git a/shader.fs b/shader.fs index 19e2d9b..1026dc2 100644 --- a/shader.fs +++ b/shader.fs @@ -1,99 +1,11 @@ #version 460 core out vec4 FragColor; -in vec3 Normal; -in vec3 FragPos; in vec2 TexCoords; -struct Material { - sampler2D diffuse; - sampler2D specular; - float shininess; -}; - -struct DirLight { - vec3 direction; - - vec3 ambient; - vec3 diffuse; - vec3 specular; - -}; - -struct PointLight{ - vec3 position; - - float constant; - float linear; - float quadratic; - - vec3 ambient; - vec3 diffuse; - vec3 specular; -}; - -#define NR_POINT_LIGHTS 4 - -uniform PointLight PointLights[NR_POINT_LIGHTS]; -uniform DirLight dirlight; -uniform Material material; - - -uniform vec3 viewPos; - -vec3 CalcDirLight(DirLight light , vec3 normal , vec3 viewDir) -{ - vec3 lightDir = normalize(-light.direction); - float diff = max(dot(normal,lightDir), 0.0); - vec3 reflectDir = reflect(-lightDir, normal); - float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); - - vec3 ambient = light.ambient * vec3 (texture(material.diffuse, TexCoords)); - vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); - vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); - - return (ambient + diffuse + specular); -} - -vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) -{ - vec3 lightDir = normalize(light.position - fragPos ); - - float diff = max(dot(normal, lightDir), 0.0); - - vec3 reflectDir = reflect(-lightDir, normal); - float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); - - float distance = length(light.position - fragPos); - float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance *distance)); - - vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); - vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); - vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); - - ambient *= attenuation; - diffuse *= attenuation; - specular *= attenuation; - - return (ambient + diffuse + specular); - -} - - +uniform sampler2D texture_diffuse1; void main() { - - vec3 norm = normalize(Normal); - vec3 viewDir = normalize(viewPos - FragPos); - - // Fase 1 : Directional lighting - vec3 result = CalcDirLight(dirlight, norm, viewDir); - - // Fase 2 : Point lights - for( int i = 0; i < NR_POINT_LIGHTS; i++){ - result += CalcPointLight(PointLights[i], norm, FragPos, viewDir); - } - - FragColor = vec4(result, 1.0); + FragColor = texture( texture_diffuse1, TexCoords); } \ No newline at end of file diff --git a/shader.vs b/shader.vs index aa0fe56..3afcf99 100644 --- a/shader.vs +++ b/shader.vs @@ -7,15 +7,11 @@ uniform mat4 model; uniform mat4 view; uniform mat4 projection; -out vec3 FragPos; -out vec3 Normal; out vec2 TexCoords; void main(){ gl_Position = projection * view * model * vec4(aPos , 1.0); - FragPos = vec3(model * vec4(aPos, 1.0)); - Normal = mat3(transpose(inverse(model))) * aNormal; TexCoords = aTexCoords; } diff --git a/src/main.cpp b/src/main.cpp index 5ba48a6..15d9ee8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,10 +8,9 @@ #include #include - -#include "stb_image.h" #include "shader.h" #include "camera.h" +#include "model.h" float deltaTime = 0.0f; // Time between current frame and last frame float lastFrame = 0.0f; // Time of last frame @@ -86,148 +85,19 @@ int main() { glViewport(0,0, 800, 600); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwSetCursorPosCallback(window, mouse_callback); + glfwSetScrollCallback(window, scroll_callback); + + glEnable(GL_DEPTH_TEST); + stbi_set_flip_vertically_on_load(true); - Shader lightshader("lightsource.vs", "lightsource.fs"); Shader shader ("shader.vs", "shader.fs"); -float vertices[] = { - // positions // normals // texture coords - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, - - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - - -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, - -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - - -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, - - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f -}; - -glm::vec3 cubePositions[] = { - glm::vec3( 0.0f, 0.0f, 0.0f), - glm::vec3( 2.0f, 5.0f, -15.0f), - glm::vec3(-1.5f, -2.2f, -2.5f), - glm::vec3(-3.8f, -2.0f, -12.3f), - glm::vec3( 2.4f, -0.4f, -3.5f), - glm::vec3(-1.7f, 3.0f, -7.5f), - glm::vec3( 1.3f, -2.0f, -2.5f), - glm::vec3( 1.5f, 2.0f, -2.5f), - glm::vec3( 1.5f, 0.2f, -1.5f), - glm::vec3(-1.3f, 1.0f, -1.5f) -}; - -glm::vec3 lightPositions[] = { - glm::vec3( 0.7f, 0.2f, 2.0f), - glm::vec3( 2.3f, -3.3f, -4.0f), - glm::vec3(-4.0f, 2.0f, -12.0f), - glm::vec3( 0.0f, 0.0f, -3.0f) -}; - - unsigned int VBO, VAO; - glGenVertexArrays(1, &VAO); - glGenBuffers(1, &VBO); - - glBindVertexArray(VAO); - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - // position attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); - - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (3*sizeof(float))); - glEnableVertexAttribArray(1); - - glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE, 8 * sizeof(float), (void*) (6*sizeof(float))); - glEnableVertexAttribArray(2); + Model backpack("Models/backpack.obj"); - unsigned int lightVAO; - glGenVertexArrays(1, &lightVAO); - glBindVertexArray(lightVAO); - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - - glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE, 8* sizeof(float), (void*) 0); - glEnableVertexAttribArray(0); - -// Load diffuse texture -int width, height, nrChannels; -unsigned int diffuseMap; -glGenTextures(1, &diffuseMap); - -glActiveTexture(GL_TEXTURE0); -glBindTexture(GL_TEXTURE_2D, diffuseMap); - -glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); -glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - -unsigned char* data = stbi_load("Textures/container2.png", &width, &height, &nrChannels, 0); -if(data){ - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); -} else{ - std::cout << "Error loading texture...." << std::endl; -} - -stbi_image_free(data); - -// Load Specular texture -unsigned int specularMap; -glGenTextures(1, &specularMap); - -glActiveTexture(GL_TEXTURE1); -glBindTexture(GL_TEXTURE_2D, specularMap); - -unsigned char* specular_data = stbi_load("Textures/container2_specular.png", &width, &height, &nrChannels, 0); -if( specular_data ){ - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, specular_data); - glGenerateMipmap(GL_TEXTURE_2D); -}else{ - std::cout << "Error loading texture...." << std::endl; -} - -stbi_image_free(specular_data); - - - -glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); -glfwSetCursorPosCallback(window, mouse_callback); -glfwSetScrollCallback(window, scroll_callback); glEnable(GL_DEPTH_TEST); while(!glfwWindowShouldClose(window)) @@ -241,155 +111,28 @@ while(!glfwWindowShouldClose(window)) glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + shader.use(); glm::mat4 model = glm::mat4(1.0f); glm::mat4 view = glm::mat4(1.0f); glm::mat4 projection = glm::mat4(1.0f); view = camera.GetViewMatrix(); - - projection = glm::perspective(glm::radians(camera.Zoom), (float)800 / (float)600, 0.1f, 100.0f); - - float orbital_speed = .4 ; - - - - - // draw cubes - shader.use(); - shader.setInt("material.diffuse", 0); - shader.setInt("material.specular", 1); - shader.setVec3("material.specular", glm::vec3(0.5, 0.5f, 0.5f)); - shader.setFloat("material.shininess", 32.0f); - - -/* -Directional light - vec3 direction; - - vec3 ambient; - vec3 diffuse; - vec3 specular; -*/ - - shader.setVec3("dirlight.direction", glm::vec3(1.0f,0.0f, 2.0f)); - - - shader.setVec3("dirlight.ambient", glm::vec3(0.2f, 0.2f, 0.2f)); - shader.setVec3("dirlight.diffuse", glm::vec3(0.5f, 0.5f, 0.5f)); - shader.setVec3("dirlight.specular", glm::vec3(1.0f, 1.0f, 1.0f)); - - - - -/* - Point Lights; -*/ - - - - shader.setVec3("PointLights[0].position", glm::vec3( 0.7f, 0.2f, 2.0f)); - shader.setVec3("PointLights[1].position", glm::vec3( 2.3f, -3.3f, -4.0f)); - shader.setVec3("PointLights[2].position", glm::vec3(-4.0f, 2.0f, -12.0f)); - shader.setVec3("PointLights[3].position", glm::vec3( 0.0f, 0.0f, -3.0f)); - - - shader.setVec3("PointLights[0].ambient", glm::vec3(0.2f, 0.2f, 0.2f)); - shader.setVec3("PointLights[0].diffuse", glm::vec3(0.5f, 0.5f, 0.5f)); - shader.setVec3("PointLights[0].specular", glm::vec3(1.0f, 1.0f, 1.0f)); - - shader.setVec3("PointLights[1].ambient", glm::vec3(0.2f, 0.2f, 0.2f)); - shader.setVec3("PointLights[1].diffuse", glm::vec3(0.5f, 0.5f, 0.5f)); - shader.setVec3("PointLights[1].specular", glm::vec3(1.0f, 1.0f, 1.0f)); - - shader.setVec3("PointLights[2].ambient", glm::vec3(0.2f, 0.2f, 0.2f)); - shader.setVec3("PointLights[2].diffuse", glm::vec3(0.5f, 0.5f, 0.5f)); - shader.setVec3("PointLights[2].specular", glm::vec3(1.0f, 1.0f, 1.0f)); - - shader.setVec3("PointLights[3].ambient", glm::vec3(0.2f, 0.2f, 0.2f)); - shader.setVec3("PointLights[3].diffuse", glm::vec3(0.5f, 0.5f, 0.5f)); - shader.setVec3("PointLights[3].specular", glm::vec3(1.0f, 1.0f, 1.0f)); - - - - - shader.setFloat("PointLights[0].constant", 1.0f); - shader.setFloat("PointLights[1].constant", 1.0f); - shader.setFloat("PointLights[2].constant", 1.0f); - shader.setFloat("PointLights[3].constant", 1.0f); - - shader.setFloat("PointLights[0].linear", 0.09f); - shader.setFloat("PointLights[1].linear", 0.09f); - shader.setFloat("PointLights[2].linear", 0.09f); - shader.setFloat("PointLights[3].linear", 0.09f); - - - shader.setFloat("PointLights[0].quadratic", 0.032f); - shader.setFloat("PointLights[1].quadratic", 0.032f); - shader.setFloat("PointLights[2].quadratic", 0.032f); - shader.setFloat("PointLights[3].quadratic", 0.032f); - - shader.setVec3("viewPos", camera.Position); - - shader.setMat4("view", view); - shader.setMat4("projection", projection); - - + projection = glm::perspective(glm::radians(camera.Zoom), (float)800 / (float)600, 0.1f, 100.0f); model = glm::mat4(1.0); + + shader.setMat4("projection", projection); + shader.setMat4("view", view); shader.setMat4("model", model); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, diffuseMap); + backpack.Draw(shader); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, specularMap); - for( unsigned int i = 0; i < 10; i++ ){ - glm::mat4 model = glm::mat4(1.0f); - model = glm::translate(model , cubePositions[i]); - float angle = 20.0f * i; - model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); - shader.setMat4("model", model); - - glBindVertexArray(VAO); - glDrawArrays(GL_TRIANGLES, 0, 36); - - - } - - - - - - // draw lights - lightshader.use(); - lightshader.setMat4("view", view); - lightshader.setMat4("projection", projection); - - model = glm::mat4(1.0f); - model = glm::translate(model, lightpos); - model = glm::scale(model, glm::vec3(0.2f)); - - - for ( int i = 0; i < 4 ; i ++){ - - model = glm::translate(model, lightPositions[i]); - lightshader.setMat4("model", model); - - glBindVertexArray(lightVAO); - glDrawArrays(GL_TRIANGLES, 0, 36); - - } - glfwSwapBuffers(window); glfwPollEvents(); } -glDeleteVertexArrays(1, &VAO); -glDeleteVertexArrays(1, &lightVAO); -glDeleteBuffers(1, &VBO); glfwTerminate(); diff --git a/src/mesh.cpp b/src/mesh.cpp new file mode 100644 index 0000000..0ca58b1 --- /dev/null +++ b/src/mesh.cpp @@ -0,0 +1,65 @@ +#include "mesh.h" + + +Mesh::Mesh(std::vector vertices, std::vector indices, std::vector textures) +: vertices(vertices) , indices(indices), textures(textures){ + setupMesh(); +} + +void Mesh::setupMesh(){ + + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + glGenBuffers(1, &EBO); + + glBindVertexArray(VAO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); + + // vertex positions + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) 0); + + // vertex normals + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal)); + + // vertex texture coords + glEnableVertexAttribArray(2); + glVertexAttribPointer(2,2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords)); + + glBindVertexArray(0); +} + +void Mesh::Draw( Shader &shader){ + unsigned int diffuseNr = 1; + unsigned int specularNr = 1; + + for(unsigned int i = 0; i < textures.size(); i++){ + glActiveTexture(GL_TEXTURE0 + i); + + std::string number; + std::string name = textures[i].type; + if( name == "texture_diffuse") + number = std::to_string(diffuseNr++); + else if(name == "texture_specular") + number = std::to_string(specularNr++); + + glUniform1i( glGetUniformLocation( shader.ID, (name + number).c_str()), i); + glBindTexture(GL_TEXTURE_2D, textures[i].id); + } + // draw mesh + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, static_cast (indices.size()), GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + + + glActiveTexture(GL_TEXTURE0); + + +} + diff --git a/src/mesh.h b/src/mesh.h new file mode 100644 index 0000000..f717f01 --- /dev/null +++ b/src/mesh.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include + + +#include +#include + +#include "vertex.h" +#include "texture.h" +#include "shader.h" + +class Mesh{ + public: + // Mesh data + std::vector vertices; + std::vector indices; + std::vector textures; + + Mesh(std::vector vertices, std::vector indices, std::vector textures); + void Draw(Shader &shader); + private: + // render data + unsigned int VAO, VBO, EBO; + + void setupMesh(); + +}; \ No newline at end of file diff --git a/src/model.cpp b/src/model.cpp new file mode 100644 index 0000000..aa6582f --- /dev/null +++ b/src/model.cpp @@ -0,0 +1,190 @@ +#include "model.h" + + +Model::Model(std::string const& path){ + loadModel(path); +} + +void Model::Draw(Shader& shader) +{ + for(unsigned int i = 0; i < meshes.size(); i++) + meshes[i].Draw(shader); +} + +void Model::loadModel(std::string path) +{ + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); + + if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) + { + std::cout << "ERROR::ASSIMP::" << importer.GetErrorString() << std::endl; + return; + } + + directory = path.substr(0, path.find_last_of('/')); + + processNode(scene->mRootNode, scene); + +} + + +void Model::processNode (aiNode* node, const aiScene* scene) +{ + + for(unsigned int i = 0; i < node->mNumMeshes; i++) + { + aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + meshes.push_back(processMesh(mesh, scene)); + } + + + for(unsigned int i = 0; i < node->mNumChildren; i++) + { + + processNode(node->mChildren[i], scene); + } + + +} + + + + unsigned int TextureFromFile(const char* path, const std::string& directory) + { + std::string filename = std::string(path); + filename = directory + '/' + filename; + + unsigned int textureID; + glGenTextures(1, &textureID); + + int width, height, nrComponents; + unsigned char* data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0); + if(data) + { + GLenum format; + if(nrComponents == 1) + format = GL_RED; + else if (nrComponents == 3) + format = GL_RGB; + else if (nrComponents == 4) + format = GL_RGBA; + + glBindTexture(GL_TEXTURE_2D, textureID); + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + + } else{ + std::cout << "Texture failed to load at path: " << path << std::endl; + + } + + stbi_image_free(data); + return textureID; + } + + +Mesh Model::processMesh (aiMesh* mesh, const aiScene* scene) +{ + std::vector vertices; + std::vector indices; + std::vector textures; + + for(unsigned int i = 0; i < mesh->mNumVertices; i++){ + Vertex vertex; + // process vertex positions , normals and texture coordinates + glm::vec3 vector; + vector.x = mesh->mVertices[i].x; + vector.y = mesh->mVertices[i].y; + vector.z = mesh->mVertices[i].z; + vertex.Position = vector; + + if( mesh->HasNormals()){ + vector.x = mesh->mNormals[i].x; + vector.y = mesh->mNormals[i].y; + vector.z = mesh->mNormals[i].z; + vertex.Normal = vector; + } + + if(mesh->mTextureCoords[0]){ + glm::vec2 vec; + + + vec.x = mesh->mTextureCoords[0][i].x; + vec.y = mesh->mTextureCoords[0][i].y; + + //std::cout << "texCoord: x=" << vec.x << " y=" << vec.y << std::endl; + vertex.TexCoords = vec; + } else{ + vertex.TexCoords = glm::vec2(0,0); + } + + vertices.push_back(vertex); + } + + // process indices + for(unsigned int i = 0; i < mesh->mNumFaces; i++ ){ + aiFace face = mesh->mFaces[i]; + if(face.mNumIndices < 3) + continue; + + for(unsigned int j = 0; j < face.mNumIndices; j++) + indices.push_back(face.mIndices[j]); + } + // process material + if(mesh->mMaterialIndex >= 0) + { + aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; + std::vector diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse"); + + textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); + std::vector specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular"); + textures.insert(textures.end(),specularMaps.begin(), specularMaps.end()); + + } + + + return Mesh(vertices, indices, textures); + + + +} + + + std::vector Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName ){ + std::vector textures; + for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) + { + aiString str; + mat->GetTexture(type, i, &str); + bool skip = false; + + + for(unsigned int j = 0; j < textures_loaded.size(); j++){ + + if( std::strcmp(textures_loaded[j].path.data(), str.C_Str()) == 0){ + textures.push_back(textures_loaded[j]); + skip = true; + break; + } + } + + if( !skip) + { + Texture texture; + texture.id = TextureFromFile(str.C_Str(), this->directory); + texture.type = typeName; + texture.path = str.C_Str(); + textures.push_back(texture); + textures_loaded.push_back(texture); + } + + } + return textures; + } diff --git a/src/model.h b/src/model.h new file mode 100644 index 0000000..a4f9d21 --- /dev/null +++ b/src/model.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include + +#include "mesh.h" +#include "shader.h" + + +#include "stb_image.h" + +#include // C++ importer interface +#include // Output data structure +#include // Post Processing flags +class Model { + public: + + + Model(std::string const& path); + void Draw(Shader& shader); + private: + // model data + + std::vector textures_loaded; + std::vector meshes; + std::string directory; + + void loadModel(std::string path); + void processNode(aiNode* node, const aiScene* scene ); + Mesh processMesh(aiMesh* mesh, const aiScene* scene); + std::vector loadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName ); +}; diff --git a/src/shader.cpp b/src/shader.cpp new file mode 100644 index 0000000..d1867a2 --- /dev/null +++ b/src/shader.cpp @@ -0,0 +1,112 @@ +#include "shader.h" + +Shader::Shader(const char* vertextPath, const char* fragmentPath) +{ + // retrieve the vertex / fragment source code from filepath + std::string vertexCode; + std::string fragmentCode; + std::ifstream vShaderFile; + std::ifstream fShaderFile; + + vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); + fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + try{ + vShaderFile.open(vertextPath); + fShaderFile.open(fragmentPath); + + std::stringstream vShaderStream,fShaderStream; + + vShaderStream << vShaderFile.rdbuf(); + fShaderStream << fShaderFile.rdbuf(); + + vShaderFile.close(); + fShaderFile.close(); + + vertexCode = vShaderStream.str(); + fragmentCode = fShaderStream.str(); + + + } + catch(std::ifstream::failure e){ + std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl << e.what() << std::endl ; + } + + const char* vShaderCode = vertexCode.c_str(); + const char* fShaderCode = fragmentCode.c_str(); + + + // Compile Shaders + unsigned int vertex, fragment; + int success; + char infoLog[512]; + + // vertex shader + vertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex, 1, &vShaderCode, NULL); + glCompileShader(vertex); + + // print any compile errors if there are any + glGetShaderiv(vertex,GL_COMPILE_STATUS, &success); + if(!success) + { + glGetShaderInfoLog(vertex, 512, NULL, infoLog); + std::cout << "ERROR::SHADER:::VERTEX::COMPILATION_FAILED" << std::endl << infoLog << std::endl; + } + + // fragment shader + + fragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment, 1, &fShaderCode, NULL); + glCompileShader(fragment); + + glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); + if(!success){ + glGetShaderInfoLog(fragment, 512, NULL, infoLog); + std::cout << "ERROR::SHADER:::VERTEX::COMPILATION_FAILED" << std::endl << infoLog << std::endl; + } + + + // Shader Program + ID = glCreateProgram(); + glAttachShader(ID, vertex); + glAttachShader(ID, fragment); + glLinkProgram(ID); + + glGetProgramiv(ID, GL_LINK_STATUS, &success); + if(!success){ + glGetProgramInfoLog(ID, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED" << std::endl << infoLog << std::endl; + } + + // delete shaders as they're now linked into our program and no longer necessary + glDeleteShader(vertex); + glDeleteShader(fragment); + + +} + + +void Shader::use(){ + glUseProgram(ID); +} + +void Shader::setBool(const std::string &name, bool value) const{ + glUniform1i(glGetUniformLocation(ID, name.c_str()), (int) value ); +} + +void Shader::setInt(const std::string &name, int value) const{ + glUniform1i(glGetUniformLocation(ID, name.c_str()), value ); +} + +void Shader::setFloat(const std::string &name, float value) const{ + glUniform1f(glGetUniformLocation(ID, name.c_str()), value ); +} + +void Shader::setMat4(const std::string &name, glm::mat4 value)const{ + glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &value[0][0] ); +} + +void Shader::setVec3(const std::string &name, glm::vec3 value)const{ + glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value.x); +} \ No newline at end of file diff --git a/src/shader.h b/src/shader.h index e44bb1a..da94717 100644 --- a/src/shader.h +++ b/src/shader.h @@ -1,6 +1,6 @@ #pragma once #include - +#include #include #include #include @@ -25,114 +25,3 @@ class Shader }; - -Shader::Shader(const char* vertextPath, const char* fragmentPath) -{ - // retrieve the vertex / fragment source code from filepath - std::string vertexCode; - std::string fragmentCode; - std::ifstream vShaderFile; - std::ifstream fShaderFile; - - vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); - fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); - - try{ - vShaderFile.open(vertextPath); - fShaderFile.open(fragmentPath); - - std::stringstream vShaderStream,fShaderStream; - - vShaderStream << vShaderFile.rdbuf(); - fShaderStream << fShaderFile.rdbuf(); - - vShaderFile.close(); - fShaderFile.close(); - - vertexCode = vShaderStream.str(); - fragmentCode = fShaderStream.str(); - - - } - catch(std::ifstream::failure e){ - std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl << e.what() << std::endl ; - } - - const char* vShaderCode = vertexCode.c_str(); - const char* fShaderCode = fragmentCode.c_str(); - - - // Compile Shaders - unsigned int vertex, fragment; - int success; - char infoLog[512]; - - // vertex shader - vertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertex, 1, &vShaderCode, NULL); - glCompileShader(vertex); - - // print any compile errors if there are any - glGetShaderiv(vertex,GL_COMPILE_STATUS, &success); - if(!success) - { - glGetShaderInfoLog(vertex, 512, NULL, infoLog); - std::cout << "ERROR::SHADER:::VERTEX::COMPILATION_FAILED" << std::endl << infoLog << std::endl; - } - - // fragment shader - - fragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragment, 1, &fShaderCode, NULL); - glCompileShader(fragment); - - glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); - if(!success){ - glGetShaderInfoLog(fragment, 512, NULL, infoLog); - std::cout << "ERROR::SHADER:::VERTEX::COMPILATION_FAILED" << std::endl << infoLog << std::endl; - } - - - // Shader Program - ID = glCreateProgram(); - glAttachShader(ID, vertex); - glAttachShader(ID, fragment); - glLinkProgram(ID); - - glGetProgramiv(ID, GL_LINK_STATUS, &success); - if(!success){ - glGetProgramInfoLog(ID, 512, NULL, infoLog); - std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED" << std::endl << infoLog << std::endl; - } - - // delete shaders as they're now linked into our program and no longer necessary - glDeleteShader(vertex); - glDeleteShader(fragment); - - -} - - -void Shader::use(){ - glUseProgram(ID); -} - -void Shader::setBool(const std::string &name, bool value) const{ - glUniform1i(glGetUniformLocation(ID, name.c_str()), (int) value ); -} - -void Shader::setInt(const std::string &name, int value) const{ - glUniform1i(glGetUniformLocation(ID, name.c_str()), value ); -} - -void Shader::setFloat(const std::string &name, float value) const{ - glUniform1f(glGetUniformLocation(ID, name.c_str()), value ); -} - -void Shader::setMat4(const std::string &name, glm::mat4 value)const{ - glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &value[0][0] ); -} - -void Shader::setVec3(const std::string &name, glm::vec3 value)const{ - glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value.x); -} \ No newline at end of file diff --git a/src/texture.h b/src/texture.h new file mode 100644 index 0000000..8475b1a --- /dev/null +++ b/src/texture.h @@ -0,0 +1,8 @@ +#pragma once +#include + +struct Texture{ + unsigned int id; + std::string type; + std::string path; +}; diff --git a/src/vertex.h b/src/vertex.h new file mode 100644 index 0000000..f111db5 --- /dev/null +++ b/src/vertex.h @@ -0,0 +1,8 @@ +#pragma once +#include + +struct Vertex { + glm::vec3 Position; + glm::vec3 Normal; + glm::vec2 TexCoords; +};