Add basics of materials
authorLuke Lau <luke_lau@icloud.com>
Wed, 31 Oct 2018 01:06:30 +0000 (01:06 +0000)
committerLuke Lau <luke_lau@icloud.com>
Wed, 31 Oct 2018 01:06:30 +0000 (01:06 +0000)
Makefile
main.cpp
material.cpp [new file with mode: 0644]
material.hpp [new file with mode: 0644]
model.cpp
model.hpp
texturefrag.glsl [new file with mode: 0644]
vertex.glsl

index 5b60118..acf1a24 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 all: main
        
 main:
-       clang++ -g --std=c++11 *.cpp -L/usr/local/lib -lassimp -framework OpenGL -framework glut -lglew -o bin/main
+       clang++ -g --std=c++11 *.cpp -L/usr/local/lib -lassimp -framework OpenGL -framework glut -framework CoreGraphics -framework CoreFoundation -lglew -o bin/main
        ctags *.cpp
index 3703395..727c5ff 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -22,7 +22,7 @@
 using namespace std;
 
 GLuint pyramidVao, lightVao, teapotVao;
-GLuint gradientProgId, plainProgId, normalProgId, solidProgId;
+GLuint gradientProgId, plainProgId, normalProgId, solidProgId, textureProgId;
 glm::vec3 camPos   = glm::vec3(0.0f, 0.0f,  -10.0f);
 glm::vec3 camFront = glm::vec3(0.0f, 0.0f, 1.0f);
 glm::vec3 camUp    = glm::vec3(0.0f, 1.0f,  0.0f);
@@ -50,6 +50,9 @@ void setLightColorAndPos(GLuint progId, glm::vec3 lightPos, glm::vec4 lightColor
 
        GLuint lightPosLoc = glGetUniformLocation(progId, "lightPos");
        glUniform3fv(lightPosLoc, 1, glm::value_ptr(lightPos));
+
+       GLuint viewPosLoc = glGetUniformLocation(progId, "viewPos");
+       glUniform3fv(viewPosLoc, 1, glm::value_ptr(camPos));
 }
 
 void drawLight(float d, glm::vec3 lightPos, glm::vec4 lightColor) {
@@ -75,9 +78,6 @@ void drawPyramids(float d, glm::vec3 lightPos, glm::vec4 lightColor) {
 
        setLightColorAndPos(gradientProgId, lightPos, lightColor);
 
-       GLuint viewPosLoc = glGetUniformLocation(gradientProgId, "viewPos");
-       glUniform3fv(viewPosLoc, 1, glm::value_ptr(camPos));
-
        GLuint modelId = glGetUniformLocation(gradientProgId, "model");
 
        for (int i = 0; i < 10; i++) {
@@ -156,7 +156,8 @@ void display() {
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        float d = (float)glutGet(GLUT_ELAPSED_TIME) * 0.001f;
 
-       glm::vec3 lightPos = glm::vec3(sin(d) * 10, 0, cos(d) * 10);
+       /* glm::vec3 lightPos = glm::vec3(sin(d) * 10, 0, cos(d) * 10); */
+       glm::vec3 lightPos = glm::vec3(0, 10, 10);
        glm::vec4 lightColor(1, 1, 1, 1);
 
        glViewport(0, 0, WIDTH, HEIGHT);
@@ -174,13 +175,17 @@ void display() {
        monkeyHead->getRoot()->model = glm::translate(glm::mat4(1), glm::vec3(2, 0, 0));
        monkeyHead->draw();
 
+       glUseProgram(textureProgId);
+       setProjectionAndViewUniforms(textureProgId);
+       setLightColorAndPos(textureProgId, lightPos, lightColor);
+
        Model::Node *top = chest->find("top");
        top->model = glm::translate(glm::mat4(1), glm::vec3(0, 1, -1));
        top->model = glm::rotate(top->model, sin(d / 2.5f) * 0.5f, glm::vec3(1, 0, 0));
        top->model = glm::translate(top->model, glm::vec3(0, -1, 1));
        
-       Model::Node *jewels = chest->find("jewels");
-       jewels->model = glm::scale(glm::mat4(1), glm::vec3((sin(d) + 1.2f) / 2.f));
+       /* Model::Node *jewels = chest->find("jewels"); */
+       /* jewels->model = glm::scale(glm::mat4(1), glm::vec3((sin(d) + 1.2f) / 2.f)); */
 
        Model::Node *lock = chest->find("lock");
        lock->model = glm::translate(glm::mat4(1), glm::vec3(0.22610, 3.36478, -0.75649));
@@ -506,8 +511,12 @@ void init() {
        glUseProgram(solidProgId);
        validateProgram(solidProgId);
 
+       textureProgId = compileShaders((char*)"vertex.glsl", (char*)"texturefrag.glsl");
+       glUseProgram(textureProgId);
+       validateProgram(textureProgId);
+
        monkeyHead = new Model("monkeyhead_smooth.dae", solidProgId);
-       chest = new Model("chest.dae", solidProgId);
+       chest = new Model("chest.dae", textureProgId);
 
        glEnable(GL_DEPTH_TEST); 
        glEnable(GL_CULL_FACE); 
diff --git a/material.cpp b/material.cpp
new file mode 100644 (file)
index 0000000..470f1a2
--- /dev/null
@@ -0,0 +1,42 @@
+#include "material.hpp"
+#include <iostream>
+#include <CoreGraphics/CoreGraphics.h>
+
+Material::Material(const aiMaterial &ai, GLuint progId): progId(progId) {
+       if (ai.GetTextureCount(aiTextureType_DIFFUSE) > 0) {
+               aiString path;
+               ai.GetTexture(aiTextureType_DIFFUSE, 0, &path);
+               texture = new Texture(std::string(path.C_Str()));
+       }
+       ai.Get(AI_MATKEY_SHININESS, shininess);
+       ai.Get(AI_MATKEY_COLOR_AMBIENT, ambient);
+       ai.Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
+       ai.Get(AI_MATKEY_COLOR_SPECULAR, specular);
+}
+
+Material::Texture::Texture(const std::string &path) {
+       auto provider = CGDataProviderCreateWithFilename(path.c_str());
+       auto ref = CGImageCreateWithJPEGDataProvider(provider, nullptr, false, kCGRenderingIntentDefault);
+       auto dataRef = CGDataProviderCopyData(CGImageGetDataProvider(ref));
+       auto img = (unsigned char*) CFDataGetBytePtr(dataRef);
+
+       glGenTextures(1, &texId);
+       glBindTexture(GL_TEXTURE_2D, texId);
+       auto width = CGImageGetWidth(ref), height = CGImageGetHeight(ref);
+       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
+       glGenerateMipmap(GL_TEXTURE_2D);
+
+       CGImageRelease(ref);
+       CFRelease(dataRef);
+}
+
+void Material::bind() const {
+       glUniform3f(glGetUniformLocation(progId, "material.ambient"), ambient.r, ambient.g, ambient.b);
+       glUniform3f(glGetUniformLocation(progId, "material.diffuse"), diffuse.r, diffuse.g, diffuse.b);
+       glUniform3f(glGetUniformLocation(progId, "material.specular"), specular.r, specular.g, specular.b);
+       glUniform1f(glGetUniformLocation(progId, "material.shininess"), shininess);
+       glUniform1i(glGetUniformLocation(progId, "material.hasTexture"), texture != nullptr);
+
+       if (texture) 
+               glBindTexture(GL_TEXTURE_2D, texture->texId);
+}
diff --git a/material.hpp b/material.hpp
new file mode 100644 (file)
index 0000000..968ea36
--- /dev/null
@@ -0,0 +1,24 @@
+#include <string>
+#ifdef __APPLE__
+#include <GL/glew.h>
+#else
+#include <OpenGL/glew.h>
+#endif
+#include <assimp/scene.h>
+
+class Material {
+       public:
+               Material(const aiMaterial &aiMaterial, GLuint progId);
+               void bind() const;
+       private:
+               GLuint progId;
+               aiColor3D ambient, diffuse, specular;
+               ai_real shininess;
+
+               struct Texture {
+                       Texture(const std::string &path);
+                       GLuint texId;
+               };
+               Texture *texture = nullptr;
+};
+
index 29f4415..4c5e2d3 100644 (file)
--- a/model.cpp
+++ b/model.cpp
@@ -23,7 +23,10 @@ Model::Mesh::Mesh(const aiMesh *aiMesh, GLuint progId) {
                if (aiMesh->HasTextureCoords(0)) {
                        const aiVector3D v = aiMesh->mTextureCoords[0][i];
                        texCoords.push_back(glm::vec2(v.x, v.y));
+               } else {
+                       texCoords.push_back(glm::vec2(0));
                }
+               materialIndex = aiMesh->mMaterialIndex;
        }
 
        std::vector<GLuint> indices;
@@ -42,12 +45,13 @@ Model::Mesh::Mesh(const aiMesh *aiMesh, GLuint progId) {
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);
        
-       GLuint vbos[3];
-       glGenBuffers(3, vbos);
-       GLuint vertexVbo = vbos[0], normalVbo = vbos[1], indicesVbo = vbos[2];
+       GLuint vbos[4];
+       glGenBuffers(4, vbos);
+       GLuint vertexVbo = vbos[0], normalVbo = vbos[1], texCoordVbo = vbos[2], indicesVbo = vbos[3];
        
        GLuint posLoc = glGetAttribLocation(progId, "vPosition");
        GLuint normalLoc = glGetAttribLocation(progId, "vNormal");
+       GLuint texCoordLoc = glGetAttribLocation(progId, "vTexCoord");
        
        glBindBuffer(GL_ARRAY_BUFFER, vertexVbo);
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
@@ -59,6 +63,11 @@ Model::Mesh::Mesh(const aiMesh *aiMesh, GLuint progId) {
        glEnableVertexAttribArray(normalLoc);
        glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
 
+       glBindBuffer(GL_ARRAY_BUFFER, texCoordVbo);
+       glBufferData(GL_ARRAY_BUFFER, texCoords.size() * sizeof(glm::vec2), &texCoords[0], GL_STATIC_DRAW);
+       glEnableVertexAttribArray(texCoordLoc);
+       glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesVbo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), &indices[0], GL_STATIC_DRAW);
 };
@@ -81,20 +90,25 @@ glm::mat4 aiMatrixToMat4(aiMatrix4x4 from) {
        return to;
 }
 
-void Model::Node::draw(const std::vector<Mesh> &meshes, glm::mat4 parentTrans = glm::mat4(1)) const {
+void Model::Node::draw(        const std::vector<Mesh> &meshes,
+                                               const std::vector<Material> &materials,
+                                               glm::mat4 parentTrans = glm::mat4(1)) const {
+
        GLuint modelLoc = glGetUniformLocation(progId, "model");
        glm::mat4 m = parentTrans * aiMatrixToMat4(ai.mTransformation) * model;
        
        for (unsigned int i: meshIndices) {
                const Mesh &mesh = meshes[i];
-
                glBindVertexArray(mesh.vao);
 
+               Material material = materials[mesh.materialIndex];
+               material.bind();
+               
                glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(m));
 
                glDrawElements(GL_TRIANGLES, mesh.numIndices, GL_UNSIGNED_INT, 0);
        }
-       for (Node *child: children) child->draw(meshes, m);
+       for (Node *child: children) child->draw(meshes, materials, m);
 }
 
 Model::Model(const std::string &path, GLuint progId): progId(progId) {
@@ -111,22 +125,16 @@ Model::Model(const std::string &path, GLuint progId): progId(progId) {
                meshes.push_back(Mesh(mesh, progId));
        }
 
-       for (int i = 0; i < scene->mNumMaterials; i++) {
+       for (unsigned int i = 0; i < scene->mNumMaterials; i++) {
                const aiMaterial &material = *scene->mMaterials[i];
-
-               for (int j = 0; j < material.GetTextureCount(aiTextureType_DIFFUSE); j++) {
-                       aiString path;
-                       material.GetTexture(aiTextureType_DIFFUSE, j, &path);
-               }
-               std::cout << material.GetTextureCount(aiTextureType_DIFFUSE) << std::endl;
-               std::cout << path.C_Str() << std::endl;
+               materials.push_back(Material(material, progId));
        }
 
        root = new Node(*(scene->mRootNode), progId);
 }
 
 void Model::draw() const {
-       root->draw(meshes);
+       root->draw(meshes, materials);
 }
 
 Model::Node* Model::find(const std::string &name) {
index 98c630e..a39c70a 100644 (file)
--- a/model.hpp
+++ b/model.hpp
@@ -7,13 +7,14 @@
 #include <glm/glm.hpp>
 #include <assimp/scene.h>
 #include <assimp/Importer.hpp>
+#include "material.hpp"
 
 class Model {
 
        struct Mesh {
                Mesh(const aiMesh *aiMesh, GLuint progId);
-               GLuint vao;
-               GLuint numIndices;
+               GLuint progId, vao, numIndices;
+               unsigned int materialIndex;
        };
        
        public:
@@ -23,7 +24,7 @@ class Model {
                class Node {
                        public:
                                Node(const aiNode &aiNode, GLuint progId);
-                               void draw(const std::vector<Mesh> &meshes, glm::mat4 parentModel) const;
+                               void draw(const std::vector<Mesh> &meshes, const std::vector<Material> &materials, glm::mat4 parentModel) const;
                                const std::vector<Node*> &getChildren() const { return children; }
                                Node* findNode(const aiNode &aiNode);
                                glm::mat4 model = glm::mat4(1);
@@ -43,6 +44,9 @@ class Model {
                
                std::vector<Mesh> meshes;
                Node *root;
+
+               std::vector<Material> materials;
+
                void loadModel(const std::string &path);
 
                Assimp::Importer importer;
diff --git a/texturefrag.glsl b/texturefrag.glsl
new file mode 100644 (file)
index 0000000..347cc01
--- /dev/null
@@ -0,0 +1,39 @@
+#version 330
+
+struct Material {
+       vec3 ambient;
+       vec3 diffuse;
+       vec3 specular;
+       float shininess;
+       bool hasTexture;
+};
+
+in vec3 normal;
+in vec3 fragPos;
+in vec2 texCoord;
+
+uniform vec3 lightPos;
+uniform vec3 viewPos;
+uniform vec4 lightColor;
+
+uniform Material material;
+uniform sampler2D tex;
+
+out vec4 FragColor;
+
+void main() {
+       vec3 lightDir = normalize(fragPos - lightPos);
+       vec3 diffuse = max(0, dot(-normal, lightDir)) * material.diffuse;
+
+       vec3 viewDir = normalize(fragPos - viewPos);
+       vec3 reflectDir = reflect(-lightDir, normal);
+       vec3 specular = pow(max(0, dot(viewDir, reflectDir)), material.shininess) * material.specular;
+
+       vec4 lighting = vec4(material.ambient + diffuse + specular, 1) * lightColor;
+
+       if (material.hasTexture)
+               FragColor = lighting * texture(tex, texCoord);
+       else
+               FragColor = lighting;
+}
+
index e7a74dd..f886c9b 100644 (file)
@@ -2,6 +2,7 @@
 in vec3 vPosition;
 in vec4 vColor;
 in vec3 vNormal;
+in vec2 vTexCoord;
 uniform mat4 model;
 uniform mat4 view;
 uniform mat4 projection;
@@ -9,6 +10,7 @@ out vec4 color;
 out vec3 normal;
 out vec3 fragPos;
 out vec3 normalEye;
+out vec2 texCoord;
 
 void main() {
        vec4 pos = model * vec4(vPosition, 1.f);
@@ -17,4 +19,5 @@ void main() {
        color = vColor;
        normal = vNormal;
        normalEye = vec3(view * vec4(normal, 0.0));
+       texCoord = vTexCoord;
 }