diff --git a/mesh.cpp b/mesh.cpp index cb47d1f..6b27424 100755 --- a/mesh.cpp +++ b/mesh.cpp @@ -62,14 +62,16 @@ namespace vb01{ void Mesh::construct(){ string libPath = Root::getSingleton()->getLibPath(); environmentShader = new Shader(libPath + "environmentPreFilter"); + irradianceShader = new Shader(libPath + "irradiance"); brdfIntegrationShader = new Shader(libPath + "brdfIntegration"); prefilterMap = new Texture(reflectionSize, false); + irradianceMap = new Texture(reflectionSize, false); postfilterMap = new Texture(reflectionSize, false, 5); brdfIntegrationMap = new Texture(reflectionSize, reflectionSize, false); - int width = reflectionSize; initFramebuffer(preFilterFramebuffer, preFilterRenderbuffer, reflectionSize); + initFramebuffer(irrandianceFramebuffer, irradianceRenderbuffer, reflectionSize); initFramebuffer(postFilterFramebuffer, postFilterRenderbuffer, reflectionSize); initFramebuffer(brdfFramebuffer, brdfRenderbuffer, reflectionSize); @@ -289,8 +291,7 @@ namespace vb01{ shader->setMat4(proj, "proj"); for(int i = 0; i < 6; i++){ - vec3 upVec = (fabs(dirs[i].y) == 1 ? vec3(0, 0, -1) : vec3(0, 1, 0)); - shader->setMat4(lookAt(vec3(0.0), dirs[i], upVec), "view"); + shader->setMat4(lookAt(vec3(0.0), dirs[i], getUpVec(dirs[i])), "view"); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, *prefilterMap->getTexture(), 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -304,10 +305,41 @@ namespace vb01{ } } + glBindRenderbuffer(GL_RENDERBUFFER, *root->getRBO()); glBindFramebuffer(GL_FRAMEBUFFER, *root->getFBO()); glViewport(0, 0, root->getWidth(), root->getHeight()); } + void Mesh::updateIrradianceMap(Vector3 pos, mat4 &proj, vec3 dirs[6]){ + glBindFramebuffer(GL_FRAMEBUFFER, irrandianceFramebuffer); + glBindRenderbuffer(GL_RENDERBUFFER, irradianceRenderbuffer); + + glViewport(0, 0, reflectionSize, reflectionSize); + irradianceShader->use(); + irradianceShader->setMat4(proj, "proj"); + irradianceShader->setInt(0, "environmentMap"); + prefilterMap->select(); + + Root *root = Root::getSingleton(); + + for(int i = 0; i < 6; i++){ + irradianceShader->setMat4(lookAt(vec3(0.0), dirs[i], getUpVec(dirs[i])), "view"); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, *irradianceMap->getTexture(), 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glDepthMask(GL_FALSE); + glCullFace(GL_FRONT); + root->getIblBox()->render(); + glDepthMask(GL_TRUE); + glCullFace(GL_BACK); + } + + glViewport(0, 0, root->getWidth(), root->getHeight()); + glBindRenderbuffer(GL_RENDERBUFFER, *root->getRBO()); + glBindFramebuffer(GL_FRAMEBUFFER, *root->getFBO()); + } + void Mesh::updatePostfilterMap(mat4 &proj, vec3 dirs[6]){ glBindFramebuffer(GL_FRAMEBUFFER, postFilterFramebuffer); glBindRenderbuffer(GL_RENDERBUFFER, postFilterRenderbuffer); @@ -329,20 +361,20 @@ namespace vb01{ environmentShader->setFloat((float)i / numMipmaps, "roughness"); for(int j = 0; j < 6; j++){ - vec3 upVec = (fabs(dirs[j].y) == 1 ? vec3(0, 0, -1) : vec3(0, 1, 0)); - environmentShader->setMat4(lookAt(vec3(0.0), dirs[j], upVec), "view"); + environmentShader->setMat4(lookAt(vec3(0.0), dirs[j], getUpVec(dirs[j])), "view"); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, *postfilterMap->getTexture(), i); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDepthMask(GL_FALSE); glCullFace(GL_FRONT); - root->getPostfilterBox()->render(); + root->getIblBox()->render(); glDepthMask(GL_TRUE); glCullFace(GL_BACK); } } + glBindRenderbuffer(GL_RENDERBUFFER, *root->getRBO()); glBindFramebuffer(GL_FRAMEBUFFER, *root->getFBO()); glViewport(0, 0, root->getWidth(), root->getHeight()); } @@ -362,6 +394,7 @@ namespace vb01{ Root *root = Root::getSingleton(); root->getBrdfLutPlane()->render(); + glBindRenderbuffer(GL_RENDERBUFFER, *root->getRBO()); glBindFramebuffer(GL_FRAMEBUFFER, *root->getFBO()); glViewport(0, 0, root->getWidth(), root->getHeight()); } @@ -371,18 +404,21 @@ namespace vb01{ mat4 proj = perspective(radians(90.f), 1.0f, 0.1f, 100.0f); updatePrefilterMap(pos, proj, dirs); + updateIrradianceMap(pos, proj, dirs); updatePostfilterMap(proj, dirs); updateBrdfLut(); Shader *shader = material->getShader(); shader->use(); - int brdfId = 10, preFilterId = 11; + int irradianceId = 10, brdfId = 11, postFilterId = 12; - shader->setInt(preFilterId, "preFilterMap"); + shader->setInt(irradianceId, "irradianceMap"); + shader->setInt(postFilterId, "postFilterMap"); shader->setInt(brdfId, "brdfIntegrationMap"); - postfilterMap->select(preFilterId); + irradianceMap->select(irradianceId); + postfilterMap->select(postFilterId); brdfIntegrationMap->select(brdfId); } diff --git a/mesh.h b/mesh.h index 83f4716..30e74bd 100755 --- a/mesh.h +++ b/mesh.h @@ -58,6 +58,7 @@ namespace vb01{ inline ShapeKey& getShapeKey(int i){return shapeKeys[i];} inline int getNumShapeKeys(){return numShapeKeys;} inline Texture* getPrefilterMap(){return prefilterMap;} + inline Texture* getIrradianceMap(){return irradianceMap;} inline Texture* getPostfilterMap(){return postfilterMap;} inline Texture* getBrdfIntegrationMap(){return brdfIntegrationMap;} private: @@ -65,15 +66,17 @@ namespace vb01{ void initFramebuffer(u32&, u32&, int); void updateSkeleton(Shader*); void updatePrefilterMap(Vector3, glm::mat4&, glm::vec3[6]); + void updateIrradianceMap(Vector3, glm::mat4&, glm::vec3[6]); void updatePostfilterMap(glm::mat4&, glm::vec3[6]); void updateBrdfLut(); void updateReflection(Vector3); void updateShapeKeys(Shader*); + inline glm::vec3 getUpVec(glm::vec3 dir){return (fabs(dir.y) == 1 ? glm::vec3(0, 0, -1) : glm::vec3(0, 1, 0));} int reflectionSize = 512; - Texture *prefilterMap = nullptr, *postfilterMap = nullptr, *brdfIntegrationMap = nullptr; - Shader *environmentShader = nullptr, *brdfIntegrationShader = nullptr; - u32 preFilterFramebuffer, preFilterRenderbuffer, postFilterFramebuffer, postFilterRenderbuffer, brdfFramebuffer, brdfRenderbuffer; + Texture *prefilterMap = nullptr, *irradianceMap = nullptr, *postfilterMap = nullptr, *brdfIntegrationMap = nullptr; + Shader *environmentShader = nullptr, *irradianceShader = nullptr, *brdfIntegrationShader = nullptr; + u32 preFilterFramebuffer, preFilterRenderbuffer, irrandianceFramebuffer, irradianceRenderbuffer, postFilterFramebuffer, postFilterRenderbuffer, brdfFramebuffer, brdfRenderbuffer; Material *material = nullptr; Node *node = nullptr; std::vector meshes; diff --git a/pbr.frag b/pbr.frag index eddd5bb..ffc832f 100644 --- a/pbr.frag +++ b/pbr.frag @@ -8,8 +8,8 @@ in vec3 biTan; in vec3 norm; in vec2 texCoords; -layout (location = 0) out vec4 FragColor; -layout (location = 1) out vec4 BrightColor; +out vec4 FragColor; +//layout (location = 1) out vec4 BrightColor; //0-POINT,1-DIRECTIONAL,2-SPOT @@ -23,20 +23,23 @@ struct Light{ mat4 lightMat; }; -struct Texture{ +struct FlatTexture{ float mixRatio; sampler2D pastTexture, nextTexture; bool animated; }; uniform Light lights[numLights]; -uniform Texture textures[5]; +uniform FlatTexture textures[5]; +uniform samplerCube irradianceMap, postFilterMap; +uniform sampler2D brdfIntegrationMap; uniform bool albedoMapEnabled; uniform bool normalMapEnabled; uniform bool roughnessMapEnabled; uniform bool metallnessMapEnabled; uniform bool ambientOcclutionMapEnabled; +uniform bool environmentMapEnabled; uniform vec4 albedoColor; uniform float roughnessVal; uniform float metalnessVal; @@ -62,12 +65,15 @@ vec3 fresnelSchlick(vec3 v, vec3 h, vec3 f0){ return f0 + (vec3(1) - f0) * pow(1 - max(dot(v, h), 0), 5); } +vec3 fresnelSchlickRoughness(vec3 n, vec3 v, vec3 f0, float roughness) { + return f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - max(dot(n, v), 0), 5.0); +} + vec3 lambertDiffuse(vec4 color){ return (color / PI).xyz; } void main() { - vec4 finalColor = vec4(0, 0, 0, 1); vec3 normal = norm; if(normalMapEnabled) { @@ -94,6 +100,7 @@ void main() { metalness = texture(textures[3].pastTexture, texCoords).r; vec3 f0 = mix(vec3(.04), albedo.rgb, metalness); + vec3 totalLightColor = vec3(0); for(int i = 0; i < numLights; ++i){ vec3 lightDir; @@ -124,17 +131,33 @@ void main() { vec3 fDiff = lambertDiffuse(albedo); vec3 kDiff = (vec3(1) - F) * (1 - metalness); - finalColor.rgb += (kDiff * fDiff + cookTor) * lights[i].color * attenuation * nDotL; + totalLightColor += (kDiff * fDiff + cookTor) * lights[i].color * attenuation * nDotL; + } + + vec3 specular = vec3(.03); + + if(environmentMapEnabled){ + // sample both the pre-filter map and the BRDF lut and combine them together as per the Split-Sum approximation to get the IBL specular part. + vec3 reflVec = reflect(-viewDir, normal); + const float MAX_REFLECTION_LOD = 4.0; + vec3 prefilteredColor = textureLod(postFilterMap, reflVec, roughness * MAX_REFLECTION_LOD).rgb; + vec2 brdf = texture(brdfIntegrationMap, vec2(max(dot(normal, viewDir), 0.0), roughness)).rg; + vec3 F = fresnelSchlickRoughness(normal, viewDir, f0, roughness); + specular = prefilteredColor * (F * brdf.x + brdf.y); } float ao = ambientOcclusion; - finalColor.rgb += vec3(.03) * albedo.rgb * ao; + vec3 totalAmbientColor = (albedo.rgb + specular) * ao; + + vec4 finalColor = vec4(totalLightColor + totalAmbientColor, 1); float brightness = dot(finalColor.rgb, vec3(0.2126, 0.7152, 0.0722)); +/* if(brightness > 1) BrightColor = vec4(finalColor.rgb, 1); +*/ finalColor.rgb /= finalColor.rgb + vec3(1.0); finalColor.rgb = pow(finalColor.rgb, vec3(1.0 / 2.2)); diff --git a/root.cpp b/root.cpp index cb65488..81cf6f0 100755 --- a/root.cpp +++ b/root.cpp @@ -46,8 +46,8 @@ namespace vb01{ initWindow(name); - brdfLutPlane = new Quad(Vector3::VEC_IJK); - postfilterBox = new Box(Vector3::VEC_IJK); + brdfLutPlane = new Quad(Vector3(1, 1, 1) * 2); + iblBox = new Box(Vector3::VEC_IJK); Texture *fragTexture = new Texture(width, height, false); Texture *brightTexture = new Texture(width, height, false); diff --git a/root.h b/root.h index 71b1810..d9aeda9 100755 --- a/root.h +++ b/root.h @@ -37,7 +37,7 @@ namespace vb01{ inline void setBloom(bool bloom){this->bloom = bloom;} inline void setBlurLevel(bool level){this->blurLevel = level;} inline Box* getSkybox(){return skybox;} - inline Box* getPostfilterBox(){return postfilterBox;} + inline Box* getIblBox(){return iblBox;} inline Quad* getBrdfLutPlane(){return brdfLutPlane;} void createSkybox(std::string[6]); void removeSkybox(); @@ -49,7 +49,7 @@ namespace vb01{ int numLights = 0; bool bloom = false, hdr = false; float exposure = 1, gamma = 1; - Box *skybox = nullptr, *postfilterBox = nullptr; + Box *skybox = nullptr, *iblBox = nullptr; Quad *guiPlane = nullptr, *brdfLutPlane = nullptr; int width, height, blurLevel = 10; u32 FBO, RBO, pingpongBuffers[2];