From 75658fa0e80b2c6d37cb0ff95deb3b505f74e896 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Sat, 20 Nov 2021 18:57:48 +0200 Subject: [PATCH] first iteration of specular IBL implementation on the CPU side --- mesh.cpp | 158 ++++++++++++++++++++++++++++++++++++-------------- mesh.h | 19 +++--- model.cpp | 20 +++++++ model.h | 3 +- pbrSample.cpp | 17 +++--- root.cpp | 2 + root.h | 3 +- texture.cpp | 2 +- texture.h | 1 + 9 files changed, 166 insertions(+), 59 deletions(-) diff --git a/mesh.cpp b/mesh.cpp index 4415794..4aa6f20 100755 --- a/mesh.cpp +++ b/mesh.cpp @@ -1,6 +1,7 @@ #include "root.h" #include "node.h" #include "box.h" +#include "quad.h" #include "texture.h" #include "skeleton.h" #include "animation.h" @@ -59,29 +60,35 @@ namespace vb01{ } void Mesh::construct(){ - //initFramebuffer(); + string libPath = Root::getSingleton()->getLibPath(); + environmentShader = new Shader(libPath + "environmentPreFilter"); + brdfIntegrationShader = new Shader(libPath + "brdfIntegration"); + + environmentMap = new Texture(reflectionSize, 5, false); + brdfIntegrationMap = new Texture(reflectionSize, reflectionSize, false); + + initFramebuffer(preFilterFramebuffer, preFilterRenderbuffer, environmentMap, reflectionSize); + initFramebuffer(brdfFramebuffer, brdfRenderbuffer, brdfIntegrationMap, reflectionSize); + initMesh(); } - void Mesh::initFramebuffer(){ - int width = Root::getSingleton()->getWidth(); + void Mesh::initFramebuffer(u32 &framebuffer, u32 &renderbuffer, Texture *map, int width){ + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - u32 RBO; - string basePath = "../../vb01/depthMap."; - environmentShader = new Shader(basePath); - environmentMap = new Texture(width, false); + if(map->isCubemap()) + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *map->getTexture(), 0); + else + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *map->getTexture(), 0); - glGenFramebuffers(1, &environmentBuffer); - glBindFramebuffer(GL_FRAMEBUFFER, environmentBuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *(environmentMap->getTexture()), 0); - - glGenRenderbuffers(1, &RBO); - glBindRenderbuffer(GL_RENDERBUFFER, RBO); + glGenRenderbuffers(1, &renderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, width); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer); if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - cout << "Not complete\n"; + cout << "Environment framebuffer not complete\n"; glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -113,6 +120,7 @@ namespace vb01{ glEnableVertexAttribArray(5); glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(Vertex, boneIndices))); glEnableVertexAttribArray(6); + for(int i = 0; i < numShapeKeys; i++){ glVertexAttribPointer(7 + i, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(Vertex, shapeKeyOffsets) + 3 * i * sizeof(float))); glEnableVertexAttribArray(7 + i); @@ -151,15 +159,15 @@ namespace vb01{ material->update(); Shader *shader = material->getShader(); - if(reflect) - updateReflection(shader, pos, width, height); - if(skeleton) updateSkeleton(shader); if(numShapeKeys > 0) updateShapeKeys(shader); + if(reflect) + updateReflection(pos); + shader->setBool(castShadow, "castShadow"); shader->setBool(skeleton, "animated"); shader->setBool(false, "environmentMapEnabled"); @@ -180,6 +188,7 @@ namespace vb01{ void Mesh::updateShapeKeys(Shader *shader){ shader->editShader(Shader::VERTEX_SHADER, 5, "const int numShapeKeys=" + to_string(numShapeKeys) + ";"); + for(int i = 0; i < numShapeKeys; i++){ if(shapeKeys[i].value < shapeKeys[i].minValue) shapeKeys[i].value = shapeKeys[i].minValue; @@ -192,11 +201,10 @@ namespace vb01{ void Mesh::updateSkeleton(Shader *shader){ skeleton->update(); - shader->editShader(Shader::VERTEX_SHADER, 2, "const int numBones=" + to_string(skeleton->getNumBones()) + ";"); shader->editShader(Shader::VERTEX_SHADER, 3, "const int numVertGroups=" + to_string(numVertexGroups) + ";"); - Node *modelNode = skeleton->getRootBone()->getParent(); + for(int i = 0; i < skeleton->getNumBones(); i++){ Bone *bone = skeleton->getBone(i), *parent = (Bone*)bone->getParent(); Vector3 boneAxis[]{ @@ -206,11 +214,13 @@ namespace vb01{ }; int vertGroupId = -1; + for(int j = 0; j < numVertexGroups; j++) if(bone->getName() == vertexGroups[j]) vertGroupId = j; - int parentId = -1; + int parentId = -1; + for(int j = 0; j < skeleton->getNumBones(); j++) if(skeleton->getBone(j) == parent){ parentId = j; @@ -235,20 +245,20 @@ namespace vb01{ } } - void Mesh::updateReflection(Shader *shader, Vector3 pos, int width, int height){ + void Mesh::updatePrefilterMap(Vector3 pos){ Root *root = Root::getSingleton(); - glViewport(0, 0, width, width); - glBindFramebuffer(GL_FRAMEBUFFER, environmentBuffer); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - environmentShader->use(); Node *rootNode = root->getRootNode(); vector descendants; rootNode->getDescendants(descendants); + + Mesh *skybox = root->getSkybox(); + Texture *skyboxTex = ((Material::TextureUniform*)skybox->getMaterial()->getUniform("skybox"))->value; + + /* for(Node *node : descendants){ for(Mesh *mesh : node->getMeshes()) - if(mesh != this){ + if(mesh != this && mesh->isReflectible()){ Vector3 position = node->localToGlobalPosition(Vector3::VEC_ZERO); Quaternion rotation = node->localToGlobalOrientation(Quaternion::QUAT_W); float far = 100; @@ -260,43 +270,107 @@ namespace vb01{ if(rotAxis == Vector3::VEC_ZERO) rotAxis = Vector3::VEC_I; + model = rotate(model, rotation.norm().getAngle(), vec3(rotAxis.x, rotAxis.y, rotAxis.z)); environmentShader->setMat4(model, "model"); environmentShader->setBool(true, "point"); environmentShader->setVec3(pos, "lightPos"); environmentShader->setFloat(far, "farPlane"); - 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) - }; - for(int i = 0; i < 6; i++){ - vec3 upVec; - if(1 < i && i < 4) - upVec = vec3(0, 0, -1); - else - upVec = vec3(0, -1, 0); - environmentShader->setMat4(proj * lookAt(p, p + dirs[i], upVec), "shadowMat[" + to_string(i) + "]"); } + mesh->render(); } } + */ - glBindFramebuffer(GL_FRAMEBUFFER, *(root->getFBO())); + 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)}; + float far = 100; + mat4 proj = perspective(radians(90.f), 1.f, .1f, far); + + glBindFramebuffer(GL_FRAMEBUFFER, preFilterFramebuffer); + glBindRenderbuffer(GL_RENDERBUFFER, preFilterRenderbuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + int numMipmaps = environmentMap->getMipmapLevel(); + environmentShader->use(); + + for(int i = 0; i < numMipmaps; ++i){ + u32 width = reflectionSize * pow(0.5, i); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, width); + glViewport(0, 0, width, width); + + for(int j = 0; j < 6; j++){ + vec3 upVec; + + if(1 < j && j < 4) + upVec = vec3(0, 0, -1); + else + upVec = vec3(0, -1, 0); + + environmentShader->setMat4(proj, "proj"); + environmentShader->setMat4(lookAt(vec3(0), dirs[j], upVec), "view"); + environmentShader->setMat4(mat4(1.f), "model"); + environmentShader->setInt(0, "environmentMap"); + environmentShader->setFloat((float)i / numMipmaps, "roughness"); + + skyboxTex->select(); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, *environmentMap->getTexture(), i); + + if(skybox) + skybox->render(); + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, *root->getFBO()); glViewport(0, 0, root->getWidth(), root->getHeight()); + } - shader->setBool(reflect, "environmentMapEnabled"); - //root->getSkybox()->getMaterial()->getDiffuseMap(0)->select(4); - environmentMap->select(4); + void Mesh::updateBrdfLut(){ + glBindFramebuffer(GL_FRAMEBUFFER, brdfFramebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *brdfIntegrationMap->getTexture(), 0); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glViewport(0, 0, reflectionSize, reflectionSize); + + glBindRenderbuffer(GL_RENDERBUFFER, brdfRenderbuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, reflectionSize, reflectionSize); + + brdfIntegrationShader->use(); + + Root *root = Root::getSingleton(); + root->getBrdfLutPlane()->render(); + + glBindFramebuffer(GL_FRAMEBUFFER, *root->getFBO()); + glViewport(0, 0, root->getWidth(), root->getHeight()); + } + + void Mesh::updateReflection(Vector3 pos){ + updatePrefilterMap(pos); + updateBrdfLut(); + + Shader *shader = material->getShader(); + shader->use(); + int brdfId = 10, preFilterId = 11; + + shader->setInt(brdfId, "brdfIntegrationMap"); + shader->setInt(preFilterId, "preFilterMap"); + + environmentMap->select(brdfId); + brdfIntegrationMap->select(preFilterId); } void Mesh::render(){ glBindVertexArray(VAO); + if(!staticVerts){ glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferSubData(GL_ARRAY_BUFFER, 0, 3 * numTris * sizeof(Vertex), vertices); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 3 * numTris * sizeof(u32), indices); } + glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); glDrawElements(GL_TRIANGLES, 3 * numTris, GL_UNSIGNED_INT, 0); } diff --git a/mesh.h b/mesh.h index bd8dbd6..e51052b 100755 --- a/mesh.h +++ b/mesh.h @@ -40,11 +40,13 @@ namespace vb01{ inline void setNode(Node *node){this->node = node;} inline void setCastShadow(bool castShadow){this->castShadow = castShadow;} inline void setReflect(bool r){this->reflect = r;} + inline void setReflective(bool r){this->reflective = r;} inline void setWireframe(bool w){this->wireframe = w;} inline void setSkeleton(Skeleton *sk){this->skeleton = sk;} inline Node* getNode(){return node;} inline Material* getMaterial(){return material;} inline std::vector& getMeshes(){return meshes;} + inline bool isReflective(){return reflective;} inline bool isCastShadow(){return castShadow;} inline int getNumVerts(){return 3 * numTris;} inline Vertex* getVerts(){return vertices;} @@ -57,14 +59,17 @@ namespace vb01{ inline int getNumShapeKeys(){return numShapeKeys;} private: void initMesh(); - void initFramebuffer(); + void initFramebuffer(u32&, u32&, Texture*, int); void updateSkeleton(Shader*); - void updateReflection(Shader*, Vector3, int, int); + void updatePrefilterMap(Vector3); + void updateBrdfLut(); + void updateReflection(Vector3); void updateShapeKeys(Shader*); - Shader *environmentShader = nullptr; - u32 environmentBuffer; - Texture *environmentMap; + int reflectionSize = 512; + Shader *environmentShader = nullptr, *brdfIntegrationShader = nullptr; + u32 preFilterFramebuffer, preFilterRenderbuffer, brdfFramebuffer, brdfRenderbuffer; + Texture *environmentMap = nullptr, *brdfIntegrationMap = nullptr; Material *material = nullptr; Node *node = nullptr; std::vector meshes; @@ -73,10 +78,10 @@ namespace vb01{ protected: Mesh(); - bool staticVerts = true, castShadow = false, reflect = false, wireframe = false; + bool staticVerts = true, castShadow = false, reflect = false, reflective = false, wireframe = false; Vertex *vertices; std::string *vertexGroups = nullptr; - ShapeKey *shapeKeys = nullptr; + ShapeKey *shapeKeys = nullptr; u32 *indices, VAO, VBO, EBO; int numTris, numVertexGroups = 0, numShapeKeys = 0; }; diff --git a/model.cpp b/model.cpp index 93f7d82..0af8186 100755 --- a/model.cpp +++ b/model.cpp @@ -24,6 +24,7 @@ namespace vb01{ int dotId = getCharId(path, '.', true); string extension = path.substr(dotId + 1, string::npos); ModelReader *modelReader = nullptr; + if(extension == "vb") modelReader = new VbModelReader(this, path); else @@ -35,6 +36,7 @@ namespace vb01{ vector descendants; getDescendants(descendants); + for(Node *node : descendants) for(Mesh *mesh : node->getMeshes()) mesh->setMaterial(nullptr); @@ -53,6 +55,7 @@ namespace vb01{ void Model::setMaterial(Material *mat){ vector descendants; getDescendants(descendants); + for(Node *node : descendants) for(Mesh *mesh : node->getMeshes()) mesh->setMaterial(mat); @@ -61,27 +64,44 @@ namespace vb01{ void Model::setCastShadow(bool castShadow){ vector descendants; getDescendants(descendants); + for(Node *node : descendants) for(Mesh *mesh : node->getMeshes()) mesh->setCastShadow(castShadow); + this->castShadow = castShadow; } void Model::setReflect(bool reflect){ vector descendants; getDescendants(descendants); + for(Node *node : descendants) for(Mesh *mesh : node->getMeshes()) mesh->setReflect(reflect); + this->reflect = reflect; } + void Model::setReflective(bool reflective){ + vector descendants; + getDescendants(descendants); + + for(Node *node : descendants) + for(Mesh *mesh : node->getMeshes()) + mesh->setReflect(reflect); + + this->reflective = reflective; + } + void Model::setWireframe(bool wireframe){ vector descendants; getDescendants(descendants); + for(Node *node : descendants) for(Mesh *mesh : node->getMeshes()) mesh->setWireframe(wireframe); + this->wireframe = wireframe; } } diff --git a/model.h b/model.h index 70b1672..434e6f3 100755 --- a/model.h +++ b/model.h @@ -24,10 +24,11 @@ namespace vb01{ void setMaterial(Material*); void setCastShadow(bool); void setReflect(bool); + void setReflective(bool); void setWireframe(bool); private: Material* material; - bool castShadow = false, reflect = false, wireframe = false; + bool castShadow = false, reflect = false, reflective = false, wireframe = false; }; } diff --git a/pbrSample.cpp b/pbrSample.cpp index eda48ea..d006482 100644 --- a/pbrSample.cpp +++ b/pbrSample.cpp @@ -36,27 +36,30 @@ int main() { Node *rootNode = root->getRootNode(); Model *model = new Model(MODEL_PATH + "teapot.vb"); + model->setReflect(true); Material *mat = new Material(PATH + "pbr"); mat->addBoolUniform("albedoMapEnabled", true); mat->addBoolUniform("normalMapEnabled", true); mat->addBoolUniform("roughnessMapEnabled", true); mat->addBoolUniform("metallnessMapEnabled", true); + mat->addBoolUniform("ambientOcclusionMapEnabled", true); + mat->addBoolUniform("environmentMapEnabled", false); string fr0[]{TEX_PATH + "geyser-rock1_albedo.jpg"}; string fr1[]{TEX_PATH + "geyser-rock1_normal.jpg"}; string fr2[]{TEX_PATH + "geyser-rock1_roughness.jpg"}; string fr3[]{TEX_PATH + "geyser-rock1_metallic.jpg"}; string fr4[]{TEX_PATH + "geyser-rock1_ao.jpg"}; - mat->addTexUniform("textures[0]", new Texture(fr0, 1), true); - mat->addTexUniform("textures[1]", new Texture(fr1, 1), true); - mat->addTexUniform("textures[2]", new Texture(fr2, 1), true); - mat->addTexUniform("textures[3]", new Texture(fr3, 1), true); - mat->addTexUniform("textures[4]", new Texture(fr4, 1), true); + mat->addTexUniform("textures[0]", new Texture(fr0, 1, false), true); + mat->addTexUniform("textures[1]", new Texture(fr1, 1, false), true); + mat->addTexUniform("textures[2]", new Texture(fr2, 1, false), true); + mat->addTexUniform("textures[3]", new Texture(fr3, 1, false), true); + mat->addTexUniform("textures[4]", new Texture(fr4, 1, false), true); model->setMaterial(mat); rootNode->attachChild(model); { Light *light = new Light(Light::POINT); - light->setColor(Vector3(10, 0, 0)); + light->setColor(Vector3(10, 10, 10)); Node *lightNode = new Node(); Box *b = new Box(Vector3(1, 1, 1) * .1); Material *m = new Material(PATH + "texture"); @@ -72,7 +75,7 @@ int main() { } { Light *light = new Light(Light::POINT); - light->setColor(Vector3(0, 0, 10)); + light->setColor(Vector3(0, 0, 0)); Node *lightNode = new Node(); Box *b = new Box(Vector3(1, 1, 1) * .1); Material *m = new Material(PATH + "texture"); diff --git a/root.cpp b/root.cpp index ddfdff2..fcd078b 100755 --- a/root.cpp +++ b/root.cpp @@ -45,6 +45,8 @@ namespace vb01{ initWindow(name); + brdfLutPlane = new Quad(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 cdc98be..7db2b5d 100755 --- a/root.h +++ b/root.h @@ -36,6 +36,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 Quad* getBrdfLutPlane(){return brdfLutPlane;} void createSkybox(std::string[6]); void removeSkybox(); static Root* getSingleton(); @@ -47,7 +48,7 @@ namespace vb01{ bool bloom = false, hdr = false; float exposure = 1, gamma = 1; Box *skybox = nullptr; - Quad *guiPlane = nullptr; + Quad *guiPlane = nullptr, *brdfLutPlane = nullptr; int width, height, blurLevel = 10; u32 FBO, RBO, pingpongBuffers[2]; GLFWwindow *window; diff --git a/texture.cpp b/texture.cpp index c5d679d..16b8dc3 100755 --- a/texture.cpp +++ b/texture.cpp @@ -90,7 +90,7 @@ namespace vb01{ this->mipmapLevel = mipmapLevel; texture = new u32; - createCubemap(true, false); + createCubemap(depth, false); } void Texture::createCubemap(bool depth, bool flip){ diff --git a/texture.h b/texture.h index c319dc2..bc769ab 100755 --- a/texture.h +++ b/texture.h @@ -25,6 +25,7 @@ namespace vb01{ inline int getNumFrames(){return numFrames;} inline int getMipmapLevel(){return mipmapLevel;} inline float getMixRatio(){return mixRatio;} + inline bool isCubemap(){return cubemap;} private: bool cubemap = false; u32 *texture = nullptr;