From 4b25859338391456e437bd8254b5de9191dae853 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sat, 27 Nov 2021 14:27:34 +0200 Subject: [PATCH] improved environment mapping for specular IBL --- camera.h | 1 + mesh.cpp | 75 +++++++++++++++++++++++++++++++++++++++-------------- mesh.h | 10 ++++--- root.cpp | 14 +++++++--- root.h | 6 +++-- texture.cpp | 6 ++--- 6 files changed, 80 insertions(+), 32 deletions(-) diff --git a/camera.h b/camera.h index fd31457..6b79062 100755 --- a/camera.h +++ b/camera.h @@ -17,6 +17,7 @@ namespace vb01{ inline Vector3 getUp(){return up;} inline void setNearPlane(float near){this->nearPlane = near;} inline void setFarPlane(float far){this->farPlane = far;} + inline void setFov(float fov){this->fov = fov;} inline float getFov(){return fov;} inline float getNearPlane(){return nearPlane;} inline float getFarPlane(){return farPlane;} diff --git a/mesh.cpp b/mesh.cpp index 96351fa..cb47d1f 100755 --- a/mesh.cpp +++ b/mesh.cpp @@ -64,11 +64,13 @@ namespace vb01{ environmentShader = new Shader(libPath + "environmentPreFilter"); brdfIntegrationShader = new Shader(libPath + "brdfIntegration"); - environmentMap = new Texture(reflectionSize, false, 5); + prefilterMap = new Texture(reflectionSize, false); + postfilterMap = new Texture(reflectionSize, false, 5); brdfIntegrationMap = new Texture(reflectionSize, reflectionSize, false); int width = reflectionSize; initFramebuffer(preFilterFramebuffer, preFilterRenderbuffer, reflectionSize); + initFramebuffer(postFilterFramebuffer, postFilterRenderbuffer, reflectionSize); initFramebuffer(brdfFramebuffer, brdfRenderbuffer, reflectionSize); initMesh(); @@ -87,7 +89,7 @@ namespace vb01{ if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) cout << "Mesh framebuffer not complete\n"; - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, *Root::getSingleton()->getFBO()); } void Mesh::initMesh(){ @@ -241,7 +243,7 @@ namespace vb01{ } } - void Mesh::updatePrefilterMap(Vector3 pos){ + void Mesh::updatePrefilterMap(Vector3 pos, mat4 &proj, vec3 dirs[6]){ /* Node *rootNode = root->getRootNode(); vector descendants; @@ -274,23 +276,50 @@ namespace vb01{ } } */ + glBindFramebuffer(GL_FRAMEBUFFER, preFilterFramebuffer); + + glViewport(0, 0, reflectionSize, reflectionSize); + Root *root = Root::getSingleton(); Mesh *skybox = root->getSkybox(); - Texture *skyboxTex = ((Material::TextureUniform*)skybox->getMaterial()->getUniform("skybox"))->value; + Material *mat = skybox->getMaterial(); + mat->update(); - glBindFramebuffer(GL_FRAMEBUFFER, preFilterFramebuffer); - glBindRenderbuffer(GL_RENDERBUFFER, preFilterRenderbuffer); + Shader *shader = mat->getShader(); + 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"); + + 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); + + if(skybox) { + glDepthMask(GL_FALSE); + glCullFace(GL_FRONT); + skybox->render(); + glDepthMask(GL_TRUE); + glCullFace(GL_BACK); + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, *root->getFBO()); + glViewport(0, 0, root->getWidth(), root->getHeight()); + } + + void Mesh::updatePostfilterMap(mat4 &proj, vec3 dirs[6]){ + glBindFramebuffer(GL_FRAMEBUFFER, postFilterFramebuffer); + glBindRenderbuffer(GL_RENDERBUFFER, postFilterRenderbuffer); - skyboxTex->select(); - environmentShader->use(); - environmentShader->setInt(0, "environmentMap"); - mat4 proj = perspective(radians(90.f), 1.f, .1f, 100.f); environmentShader->setMat4(proj, "proj"); - environmentShader->setMat4(mat4(1.f), "model"); + environmentShader->setInt(0, "environmentMap"); - int numMipmaps = environmentMap->getMipmapLevel(); - vec3 dirs[]{vec3(1, 0, 0), vec3(-1, 0, 0), vec3(0, 1, 0), vec3(0, -1, 0), vec3(0, 0, 1), vec3(0, 0, -1)}; + prefilterMap->select(0); + + Root *root = Root::getSingleton(); + int numMipmaps = postfilterMap->getMipmapLevel(); for(int i = 0; i < numMipmaps; ++i){ u32 width = reflectionSize * pow(0.5, i); @@ -300,15 +329,17 @@ namespace vb01{ environmentShader->setFloat((float)i / numMipmaps, "roughness"); for(int j = 0; j < 6; j++){ - vec3 v = vec3(pos.x, pos.y, pos.z); vec3 upVec = (fabs(dirs[j].y) == 1 ? vec3(0, 0, -1) : vec3(0, 1, 0)); - environmentShader->setMat4(lookAt(v, v + dirs[j], upVec), "view"); + environmentShader->setMat4(lookAt(vec3(0.0), dirs[j], upVec), "view"); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, *environmentMap->getTexture(), i); + 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); - if(skybox) - skybox->render(); + glDepthMask(GL_FALSE); + glCullFace(GL_FRONT); + root->getPostfilterBox()->render(); + glDepthMask(GL_TRUE); + glCullFace(GL_BACK); } } @@ -336,7 +367,11 @@ namespace vb01{ } void Mesh::updateReflection(Vector3 pos){ - updatePrefilterMap(pos); + vec3 dirs[]{ vec3(1, 0, 0), vec3(-1, 0, 0), vec3(0, 1, 0), vec3(0, -1, 0), vec3(0, 0, 1), vec3(0, 0, -1) }; + mat4 proj = perspective(radians(90.f), 1.0f, 0.1f, 100.0f); + + updatePrefilterMap(pos, proj, dirs); + updatePostfilterMap(proj, dirs); updateBrdfLut(); Shader *shader = material->getShader(); @@ -347,7 +382,7 @@ namespace vb01{ shader->setInt(preFilterId, "preFilterMap"); shader->setInt(brdfId, "brdfIntegrationMap"); - environmentMap->select(preFilterId); + postfilterMap->select(preFilterId); brdfIntegrationMap->select(brdfId); } diff --git a/mesh.h b/mesh.h index 3f8b31d..83f4716 100755 --- a/mesh.h +++ b/mesh.h @@ -57,21 +57,23 @@ namespace vb01{ inline u32* getIndices(){return indices;} inline ShapeKey& getShapeKey(int i){return shapeKeys[i];} inline int getNumShapeKeys(){return numShapeKeys;} - inline Texture* getEnvironmentMap(){return environmentMap;} + inline Texture* getPrefilterMap(){return prefilterMap;} + inline Texture* getPostfilterMap(){return postfilterMap;} inline Texture* getBrdfIntegrationMap(){return brdfIntegrationMap;} private: void initMesh(); void initFramebuffer(u32&, u32&, int); void updateSkeleton(Shader*); - void updatePrefilterMap(Vector3); + void updatePrefilterMap(Vector3, glm::mat4&, glm::vec3[6]); + void updatePostfilterMap(glm::mat4&, glm::vec3[6]); void updateBrdfLut(); void updateReflection(Vector3); void updateShapeKeys(Shader*); int reflectionSize = 512; - Texture *environmentMap = nullptr, *brdfIntegrationMap = nullptr; + Texture *prefilterMap = nullptr, *postfilterMap = nullptr, *brdfIntegrationMap = nullptr; Shader *environmentShader = nullptr, *brdfIntegrationShader = nullptr; - u32 preFilterFramebuffer, preFilterRenderbuffer, brdfFramebuffer, brdfRenderbuffer; + u32 preFilterFramebuffer, preFilterRenderbuffer, postFilterFramebuffer, postFilterRenderbuffer, brdfFramebuffer, brdfRenderbuffer; Material *material = nullptr; Node *node = nullptr; std::vector meshes; diff --git a/root.cpp b/root.cpp index fcd078b..cb65488 100755 --- a/root.cpp +++ b/root.cpp @@ -8,6 +8,7 @@ #include "glad.h" #include #include + #include using namespace std; @@ -46,6 +47,7 @@ namespace vb01{ initWindow(name); brdfLutPlane = new Quad(Vector3::VEC_IJK); + postfilterBox = new Box(Vector3::VEC_IJK); Texture *fragTexture = new Texture(width, height, false); Texture *brightTexture = new Texture(width, height, false); @@ -57,19 +59,25 @@ namespace vb01{ void Root::initWindow(string name){ glfwSetErrorCallback(error_callback); + if (GL_TRUE != glfwInit()) std::cerr << "Error initialising glfw" << std::endl; + window = glfwCreateWindow(width, height, name.c_str(), NULL, NULL); + if(window == NULL){ cout << "Failed to load window...\n"; exit(-1); } + glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, foo); + if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){ cout << "Failed to load GLAD.\n"; exit(-1); } + glEnable(GL_DEPTH_TEST); glEnable(GL_STENCIL_TEST); glEnable(GL_CULL_FACE); @@ -92,8 +100,8 @@ namespace vb01{ glGenRenderbuffers(1, &RBO); glBindRenderbuffer(GL_RENDERBUFFER, RBO); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, RBO); if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) cout << "Not complete\n"; @@ -199,7 +207,7 @@ namespace vb01{ skybox = new Box(Vector3(1, 1, 1) * 10); Material *skyboxMat = new Material(libPath + "skybox"); Texture *texture = new Texture(paths, 6, true); - skyboxMat->addTexUniform("skybox", texture, true); + skyboxMat->addTexUniform("tex", texture, true); skybox->setMaterial(skyboxMat); } diff --git a/root.h b/root.h index 7db2b5d..71b1810 100755 --- a/root.h +++ b/root.h @@ -28,7 +28,8 @@ namespace vb01{ inline Node* getGuiNode(){return guiNode;} inline int getWidth(){return width;} inline int getHeight(){return height;} - inline unsigned int* getFBO(){return &FBO;} + inline u32* getFBO(){return &FBO;} + inline u32* getRBO(){return &RBO;} inline GLFWwindow* getWindow(){return window;} inline void setHDREnabled(bool hdr){this->hdr = hdr;} inline void setExposure(float exposure){this->exposure = exposure;} @@ -36,6 +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 Quad* getBrdfLutPlane(){return brdfLutPlane;} void createSkybox(std::string[6]); void removeSkybox(); @@ -47,7 +49,7 @@ namespace vb01{ int numLights = 0; bool bloom = false, hdr = false; float exposure = 1, gamma = 1; - Box *skybox = nullptr; + Box *skybox = nullptr, *postfilterBox = nullptr; Quad *guiPlane = nullptr, *brdfLutPlane = nullptr; int width, height, blurLevel = 10; u32 FBO, RBO, pingpongBuffers[2]; diff --git a/texture.cpp b/texture.cpp index 4aa5d3e..3fddeab 100755 --- a/texture.cpp +++ b/texture.cpp @@ -41,7 +41,6 @@ namespace vb01{ } Texture::Texture(string paths[], int numPaths, bool cubemap, int mipmapLevel, bool flip){ - this->numFrames = numPaths; this->cubemap = cubemap; this->paths = new string[numPaths]; @@ -53,6 +52,7 @@ namespace vb01{ createCubemap(false, flip, true); } else{ + this->numFrames = numPaths; texture = new u32[numPaths]; create2DTexture(flip); } @@ -116,7 +116,7 @@ namespace vb01{ } } else - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, width, 0, GL_RGB, GL_FLOAT, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, width, 0, GL_RGB, GL_UNSIGNED_INT, NULL); } else{ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, width, width, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); @@ -126,7 +126,7 @@ namespace vb01{ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glGenerateMipmap(GL_TEXTURE_CUBE_MAP); }