From: Luke Lau Date: Wed, 31 Oct 2018 01:06:30 +0000 (+0000) Subject: Add basics of materials X-Git-Tag: cs7gv3-a3~27 X-Git-Url: http://git.lukelau.me/?p=opengl.git;a=commitdiff_plain;h=37cba564a96018a5500e942498d4e48c0ebe73ed;hp=ba5e08bf25de722d907748ce55b27a45b2b270bf Add basics of materials --- diff --git a/Makefile b/Makefile index 5b60118..acf1a24 100644 --- 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 diff --git a/main.cpp b/main.cpp index 3703395..727c5ff 100644 --- 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 index 0000000..470f1a2 --- /dev/null +++ b/material.cpp @@ -0,0 +1,42 @@ +#include "material.hpp" +#include +#include + +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 index 0000000..968ea36 --- /dev/null +++ b/material.hpp @@ -0,0 +1,24 @@ +#include +#ifdef __APPLE__ +#include +#else +#include +#endif +#include + +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; +}; + diff --git a/model.cpp b/model.cpp index 29f4415..4c5e2d3 100644 --- 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 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 &meshes, glm::mat4 parentTrans = glm::mat4(1)) const { +void Model::Node::draw( const std::vector &meshes, + const std::vector &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) { diff --git a/model.hpp b/model.hpp index 98c630e..a39c70a 100644 --- a/model.hpp +++ b/model.hpp @@ -7,13 +7,14 @@ #include #include #include +#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 &meshes, glm::mat4 parentModel) const; + void draw(const std::vector &meshes, const std::vector &materials, glm::mat4 parentModel) const; const std::vector &getChildren() const { return children; } Node* findNode(const aiNode &aiNode); glm::mat4 model = glm::mat4(1); @@ -43,6 +44,9 @@ class Model { std::vector meshes; Node *root; + + std::vector materials; + void loadModel(const std::string &path); Assimp::Importer importer; diff --git a/texturefrag.glsl b/texturefrag.glsl new file mode 100644 index 0000000..347cc01 --- /dev/null +++ b/texturefrag.glsl @@ -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; +} + diff --git a/vertex.glsl b/vertex.glsl index e7a74dd..f886c9b 100644 --- a/vertex.glsl +++ b/vertex.glsl @@ -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; }