From: Luke Lau Date: Fri, 2 Nov 2018 11:32:54 +0000 (+0000) Subject: Add specular and normal mapping X-Git-Tag: cs7gv3-a3~26 X-Git-Url: http://git.lukelau.me/?p=opengl.git;a=commitdiff_plain;h=ba9c738e8660304aa0341eb44118e63502a4a009 Add specular and normal mapping --- diff --git a/main.cpp b/main.cpp index 727c5ff..f7b2f85 100644 --- a/main.cpp +++ b/main.cpp @@ -23,7 +23,7 @@ using namespace std; GLuint pyramidVao, lightVao, teapotVao; GLuint gradientProgId, plainProgId, normalProgId, solidProgId, textureProgId; -glm::vec3 camPos = glm::vec3(0.0f, 0.0f, -10.0f); +glm::vec3 camPos = glm::vec3(0.0f, 0.0f, 0.0f); glm::vec3 camFront = glm::vec3(0.0f, 0.0f, 1.0f); glm::vec3 camUp = glm::vec3(0.0f, 1.0f, 0.0f); float yaw = 1.57, pitch = 0; @@ -48,10 +48,10 @@ void setLightColorAndPos(GLuint progId, glm::vec3 lightPos, glm::vec4 lightColor GLuint lightColorLoc = glGetUniformLocation(progId, "lightColor"); glUniform4fv(lightColorLoc, 1, glm::value_ptr(lightColor)); - GLuint lightPosLoc = glGetUniformLocation(progId, "lightPos"); + GLuint lightPosLoc = glGetUniformLocation(progId, "vLightPos"); glUniform3fv(lightPosLoc, 1, glm::value_ptr(lightPos)); - GLuint viewPosLoc = glGetUniformLocation(progId, "viewPos"); + GLuint viewPosLoc = glGetUniformLocation(progId, "vViewPos"); glUniform3fv(viewPosLoc, 1, glm::value_ptr(camPos)); } @@ -156,25 +156,12 @@ 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(0, 10, 10); + /* glm::vec3 lightPos = glm::vec3(sin(d / 10.f) * 10, 0, cos(d / 10.f) * 10); */ + glm::vec3 lightPos = chestPos; glm::vec4 lightColor(1, 1, 1, 1); - glViewport(0, 0, WIDTH, HEIGHT); - /* drawPyramids(d, lightPos, lightColor); */ drawLight(d, lightPos, lightColor); - glUseProgram(solidProgId); - setProjectionAndViewUniforms(solidProgId); - setLightColorAndPos(solidProgId, lightPos, lightColor); - - GLuint colorLoc = glGetUniformLocation(solidProgId, "color"); - glm::vec4 c(1); - glUniform4fv(colorLoc, 1, glm::value_ptr(c)); - - monkeyHead->getRoot()->model = glm::translate(glm::mat4(1), glm::vec3(2, 0, 0)); - monkeyHead->draw(); - glUseProgram(textureProgId); setProjectionAndViewUniforms(textureProgId); setLightColorAndPos(textureProgId, lightPos, lightColor); @@ -187,34 +174,17 @@ void display() { /* 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)); - lock->model = glm::rotate(lock->model, (d / 2.5f), glm::vec3(0, 1, 0.4)); - lock->model = glm::translate(lock->model, -glm::vec3(0.22610, 3.36478, -0.75649)); + /* Model::Node *lock = chest->find("lock"); */ + /* lock->model = glm::translate(glm::mat4(1), glm::vec3(0.22610, 3.36478, -0.75649)); */ + /* lock->model = glm::rotate(lock->model, (d / 2.5f), glm::vec3(0, 1, 0.4)); */ + /* lock->model = glm::translate(lock->model, -glm::vec3(0.22610, 3.36478, -0.75649)); */ - Model::Node *key = chest->find("key"); - key->model = glm::translate(glm::mat4(1), glm::vec3(0, 0, sin(d))); + /* Model::Node *key = chest->find("key"); */ + /* key->model = glm::translate(glm::mat4(1), glm::vec3(0, 0, sin(d))); */ - chest->getRoot()->model = glm::translate(glm::mat4(1), chestPos); + /* chest->getRoot()->model = glm::translate(glm::mat4(1), chestPos); */ chest->draw(); - /* drawTeapot(teapotCamera, false, d, lightPos, lightColor); */ - - /* glClear(GL_DEPTH_BUFFER_BIT); */ - - /* glViewport(0, 0, WIDTH / 4, HEIGHT / 4); */ - /* drawTeapot(teapotOrtho, false, d, lightPos, lightColor); */ - - /* glViewport(WIDTH / 4, 0, WIDTH / 4, HEIGHT / 4); */ - /* drawTeapot(teapotOrtho, true, d, lightPos, lightColor); */ - - /* glViewport(WIDTH / 4 * 2, 0, WIDTH / 4, HEIGHT / 4); */ - /* drawTeapot(teapotPerspStatic, false, d, lightPos, lightColor); */ - - /* glViewport(WIDTH / 4 * 3, 0, WIDTH / 4, HEIGHT / 4); */ - /* drawTeapot(teapotPerspAnimated, false, d, lightPos, lightColor); */ - - glutSwapBuffers(); } @@ -511,7 +481,7 @@ void init() { glUseProgram(solidProgId); validateProgram(solidProgId); - textureProgId = compileShaders((char*)"vertex.glsl", (char*)"texturefrag.glsl"); + textureProgId = compileShaders((char*)"texturevertex.glsl", (char*)"texturefrag.glsl"); glUseProgram(textureProgId); validateProgram(textureProgId); @@ -557,6 +527,8 @@ void timer(int _) { if (keyStates['k']) chestPos.z -= 0.1f; if (keyStates['h']) chestPos.x -= 0.1f; if (keyStates['l']) chestPos.x += 0.1f; + if (keyStates['m']) chestPos.y -= 0.1f; + if (keyStates['n']) chestPos.y += 0.1f; camPos.x += xSpeed * sin(yaw) + zSpeed * cos(yaw); camPos.y += ySpeed; diff --git a/material.cpp b/material.cpp index 470f1a2..06bf6fd 100644 --- a/material.cpp +++ b/material.cpp @@ -1,12 +1,23 @@ #include "material.hpp" #include +#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())); + diffuseMap = new Texture(std::string(path.C_Str())); + } + if (ai.GetTextureCount(aiTextureType_SPECULAR) > 0) { + aiString path; + ai.GetTexture(aiTextureType_SPECULAR, 0, &path); + specularMap = new Texture(std::string(path.C_Str())); + } + if (ai.GetTextureCount(aiTextureType_NORMALS) > 0) { + aiString path; + ai.GetTexture(aiTextureType_NORMALS, 0, &path); + normalMap = new Texture(std::string(path.C_Str())); } ai.Get(AI_MATKEY_SHININESS, shininess); ai.Get(AI_MATKEY_COLOR_AMBIENT, ambient); @@ -15,8 +26,20 @@ Material::Material(const aiMaterial &ai, GLuint progId): progId(progId) { } Material::Texture::Texture(const std::string &path) { + auto provider = CGDataProviderCreateWithFilename(path.c_str()); - auto ref = CGImageCreateWithJPEGDataProvider(provider, nullptr, false, kCGRenderingIntentDefault); + std::ifstream file(path); + long magic; + file.read((char*)&magic, 8); + file.close(); + + CGImageRef ref; + + if (magic == 0x0a1a0a0d474e5089) // png magic number + ref = CGImageCreateWithPNGDataProvider(provider, nullptr, false, kCGRenderingIntentDefault); + else + ref = CGImageCreateWithJPEGDataProvider(provider, nullptr, false, kCGRenderingIntentDefault); + auto dataRef = CGDataProviderCopyData(CGImageGetDataProvider(ref)); auto img = (unsigned char*) CFDataGetBytePtr(dataRef); @@ -35,8 +58,23 @@ void Material::bind() const { 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); + glUniform1i(glGetUniformLocation(progId, "material.hasTexture"), diffuseMap != nullptr); + glUniform1i(glGetUniformLocation(progId, "material.hasSpecularMap"), specularMap != nullptr); + glUniform1i(glGetUniformLocation(progId, "material.hasNormalMap"), normalMap != nullptr); - if (texture) - glBindTexture(GL_TEXTURE_2D, texture->texId); + if (diffuseMap) { + glUniform1i(glGetUniformLocation(progId, "material.diffuseMap"), 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, diffuseMap->texId); + } + if (specularMap) { + glUniform1i(glGetUniformLocation(progId, "material.specularMap"), 1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, specularMap->texId); + } + if (normalMap) { + glUniform1i(glGetUniformLocation(progId, "material.normalMap"), 2); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, normalMap->texId); + } } diff --git a/material.hpp b/material.hpp index 968ea36..c28bcb4 100644 --- a/material.hpp +++ b/material.hpp @@ -19,6 +19,8 @@ class Material { Texture(const std::string &path); GLuint texId; }; - Texture *texture = nullptr; + Texture *diffuseMap = nullptr; + Texture *specularMap = nullptr; + Texture *normalMap = nullptr; }; diff --git a/model.cpp b/model.cpp index 4c5e2d3..8046e29 100644 --- a/model.cpp +++ b/model.cpp @@ -5,7 +5,7 @@ Model::Mesh::Mesh(const aiMesh *aiMesh, GLuint progId) { - std::vector vertices, normals; + std::vector vertices, normals, tangents, bitangents; std::vector texCoords; for (int i = 0; i < aiMesh->mNumVertices; i++) { @@ -14,11 +14,20 @@ Model::Mesh::Mesh(const aiMesh *aiMesh, GLuint progId) { vertices.push_back(glm::vec3(v.x, v.y, v.z)); } if (aiMesh->HasNormals()) { - const aiVector3D v = aiMesh->mNormals[i]; + aiVector3D v = aiMesh->mNormals[i]; normals.push_back(glm::vec3(v.x, v.y, v.z)); } else { normals.push_back(glm::vec3(0)); } + if (aiMesh->HasTangentsAndBitangents()) { + aiVector3D t = aiMesh->mTangents[i]; + tangents.push_back(glm::vec3(t.x, t.y, t.z)); + aiVector3D b = aiMesh->mBitangents[i]; + bitangents.push_back(glm::vec3(b.x, b.y, b.z)); + } else { + tangents.push_back(glm::vec3(0)); + bitangents.push_back(glm::vec3(0)); + } // check for texture coord set 0 if (aiMesh->HasTextureCoords(0)) { const aiVector3D v = aiMesh->mTextureCoords[0][i]; @@ -45,29 +54,41 @@ Model::Mesh::Mesh(const aiMesh *aiMesh, GLuint progId) { glGenVertexArrays(1, &vao); glBindVertexArray(vao); - GLuint vbos[4]; - glGenBuffers(4, vbos); + GLuint vbos[6]; + glGenBuffers(6, vbos); GLuint vertexVbo = vbos[0], normalVbo = vbos[1], texCoordVbo = vbos[2], indicesVbo = vbos[3]; + GLuint tangentVbo = vbos[4], bitangentVbo = vbos[5]; 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); glEnableVertexAttribArray(posLoc); glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); + GLuint normalLoc = glGetAttribLocation(progId, "vNormal"); glBindBuffer(GL_ARRAY_BUFFER, normalVbo); glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW); glEnableVertexAttribArray(normalLoc); glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); + GLuint texCoordLoc = glGetAttribLocation(progId, "vTexCoord"); 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); + GLuint tangentLoc = glGetAttribLocation(progId, "tangent"); + glBindBuffer(GL_ARRAY_BUFFER, tangentVbo); + glBufferData(GL_ARRAY_BUFFER, tangents.size() * sizeof(glm::vec3), &tangents[0], GL_STATIC_DRAW); + glEnableVertexAttribArray(tangentLoc); + glVertexAttribPointer(tangentLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); + + GLuint bitangentLoc = glGetAttribLocation(progId, "bitangent"); + glBindBuffer(GL_ARRAY_BUFFER, bitangentVbo); + glBufferData(GL_ARRAY_BUFFER, bitangents.size() * sizeof(glm::vec3), &bitangents[0], GL_STATIC_DRAW); + glEnableVertexAttribArray(bitangentLoc); + glVertexAttribPointer(bitangentLoc, 3, 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); }; @@ -113,8 +134,7 @@ void Model::Node::draw( const std::vector &meshes, Model::Model(const std::string &path, GLuint progId): progId(progId) { const aiScene *scene = importer.ReadFile(path, - aiProcess_Triangulate | - aiProcess_GenNormals); + aiProcess_Triangulate | aiProcess_CalcTangentSpace | aiProcess_GenNormals); if (!scene) { std::cerr << importer.GetErrorString() << std::endl; exit(1); diff --git a/normalfrag.glsl b/normalfrag.glsl index 1683592..f78fd81 100644 --- a/normalfrag.glsl +++ b/normalfrag.glsl @@ -19,6 +19,6 @@ void main() { vec4 lighting = (ambient + diffuse + specular) * lightColor; - FragColor = lighting * vec4(normalEye, 1); + FragColor = lighting * vec4((normal + 1) / 2, 1); } diff --git a/texturefrag.glsl b/texturefrag.glsl index 347cc01..83cce42 100644 --- a/texturefrag.glsl +++ b/texturefrag.glsl @@ -3,37 +3,65 @@ struct Material { vec3 ambient; vec3 diffuse; + sampler2D diffuseMap; vec3 specular; + sampler2D specularMap; float shininess; + bool hasTexture; + bool hasSpecularMap; + + sampler2D normalMap; + bool hasNormalMap; }; -in vec3 normal; -in vec3 fragPos; +in vec3 defNormal; in vec2 texCoord; -uniform vec3 lightPos; -uniform vec3 viewPos; +// These are all in tangent space +in vec3 lightPos; +in vec3 viewPos; +in vec3 fragPos; + 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; + vec3 normal; + if (material.hasNormalMap) { + normal = texture(material.normalMap, texCoord).rgb; + normal = normalize(normal * 2 - 1); + } else { + normal = defNormal; + } - vec4 lighting = vec4(material.ambient + diffuse + specular, 1) * lightColor; + vec3 lightDir = normalize(lightPos - fragPos); + vec4 diffTex; if (material.hasTexture) - FragColor = lighting * texture(tex, texCoord); + diffTex = texture(material.diffuseMap, texCoord); else + diffTex = vec4(1); + vec4 diffuse = vec4(max(0, dot(lightDir, normal)) * material.diffuse, 1) * diffTex; + + vec3 viewDir = normalize(viewPos - fragPos); + vec3 reflectDir = reflect(-lightDir, normal); + + + vec4 specTex; + if (material.hasSpecularMap) + specTex = texture(material.specularMap, texCoord); + else + specTex = vec4(1); + + vec4 specular = vec4(pow(max(0, dot(viewDir, reflectDir)), material.shininess) * material.specular, 1) * specTex; + + vec4 lighting = (vec4(material.ambient, 1) + diffuse + specular) * lightColor; + FragColor = lighting; } diff --git a/texturevertex.glsl b/texturevertex.glsl new file mode 100644 index 0000000..d8c97f4 --- /dev/null +++ b/texturevertex.glsl @@ -0,0 +1,61 @@ +#version 330 +in vec3 vPosition; +in vec4 vColor; +in vec3 vNormal; +in vec3 tangent; +in vec3 bitangent; +in vec2 vTexCoord; +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; +out vec3 defNormal; +out vec2 texCoord; + +uniform vec3 vLightPos; +uniform vec3 vViewPos; + +out vec3 lightPos; +out vec3 viewPos; +out vec3 fragPos; + +struct Material { + vec3 ambient; + vec3 diffuse; + sampler2D diffuseMap; + vec3 specular; + sampler2D specularMap; + float shininess; + + bool hasTexture; + bool hasSpecularMap; + + sampler2D normalMap; + bool hasNormalMap; +}; + +uniform Material material; + + +void main() { + vec4 pos = model * vec4(vPosition, 1.f); + defNormal = mat3(transpose(inverse(model))) * vNormal; + texCoord = vTexCoord; + + //tangent space stuff + if (material.hasNormalMap) { + vec3 T = normalize(vec3(model * vec4(tangent, 0.0))); + vec3 B = normalize(vec3(model * vec4(bitangent, 0.0))); + vec3 N = normalize(vec3(model * vec4(vNormal, 0.0))); + // convert TBN to world->tangent space + mat3 TBN = transpose(mat3(T, B, N)); + lightPos = TBN * vLightPos; + viewPos = TBN * vViewPos; + fragPos = TBN * vec3(pos); + } else { + lightPos = vLightPos; + viewPos = vViewPos; + fragPos = vec3(pos); + } + + gl_Position = projection * view * pos; +} diff --git a/vertex.glsl b/vertex.glsl index f886c9b..341b26a 100644 --- a/vertex.glsl +++ b/vertex.glsl @@ -17,7 +17,7 @@ void main() { gl_Position = projection * view * pos; fragPos = vec3(pos); color = vColor; - normal = vNormal; + normal = mat3(transpose(inverse(model))) * vNormal; normalEye = vec3(view * vec4(normal, 0.0)); texCoord = vTexCoord; }