From d2d9db4affb230a4898cfcd5099162188d4c5f14 Mon Sep 17 00:00:00 2001 From: InkSoul Date: Sat, 22 Nov 2025 23:05:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=83=A8=E5=88=86=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=BD=93=E5=90=91=E7=B1=BB=E7=9A=84=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../index/glTFModel.cpp.246B94A7A9CABEC6.idx | Bin 5576 -> 0 bytes .../index/glTFModel.h.18C204E02E1430C2.idx | Bin 13660 -> 0 bytes .../index/render.cpp.2517D1DB05BB2BAC.idx | Bin 6288 -> 0 bytes .../index/render.h.AA34C5489F161A03.idx | Bin 14984 -> 0 bytes .../renderFoundation.cpp.A2C02532E8A340E2.idx | Bin 138 -> 0 bytes .gitignore | 6 +- src/render/ConfigFilePath.cpp | 170 +- src/render/ConfigFilePath.h | 117 +- src/render/LocalizationStrings.cpp | 188 +- src/render/LocalizationStrings.h | 3 + src/render/RenderSceneTextures.cpp | 41 +- src/render/RenderSceneTextures.h | 17 +- src/render/render.cpp | 4625 +++++++++-------- src/render/render.h | 184 +- src/render/renderSceneModel.cpp | 20 +- src/render/renderSceneModel.h | 8 +- src/render/renderShaderData.cpp | 16 +- src/render/renderShaderData.h | 16 +- src/render/renderUniformBufferSet.cpp | 12 +- src/render/renderUniformBufferSet.h | 12 +- 20 files changed, 2809 insertions(+), 2626 deletions(-) delete mode 100644 .cache/clangd/index/glTFModel.cpp.246B94A7A9CABEC6.idx delete mode 100644 .cache/clangd/index/glTFModel.h.18C204E02E1430C2.idx delete mode 100644 .cache/clangd/index/render.cpp.2517D1DB05BB2BAC.idx delete mode 100644 .cache/clangd/index/render.h.AA34C5489F161A03.idx delete mode 100644 .cache/clangd/index/renderFoundation.cpp.A2C02532E8A340E2.idx diff --git a/.cache/clangd/index/glTFModel.cpp.246B94A7A9CABEC6.idx b/.cache/clangd/index/glTFModel.cpp.246B94A7A9CABEC6.idx deleted file mode 100644 index add05eef95cd86e660116c05abf0b26b82503761..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5576 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 Kq#$*eO#cI!wr4f~ diff --git a/.cache/clangd/index/glTFModel.h.18C204E02E1430C2.idx b/.cache/clangd/index/glTFModel.h.18C204E02E1430C2.idx deleted file mode 100644 index f4bcdee0dd84207bc4cfd0401e292850fda687fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13660 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 HpHBBLmV&^r diff --git a/.cache/clangd/index/render.h.AA34C5489F161A03.idx b/.cache/clangd/index/render.h.AA34C5489F161A03.idx deleted file mode 100644 index 3791d7a407754e3a85135520ebe32d5cbb927d1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14984 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 T{TyBO)3@rUPu0&MRX_g^2CE29 diff --git a/.cache/clangd/index/renderFoundation.cpp.A2C02532E8A340E2.idx b/.cache/clangd/index/renderFoundation.cpp.A2C02532E8A340E2.idx deleted file mode 100644 index d42bc5d518f7b80a8f7efbf234b549c5b4599e1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138 zcmWIYbaQKBU|?`g@vO*AElFenvIT*-xTGl47D!tGamAcukJD#7w_dt_y?pZ}{S%sJ zeSQ3Sz0P`j>R!^<^SY+rWS}@Dx-K)$E6FphZeCoGBO^0|_f3)g48@hXNk9V_ic-^x dA#_e6h%PQlF6IW(jEpm1-Uu|m?e?C50RY1&D`Efu diff --git a/.gitignore b/.gitignore index c59780b..74635c2 100644 --- a/.gitignore +++ b/.gitignore @@ -39,8 +39,8 @@ out/ .vs/ vulkan_asset_pack_gltf.zip *.zip -.cache/ -/.cache +.cache + # vscode build file build/ @@ -58,3 +58,5 @@ build/ data/output/video/device0/result.mp4 *.idx + +/.cache diff --git a/src/render/ConfigFilePath.cpp b/src/render/ConfigFilePath.cpp index acc9533..8593da9 100644 --- a/src/render/ConfigFilePath.cpp +++ b/src/render/ConfigFilePath.cpp @@ -1,7 +1,7 @@ #include "configFilePath.h" #include -std::string getAssetPath() +std::string ConfigFilePath::getAssetPath() const { if (_access("./../data/", 0) != -1) { @@ -25,283 +25,283 @@ std::string getAssetPath() } } // Getter method definitions -const std::string &ConfigFilePath::getGlTFModelFilePath() const +const std::string ConfigFilePath::getGlTFModelFilePath() const { - return glTFModelFilePath; + return getAssetPath() + glTFModelFilePath; } -const std::string &ConfigFilePath::getModelVertShaderPath() const +const std::string ConfigFilePath::getModelVertShaderPath() const { - return modelVertShaderPath; + return getAssetPath() + modelVertShaderPath; } -const std::string &ConfigFilePath::getModelFragShaderPath() const +const std::string ConfigFilePath::getModelFragShaderPath() const { - return modelFragShaderPath; + return getAssetPath() + modelFragShaderPath; } -const std::string &ConfigFilePath::getUiVertShaderPath() const +const std::string ConfigFilePath::getUiVertShaderPath() const { - return uiVertShaderPath; + return getAssetPath() + uiVertShaderPath; } -const std::string &ConfigFilePath::getUiFragShaderPath() const +const std::string ConfigFilePath::getUiFragShaderPath() const { - return uiFragShaderPath; + return getAssetPath() + uiFragShaderPath; } -const std::string &ConfigFilePath::getSkyboxModleFilePath() const +const std::string ConfigFilePath::getSkyboxModleFilePath() const { - return skyboxModleFilePath; + return getAssetPath() + skyboxModleFilePath; } -const std::string &ConfigFilePath::getSkyboxVertShaderPath() const +const std::string ConfigFilePath::getSkyboxVertShaderPath() const { - return skyboxVertShaderPath; + return getAssetPath() + skyboxVertShaderPath; } -const std::string &ConfigFilePath::getSkyboxFragShaderPath() const +const std::string ConfigFilePath::getSkyboxFragShaderPath() const { - return skyboxFragShaderPath; + return getAssetPath() + skyboxFragShaderPath; } -const std::string &ConfigFilePath::getIblTexturesFilePath() const +const std::string ConfigFilePath::getIblTexturesFilePath() const { - return iblTexturesFilePath; + return getAssetPath() + iblTexturesFilePath; } -const std::string &ConfigFilePath::getTonemappingVertShaderPath() const +const std::string ConfigFilePath::getTonemappingVertShaderPath() const { - return tonemappingVertShaderPath; + return getAssetPath() + tonemappingVertShaderPath; } -const std::string &ConfigFilePath::getTonemappingEnableFragShaderPath() const +const std::string ConfigFilePath::getTonemappingEnableFragShaderPath() const { - return tonemappingEnableFragShaderPath; + return getAssetPath() + tonemappingEnableFragShaderPath; } -const std::string &ConfigFilePath::getTonemappingDisableFragShaderPath() const +const std::string ConfigFilePath::getTonemappingDisableFragShaderPath() const { - return tonemappingDisableFragShaderPath; + return getAssetPath() + tonemappingDisableFragShaderPath; } -const std::string &ConfigFilePath::getIrradianceFragShaderPath() const +const std::string ConfigFilePath::getIrradianceFragShaderPath() const { - return irradianceFragShaderPath; + return getAssetPath() + irradianceFragShaderPath; } -const std::string &ConfigFilePath::getFilterVertShaderPath() const +const std::string ConfigFilePath::getFilterVertShaderPath() const { - return filterVertShaderPath; + return getAssetPath() + filterVertShaderPath; } -const std::string &ConfigFilePath::getPrefilterEnvmapFragShaderPath() const +const std::string ConfigFilePath::getPrefilterEnvmapFragShaderPath() const { - return prefilterEnvmapFragShaderPath; + return getAssetPath() + prefilterEnvmapFragShaderPath; } -const std::string &ConfigFilePath::getBrdfVertShaderPath() const +const std::string ConfigFilePath::getBrdfVertShaderPath() const { - return brdfVertShaderPath; + return getAssetPath() + brdfVertShaderPath; } -const std::string &ConfigFilePath::getBrdfFragShaderPath() const +const std::string ConfigFilePath::getBrdfFragShaderPath() const { - return brdfFragShaderPath; + return getAssetPath() + brdfFragShaderPath; } -const std::string &ConfigFilePath::getEnvMapFilePath() const +const std::string ConfigFilePath::getEnvMapFilePath() const { - return envMapFilePath; + return getAssetPath() + envMapFilePath; } -const std::string &ConfigFilePath::getEmptyEnvmapFilePath() const +const std::string ConfigFilePath::getEmptyEnvmapFilePath() const { - return emptyEnvmapFilePath; + return getAssetPath() + emptyEnvmapFilePath; } -const std::string &ConfigFilePath::getPbrVertShaderPath() const +const std::string ConfigFilePath::getPbrVertShaderPath() const { - return pbrVertShaderPath; + return getAssetPath() + pbrVertShaderPath; } -const std::string &ConfigFilePath::getPbrFragShaderPath() const +const std::string ConfigFilePath::getPbrFragShaderPath() const { - return pbrFragShaderPath; + return getAssetPath() + pbrFragShaderPath; } -const std::string &ConfigFilePath::getTtfFilePath() const +const std::string ConfigFilePath::getTtfFilePath() const { - return ttfFilePath; + return getAssetPath() + ttfFilePath; } -const std::string &ConfigFilePath::getImageOutputPath() const +const std::string ConfigFilePath::getImageOutputPath() const { - return imageOutputPath; + return getAssetPath() + imageOutputPath; } -const std::string &ConfigFilePath::getVideoOutputPath() const +const std::string ConfigFilePath::getVideoOutputPath() const { - return videoOutputPath; + return getAssetPath() + videoOutputPath; } -const std::string &ConfigFilePath::getTotalImageOutputPath() const +const std::string ConfigFilePath::getTotalImageOutputPath() const { - return totalImageOutputPath; + return getAssetPath() + totalImageOutputPath; } -const std::string &ConfigFilePath::getDeviceSpecFilePath() const +const std::string ConfigFilePath::getDeviceSpecFilePath() const { - return deviceSpecFilePath; + return getAssetPath() + deviceSpecFilePath; } -const std::string &ConfigFilePath::getImage2videoBatFilePath() const +const std::string ConfigFilePath::getImage2videoBatFilePath() const { - return image2videoBatFilePath; + return getAssetPath() + image2videoBatFilePath; } -const std::string &ConfigFilePath::getImage2videoShFilePath() const +const std::string ConfigFilePath::getImage2videoShFilePath() const { - return image2videoShFilePath; + return getAssetPath() + image2videoShFilePath; } // Setter method definitions -void ConfigFilePath::setGlTFModelFilePath(const std::string &path) +void ConfigFilePath::setGlTFModelFilePath(const std::string path) { glTFModelFilePath = path; } -void ConfigFilePath::setModelVertShaderPath(const std::string &path) +void ConfigFilePath::setModelVertShaderPath(const std::string path) { modelVertShaderPath = path; } -void ConfigFilePath::setModelFragShaderPath(const std::string &path) +void ConfigFilePath::setModelFragShaderPath(const std::string path) { modelFragShaderPath = path; } -void ConfigFilePath::setUiVertShaderPath(const std::string &path) +void ConfigFilePath::setUiVertShaderPath(const std::string path) { uiVertShaderPath = path; } -void ConfigFilePath::setUiFragShaderPath(const std::string &path) +void ConfigFilePath::setUiFragShaderPath(const std::string path) { uiFragShaderPath = path; } -void ConfigFilePath::setSkyboxModleFilePath(const std::string &path) +void ConfigFilePath::setSkyboxModleFilePath(const std::string path) { skyboxModleFilePath = path; } -void ConfigFilePath::setSkyboxVertShaderPath(const std::string &path) +void ConfigFilePath::setSkyboxVertShaderPath(const std::string path) { skyboxVertShaderPath = path; } -void ConfigFilePath::setSkyboxFragShaderPath(const std::string &path) +void ConfigFilePath::setSkyboxFragShaderPath(const std::string path) { skyboxFragShaderPath = path; } -void ConfigFilePath::setIblTexturesFilePath(const std::string &path) +void ConfigFilePath::setIblTexturesFilePath(const std::string path) { iblTexturesFilePath = path; } -void ConfigFilePath::setTonemappingVertShaderPath(const std::string &path) +void ConfigFilePath::setTonemappingVertShaderPath(const std::string path) { tonemappingVertShaderPath = path; } -void ConfigFilePath::setTonemappingEnableFragShaderPath(const std::string &path) +void ConfigFilePath::setTonemappingEnableFragShaderPath(const std::string path) { tonemappingEnableFragShaderPath = path; } -void ConfigFilePath::setTonemappingDisableFragShaderPath(const std::string &path) +void ConfigFilePath::setTonemappingDisableFragShaderPath(const std::string path) { tonemappingDisableFragShaderPath = path; } -void ConfigFilePath::setIrradianceFragShaderPath(const std::string &path) +void ConfigFilePath::setIrradianceFragShaderPath(const std::string path) { irradianceFragShaderPath = path; } -void ConfigFilePath::setFilterVertShaderPath(const std::string &path) +void ConfigFilePath::setFilterVertShaderPath(const std::string path) { filterVertShaderPath = path; } -void ConfigFilePath::setPrefilterEnvmapFragShaderPath(const std::string &path) +void ConfigFilePath::setPrefilterEnvmapFragShaderPath(const std::string path) { prefilterEnvmapFragShaderPath = path; } -void ConfigFilePath::setBrdfVertShaderPath(const std::string &path) +void ConfigFilePath::setBrdfVertShaderPath(const std::string path) { brdfVertShaderPath = path; } -void ConfigFilePath::setBrdfFragShaderPath(const std::string &path) +void ConfigFilePath::setBrdfFragShaderPath(const std::string path) { brdfFragShaderPath = path; } -void ConfigFilePath::setEnvMapFilePath(const std::string &path) +void ConfigFilePath::setEnvMapFilePath(const std::string path) { envMapFilePath = path; } -void ConfigFilePath::setEmptyEnvmapFilePath(const std::string &path) +void ConfigFilePath::setEmptyEnvmapFilePath(const std::string path) { emptyEnvmapFilePath = path; } -void ConfigFilePath::setPbrVertShaderPath(const std::string &path) +void ConfigFilePath::setPbrVertShaderPath(const std::string path) { pbrVertShaderPath = path; } -void ConfigFilePath::setPbrFragShaderPath(const std::string &path) +void ConfigFilePath::setPbrFragShaderPath(const std::string path) { pbrFragShaderPath = path; } -void ConfigFilePath::setTtfFilePath(const std::string &path) +void ConfigFilePath::setTtfFilePath(const std::string path) { ttfFilePath = path; } -void ConfigFilePath::setImageOutputPath(const std::string &path) +void ConfigFilePath::setImageOutputPath(const std::string path) { imageOutputPath = path; } -void ConfigFilePath::setVideoOutputPath(const std::string &path) +void ConfigFilePath::setVideoOutputPath(const std::string path) { videoOutputPath = path; } -void ConfigFilePath::setTotalImageOutputPath(const std::string &path) +void ConfigFilePath::setTotalImageOutputPath(const std::string path) { totalImageOutputPath = path; } -void ConfigFilePath::setDeviceSpecFilePath(const std::string &path) +void ConfigFilePath::setDeviceSpecFilePath(const std::string path) { deviceSpecFilePath = path; } -void ConfigFilePath::setImage2videoBatFilePath(const std::string &path) +void ConfigFilePath::setImage2videoBatFilePath(const std::string path) { image2videoBatFilePath = path; } -void ConfigFilePath::setImage2videoShFilePath(const std::string &path) +void ConfigFilePath::setImage2videoShFilePath(const std::string path) { image2videoShFilePath = path; } \ No newline at end of file diff --git a/src/render/ConfigFilePath.h b/src/render/ConfigFilePath.h index 1bef60e..1c0650d 100644 --- a/src/render/ConfigFilePath.h +++ b/src/render/ConfigFilePath.h @@ -4,67 +4,68 @@ class ConfigFilePath { public: - std::string getAssetPath(); - // Getter methods - const std::string &getGlTFModelFilePath() const; - const std::string &getModelVertShaderPath() const; - const std::string &getModelFragShaderPath() const; - const std::string &getUiVertShaderPath() const; - const std::string &getUiFragShaderPath() const; - const std::string &getSkyboxModleFilePath() const; - const std::string &getSkyboxVertShaderPath() const; - const std::string &getSkyboxFragShaderPath() const; - const std::string &getIblTexturesFilePath() const; - const std::string &getTonemappingVertShaderPath() const; - const std::string &getTonemappingEnableFragShaderPath() const; - const std::string &getTonemappingDisableFragShaderPath() const; - const std::string &getIrradianceFragShaderPath() const; - const std::string &getFilterVertShaderPath() const; - const std::string &getPrefilterEnvmapFragShaderPath() const; - const std::string &getBrdfVertShaderPath() const; - const std::string &getBrdfFragShaderPath() const; - const std::string &getEnvMapFilePath() const; - const std::string &getEmptyEnvmapFilePath() const; - const std::string &getPbrVertShaderPath() const; - const std::string &getPbrFragShaderPath() const; - const std::string &getTtfFilePath() const; - const std::string &getImageOutputPath() const; - const std::string &getVideoOutputPath() const; - const std::string &getTotalImageOutputPath() const; - const std::string &getDeviceSpecFilePath() const; - const std::string &getImage2videoBatFilePath() const; - const std::string &getImage2videoShFilePath() const; + const std::string getGlTFModelFilePath() const; + const std::string getModelVertShaderPath() const; + const std::string getModelFragShaderPath() const; + const std::string getUiVertShaderPath() const; + const std::string getUiFragShaderPath() const; + const std::string getSkyboxModleFilePath() const; + const std::string getSkyboxVertShaderPath() const; + const std::string getSkyboxFragShaderPath() const; + const std::string getIblTexturesFilePath() const; + const std::string getTonemappingVertShaderPath() const; + const std::string getTonemappingEnableFragShaderPath() const; + const std::string getTonemappingDisableFragShaderPath() const; + const std::string getIrradianceFragShaderPath() const; + const std::string getFilterVertShaderPath() const; + const std::string getPrefilterEnvmapFragShaderPath() const; + const std::string getBrdfVertShaderPath() const; + const std::string getBrdfFragShaderPath() const; + const std::string getEnvMapFilePath() const; + const std::string getEmptyEnvmapFilePath() const; + const std::string getPbrVertShaderPath() const; + const std::string getPbrFragShaderPath() const; + const std::string getTtfFilePath() const; + const std::string getImageOutputPath() const; + const std::string getVideoOutputPath() const; + const std::string getTotalImageOutputPath() const; + const std::string getDeviceSpecFilePath() const; + const std::string getImage2videoBatFilePath() const; + const std::string getImage2videoShFilePath() const; // Setter methods - void setGlTFModelFilePath(const std::string &path); - void setModelVertShaderPath(const std::string &path); - void setModelFragShaderPath(const std::string &path); - void setUiVertShaderPath(const std::string &path); - void setUiFragShaderPath(const std::string &path); - void setSkyboxModleFilePath(const std::string &path); - void setSkyboxVertShaderPath(const std::string &path); - void setSkyboxFragShaderPath(const std::string &path); - void setIblTexturesFilePath(const std::string &path); - void setTonemappingVertShaderPath(const std::string &path); - void setTonemappingEnableFragShaderPath(const std::string &path); - void setTonemappingDisableFragShaderPath(const std::string &path); - void setIrradianceFragShaderPath(const std::string &path); - void setFilterVertShaderPath(const std::string &path); - void setPrefilterEnvmapFragShaderPath(const std::string &path); - void setBrdfVertShaderPath(const std::string &path); - void setBrdfFragShaderPath(const std::string &path); - void setEnvMapFilePath(const std::string &path); - void setEmptyEnvmapFilePath(const std::string &path); - void setPbrVertShaderPath(const std::string &path); - void setPbrFragShaderPath(const std::string &path); - void setTtfFilePath(const std::string &path); - void setImageOutputPath(const std::string &path); - void setVideoOutputPath(const std::string &path); - void setTotalImageOutputPath(const std::string &path); - void setDeviceSpecFilePath(const std::string &path); - void setImage2videoBatFilePath(const std::string &path); - void setImage2videoShFilePath(const std::string &path); + void setGlTFModelFilePath(const std::string path); + void setModelVertShaderPath(const std::string path); + void setModelFragShaderPath(const std::string path); + void setUiVertShaderPath(const std::string path); + void setUiFragShaderPath(const std::string path); + void setSkyboxModleFilePath(const std::string path); + void setSkyboxVertShaderPath(const std::string path); + void setSkyboxFragShaderPath(const std::string path); + void setIblTexturesFilePath(const std::string path); + void setTonemappingVertShaderPath(const std::string path); + void setTonemappingEnableFragShaderPath(const std::string path); + void setTonemappingDisableFragShaderPath(const std::string path); + void setIrradianceFragShaderPath(const std::string path); + void setFilterVertShaderPath(const std::string path); + void setPrefilterEnvmapFragShaderPath(const std::string path); + void setBrdfVertShaderPath(const std::string path); + void setBrdfFragShaderPath(const std::string path); + void setEnvMapFilePath(const std::string path); + void setEmptyEnvmapFilePath(const std::string path); + void setPbrVertShaderPath(const std::string path); + void setPbrFragShaderPath(const std::string path); + void setTtfFilePath(const std::string path); + void setImageOutputPath(const std::string path); + void setVideoOutputPath(const std::string path); + void setTotalImageOutputPath(const std::string path); + void setDeviceSpecFilePath(const std::string path); + void setImage2videoBatFilePath(const std::string path); + void setImage2videoShFilePath(const std::string path); + +private: + std::string getAssetPath() const; private: std::string glTFModelFilePath = "models/DamagedHelmet/DamagedHelmet.gltf"; diff --git a/src/render/LocalizationStrings.cpp b/src/render/LocalizationStrings.cpp index f081586..447dac1 100644 --- a/src/render/LocalizationStrings.cpp +++ b/src/render/LocalizationStrings.cpp @@ -1,39 +1,155 @@ #include "LocalizationStrings.h" -const char *LocalizationStrings::getModel() const { return m_model; } -const char *LocalizationStrings::getEnvironmentMap() const { return m_environmentMap; } -const char *LocalizationStrings::getEnvironmentBackGround() const { return m_environmentBackGround; } -const char *LocalizationStrings::getDebugInput() const { return m_debugInput; } -const char *LocalizationStrings::getDebugPBREquation() const { return m_debugPBREquation; } -const char *LocalizationStrings::getAnimation() const { return m_animation; } -const char *LocalizationStrings::getPauseAnimation() const { return m_pauseAnimation; } -const char *LocalizationStrings::getAnimationSeq() const { return m_animationSeq; } -const char *LocalizationStrings::getMenuFile() const { return m_menuFile; } -const char *LocalizationStrings::getMenuOpenNewModel() const { return m_menuOpenNewModel; } -const char *LocalizationStrings::getMenuEnvironment() const { return m_menuEnvironment; } -const char *LocalizationStrings::getMenuEnvironmentConfig() const { return m_menuEnvironmentConfig; } -const char *LocalizationStrings::getMenuAnimation() const { return m_menuAnimation; } -const char *LocalizationStrings::getMenuDebugFrameRate() const { return m_menuDebugFrameRate; } -const char *LocalizationStrings::getMenuDebugInput() const { return m_menuDebugInput; } -const char *LocalizationStrings::getMenuAnimationNoAnimation() const { return m_menuAnimationNoAnimation; } -const char *LocalizationStrings::getMenuAnimationActivation() const { return m_menuAnimationActivation; } -const char *LocalizationStrings::getMenuAnimationAnimationSequence() const { return m_menuAnimationAnimationSequence; } +LocalizationStrings::LocalizationStrings() +{ +} -void LocalizationStrings::setModel(const char *model) { m_model = model; } -void LocalizationStrings::setEnvironmentMap(const char *environmentMap) { m_environmentMap = environmentMap; } -void LocalizationStrings::setEnvironmentBackGround(const char *environmentBackGround) { m_environmentBackGround = environmentBackGround; } -void LocalizationStrings::setDebugInput(const char *debugInput) { m_debugInput = debugInput; } -void LocalizationStrings::setDebugPBREquation(const char *debugPBREquation) { m_debugPBREquation = debugPBREquation; } -void LocalizationStrings::setAnimation(const char *animation) { m_animation = animation; } -void LocalizationStrings::setPauseAnimation(const char *pauseAnimation) { m_pauseAnimation = pauseAnimation; } -void LocalizationStrings::setAnimationSeq(const char *animationSeq) { m_animationSeq = animationSeq; } -void LocalizationStrings::setMenuFile(const char *menuFile) { m_menuFile = menuFile; } -void LocalizationStrings::setMenuOpenNewModel(const char *menuOpenNewModel) { m_menuOpenNewModel = menuOpenNewModel; } -void LocalizationStrings::setMenuEnvironment(const char *menuEnvironment) { m_menuEnvironment = menuEnvironment; } -void LocalizationStrings::setMenuEnvironmentConfig(const char *menuEnvironmentConfig) { m_menuEnvironmentConfig = menuEnvironmentConfig; } -void LocalizationStrings::setMenuAnimation(const char *menuAnimation) { m_menuAnimation = menuAnimation; } -void LocalizationStrings::setMenuDebugFrameRate(const char *menuDebugFrameRate) { m_menuDebugFrameRate = menuDebugFrameRate; } -void LocalizationStrings::setMenuDebugInput(const char *menuDebugInput) { m_menuDebugInput = menuDebugInput; } -void LocalizationStrings::setMenuAnimationNoAnimation(const char *menuAnimationNoAnimation) { m_menuAnimationNoAnimation = menuAnimationNoAnimation; } -void LocalizationStrings::setMenuAnimationActivation(const char *menuAnimationActivation) { m_menuAnimationActivation = menuAnimationActivation; } -void LocalizationStrings::setMenuAnimationAnimationSequence(const char *menuAnimationAnimationSequence) { m_menuAnimationAnimationSequence = menuAnimationAnimationSequence; } \ No newline at end of file +LocalizationStrings::~LocalizationStrings() +{ +} + +const char *LocalizationStrings::getModel() const +{ + return m_model; +} +const char *LocalizationStrings::getEnvironmentMap() const +{ + return m_environmentMap; +} +const char *LocalizationStrings::getEnvironmentBackGround() const +{ + return m_environmentBackGround; +} +const char *LocalizationStrings::getDebugInput() const +{ + return m_debugInput; +} +const char *LocalizationStrings::getDebugPBREquation() const +{ + return m_debugPBREquation; +} +const char *LocalizationStrings::getAnimation() const +{ + return m_animation; +} +const char *LocalizationStrings::getPauseAnimation() const +{ + return m_pauseAnimation; +} +const char *LocalizationStrings::getAnimationSeq() const +{ + return m_animationSeq; +} +const char *LocalizationStrings::getMenuFile() const +{ + return m_menuFile; +} +const char *LocalizationStrings::getMenuOpenNewModel() const +{ + return m_menuOpenNewModel; +} +const char *LocalizationStrings::getMenuEnvironment() const +{ + return m_menuEnvironment; +} +const char *LocalizationStrings::getMenuEnvironmentConfig() const +{ + return m_menuEnvironmentConfig; +} +const char *LocalizationStrings::getMenuAnimation() const +{ + return m_menuAnimation; +} +const char *LocalizationStrings::getMenuDebugFrameRate() const +{ + return m_menuDebugFrameRate; +} +const char *LocalizationStrings::getMenuDebugInput() const +{ + return m_menuDebugInput; +} +const char *LocalizationStrings::getMenuAnimationNoAnimation() const +{ + return m_menuAnimationNoAnimation; +} +const char *LocalizationStrings::getMenuAnimationActivation() const +{ + return m_menuAnimationActivation; +} +const char *LocalizationStrings::getMenuAnimationAnimationSequence() const +{ + return m_menuAnimationAnimationSequence; +} + +void LocalizationStrings::setModel(const char *model) +{ + m_model = model; +} +void LocalizationStrings::setEnvironmentMap(const char *environmentMap) +{ + m_environmentMap = environmentMap; +} +void LocalizationStrings::setEnvironmentBackGround(const char *environmentBackGround) +{ + m_environmentBackGround = environmentBackGround; +} +void LocalizationStrings::setDebugInput(const char *debugInput) +{ + m_debugInput = debugInput; +} +void LocalizationStrings::setDebugPBREquation(const char *debugPBREquation) +{ + m_debugPBREquation = debugPBREquation; +} +void LocalizationStrings::setAnimation(const char *animation) +{ + m_animation = animation; +} +void LocalizationStrings::setPauseAnimation(const char *pauseAnimation) +{ + m_pauseAnimation = pauseAnimation; +} +void LocalizationStrings::setAnimationSeq(const char *animationSeq) +{ + m_animationSeq = animationSeq; +} +void LocalizationStrings::setMenuFile(const char *menuFile) +{ + m_menuFile = menuFile; +} +void LocalizationStrings::setMenuOpenNewModel(const char *menuOpenNewModel) +{ + m_menuOpenNewModel = menuOpenNewModel; +} +void LocalizationStrings::setMenuEnvironment(const char *menuEnvironment) +{ + m_menuEnvironment = menuEnvironment; +} +void LocalizationStrings::setMenuEnvironmentConfig(const char *menuEnvironmentConfig) +{ + m_menuEnvironmentConfig = menuEnvironmentConfig; +} +void LocalizationStrings::setMenuAnimation(const char *menuAnimation) +{ + m_menuAnimation = menuAnimation; +} +void LocalizationStrings::setMenuDebugFrameRate(const char *menuDebugFrameRate) +{ + m_menuDebugFrameRate = menuDebugFrameRate; +} +void LocalizationStrings::setMenuDebugInput(const char *menuDebugInput) +{ + m_menuDebugInput = menuDebugInput; +} +void LocalizationStrings::setMenuAnimationNoAnimation(const char *menuAnimationNoAnimation) +{ + m_menuAnimationNoAnimation = menuAnimationNoAnimation; +} +void LocalizationStrings::setMenuAnimationActivation(const char *menuAnimationActivation) +{ + m_menuAnimationActivation = menuAnimationActivation; +} +void LocalizationStrings::setMenuAnimationAnimationSequence(const char *menuAnimationAnimationSequence) +{ + m_menuAnimationAnimationSequence = menuAnimationAnimationSequence; +} \ No newline at end of file diff --git a/src/render/LocalizationStrings.h b/src/render/LocalizationStrings.h index 87c13f7..94a13a0 100644 --- a/src/render/LocalizationStrings.h +++ b/src/render/LocalizationStrings.h @@ -5,6 +5,9 @@ class LocalizationStrings { public: + LocalizationStrings(); + ~LocalizationStrings(); + // getters const char *getModel() const; const char *getEnvironmentMap() const; diff --git a/src/render/RenderSceneTextures.cpp b/src/render/RenderSceneTextures.cpp index d7106d5..7cf6015 100644 --- a/src/render/RenderSceneTextures.cpp +++ b/src/render/RenderSceneTextures.cpp @@ -3,45 +3,45 @@ // Getters vks::TextureCubeMap &RenderSceneTextures::getEnvironmentCube() { - return environmentCube; + return m_environmentCube; } vks::Texture2D &RenderSceneTextures::getEmpty() { - return empty; + return m_empty; } vks::Texture2D &RenderSceneTextures::getLutBrdf() { - return lutBrdf; + return m_lutBrdf; } vks::TextureCubeMap &RenderSceneTextures::getIrradianceCube() { - return irradianceCube; + return m_irradianceCube; } vks::TextureCubeMap &RenderSceneTextures::getPrefilteredCube() { - return prefilteredCube; + return m_prefilteredCube; } // Setters void RenderSceneTextures::setEnvironmentCube(const vks::TextureCubeMap &texture) { - environmentCube = texture; + m_environmentCube = texture; } void RenderSceneTextures::setEmpty(const vks::Texture2D &texture) { - empty = texture; + m_empty = texture; } void RenderSceneTextures::setLutBrdf(const vks::Texture2D &texture) { - lutBrdf = texture; + m_lutBrdf = texture; } void RenderSceneTextures::setIrradianceCube(const vks::TextureCubeMap &texture) { - irradianceCube = texture; + m_irradianceCube = texture; } void RenderSceneTextures::setPrefilteredCube(const vks::TextureCubeMap &texture) { - prefilteredCube = texture; + m_prefilteredCube = texture; } RenderSceneTextures::RenderSceneTextures() @@ -50,4 +50,25 @@ RenderSceneTextures::RenderSceneTextures() RenderSceneTextures::~RenderSceneTextures() { +} + +void RenderSceneTextures::destroyEnvironmentCube() +{ + m_environmentCube.destroy(); +} +void RenderSceneTextures::destroyEmpty() +{ + m_empty.destroy(); +} +void RenderSceneTextures::destroyLutBrdf() +{ + m_lutBrdf.destroy(); +} +void RenderSceneTextures::destroyIrradianceCube() +{ + m_irradianceCube.destroy(); +} +void RenderSceneTextures::destroyPrefilteredCube() +{ + m_prefilteredCube.destroy(); } \ No newline at end of file diff --git a/src/render/RenderSceneTextures.h b/src/render/RenderSceneTextures.h index 5ee9dbf..063a542 100644 --- a/src/render/RenderSceneTextures.h +++ b/src/render/RenderSceneTextures.h @@ -22,10 +22,17 @@ public: void setIrradianceCube(const vks::TextureCubeMap &texture); void setPrefilteredCube(const vks::TextureCubeMap &texture); + // destroy + void destroyEnvironmentCube(); + void destroyEmpty(); + void destroyLutBrdf(); + void destroyIrradianceCube(); + void destroyPrefilteredCube(); + private: - vks::TextureCubeMap environmentCube; - vks::Texture2D empty; - vks::Texture2D lutBrdf; - vks::TextureCubeMap irradianceCube; - vks::TextureCubeMap prefilteredCube; + vks::TextureCubeMap m_environmentCube; + vks::Texture2D m_empty; + vks::Texture2D m_lutBrdf; + vks::TextureCubeMap m_irradianceCube; + vks::TextureCubeMap m_prefilteredCube; }; diff --git a/src/render/render.cpp b/src/render/render.cpp index 2d4f363..4dc6b68 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -1,8 +1,16 @@  - #ifndef TINYGLTF_IMPLEMENTATION #define TINYGLTF_IMPLEMENTATION + +#include "PushConstBlockMaterial.h" +#include "VulkanTexture.hpp" +#include "glTFModel.h" +#include "glm/gtc/matrix_transform.hpp" +#include "renderUniformBufferSet.h" +#include +#include + #endif #ifndef STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION @@ -12,2294 +20,2423 @@ #define TINYGLTF_NO_STB_IMAGE_WRITE #endif - #include "render.h" -//#include "VulkanUtils.hpp" -//#include "assetLoader.h" - - +// #include "VulkanUtils.hpp" +// #include "assetLoader.h" PlumageRender::PlumageRender() - { - title = "plumage render"; - - } - - - void PlumageRender::renderNode(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode) { - if (node->mesh) { - // Render mesh primitives - for (glTFModel::Primitive* primitive : node->mesh->primitives) { - if (primitive->material.alphaMode == alphaMode) { - VkPipeline pipeline = VK_NULL_HANDLE; - switch (alphaMode) { - case glTFModel::Material::ALPHAMODE_OPAQUE: - case glTFModel::Material::ALPHAMODE_MASK: - pipeline = primitive->material.doubleSided ? pipelines.pbrDoubleSided : pipelines.pbr; - break; - case glTFModel::Material::ALPHAMODE_BLEND: - pipeline = pipelines.pbrAlphaBlend; - break; - } - - if (pipeline != boundPipeline) { - vkCmdBindPipeline(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - boundPipeline = pipeline; - } - - const std::vector descriptorsets = { - descriptorSets[cbIndex].scene, - primitive->material.descriptorSet, - node->mesh->uniformBuffer.descriptorSet, - }; - vkCmdBindDescriptorSets(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast(descriptorsets.size()), descriptorsets.data(), 0, NULL); - - // Pass material parameters as push constants - PushConstBlockMaterial pushConstBlockMaterial{}; - pushConstBlockMaterial.emissiveFactor = primitive->material.emissiveFactor; - // To save push constant space, availabilty and texture coordiante set are combined - // -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set - pushConstBlockMaterial.colorTextureSet = primitive->material.baseColorTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1; - pushConstBlockMaterial.normalTextureSet = primitive->material.normalTexture != nullptr ? primitive->material.texCoordSets.normal : -1; - pushConstBlockMaterial.occlusionTextureSet = primitive->material.occlusionTexture != nullptr ? primitive->material.texCoordSets.occlusion : -1; - pushConstBlockMaterial.emissiveTextureSet = primitive->material.emissiveTexture != nullptr ? primitive->material.texCoordSets.emissive : -1; - pushConstBlockMaterial.alphaMask = static_cast(primitive->material.alphaMode == glTFModel::Material::ALPHAMODE_MASK); - pushConstBlockMaterial.alphaMaskCutoff = primitive->material.alphaCutoff; - - // TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present - - if (primitive->material.pbrWorkflows.metallicRoughness) { - // Metallic roughness workflow - pushConstBlockMaterial.workflow = static_cast(PBR_WORKFLOW_METALLIC_ROUGHNESS); - pushConstBlockMaterial.baseColorFactor = primitive->material.baseColorFactor; - pushConstBlockMaterial.metallicFactor = primitive->material.metallicFactor; - pushConstBlockMaterial.roughnessFactor = primitive->material.roughnessFactor; - pushConstBlockMaterial.PhysicalDescriptorTextureSet = primitive->material.metallicRoughnessTexture != nullptr ? primitive->material.texCoordSets.metallicRoughness : -1; - pushConstBlockMaterial.colorTextureSet = primitive->material.baseColorTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1; - } - - if (primitive->material.pbrWorkflows.specularGlossiness) { - // Specular glossiness workflow - pushConstBlockMaterial.workflow = static_cast(PBR_WORKFLOW_SPECULAR_GLOSINESS); - pushConstBlockMaterial.PhysicalDescriptorTextureSet = primitive->material.extension.specularGlossinessTexture != nullptr ? primitive->material.texCoordSets.specularGlossiness : -1; - pushConstBlockMaterial.colorTextureSet = primitive->material.extension.diffuseTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1; - pushConstBlockMaterial.diffuseFactor = primitive->material.extension.diffuseFactor; - pushConstBlockMaterial.specularFactor = glm::vec4(primitive->material.extension.specularFactor, 1.0f); - } - - vkCmdPushConstants(commandBuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlockMaterial), &pushConstBlockMaterial); - - if (primitive->hasIndices) { - vkCmdDrawIndexed(commandBuffers[cbIndex], primitive->indexCount, 1, primitive->firstIndex, 0, 0); - } - else { - vkCmdDraw(commandBuffers[cbIndex], primitive->vertexCount, 1, 0, 0); - } - } - } - - }; - for (auto child : node->children) { - renderNode(child, cbIndex, alphaMode); - } - } - - void PlumageRender::buildCommandBuffers() - { - VkCommandBufferBeginInfo cmdBufferBeginInfo{}; - cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - VkClearValue clearValues[3]; - if (settings.multiSampling) { - clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; - clearValues[1].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; - clearValues[2].depthStencil = { 1.0f, 0 }; - } - else { - clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; - clearValues[1].depthStencil = { 1.0f, 0 }; - } - - VkRenderPassBeginInfo renderPassBeginInfo{}; - renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBeginInfo.renderPass = renderPass; - renderPassBeginInfo.renderArea.offset.x = 0; - renderPassBeginInfo.renderArea.offset.y = 0; - renderPassBeginInfo.renderArea.extent.width = width; - renderPassBeginInfo.renderArea.extent.height = height; - renderPassBeginInfo.clearValueCount = settings.multiSampling ? 3 : 2; - renderPassBeginInfo.pClearValues = clearValues; - - - - for (uint32_t i = 0; i < commandBuffers.size(); ++i) { - renderPassBeginInfo.framebuffer = frameBuffers[i]; - - VkCommandBuffer currentCB = commandBuffers[i]; - - VK_CHECK_RESULT(vkBeginCommandBuffer(currentCB, &cmdBufferBeginInfo)); - vkCmdBeginRenderPass(currentCB, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - VkViewport viewport{}; - viewport.width = (float)width; - viewport.height = (float)height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - vkCmdSetViewport(currentCB, 0, 1, &viewport); - - VkRect2D scissor{}; - scissor.extent = { width, height }; - vkCmdSetScissor(currentCB, 0, 1, &scissor); - - VkDeviceSize offsets[1] = { 0 }; - - if (displayBackground) { - vkCmdBindDescriptorSets(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i].skybox, 0, nullptr); - vkCmdBindPipeline(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox); - models.skybox.draw(currentCB); - } - - glTFModel::Model& model = models.scene; - - vkCmdBindVertexBuffers(currentCB, 0, 1, &model.vertices.buffer, offsets); - if (model.indices.buffer != VK_NULL_HANDLE) { - vkCmdBindIndexBuffer(currentCB, model.indices.buffer, 0, VK_INDEX_TYPE_UINT32); - } - - boundPipeline = VK_NULL_HANDLE; - - // Opaque primitives first - for (auto node : model.nodes) { - renderNode(node, i, glTFModel::Material::ALPHAMODE_OPAQUE); - } - // Alpha masked primitives - for (auto node : model.nodes) { - renderNode(node, i, glTFModel::Material::ALPHAMODE_MASK); - } - // Transparent primitives - // TODO: Correct depth sorting - for (auto node : model.nodes) { - renderNode(node, i, glTFModel::Material::ALPHAMODE_BLEND); - } - - // User interface - gui->draw(currentCB); - - vkCmdEndRenderPass(currentCB); - VK_CHECK_RESULT(vkEndCommandBuffer(currentCB)); - - } - } - - - void PlumageRender::loadScene(std::string filename) - { - std::cout << "Loading scene from " << filename << std::endl; - models.scene.destroy(device); - - animationIndex = 0; - animationTimer = 0.0f; - auto tStart = std::chrono::high_resolution_clock::now(); - models.scene.loadFromFile(filename, vulkanDevice, queue); - auto tFileLoad = std::chrono::duration(std::chrono::high_resolution_clock::now() - tStart).count(); - std::cout << "Loading took " << tFileLoad << " ms" << std::endl; - camera.setPosition({ 0.0f, 0.0f, -2.0f }); - camera.setRotation({ 0.0f, 0.0f, 0.0f }); - } - - void PlumageRender::loadEnvironment(std::string filename) - { - std::cout << "Loading environment from " << filename << std::endl; - if (textures.environmentCube.image) { - textures.environmentCube.destroy(); - textures.irradianceCube.destroy(); - textures.prefilteredCube.destroy(); - } - textures.environmentCube.loadFromFile(filename, VK_FORMAT_R16G16B16A16_SFLOAT, vulkanDevice, queue); - generateCubemaps(); - } - - void PlumageRender::loadAssets() - { - const std::string assetpath = getAssetPath(); - - if (_access(assetpath.c_str(),0) != 0) { - std::string msg = "Could not locate asset path in \"" + assetpath + "\".\nMake sure binary is running from correct relative directory!"; - std::cerr << msg << std::endl; - system("pause"); - //exit(-1); - } - else { - std::string msg = "asset path get " + assetpath; - std::cout << msg << std::endl; - } - - readDirectory(assetpath + "environments", "*.ktx", environments, false); - - textures.empty.loadFromFile(PlumageRender::filePath.emptyEnvmapFilePath, VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue); - - std::string sceneFile = filePath.glTFModelFilePath; - std::string envMapFile = filePath.envMapFilePath; - for (size_t i = 0; i < args.size(); i++) { - if ((std::string(args[i]).find(".gltf") != std::string::npos) || (std::string(args[i]).find(".glb") != std::string::npos)) { - std::ifstream file(args[i]); - if (file.good()) { - sceneFile = args[i]; - } - else { - std::cout << "could not load \"" << args[i] << "\"" << std::endl; - } - } - if (std::string(args[i]).find(".ktx") != std::string::npos) { - std::ifstream file(args[i]); - if (file.good()) { - envMapFile = args[i]; - } - else { - std::cout << "could not load \"" << args[i] << "\"" << std::endl; - } - } - } - - loadScene(sceneFile.c_str()); - models.skybox.loadFromFile(PlumageRender::filePath.skyboxModleFilePath, vulkanDevice, queue); - - loadEnvironment(envMapFile.c_str()); - } - - void PlumageRender::setupNodeDescriptorSet(glTFModel::Node* node) - { - /* - This sample uses separate descriptor sets (and layouts) for the matrices and materials (textures) - */ - if (node->mesh) { - VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; - descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptorSetAllocInfo.descriptorPool = descriptorPool; - descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.node; - descriptorSetAllocInfo.descriptorSetCount = 1; - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &node->mesh->uniformBuffer.descriptorSet)); - - VkWriteDescriptorSet writeDescriptorSet{}; - writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - writeDescriptorSet.descriptorCount = 1; - writeDescriptorSet.dstSet = node->mesh->uniformBuffer.descriptorSet; - writeDescriptorSet.dstBinding = 0; - writeDescriptorSet.pBufferInfo = &node->mesh->uniformBuffer.descriptor; - - vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); - } - for (auto& child : node->children) { - setupNodeDescriptorSet(child); - } - } - - void PlumageRender::setupDescriptors() - { - /* - Descriptor Pool - */ - uint32_t imageSamplerCount = 0; - uint32_t materialCount = 0; - uint32_t meshCount = 0; - - // Environment samplers (radiance, irradiance, brdflut) - imageSamplerCount += 3; - - std::vector modellist = { &models.skybox, &models.scene }; - for (auto& model : modellist) { - for (auto& material : model->materials) { - imageSamplerCount += 5; - materialCount++; - } - for (auto node : model->linearNodes) { - if (node->mesh) { - meshCount++; - } - } - } - - std::vector poolSizes = { - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (4 + meshCount) * swapChain.imageCount }, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageSamplerCount * swapChain.imageCount } - }; - VkDescriptorPoolCreateInfo descriptorPoolCI{}; - descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptorPoolCI.poolSizeCount = 2; - descriptorPoolCI.pPoolSizes = poolSizes.data(); - descriptorPoolCI.maxSets = (2 + materialCount + meshCount) * swapChain.imageCount; - VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool)); - - /* - Descriptor sets - */ - - // Scene (matrices and environment maps) - { - std::vector setLayoutBindings = { - { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - { 2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - { 3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - { 4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - }; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; - descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCI.pBindings = setLayoutBindings.data(); - descriptorSetLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.scene)); - - for (auto i = 0; i < descriptorSets.size(); i++) { - - VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; - descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptorSetAllocInfo.descriptorPool = descriptorPool; - descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.scene; - descriptorSetAllocInfo.descriptorSetCount = 1; - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSets[i].scene)); - - std::array writeDescriptorSets{}; - - writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - writeDescriptorSets[0].descriptorCount = 1; - writeDescriptorSets[0].dstSet = descriptorSets[i].scene; - writeDescriptorSets[0].dstBinding = 0; - writeDescriptorSets[0].pBufferInfo = &uniformBuffers[i].scene.descriptor; - - writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - writeDescriptorSets[1].descriptorCount = 1; - writeDescriptorSets[1].dstSet = descriptorSets[i].scene; - writeDescriptorSets[1].dstBinding = 1; - writeDescriptorSets[1].pBufferInfo = &uniformBuffers[i].params.descriptor; - - writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSets[2].descriptorCount = 1; - writeDescriptorSets[2].dstSet = descriptorSets[i].scene; - writeDescriptorSets[2].dstBinding = 2; - writeDescriptorSets[2].pImageInfo = &textures.irradianceCube.descriptor; - - writeDescriptorSets[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSets[3].descriptorCount = 1; - writeDescriptorSets[3].dstSet = descriptorSets[i].scene; - writeDescriptorSets[3].dstBinding = 3; - writeDescriptorSets[3].pImageInfo = &textures.prefilteredCube.descriptor; - - writeDescriptorSets[4].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[4].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSets[4].descriptorCount = 1; - writeDescriptorSets[4].dstSet = descriptorSets[i].scene; - writeDescriptorSets[4].dstBinding = 4; - writeDescriptorSets[4].pImageInfo = &textures.lutBrdf.descriptor; - - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); - } - } - - // Material (samplers) - { - std::vector setLayoutBindings = { - { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - { 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - { 2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - { 3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - { 4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }, - }; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; - descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCI.pBindings = setLayoutBindings.data(); - descriptorSetLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.material)); - - // Per-Material descriptor sets - for (auto& material : models.scene.materials) { - VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; - descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptorSetAllocInfo.descriptorPool = descriptorPool; - descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.material; - descriptorSetAllocInfo.descriptorSetCount = 1; - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &material.descriptorSet)); - - std::vector imageDescriptors = { - textures.empty.descriptor, - textures.empty.descriptor, - material.normalTexture ? material.normalTexture->descriptor : textures.empty.descriptor, - material.occlusionTexture ? material.occlusionTexture->descriptor : textures.empty.descriptor, - material.emissiveTexture ? material.emissiveTexture->descriptor : textures.empty.descriptor - }; - - if (material.pbrWorkflows.metallicRoughness) { - if (material.baseColorTexture) { - imageDescriptors[0] = material.baseColorTexture->descriptor; - } - if (material.metallicRoughnessTexture) { - imageDescriptors[1] = material.metallicRoughnessTexture->descriptor; - } - } - - if (material.pbrWorkflows.specularGlossiness) { - if (material.extension.diffuseTexture) { - imageDescriptors[0] = material.extension.diffuseTexture->descriptor; - } - if (material.extension.specularGlossinessTexture) { - imageDescriptors[1] = material.extension.specularGlossinessTexture->descriptor; - } - } - - std::array writeDescriptorSets{}; - for (size_t i = 0; i < imageDescriptors.size(); i++) { - writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSets[i].descriptorCount = 1; - writeDescriptorSets[i].dstSet = material.descriptorSet; - writeDescriptorSets[i].dstBinding = static_cast(i); - writeDescriptorSets[i].pImageInfo = &imageDescriptors[i]; - } - - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); - } - - // Model node (matrices) - { - std::vector setLayoutBindings = { - { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr }, - }; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; - descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCI.pBindings = setLayoutBindings.data(); - descriptorSetLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.node)); - - // Per-Node descriptor set - for (auto& node : models.scene.nodes) { - setupNodeDescriptorSet(node); - } - } - - } - - // Skybox (fixed set) - for (auto i = 0; i < uniformBuffers.size(); i++) { - VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; - descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptorSetAllocInfo.descriptorPool = descriptorPool; - descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.scene; - descriptorSetAllocInfo.descriptorSetCount = 1; - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSets[i].skybox)); - - std::array writeDescriptorSets{}; - - writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - writeDescriptorSets[0].descriptorCount = 1; - writeDescriptorSets[0].dstSet = descriptorSets[i].skybox; - writeDescriptorSets[0].dstBinding = 0; - writeDescriptorSets[0].pBufferInfo = &uniformBuffers[i].skybox.descriptor; - - writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - writeDescriptorSets[1].descriptorCount = 1; - writeDescriptorSets[1].dstSet = descriptorSets[i].skybox; - writeDescriptorSets[1].dstBinding = 1; - writeDescriptorSets[1].pBufferInfo = &uniformBuffers[i].params.descriptor; - - writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSets[2].descriptorCount = 1; - writeDescriptorSets[2].dstSet = descriptorSets[i].skybox; - writeDescriptorSets[2].dstBinding = 2; - writeDescriptorSets[2].pImageInfo = &textures.prefilteredCube.descriptor; - - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); - } - } - - void PlumageRender::preparePipelines() - { - VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; - inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - - VkPipelineRasterizationStateCreateInfo rasterizationStateCI{}; - rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL; - rasterizationStateCI.cullMode = VK_CULL_MODE_BACK_BIT; - rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizationStateCI.lineWidth = 1.0f; - - VkPipelineColorBlendAttachmentState blendAttachmentState{}; - blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - blendAttachmentState.blendEnable = VK_FALSE; - - VkPipelineColorBlendStateCreateInfo colorBlendStateCI{}; - colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlendStateCI.attachmentCount = 1; - colorBlendStateCI.pAttachments = &blendAttachmentState; - - VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{}; - depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencilStateCI.depthTestEnable = VK_FALSE; - depthStencilStateCI.depthWriteEnable = VK_FALSE; - depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; - depthStencilStateCI.front = depthStencilStateCI.back; - depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS; - - VkPipelineViewportStateCreateInfo viewportStateCI{}; - viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportStateCI.viewportCount = 1; - viewportStateCI.scissorCount = 1; - - VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; - multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - - if (settings.multiSampling) { - multisampleStateCI.rasterizationSamples = settings.sampleCount; - } - - std::vector dynamicStateEnables = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR - }; - VkPipelineDynamicStateCreateInfo dynamicStateCI{}; - dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicStateCI.pDynamicStates = dynamicStateEnables.data(); - dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); - - // Pipeline layout - const std::vector setLayouts = { - descriptorSetLayouts.scene, descriptorSetLayouts.material, descriptorSetLayouts.node - }; - VkPipelineLayoutCreateInfo pipelineLayoutCI{}; - pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutCI.setLayoutCount = static_cast(setLayouts.size()); - pipelineLayoutCI.pSetLayouts = setLayouts.data(); - VkPushConstantRange pushConstantRange{}; - pushConstantRange.size = sizeof(PushConstBlockMaterial); - pushConstantRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - pipelineLayoutCI.pushConstantRangeCount = 1; - pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); - - // Vertex bindings an attributes - VkVertexInputBindingDescription vertexInputBinding = { 0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX }; - std::vector vertexInputAttributes = { - { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 }, - { 1, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3 }, - { 2, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6 }, - { 3, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 8 }, - { 4, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 10 }, - { 5, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 14 }, - { 6, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 18 } - }; - VkPipelineVertexInputStateCreateInfo vertexInputStateCI{}; - vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputStateCI.vertexBindingDescriptionCount = 1; - vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding; - vertexInputStateCI.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); - vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data(); - - // Pipelines - std::array shaderStages; - - VkGraphicsPipelineCreateInfo pipelineCI{}; - pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineCI.layout = pipelineLayout; - pipelineCI.renderPass = renderPass; - pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; - pipelineCI.pVertexInputState = &vertexInputStateCI; - pipelineCI.pRasterizationState = &rasterizationStateCI; - pipelineCI.pColorBlendState = &colorBlendStateCI; - pipelineCI.pMultisampleState = &multisampleStateCI; - pipelineCI.pViewportState = &viewportStateCI; - pipelineCI.pDepthStencilState = &depthStencilStateCI; - pipelineCI.pDynamicState = &dynamicStateCI; - pipelineCI.stageCount = static_cast(shaderStages.size()); - pipelineCI.pStages = shaderStages.data(); - - if (settings.multiSampling) { - multisampleStateCI.rasterizationSamples = settings.sampleCount; - } - - // Skybox pipeline (background cube) - shaderStages = { - loadShader(device,PlumageRender::filePath.skyboxVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT), - loadShader(device,PlumageRender::filePath.skyboxFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT) - }; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.skybox)); - for (auto shaderStage : shaderStages) { - vkDestroyShaderModule(device, shaderStage.module, nullptr); - } - - // PBR pipeline - shaderStages = { - loadShader(device,PlumageRender::filePath.pbrVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT), - loadShader(device,PlumageRender::filePath.pbrFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT) - }; - depthStencilStateCI.depthWriteEnable = VK_TRUE; - depthStencilStateCI.depthTestEnable = VK_TRUE; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbr)); - rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbrDoubleSided)); - - rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; - blendAttachmentState.blendEnable = VK_TRUE; - blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; - blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbrAlphaBlend)); - - for (auto shaderStage : shaderStages) { - vkDestroyShaderModule(device, shaderStage.module, nullptr); - } - //Create Tone Mapping render pipeline - //CreateToneMappingPipeline(); - - - - } - - // generate two cube maps - // irradiance cube map - // prefileter environment cube map - void PlumageRender::generateCubemaps() - { - enum Target { IRRADIANCE = 0, PREFILTEREDENV = 1 }; - - for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++) { - - vks::TextureCubeMap cubemap; - - auto tStart = std::chrono::high_resolution_clock::now(); - - VkFormat format; - int32_t dim; - - switch (target) { - case IRRADIANCE: - format = VK_FORMAT_R32G32B32A32_SFLOAT; - dim = 128; - break; - case PREFILTEREDENV: - format = VK_FORMAT_R16G16B16A16_SFLOAT; - dim = 4096; - break; - }; - - const uint32_t numMips = static_cast(floor(log2(dim))) + 1; - - // Create target cubemap static_cast(floor(log2(dim))) + - { - // Image - VkImageCreateInfo imageCI{}; - imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCI.imageType = VK_IMAGE_TYPE_2D; - imageCI.format = format; - imageCI.extent.width = dim; - imageCI.extent.height = dim; - imageCI.extent.depth = 1; - imageCI.mipLevels = numMips; - imageCI.arrayLayers = 6; - imageCI.samples = VK_SAMPLE_COUNT_1_BIT; - imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - imageCI.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &cubemap.image)); - VkMemoryRequirements memReqs; - vkGetImageMemoryRequirements(device, cubemap.image, &memReqs); - VkMemoryAllocateInfo memAllocInfo{}; - memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memAllocInfo.allocationSize = memReqs.size; - memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &cubemap.deviceMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device, cubemap.image, cubemap.deviceMemory, 0)); - - // View - VkImageViewCreateInfo viewCI{}; - viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - viewCI.format = format; - viewCI.subresourceRange = {}; - viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewCI.subresourceRange.levelCount = numMips; - viewCI.subresourceRange.layerCount = 6; - viewCI.image = cubemap.image; - VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &cubemap.view)); - - // Sampler - VkSamplerCreateInfo samplerCI{}; - samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerCI.magFilter = VK_FILTER_LINEAR; - samplerCI.minFilter = VK_FILTER_LINEAR; - samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.minLod = 0.0f; - samplerCI.maxLod = static_cast(numMips); - samplerCI.maxAnisotropy = 1.0f; - samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &cubemap.sampler)); - } - - // FB, Att, RP, Pipe, etc. - VkAttachmentDescription attDesc{}; - // Color attachment - attDesc.format = format; - attDesc.samples = VK_SAMPLE_COUNT_1_BIT; - attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - - VkSubpassDescription subpassDescription{}; - subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDescription.colorAttachmentCount = 1; - subpassDescription.pColorAttachments = &colorReference; - - // Use subpass dependencies for layout transitions - std::array dependencies; - dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; - dependencies[0].dstSubpass = 0; - dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - dependencies[1].srcSubpass = 0; - dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; - dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - - // Renderpass - VkRenderPassCreateInfo renderPassCI{}; - renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassCI.attachmentCount = 1; - renderPassCI.pAttachments = &attDesc; - renderPassCI.subpassCount = 1; - renderPassCI.pSubpasses = &subpassDescription; - renderPassCI.dependencyCount = 2; - renderPassCI.pDependencies = dependencies.data(); - VkRenderPass renderpass; - VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass)); - - - // Create offscreen framebuffer - { - // Image - VkImageCreateInfo imageCI{}; - imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCI.imageType = VK_IMAGE_TYPE_2D; - imageCI.format = format; - imageCI.extent.width = dim; - imageCI.extent.height = dim; - imageCI.extent.depth = 1; - imageCI.mipLevels = 1; - imageCI.arrayLayers = 1; - imageCI.samples = VK_SAMPLE_COUNT_1_BIT; - imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &offscreen.image)); - VkMemoryRequirements memReqs; - vkGetImageMemoryRequirements(device, offscreen.image, &memReqs); - VkMemoryAllocateInfo memAllocInfo{}; - memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memAllocInfo.allocationSize = memReqs.size; - memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &offscreen.memory)); - VK_CHECK_RESULT(vkBindImageMemory(device, offscreen.image, offscreen.memory, 0)); - - // View - VkImageViewCreateInfo viewCI{}; - viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewCI.format = format; - viewCI.flags = 0; - viewCI.subresourceRange = {}; - viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewCI.subresourceRange.baseMipLevel = 0; - viewCI.subresourceRange.levelCount = 1; - viewCI.subresourceRange.baseArrayLayer = 0; - viewCI.subresourceRange.layerCount = 1; - viewCI.image = offscreen.image; - VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &offscreen.view)); - - // Framebuffer - VkFramebufferCreateInfo framebufferCI{}; - framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferCI.renderPass = renderpass; - framebufferCI.attachmentCount = 1; - framebufferCI.pAttachments = &offscreen.view; - framebufferCI.width = dim; - framebufferCI.height = dim; - framebufferCI.layers = 1; - VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCI, nullptr, &offscreen.framebuffer)); - - VkCommandBuffer layoutCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.image = offscreen.image; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - imageMemoryBarrier.srcAccessMask = 0; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - vkCmdPipelineBarrier(layoutCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - vulkanDevice->flushCommandBuffer(layoutCmd, queue, true); - } - - // Descriptors - VkDescriptorSetLayout descriptorsetlayout; - VkDescriptorSetLayoutBinding setLayoutBinding = { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; - descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCI.pBindings = &setLayoutBinding; - descriptorSetLayoutCI.bindingCount = 1; - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout)); - - // Descriptor Pool - VkDescriptorPoolSize poolSize = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }; - VkDescriptorPoolCreateInfo descriptorPoolCI{}; - descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptorPoolCI.poolSizeCount = 1; - descriptorPoolCI.pPoolSizes = &poolSize; - descriptorPoolCI.maxSets = 2; - VkDescriptorPool descriptorpool; - VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorpool)); - - // Descriptor sets - VkDescriptorSet descriptorset; - VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; - descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptorSetAllocInfo.descriptorPool = descriptorpool; - descriptorSetAllocInfo.pSetLayouts = &descriptorsetlayout; - descriptorSetAllocInfo.descriptorSetCount = 1; - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorset)); - VkWriteDescriptorSet writeDescriptorSet{}; - writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSet.descriptorCount = 1; - writeDescriptorSet.dstSet = descriptorset; - writeDescriptorSet.dstBinding = 0; - writeDescriptorSet.pImageInfo = &textures.environmentCube.descriptor; - vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); - - // Pipeline layout - VkPipelineLayout pipelinelayout; - VkPushConstantRange pushConstantRange{}; - pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - - switch (target) { - case IRRADIANCE: - pushConstantRange.size = sizeof(IrradiancePushBlock); - break; - case PREFILTEREDENV: - pushConstantRange.size = sizeof(PrefilterPushBlock); - break; - }; - - VkPipelineLayoutCreateInfo pipelineLayoutCI{}; - pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutCI.setLayoutCount = 1; - pipelineLayoutCI.pSetLayouts = &descriptorsetlayout; - pipelineLayoutCI.pushConstantRangeCount = 1; - pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout)); - - // Pipeline - VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; - inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - - VkPipelineRasterizationStateCreateInfo rasterizationStateCI{}; - rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL; - rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; - rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizationStateCI.lineWidth = 1.0f; - - VkPipelineColorBlendAttachmentState blendAttachmentState{}; - blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - blendAttachmentState.blendEnable = VK_FALSE; - - VkPipelineColorBlendStateCreateInfo colorBlendStateCI{}; - colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlendStateCI.attachmentCount = 1; - colorBlendStateCI.pAttachments = &blendAttachmentState; - - VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{}; - depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencilStateCI.depthTestEnable = VK_FALSE; - depthStencilStateCI.depthWriteEnable = VK_FALSE; - depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; - depthStencilStateCI.front = depthStencilStateCI.back; - depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS; - - VkPipelineViewportStateCreateInfo viewportStateCI{}; - viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportStateCI.viewportCount = 1; - viewportStateCI.scissorCount = 1; - - VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; - multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - - std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; - VkPipelineDynamicStateCreateInfo dynamicStateCI{}; - dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicStateCI.pDynamicStates = dynamicStateEnables.data(); - dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); - - // Vertex input state - VkVertexInputBindingDescription vertexInputBinding = { 0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX }; - VkVertexInputAttributeDescription vertexInputAttribute = { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 }; - - VkPipelineVertexInputStateCreateInfo vertexInputStateCI{}; - vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputStateCI.vertexBindingDescriptionCount = 1; - vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding; - vertexInputStateCI.vertexAttributeDescriptionCount = 1; - vertexInputStateCI.pVertexAttributeDescriptions = &vertexInputAttribute; - - std::array shaderStages; - - VkGraphicsPipelineCreateInfo pipelineCI{}; - pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineCI.layout = pipelinelayout; - pipelineCI.renderPass = renderpass; - pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; - pipelineCI.pVertexInputState = &vertexInputStateCI; - pipelineCI.pRasterizationState = &rasterizationStateCI; - pipelineCI.pColorBlendState = &colorBlendStateCI; - pipelineCI.pMultisampleState = &multisampleStateCI; - pipelineCI.pViewportState = &viewportStateCI; - pipelineCI.pDepthStencilState = &depthStencilStateCI; - pipelineCI.pDynamicState = &dynamicStateCI; - pipelineCI.stageCount = 2; - pipelineCI.pStages = shaderStages.data(); - pipelineCI.renderPass = renderpass; - - shaderStages[0] = loadShader(device, PlumageRender::filePath.filterVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT); - switch (target) { - case IRRADIANCE: - shaderStages[1] = loadShader(device, PlumageRender::filePath.irradianceFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT); - break; - case PREFILTEREDENV: - shaderStages[1] = loadShader(device, PlumageRender::filePath.prefilterEnvmapFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT); - break; - }; - VkPipeline pipeline; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); - for (auto shaderStage : shaderStages) { - vkDestroyShaderModule(device, shaderStage.module, nullptr); - } - - // Render cubemap - VkClearValue clearValues[1]; - clearValues[0].color = { { 0.0f, 0.0f, 0.2f, 0.0f } }; - - VkRenderPassBeginInfo renderPassBeginInfo{}; - renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBeginInfo.renderPass = renderpass; - renderPassBeginInfo.framebuffer = offscreen.framebuffer; - renderPassBeginInfo.renderArea.extent.width = dim; - renderPassBeginInfo.renderArea.extent.height = dim; - renderPassBeginInfo.clearValueCount = 1; - renderPassBeginInfo.pClearValues = clearValues; - - std::vector matrices = { - glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), - glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f)), - }; - - VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); - - VkViewport viewport{}; - viewport.width = (float)dim; - viewport.height = -(float)dim; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - viewport.x = 0; - viewport.y = -viewport.height; - - VkRect2D scissor{}; - scissor.extent.width = dim; - scissor.extent.height = dim; - - VkImageSubresourceRange subresourceRange{}; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.baseMipLevel = 0; - subresourceRange.levelCount = numMips; - subresourceRange.layerCount = 6; - - // Change image layout for all cubemap faces to transfer destination - { - vulkanDevice->beginCommandBuffer(cmdBuf); - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.image = cubemap.image; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.srcAccessMask = 0; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.subresourceRange = subresourceRange; - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - vulkanDevice->flushCommandBuffer(cmdBuf, queue, false); - } - - for (uint32_t m = 0; m < numMips; m++) { - for (uint32_t f = 0; f < 6; f++) { - - vulkanDevice->beginCommandBuffer(cmdBuf); - - viewport.width = static_cast(dim * std::pow(0.5f, m)); - viewport.height = -static_cast(dim * std::pow(0.5f, m)); - viewport.x = 0; - viewport.y = -viewport.height; - vkCmdSetViewport(cmdBuf, 0, 1, &viewport); - vkCmdSetScissor(cmdBuf, 0, 1, &scissor); - - // Render scene from cube face's point of view - vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - // Pass parameters for current pass using a push constant block - switch (target) { - case IRRADIANCE: - irradiancePushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f]; - vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(IrradiancePushBlock), &irradiancePushBlock); - break; - case PREFILTEREDENV: - prefilterPushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f]; - prefilterPushBlock.roughness = 0.0;//(float)m / (float)(numMips - 1); - vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PrefilterPushBlock), &prefilterPushBlock); - break; - }; - - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 0, 1, &descriptorset, 0, NULL); - - VkDeviceSize offsets[1] = { 0 }; - - models.skybox.draw(cmdBuf); - - vkCmdEndRenderPass(cmdBuf); - - VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.baseMipLevel = 0; - subresourceRange.levelCount = numMips; - subresourceRange.layerCount = 6; - - { - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.image = offscreen.image; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - } - - // Copy region for transfer from framebuffer to cube face - VkImageCopy copyRegion{}; - - copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyRegion.srcSubresource.baseArrayLayer = 0; - copyRegion.srcSubresource.mipLevel = 0; - copyRegion.srcSubresource.layerCount = 1; - copyRegion.srcOffset = { 0, 0, 0 }; - - copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyRegion.dstSubresource.baseArrayLayer = f; - copyRegion.dstSubresource.mipLevel = m; - copyRegion.dstSubresource.layerCount = 1; - copyRegion.dstOffset = { 0, 0, 0 }; - - copyRegion.extent.width = static_cast(viewport.width); - copyRegion.extent.height = -static_cast(viewport.height); - copyRegion.extent.depth = 1; - - vkCmdCopyImage( - cmdBuf, - offscreen.image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - cubemap.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - ©Region); - - { - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.image = offscreen.image; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - } - - vulkanDevice->flushCommandBuffer(cmdBuf, queue, false); - } - } - - { - vulkanDevice->beginCommandBuffer(cmdBuf); - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.image = cubemap.image; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.subresourceRange = subresourceRange; - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - vulkanDevice->flushCommandBuffer(cmdBuf, queue, false); - } - - - vkDestroyRenderPass(device, renderpass, nullptr); - vkDestroyFramebuffer(device, offscreen.framebuffer, nullptr); - vkFreeMemory(device, offscreen.memory, nullptr); - vkDestroyImageView(device, offscreen.view, nullptr); - vkDestroyImage(device, offscreen.image, nullptr); - vkDestroyDescriptorPool(device, descriptorpool, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr); - vkDestroyPipeline(device, pipeline, nullptr); - vkDestroyPipelineLayout(device, pipelinelayout, nullptr); - - cubemap.descriptor.imageView = cubemap.view; - cubemap.descriptor.sampler = cubemap.sampler; - cubemap.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - cubemap.device = vulkanDevice; - - switch (target) { - case IRRADIANCE: - textures.irradianceCube = cubemap; - break; - case PREFILTEREDENV: - textures.prefilteredCube = cubemap; - shaderData.prefilteredCubeMipLevels = static_cast(numMips); - break; - }; - - auto tEnd = std::chrono::high_resolution_clock::now(); - auto tDiff = std::chrono::duration(tEnd - tStart).count(); - std::cout << "Generating cube map with " << numMips << " mip levels took " << tDiff << " ms" << std::endl; - } - } - // generate BRDF integration map for roughness/NdotV - void PlumageRender::generateBRDFLUT() - { - auto tStart = std::chrono::high_resolution_clock::now(); - - const VkFormat format = VK_FORMAT_R16G16_SFLOAT; - const int32_t dim = 2048; - - // Image - VkImageCreateInfo imageCI{}; - imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCI.imageType = VK_IMAGE_TYPE_2D; - imageCI.format = format; - imageCI.extent.width = dim; - imageCI.extent.height = dim; - imageCI.extent.depth = 1; - imageCI.mipLevels = 1; - imageCI.arrayLayers = 1; - imageCI.samples = VK_SAMPLE_COUNT_1_BIT; - imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &textures.lutBrdf.image)); - VkMemoryRequirements memReqs; - vkGetImageMemoryRequirements(device, textures.lutBrdf.image, &memReqs); - VkMemoryAllocateInfo memAllocInfo{}; - memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memAllocInfo.allocationSize = memReqs.size; - memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &textures.lutBrdf.deviceMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device, textures.lutBrdf.image, textures.lutBrdf.deviceMemory, 0)); - - // View - VkImageViewCreateInfo viewCI{}; - viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewCI.format = format; - viewCI.subresourceRange = {}; - viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewCI.subresourceRange.levelCount = 1; - viewCI.subresourceRange.layerCount = 1; - viewCI.image = textures.lutBrdf.image; - VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &textures.lutBrdf.view)); - - // Sampler - VkSamplerCreateInfo samplerCI{}; - samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerCI.magFilter = VK_FILTER_LINEAR; - samplerCI.minFilter = VK_FILTER_LINEAR; - samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCI.minLod = 0.0f; - samplerCI.maxLod = 1.0f; - samplerCI.maxAnisotropy = 1.0f; - samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &textures.lutBrdf.sampler)); - - // FB, Att, RP, Pipe, etc. - VkAttachmentDescription attDesc{}; - // Color attachment - attDesc.format = format; - attDesc.samples = VK_SAMPLE_COUNT_1_BIT; - attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - - VkSubpassDescription subpassDescription{}; - subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDescription.colorAttachmentCount = 1; - subpassDescription.pColorAttachments = &colorReference; - - // Use subpass dependencies for layout transitions - std::array dependencies; - dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; - dependencies[0].dstSubpass = 0; - dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - dependencies[1].srcSubpass = 0; - dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; - dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - - // Create the actual renderpass - VkRenderPassCreateInfo renderPassCI{}; - renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassCI.attachmentCount = 1; - renderPassCI.pAttachments = &attDesc; - renderPassCI.subpassCount = 1; - renderPassCI.pSubpasses = &subpassDescription; - renderPassCI.dependencyCount = 2; - renderPassCI.pDependencies = dependencies.data(); - - VkRenderPass renderpass; - VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass)); - - VkFramebufferCreateInfo framebufferCI{}; - framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferCI.renderPass = renderpass; - framebufferCI.attachmentCount = 1; - framebufferCI.pAttachments = &textures.lutBrdf.view; - framebufferCI.width = dim; - framebufferCI.height = dim; - framebufferCI.layers = 1; - - VkFramebuffer framebuffer; - VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCI, nullptr, &framebuffer)); - - // Desriptors - VkDescriptorSetLayout descriptorsetlayout; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; - descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout)); - - // Pipeline layout - VkPipelineLayout pipelinelayout; - VkPipelineLayoutCreateInfo pipelineLayoutCI{}; - pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutCI.setLayoutCount = 1; - pipelineLayoutCI.pSetLayouts = &descriptorsetlayout; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout)); - - // Pipeline - VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; - inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - - VkPipelineRasterizationStateCreateInfo rasterizationStateCI{}; - rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL; - rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; - rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizationStateCI.lineWidth = 1.0f; - - VkPipelineColorBlendAttachmentState blendAttachmentState{}; - blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - blendAttachmentState.blendEnable = VK_FALSE; - - VkPipelineColorBlendStateCreateInfo colorBlendStateCI{}; - colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlendStateCI.attachmentCount = 1; - colorBlendStateCI.pAttachments = &blendAttachmentState; - - VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{}; - depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencilStateCI.depthTestEnable = VK_FALSE; - depthStencilStateCI.depthWriteEnable = VK_FALSE; - depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; - depthStencilStateCI.front = depthStencilStateCI.back; - depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS; - - VkPipelineViewportStateCreateInfo viewportStateCI{}; - viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportStateCI.viewportCount = 1; - viewportStateCI.scissorCount = 1; - - VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; - multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - - std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; - VkPipelineDynamicStateCreateInfo dynamicStateCI{}; - dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicStateCI.pDynamicStates = dynamicStateEnables.data(); - dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); - - VkPipelineVertexInputStateCreateInfo emptyInputStateCI{}; - emptyInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - - std::array shaderStages; - - VkGraphicsPipelineCreateInfo pipelineCI{}; - pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineCI.layout = pipelinelayout; - pipelineCI.renderPass = renderpass; - pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; - pipelineCI.pVertexInputState = &emptyInputStateCI; - pipelineCI.pRasterizationState = &rasterizationStateCI; - pipelineCI.pColorBlendState = &colorBlendStateCI; - pipelineCI.pMultisampleState = &multisampleStateCI; - pipelineCI.pViewportState = &viewportStateCI; - pipelineCI.pDepthStencilState = &depthStencilStateCI; - pipelineCI.pDynamicState = &dynamicStateCI; - pipelineCI.stageCount = 2; - pipelineCI.pStages = shaderStages.data(); - - // Look-up-table (from BRDF) pipeline - shaderStages = { - loadShader(device,PlumageRender::filePath.brdfVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT), - loadShader(device,PlumageRender::filePath.brdfFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT) - }; - VkPipeline pipeline; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); - for (auto shaderStage : shaderStages) { - vkDestroyShaderModule(device, shaderStage.module, nullptr); - } - - // Render - VkClearValue clearValues[1]; - clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; - - VkRenderPassBeginInfo renderPassBeginInfo{}; - renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBeginInfo.renderPass = renderpass; - renderPassBeginInfo.renderArea.extent.width = dim; - renderPassBeginInfo.renderArea.extent.height = dim; - renderPassBeginInfo.clearValueCount = 1; - renderPassBeginInfo.pClearValues = clearValues; - renderPassBeginInfo.framebuffer = framebuffer; - - VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - VkViewport viewport{}; - viewport.width = (float)dim; - viewport.height = (float)dim; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - //viewport.x = 0; - //viewport.y = -viewport.height; - - VkRect2D scissor{}; - scissor.extent.width = dim; - scissor.extent.height = dim; - - vkCmdSetViewport(cmdBuf, 0, 1, &viewport); - vkCmdSetScissor(cmdBuf, 0, 1, &scissor); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - vkCmdEndRenderPass(cmdBuf); - vulkanDevice->flushCommandBuffer(cmdBuf, queue); - - vkQueueWaitIdle(queue); - - vkDestroyPipeline(device, pipeline, nullptr); - vkDestroyPipelineLayout(device, pipelinelayout, nullptr); - vkDestroyRenderPass(device, renderpass, nullptr); - vkDestroyFramebuffer(device, framebuffer, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr); - - textures.lutBrdf.descriptor.imageView = textures.lutBrdf.view; - textures.lutBrdf.descriptor.sampler = textures.lutBrdf.sampler; - textures.lutBrdf.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - textures.lutBrdf.device = vulkanDevice; - - auto tEnd = std::chrono::high_resolution_clock::now(); - auto tDiff = std::chrono::duration(tEnd - tStart).count(); - std::cout << "Generating BRDF LUT took " << tDiff << " ms" << std::endl; - } - - // Prepare and initialize uniform buffer containing shader uniforms - void PlumageRender::prepareUniformBuffers() - { - for (auto& uniformBuffer : uniformBuffers) { - uniformBuffer.scene.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderDataScene)); - uniformBuffer.skybox.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderDataSkybox)); - uniformBuffer.params.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderData)); - } - updateUniformBuffers(); - } - - void PlumageRender::updateUniformBuffers() - { - // Scene - shaderDataScene.projection = camera.matrices.perspective; - shaderDataScene.view = camera.matrices.view; - - float modelSize = std::max(models.scene.aabb[0][0], std::max(models.scene.aabb[1][1], models.scene.aabb[2][2])); - // Center and scale model - float scale = (1.0f / modelSize ) * 0.5f; - glm::vec3 translate = -glm::vec3(models.scene.aabb[3][0], models.scene.aabb[3][1], models.scene.aabb[3][2]); - translate += -0.5f * glm::vec3(models.scene.aabb[0][0], models.scene.aabb[1][1], models.scene.aabb[2][2]); - - //camera.setPosition(glm::vec3(0, 0, -modelSize - 2)); - - shaderDataScene.model = glm::mat4(1.0f); - shaderDataScene.model[0][0] = scale; - shaderDataScene.model[1][1] = scale; - shaderDataScene.model[2][2] = scale; - shaderDataScene.model = glm::translate(shaderDataScene.model, translate); - - if (settings.rotateModel) - { - //shaderDataScene.model = glm::mat4(1.0f); - shaderDataScene.model = glm::rotate(shaderDataScene.model, glm::radians(modelrot), glm::vec3(0, 1, 0)); - } - - - shaderDataScene.camPos = glm::vec3( - -camera.position.z * sin(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)), - -camera.position.z * sin(glm::radians(camera.rotation.x)), - camera.position.z * cos(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)) - ); - - - - // Skybox - shaderDataSkybox.projection = camera.matrices.perspective; - shaderDataSkybox.view = camera.matrices.view; - shaderDataSkybox.model = glm::mat4(glm::mat3(camera.matrices.view)); - } - - void PlumageRender::updateShaderData() - { - shaderData.lightDir = glm::vec4( - sin(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)), - sin(glm::radians(lightSource.rotation.y)), - cos(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)), - 0.0f); - - } - - void PlumageRender::windowResized() - { - buildCommandBuffers(); - vkDeviceWaitIdle(device); - updateUniformBuffers(); - //update UI - updateUIOverlay(); - } - - void PlumageRender::prepare() - { - VulkanExampleBase::prepare(); - - camera.type = Camera::CameraType::lookat; - - camera.setPerspective(45.0f, (float)width / (float)height, 0.1f, 256.0f); - camera.rotationSpeed = 0.25f; - camera.movementSpeed = 0.1f; - - - waitFences.resize(renderAhead); - presentCompleteSemaphores.resize(renderAhead); - renderCompleteSemaphores.resize(renderAhead); - commandBuffers.resize(swapChain.imageCount); - uniformBuffers.resize(swapChain.imageCount); - descriptorSets.resize(swapChain.imageCount); - // Command buffer execution fences - for (auto& waitFence : waitFences) { - VkFenceCreateInfo fenceCI{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT }; - VK_CHECK_RESULT(vkCreateFence(device, &fenceCI, nullptr, &waitFence)); - } - // Queue ordering semaphores - for (auto& semaphore : presentCompleteSemaphores) { - VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; - VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore)); - } - for (auto& semaphore : renderCompleteSemaphores) { - VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; - VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore)); - } - // Command buffers - { - VkCommandBufferAllocateInfo cmdBufAllocateInfo{}; - cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - cmdBufAllocateInfo.commandPool = cmdPool; - cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - cmdBufAllocateInfo.commandBufferCount = static_cast(commandBuffers.size()); - VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commandBuffers.data())); - } - - loadAssets(); - generateBRDFLUT(); - generateCubemaps(); - prepareUniformBuffers(); - setupDescriptors(); - preparePipelines(); - - gui = new UI(vulkanDevice, renderPass, queue, pipelineCache, settings.sampleCount); - updateUIOverlay(); - - buildCommandBuffers(); - - prepared = true; - } - - void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue) - { - VkSubmitInfo submitInfo = vks::initializers::submitInfo(); - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &cmdBuffer; - VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(); - VkFence fence; - VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence)); - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence)); - VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX)); - vkDestroyFence(device, fence, nullptr); - } - - // todo :根据physicalDeviceIndex确定子文件夹路径,frameIndex确定fileName - void PlumageRender::writeImageToFile(std::string filePath) - { - - bool screenshotSaved = false; - bool supportsBlit = true; - - // Check blit support for source and destination - VkFormatProperties formatProps; - - // Check if the device supports blitting from optimal images (the swapchain images are in optimal format) - vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChain.colorFormat, &formatProps); - if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) { - std::cerr << "Device does not support blitting from optimal tiled images, using copy instead of blit!" << std::endl; - supportsBlit = false; - } - - // Check if the device supports blitting to linear images - vkGetPhysicalDeviceFormatProperties(physicalDevice, VK_FORMAT_R8G8B8A8_UNORM, &formatProps); - if (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) { - std::cerr << "Device does not support blitting to linear tiled images, using copy instead of blit!" << std::endl; - supportsBlit = false; - } - - // Source for the copy is the last rendered swapchain image - VkImage srcImage = swapChain.images[currentBuffer]; - - // Create the linear tiled destination image to copy to and to read the memory from - VkImageCreateInfo imageCreateCI(vks::initializers::imageCreateInfo()); - imageCreateCI.imageType = VK_IMAGE_TYPE_2D; - // Note that vkCmdBlitImage (if supported) will also do format conversions if the swapchain color format would differ - imageCreateCI.format = VK_FORMAT_R8G8B8A8_UNORM; - imageCreateCI.extent.width = width; - imageCreateCI.extent.height = height; - imageCreateCI.extent.depth = 1; - imageCreateCI.arrayLayers = 1; - imageCreateCI.mipLevels = 1; - imageCreateCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCreateCI.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateCI.tiling = VK_IMAGE_TILING_LINEAR; - imageCreateCI.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; - // Create the image - VkImage dstImage; - VK_CHECK_RESULT(vkCreateImage(device, &imageCreateCI, nullptr, &dstImage)); - // Create memory to back up the image - VkMemoryRequirements memRequirements; - VkMemoryAllocateInfo memAllocInfo(vks::initializers::memoryAllocateInfo()); - VkDeviceMemory dstImageMemory; - vkGetImageMemoryRequirements(device, dstImage, &memRequirements); - memAllocInfo.allocationSize = memRequirements.size; - // Memory must be host visible to copy from - memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &dstImageMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device, dstImage, dstImageMemory, 0)); - - // Do the actual blit from the swapchain image to our host visible destination image - VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - // Transition destination image to transfer destination layout - vks::tools::insertImageMemoryBarrier( - copyCmd, - dstImage, - 0, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); - - // Transition swapchain image from present to transfer source layout - vks::tools::insertImageMemoryBarrier( - copyCmd, - srcImage, - VK_ACCESS_MEMORY_READ_BIT, - VK_ACCESS_TRANSFER_READ_BIT, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); - - // If source and destination support blit we'll blit as this also does automatic format conversion (e.g. from BGR to RGB) - if (supportsBlit) - { - // Define the region to blit (we will blit the whole swapchain image) - VkOffset3D blitSize; - blitSize.x = width; - blitSize.y = height; - blitSize.z = 1; - VkImageBlit imageBlitRegion{}; - imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageBlitRegion.srcSubresource.layerCount = 1; - imageBlitRegion.srcOffsets[1] = blitSize; - imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageBlitRegion.dstSubresource.layerCount = 1; - imageBlitRegion.dstOffsets[1] = blitSize; - - // Issue the blit command - vkCmdBlitImage( - copyCmd, - srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - &imageBlitRegion, - VK_FILTER_NEAREST); - } - else - { - // Otherwise use image copy (requires us to manually flip components) - VkImageCopy imageCopyRegion{}; - imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageCopyRegion.srcSubresource.layerCount = 1; - imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageCopyRegion.dstSubresource.layerCount = 1; - imageCopyRegion.extent.width = width; - imageCopyRegion.extent.height = height; - imageCopyRegion.extent.depth = 1; - - // Issue the copy command - vkCmdCopyImage( - copyCmd, - srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - &imageCopyRegion); - } - - // Transition destination image to general layout, which is the required layout for mapping the image memory later on - vks::tools::insertImageMemoryBarrier( - copyCmd, - dstImage, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_MEMORY_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_GENERAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); - - // Transition back the swap chain image after the blit is done - vks::tools::insertImageMemoryBarrier( - copyCmd, - srcImage, - VK_ACCESS_TRANSFER_READ_BIT, - VK_ACCESS_MEMORY_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); - - vulkanDevice->flushCommandBuffer(copyCmd, queue); - - // Get layout of the image (including row pitch) - VkImageSubresource subResource{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 }; - VkSubresourceLayout subResourceLayout; - vkGetImageSubresourceLayout(device, dstImage, &subResource, &subResourceLayout); - - // Map image memory so we can start copying from it - const char* data; - vkMapMemory(device, dstImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&data); - data += subResourceLayout.offset; - - - if (settings.outputPNGimage) - { - stbi_write_png(filePath.c_str(), width, height, 4, data, static_cast(subResourceLayout.rowPitch)); - } - else - { - std::ofstream file(filePath, std::ios::out | std::ios::binary); - - // ppm header - file << "P6\n" << width << "\n" << height << "\n" << 255 << "\n"; - - // If source is BGR (destination is always RGB) and we can't use blit (which does automatic conversion), we'll have to manually swizzle color components - bool colorSwizzle = false; - // Check if source is BGR - // Note: Not complete, only contains most common and basic BGR surface formats for demonstration purposes - if (!supportsBlit) - { - std::vector formatsBGR = { VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM }; - colorSwizzle = (std::find(formatsBGR.begin(), formatsBGR.end(), swapChain.colorFormat) != formatsBGR.end()); - } - // ppm binary pixel data - for (uint32_t y = 0; y < height; y++) - { - unsigned int* row = (unsigned int*)data; - for (uint32_t x = 0; x < width; x++) - { - if (colorSwizzle) - { - file.write((char*)row + 2, 1); - file.write((char*)row + 1, 1); - file.write((char*)row, 1); - } - else - { - file.write((char*)row, 3); - } - row++; - } - data += subResourceLayout.rowPitch; - } - file.close(); - } - - std::cout << "Screenshot saved to " << filePath << std::endl; - - // Clean up resources - vkUnmapMemory(device, dstImageMemory); - vkFreeMemory(device, dstImageMemory, nullptr); - vkDestroyImage(device, dstImage, nullptr); - - screenshotSaved = true; - - } - - void PlumageRender::outputImageSequence() - { - - if (savedFrameCounter == settings.startFrameCount) - { - std::cout << "clean up directory for image sequence generation" << std::endl; - removeImageSequence(); - } - - filePath.deviceSpecFilePath = filePath.imageOutputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex); - - if (savedFrameCounter > settings.outputFrameCount) - { - if (signal.imageSequenceOutputComplete) // 避免重复改变为true - { - return; - } - signal.imageSequenceOutputComplete = true; - - std::string fileName; - - if (settings.outputPNGimage) - { - fileName = "/%dresult.png"; - } - else - { - fileName = "/%dresult.ppm"; - } - - filePath.totalImageOutputPath = filePath.deviceSpecFilePath + fileName; - return; - } - if (_access(filePath.deviceSpecFilePath.c_str(), 0) == -1) - { - std::filesystem::create_directories(filePath.deviceSpecFilePath.c_str()); - } - std::string fileNameSuffix; - if (settings.outputPNGimage) - { - fileNameSuffix = "result.png"; - } - else - { - fileNameSuffix = "result.ppm"; - } - std::string fileName ="/" + std::to_string(savedFrameCounter) + fileNameSuffix; - filePath.totalImageOutputPath = filePath.deviceSpecFilePath + fileName; - //std::cout << outputPath << std::endl; - writeImageToFile(filePath.totalImageOutputPath.c_str()); - savedFrameCounter++; - } - - void PlumageRender::imageSequenceToVideo() - { - if (!signal.imageSequenceOutputComplete) - { - return; - } - if (signal.imageSequenceToVideoComplete) - { - return; - } - std::string deviceFilePath = filePath.videoOutputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex); - if (_access(deviceFilePath.c_str(), 0) == -1) - { - std::filesystem::create_directories(deviceFilePath.c_str()); - } - - std::string resultVideoPath = deviceFilePath + "/result.mp4"; - - std::string commandLineImageSequencePath = filePath.totalImageOutputPath; - //std::string commandLineCodecAndResultPath = resultVideoPath; - std::string commandLineFrameRate = std::to_string(settings.videoFrameRate); +{ + title = "plumage render"; +} + +void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode) +{ + if (node->mesh) + { + // Render mesh primitives + for (glTFModel::Primitive *primitive : node->mesh->primitives) + { + if (primitive->material.alphaMode == alphaMode) + { + VkPipeline pipeline = VK_NULL_HANDLE; + switch (alphaMode) + { + case glTFModel::Material::ALPHAMODE_OPAQUE: + case glTFModel::Material::ALPHAMODE_MASK: + pipeline = primitive->material.doubleSided ? pipelines.pbrDoubleSided : pipelines.pbr; + break; + case glTFModel::Material::ALPHAMODE_BLEND: + pipeline = pipelines.pbrAlphaBlend; + break; + } + + if (pipeline != boundPipeline) + { + vkCmdBindPipeline(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + boundPipeline = pipeline; + } + + const std::vector descriptorsets = { + descriptorSets[cbIndex].scene, + primitive->material.descriptorSet, + node->mesh->uniformBuffer.descriptorSet, + }; + vkCmdBindDescriptorSets(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast(descriptorsets.size()), descriptorsets.data(), 0, NULL); + + // Pass material parameters as push constants + PushConstBlockMaterial m_pushConstBlockMaterial; + m_pushConstBlockMaterial.setEmissiveFactor(primitive->material.emissiveFactor); + // To save push constant space, availabilty and texture coordiante set are combined + // -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set + if (primitive->material.baseColorTexture != nullptr) + { + + m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor); + } + else + { + m_pushConstBlockMaterial.setColorTextureSet(-1); + } + + if (primitive->material.normalTexture != nullptr) + { + m_pushConstBlockMaterial.setNormalTextureSet(primitive->material.texCoordSets.normal); + } + else + { + m_pushConstBlockMaterial.setNormalTextureSet(-1); + } + if (primitive->material.occlusionTexture != nullptr) + { + m_pushConstBlockMaterial.setOcclusionTextureSet(primitive->material.texCoordSets.occlusion); + } + else + { + m_pushConstBlockMaterial.setOcclusionTextureSet(-1); + } + + if (primitive->material.emissiveTexture != nullptr) + { + m_pushConstBlockMaterial.setEmissiveTextureSet(primitive->material.texCoordSets.emissive); + } + else + { + m_pushConstBlockMaterial.setEmissiveTextureSet(-1); + } + if (primitive->material.alphaMode == glTFModel::Material::ALPHAMODE_MASK) + { + m_pushConstBlockMaterial.setAlphaMask(static_cast(primitive->material.alphaMode)); + } + m_pushConstBlockMaterial.setAlphaMaskCutoff(primitive->material.alphaCutoff); + + // TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present + + if (primitive->material.pbrWorkflows.metallicRoughness) + { + // Metallic roughness workflow + m_pushConstBlockMaterial.setWorkflow(static_cast(PBR_WORKFLOW_METALLIC_ROUGHNESS)); + m_pushConstBlockMaterial.setBaseColorFactor(primitive->material.baseColorFactor); + m_pushConstBlockMaterial.setMetallicFactor(primitive->material.metallicFactor); + m_pushConstBlockMaterial.setRoughnessFactor(primitive->material.roughnessFactor); + if (primitive->material.metallicRoughnessTexture != nullptr) + { + m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(primitive->material.texCoordSets.metallicRoughness); + } + else + { + m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1); + } + + if (primitive->material.baseColorTexture != nullptr) + { + m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor); + } + else + { + m_pushConstBlockMaterial.setColorTextureSet(-1); + } + } + + if (primitive->material.pbrWorkflows.specularGlossiness) + { + + // Specular glossiness workflow + m_pushConstBlockMaterial.setWorkflow(static_cast(PBR_WORKFLOW_SPECULAR_GLOSINESS)); + if (primitive->material.extension.specularGlossinessTexture != nullptr) + { + m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(primitive->material.texCoordSets.specularGlossiness); + } + else + { + m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1); + } + + if (primitive->material.extension.diffuseTexture != nullptr) + { + m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor); + } + else + { + m_pushConstBlockMaterial.setColorTextureSet(-1); + } + + m_pushConstBlockMaterial.setDiffuseFactor(primitive->material.extension.diffuseFactor); + m_pushConstBlockMaterial.setSpecularFactor(glm::vec4(primitive->material.extension.specularFactor, 1.0f)); + } + + vkCmdPushConstants(commandBuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlockMaterial), &m_pushConstBlockMaterial); + + if (primitive->hasIndices) + { + vkCmdDrawIndexed(commandBuffers[cbIndex], primitive->indexCount, 1, primitive->firstIndex, 0, 0); + } + else + { + vkCmdDraw(commandBuffers[cbIndex], primitive->vertexCount, 1, 0, 0); + } + } + } + }; + for (auto child : node->children) + { + renderNode(child, cbIndex, alphaMode); + } +} + +void PlumageRender::buildCommandBuffers() +{ + VkCommandBufferBeginInfo cmdBufferBeginInfo{}; + cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + VkClearValue clearValues[3]; + if (settings.multiSampling) + { + clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; + clearValues[1].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; + clearValues[2].depthStencil = {1.0f, 0}; + } + else + { + clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; + clearValues[1].depthStencil = {1.0f, 0}; + } + + VkRenderPassBeginInfo renderPassBeginInfo{}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.renderArea.offset.x = 0; + renderPassBeginInfo.renderArea.offset.y = 0; + renderPassBeginInfo.renderArea.extent.width = width; + renderPassBeginInfo.renderArea.extent.height = height; + renderPassBeginInfo.clearValueCount = settings.multiSampling ? 3 : 2; + renderPassBeginInfo.pClearValues = clearValues; + + for (uint32_t i = 0; i < commandBuffers.size(); ++i) + { + renderPassBeginInfo.framebuffer = frameBuffers[i]; + + VkCommandBuffer currentCB = commandBuffers[i]; + + VK_CHECK_RESULT(vkBeginCommandBuffer(currentCB, &cmdBufferBeginInfo)); + vkCmdBeginRenderPass(currentCB, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport{}; + viewport.width = (float)width; + viewport.height = (float)height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(currentCB, 0, 1, &viewport); + + VkRect2D scissor{}; + scissor.extent = {width, height}; + vkCmdSetScissor(currentCB, 0, 1, &scissor); + + VkDeviceSize offsets[1] = {0}; + + if (displayBackground) + { + vkCmdBindDescriptorSets(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i].skybox, 0, nullptr); + vkCmdBindPipeline(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox); + m_sceneModel.getSkyBox().draw(currentCB); + } + + glTFModel::Model &model = m_sceneModel.getScene(); + + vkCmdBindVertexBuffers(currentCB, 0, 1, &model.vertices.buffer, offsets); + if (model.indices.buffer != VK_NULL_HANDLE) + { + vkCmdBindIndexBuffer(currentCB, model.indices.buffer, 0, VK_INDEX_TYPE_UINT32); + } + + boundPipeline = VK_NULL_HANDLE; + + // Opaque primitives first + for (auto node : model.nodes) + { + renderNode(node, i, glTFModel::Material::ALPHAMODE_OPAQUE); + } + // Alpha masked primitives + for (auto node : model.nodes) + { + renderNode(node, i, glTFModel::Material::ALPHAMODE_MASK); + } + // Transparent primitives + // TODO: Correct depth sorting + for (auto node : model.nodes) + { + renderNode(node, i, glTFModel::Material::ALPHAMODE_BLEND); + } + + // User interface + gui->draw(currentCB); + + vkCmdEndRenderPass(currentCB); + VK_CHECK_RESULT(vkEndCommandBuffer(currentCB)); + } +} + +void PlumageRender::loadScene(std::string filename) +{ + std::cout << "Loading scene from " << filename << std::endl; + m_sceneModel.destroyScene(device); + + animationIndex = 0; + animationTimer = 0.0f; + auto tStart = std::chrono::high_resolution_clock::now(); + m_sceneModel.getScene().loadFromFile(filename, vulkanDevice, queue); + auto tFileLoad = std::chrono::duration(std::chrono::high_resolution_clock::now() - tStart).count(); + std::cout << "Loading took " << tFileLoad << " ms" << std::endl; + camera.setPosition({0.0f, 0.0f, -2.0f}); + camera.setRotation({0.0f, 0.0f, 0.0f}); +} + +void PlumageRender::loadEnvironment(std::string filename) +{ + std::cout << "Loading environment from " << filename << std::endl; + if (m_sceneTextures.getEnvironmentCube().image) + { + m_sceneTextures.destroyEnvironmentCube(); + m_sceneTextures.destroyIrradianceCube(); + m_sceneTextures.destroyPrefilteredCube(); + } + m_sceneTextures.getEnvironmentCube().loadFromFile(filename, VK_FORMAT_R16G16B16A16_SFLOAT, vulkanDevice, queue); + generateCubemaps(); +} + +void PlumageRender::loadAssets() +{ + const std::string assetpath = getAssetPath(); + + if (_access(assetpath.c_str(), 0) != 0) + { + std::string msg = "Could not locate asset path in \"" + assetpath + "\".\nMake sure binary is running from correct relative directory!"; + std::cerr << msg << std::endl; + system("pause"); + // exit(-1); + } + else + { + std::string msg = "asset path get " + assetpath; + std::cout << msg << std::endl; + } + + readDirectory(assetpath + "environments", "*.ktx", environments, false); + + m_sceneTextures.getEmpty().loadFromFile(PlumageRender::m_configFilePath.getEmptyEnvmapFilePath(), VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue); + + std::string sceneFile = m_configFilePath.getGlTFModelFilePath(); + std::string envMapFile = m_configFilePath.getEnvMapFilePath(); + for (size_t i = 0; i < args.size(); i++) + { + if ((std::string(args[i]).find(".gltf") != std::string::npos) || (std::string(args[i]).find(".glb") != std::string::npos)) + { + std::ifstream file(args[i]); + if (file.good()) + { + sceneFile = args[i]; + } + else + { + std::cout << "could not load \"" << args[i] << "\"" << std::endl; + } + } + if (std::string(args[i]).find(".ktx") != std::string::npos) + { + std::ifstream file(args[i]); + if (file.good()) + { + envMapFile = args[i]; + } + else + { + std::cout << "could not load \"" << args[i] << "\"" << std::endl; + } + } + } + + loadScene(sceneFile.c_str()); + m_sceneModel.getSkyBox().loadFromFile(PlumageRender::m_configFilePath.getSkyboxModleFilePath(), vulkanDevice, queue); + + loadEnvironment(envMapFile.c_str()); +} + +void PlumageRender::setupNodeDescriptorSet(glTFModel::Node *node) +{ + /* + This sample uses separate descriptor sets (and layouts) for the matrices and materials (textures) + */ + if (node->mesh) + { + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.node; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &node->mesh->uniformBuffer.descriptorSet)); + + VkWriteDescriptorSet writeDescriptorSet{}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSet.descriptorCount = 1; + writeDescriptorSet.dstSet = node->mesh->uniformBuffer.descriptorSet; + writeDescriptorSet.dstBinding = 0; + writeDescriptorSet.pBufferInfo = &node->mesh->uniformBuffer.descriptor; + + vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); + } + for (auto &child : node->children) + { + setupNodeDescriptorSet(child); + } +} + +void PlumageRender::setupDescriptors() +{ + /* + Descriptor Pool + */ + uint32_t imageSamplerCount = 0; + uint32_t materialCount = 0; + uint32_t meshCount = 0; + + // Environment samplers (radiance, irradiance, brdflut) + imageSamplerCount += 3; + + std::vector modellist = {&m_sceneModel.getSkyBox(), &m_sceneModel.getScene()}; + for (auto &model : modellist) + { + for (auto &material : model->materials) + { + imageSamplerCount += 5; + materialCount++; + } + for (auto node : model->linearNodes) + { + if (node->mesh) + { + meshCount++; + } + } + } + + std::vector poolSizes = { + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (4 + meshCount) * swapChain.imageCount}, + {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageSamplerCount * swapChain.imageCount}}; + VkDescriptorPoolCreateInfo descriptorPoolCI{}; + descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolCI.poolSizeCount = 2; + descriptorPoolCI.pPoolSizes = poolSizes.data(); + descriptorPoolCI.maxSets = (2 + materialCount + meshCount) * swapChain.imageCount; + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool)); + + /* + Descriptor sets + */ + + // Scene (matrices and environment maps) + { + std::vector setLayoutBindings = { + {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + {1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + {2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + {3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + {4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + }; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCI.pBindings = setLayoutBindings.data(); + descriptorSetLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.scene)); + + vks::TextureCubeMap refIrradianceCube = m_sceneTextures.getIrradianceCube(); + for (auto i = 0; i < descriptorSets.size(); i++) + { + + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.scene; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSets[i].scene)); + + std::array writeDescriptorSets{}; + + writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSets[0].descriptorCount = 1; + writeDescriptorSets[0].dstSet = descriptorSets[i].scene; + writeDescriptorSets[0].dstBinding = 0; + writeDescriptorSets[0].pBufferInfo = &uniformBuffers[i].getScene().descriptor; + + writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSets[1].descriptorCount = 1; + writeDescriptorSets[1].dstSet = descriptorSets[i].scene; + writeDescriptorSets[1].dstBinding = 1; + writeDescriptorSets[1].pBufferInfo = &uniformBuffers[i].getParams().descriptor; + + writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[2].descriptorCount = 1; + writeDescriptorSets[2].dstSet = descriptorSets[i].scene; + writeDescriptorSets[2].dstBinding = 2; + writeDescriptorSets[2].pImageInfo = &refIrradianceCube.descriptor; + + writeDescriptorSets[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[3].descriptorCount = 1; + writeDescriptorSets[3].dstSet = descriptorSets[i].scene; + writeDescriptorSets[3].dstBinding = 3; + writeDescriptorSets[3].pImageInfo = &refIrradianceCube.descriptor; + + writeDescriptorSets[4].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[4].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[4].descriptorCount = 1; + writeDescriptorSets[4].dstSet = descriptorSets[i].scene; + writeDescriptorSets[4].dstBinding = 4; + writeDescriptorSets[4].pImageInfo = &refIrradianceCube.descriptor; + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + } + } + + // Material (samplers) + { + std::vector setLayoutBindings = { + {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + {2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + {3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + {4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, + }; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCI.pBindings = setLayoutBindings.data(); + descriptorSetLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.material)); + + // Per-Material descriptor sets + for (auto &material : m_sceneModel.getScene().materials) + { + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.material; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &material.descriptorSet)); + VkDescriptorImageInfo emptyTexDescriptor = m_sceneTextures.getEmpty().descriptor; + std::vector imageDescriptors = { + emptyTexDescriptor, + emptyTexDescriptor, + material.normalTexture ? material.normalTexture->descriptor : emptyTexDescriptor, + material.occlusionTexture ? material.occlusionTexture->descriptor : emptyTexDescriptor, + material.emissiveTexture ? material.emissiveTexture->descriptor : emptyTexDescriptor}; + + if (material.pbrWorkflows.metallicRoughness) + { + if (material.baseColorTexture) + { + imageDescriptors[0] = material.baseColorTexture->descriptor; + } + if (material.metallicRoughnessTexture) + { + imageDescriptors[1] = material.metallicRoughnessTexture->descriptor; + } + } + + if (material.pbrWorkflows.specularGlossiness) + { + if (material.extension.diffuseTexture) + { + imageDescriptors[0] = material.extension.diffuseTexture->descriptor; + } + if (material.extension.specularGlossinessTexture) + { + imageDescriptors[1] = material.extension.specularGlossinessTexture->descriptor; + } + } + + std::array writeDescriptorSets{}; + for (size_t i = 0; i < imageDescriptors.size(); i++) + { + writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[i].descriptorCount = 1; + writeDescriptorSets[i].dstSet = material.descriptorSet; + writeDescriptorSets[i].dstBinding = static_cast(i); + writeDescriptorSets[i].pImageInfo = &imageDescriptors[i]; + } + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + } + + // Model node (matrices) + { + std::vector setLayoutBindings = { + {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}, + }; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCI.pBindings = setLayoutBindings.data(); + descriptorSetLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.node)); + + // Per-Node descriptor set + for (auto &node : m_sceneModel.getScene().nodes) + { + setupNodeDescriptorSet(node); + } + } + } + + vks::TextureCubeMap refPrefilterCube = m_sceneTextures.getPrefilteredCube(); + // Skybox (fixed set) + for (auto i = 0; i < uniformBuffers.size(); i++) + { + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.scene; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSets[i].skybox)); + + std::array writeDescriptorSets{}; + + writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSets[0].descriptorCount = 1; + writeDescriptorSets[0].dstSet = descriptorSets[i].skybox; + writeDescriptorSets[0].dstBinding = 0; + writeDescriptorSets[0].pBufferInfo = &uniformBuffers[i].getSkybox().descriptor; + + writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSets[1].descriptorCount = 1; + writeDescriptorSets[1].dstSet = descriptorSets[i].skybox; + writeDescriptorSets[1].dstBinding = 1; + writeDescriptorSets[1].pBufferInfo = &uniformBuffers[i].getParams().descriptor; + + writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[2].descriptorCount = 1; + writeDescriptorSets[2].dstSet = descriptorSets[i].skybox; + writeDescriptorSets[2].dstBinding = 2; + writeDescriptorSets[2].pImageInfo = &refPrefilterCube.descriptor; + + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); + } +} + +void PlumageRender::preparePipelines() +{ + VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; + inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineRasterizationStateCreateInfo rasterizationStateCI{}; + rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL; + rasterizationStateCI.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizationStateCI.lineWidth = 1.0f; + + VkPipelineColorBlendAttachmentState blendAttachmentState{}; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendAttachmentState.blendEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo colorBlendStateCI{}; + colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlendStateCI.attachmentCount = 1; + colorBlendStateCI.pAttachments = &blendAttachmentState; + + VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{}; + depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencilStateCI.depthTestEnable = VK_FALSE; + depthStencilStateCI.depthWriteEnable = VK_FALSE; + depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencilStateCI.front = depthStencilStateCI.back; + depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS; + + VkPipelineViewportStateCreateInfo viewportStateCI{}; + viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportStateCI.viewportCount = 1; + viewportStateCI.scissorCount = 1; + + VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; + multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + + if (settings.multiSampling) + { + multisampleStateCI.rasterizationSamples = settings.sampleCount; + } + + std::vector dynamicStateEnables = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR}; + VkPipelineDynamicStateCreateInfo dynamicStateCI{}; + dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicStateCI.pDynamicStates = dynamicStateEnables.data(); + dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); + + // Pipeline layout + const std::vector setLayouts = { + descriptorSetLayouts.scene, descriptorSetLayouts.material, descriptorSetLayouts.node}; + VkPipelineLayoutCreateInfo pipelineLayoutCI{}; + pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCI.setLayoutCount = static_cast(setLayouts.size()); + pipelineLayoutCI.pSetLayouts = setLayouts.data(); + VkPushConstantRange pushConstantRange{}; + pushConstantRange.size = sizeof(PushConstBlockMaterial); + pushConstantRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + pipelineLayoutCI.pushConstantRangeCount = 1; + pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); + + // Vertex bindings an attributes + VkVertexInputBindingDescription vertexInputBinding = {0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX}; + std::vector vertexInputAttributes = { + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3}, + {2, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 8}, + {4, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 10}, + {5, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 14}, + {6, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 18}}; + VkPipelineVertexInputStateCreateInfo vertexInputStateCI{}; + vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputStateCI.vertexBindingDescriptionCount = 1; + vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding; + vertexInputStateCI.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); + vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data(); + + // Pipelines + std::array shaderStages; + + VkGraphicsPipelineCreateInfo pipelineCI{}; + pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCI.layout = pipelineLayout; + pipelineCI.renderPass = renderPass; + pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; + pipelineCI.pVertexInputState = &vertexInputStateCI; + pipelineCI.pRasterizationState = &rasterizationStateCI; + pipelineCI.pColorBlendState = &colorBlendStateCI; + pipelineCI.pMultisampleState = &multisampleStateCI; + pipelineCI.pViewportState = &viewportStateCI; + pipelineCI.pDepthStencilState = &depthStencilStateCI; + pipelineCI.pDynamicState = &dynamicStateCI; + pipelineCI.stageCount = static_cast(shaderStages.size()); + pipelineCI.pStages = shaderStages.data(); + + if (settings.multiSampling) + { + multisampleStateCI.rasterizationSamples = settings.sampleCount; + } + + // Skybox pipeline (background cube) + shaderStages = { + loadShader(device, m_configFilePath.getSkyboxVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT), + loadShader(device, m_configFilePath.getSkyboxFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)}; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.skybox)); + for (auto shaderStage : shaderStages) + { + vkDestroyShaderModule(device, shaderStage.module, nullptr); + } + + // PBR pipeline + shaderStages = { + loadShader(device, m_configFilePath.getPbrVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT), + loadShader(device, m_configFilePath.getPbrFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)}; + depthStencilStateCI.depthWriteEnable = VK_TRUE; + depthStencilStateCI.depthTestEnable = VK_TRUE; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbr)); + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbrDoubleSided)); + + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + blendAttachmentState.blendEnable = VK_TRUE; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbrAlphaBlend)); + + for (auto shaderStage : shaderStages) + { + vkDestroyShaderModule(device, shaderStage.module, nullptr); + } + // Create Tone Mapping render pipeline + // CreateToneMappingPipeline(); +} + +// generate two cube maps +// irradiance cube map +// prefileter environment cube map +void PlumageRender::generateCubemaps() +{ + enum Target + { + IRRADIANCE = 0, + PREFILTEREDENV = 1 + }; + + for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++) + { + + vks::TextureCubeMap cubemap; + + auto tStart = std::chrono::high_resolution_clock::now(); + + VkFormat format; + int32_t dim; + + switch (target) + { + case IRRADIANCE: + format = VK_FORMAT_R32G32B32A32_SFLOAT; + dim = 128; + break; + case PREFILTEREDENV: + format = VK_FORMAT_R16G16B16A16_SFLOAT; + dim = 4096; + break; + }; + + const uint32_t numMips = static_cast(floor(log2(dim))) + 1; + + // Create target cubemap static_cast(floor(log2(dim))) + + { + // Image + VkImageCreateInfo imageCI{}; + imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCI.imageType = VK_IMAGE_TYPE_2D; + imageCI.format = format; + imageCI.extent.width = dim; + imageCI.extent.height = dim; + imageCI.extent.depth = 1; + imageCI.mipLevels = numMips; + imageCI.arrayLayers = 6; + imageCI.samples = VK_SAMPLE_COUNT_1_BIT; + imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + imageCI.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &cubemap.image)); + VkMemoryRequirements memReqs; + vkGetImageMemoryRequirements(device, cubemap.image, &memReqs); + VkMemoryAllocateInfo memAllocInfo{}; + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &cubemap.deviceMemory)); + VK_CHECK_RESULT(vkBindImageMemory(device, cubemap.image, cubemap.deviceMemory, 0)); + + // View + VkImageViewCreateInfo viewCI{}; + viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE; + viewCI.format = format; + viewCI.subresourceRange = {}; + viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewCI.subresourceRange.levelCount = numMips; + viewCI.subresourceRange.layerCount = 6; + viewCI.image = cubemap.image; + VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &cubemap.view)); + + // Sampler + VkSamplerCreateInfo samplerCI{}; + samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerCI.magFilter = VK_FILTER_LINEAR; + samplerCI.minFilter = VK_FILTER_LINEAR; + samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCI.minLod = 0.0f; + samplerCI.maxLod = static_cast(numMips); + samplerCI.maxAnisotropy = 1.0f; + samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &cubemap.sampler)); + } + + // FB, Att, RP, Pipe, etc. + VkAttachmentDescription attDesc{}; + // Color attachment + attDesc.format = format; + attDesc.samples = VK_SAMPLE_COUNT_1_BIT; + attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentReference colorReference = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpassDescription{}; + subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDescription.colorAttachmentCount = 1; + subpassDescription.pColorAttachments = &colorReference; + + // Use subpass dependencies for layout transitions + std::array dependencies; + dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + dependencies[1].srcSubpass = 0; + dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; + dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + // Renderpass + VkRenderPassCreateInfo renderPassCI{}; + renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassCI.attachmentCount = 1; + renderPassCI.pAttachments = &attDesc; + renderPassCI.subpassCount = 1; + renderPassCI.pSubpasses = &subpassDescription; + renderPassCI.dependencyCount = 2; + renderPassCI.pDependencies = dependencies.data(); + VkRenderPass renderpass; + VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass)); + + // Create offscreen framebuffer + { + // Image + VkImageCreateInfo imageCI{}; + imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCI.imageType = VK_IMAGE_TYPE_2D; + imageCI.format = format; + imageCI.extent.width = dim; + imageCI.extent.height = dim; + imageCI.extent.depth = 1; + imageCI.mipLevels = 1; + imageCI.arrayLayers = 1; + imageCI.samples = VK_SAMPLE_COUNT_1_BIT; + imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &offscreen.image)); + VkMemoryRequirements memReqs; + vkGetImageMemoryRequirements(device, offscreen.image, &memReqs); + VkMemoryAllocateInfo memAllocInfo{}; + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &offscreen.memory)); + VK_CHECK_RESULT(vkBindImageMemory(device, offscreen.image, offscreen.memory, 0)); + + // View + VkImageViewCreateInfo viewCI{}; + viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewCI.format = format; + viewCI.flags = 0; + viewCI.subresourceRange = {}; + viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewCI.subresourceRange.baseMipLevel = 0; + viewCI.subresourceRange.levelCount = 1; + viewCI.subresourceRange.baseArrayLayer = 0; + viewCI.subresourceRange.layerCount = 1; + viewCI.image = offscreen.image; + VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &offscreen.view)); + + // Framebuffer + VkFramebufferCreateInfo framebufferCI{}; + framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferCI.renderPass = renderpass; + framebufferCI.attachmentCount = 1; + framebufferCI.pAttachments = &offscreen.view; + framebufferCI.width = dim; + framebufferCI.height = dim; + framebufferCI.layers = 1; + VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCI, nullptr, &offscreen.framebuffer)); + + VkCommandBuffer layoutCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = offscreen.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imageMemoryBarrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + vkCmdPipelineBarrier(layoutCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + vulkanDevice->flushCommandBuffer(layoutCmd, queue, true); + } + + // Descriptors + VkDescriptorSetLayout descriptorsetlayout; + VkDescriptorSetLayoutBinding setLayoutBinding = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCI.pBindings = &setLayoutBinding; + descriptorSetLayoutCI.bindingCount = 1; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout)); + + // Descriptor Pool + VkDescriptorPoolSize poolSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1}; + VkDescriptorPoolCreateInfo descriptorPoolCI{}; + descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolCI.poolSizeCount = 1; + descriptorPoolCI.pPoolSizes = &poolSize; + descriptorPoolCI.maxSets = 2; + VkDescriptorPool descriptorpool; + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorpool)); + + // Descriptor sets + VkDescriptorSet descriptorset; + VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; + descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocInfo.descriptorPool = descriptorpool; + descriptorSetAllocInfo.pSetLayouts = &descriptorsetlayout; + descriptorSetAllocInfo.descriptorSetCount = 1; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorset)); + VkWriteDescriptorSet writeDescriptorSet{}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSet.descriptorCount = 1; + writeDescriptorSet.dstSet = descriptorset; + writeDescriptorSet.dstBinding = 0; + writeDescriptorSet.pImageInfo = &m_sceneTextures.getEnvironmentCube().descriptor; + vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); + + // Pipeline layout + VkPipelineLayout pipelinelayout; + VkPushConstantRange pushConstantRange{}; + pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + + switch (target) + { + case IRRADIANCE: + pushConstantRange.size = sizeof(IrradiancePushBlock); + break; + case PREFILTEREDENV: + pushConstantRange.size = sizeof(PrefilterPushBlock); + break; + }; + + VkPipelineLayoutCreateInfo pipelineLayoutCI{}; + pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCI.setLayoutCount = 1; + pipelineLayoutCI.pSetLayouts = &descriptorsetlayout; + pipelineLayoutCI.pushConstantRangeCount = 1; + pipelineLayoutCI.pPushConstantRanges = &pushConstantRange; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout)); + + // Pipeline + VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; + inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineRasterizationStateCreateInfo rasterizationStateCI{}; + rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL; + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizationStateCI.lineWidth = 1.0f; + + VkPipelineColorBlendAttachmentState blendAttachmentState{}; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendAttachmentState.blendEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo colorBlendStateCI{}; + colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlendStateCI.attachmentCount = 1; + colorBlendStateCI.pAttachments = &blendAttachmentState; + + VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{}; + depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencilStateCI.depthTestEnable = VK_FALSE; + depthStencilStateCI.depthWriteEnable = VK_FALSE; + depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencilStateCI.front = depthStencilStateCI.back; + depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS; + + VkPipelineViewportStateCreateInfo viewportStateCI{}; + viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportStateCI.viewportCount = 1; + viewportStateCI.scissorCount = 1; + + VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; + multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + std::vector dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + VkPipelineDynamicStateCreateInfo dynamicStateCI{}; + dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicStateCI.pDynamicStates = dynamicStateEnables.data(); + dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); + + // Vertex input state + VkVertexInputBindingDescription vertexInputBinding = {0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX}; + VkVertexInputAttributeDescription vertexInputAttribute = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; + + VkPipelineVertexInputStateCreateInfo vertexInputStateCI{}; + vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputStateCI.vertexBindingDescriptionCount = 1; + vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding; + vertexInputStateCI.vertexAttributeDescriptionCount = 1; + vertexInputStateCI.pVertexAttributeDescriptions = &vertexInputAttribute; + + std::array shaderStages; + + VkGraphicsPipelineCreateInfo pipelineCI{}; + pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCI.layout = pipelinelayout; + pipelineCI.renderPass = renderpass; + pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; + pipelineCI.pVertexInputState = &vertexInputStateCI; + pipelineCI.pRasterizationState = &rasterizationStateCI; + pipelineCI.pColorBlendState = &colorBlendStateCI; + pipelineCI.pMultisampleState = &multisampleStateCI; + pipelineCI.pViewportState = &viewportStateCI; + pipelineCI.pDepthStencilState = &depthStencilStateCI; + pipelineCI.pDynamicState = &dynamicStateCI; + pipelineCI.stageCount = 2; + pipelineCI.pStages = shaderStages.data(); + pipelineCI.renderPass = renderpass; + + shaderStages[0] = loadShader(device, m_configFilePath.getFilterVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT); + switch (target) + { + case IRRADIANCE: + shaderStages[1] = loadShader(device, m_configFilePath.getIrradianceFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT); + break; + case PREFILTEREDENV: + shaderStages[1] = loadShader(device, m_configFilePath.getPrefilterEnvmapFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT); + break; + }; + VkPipeline pipeline; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); + for (auto shaderStage : shaderStages) + { + vkDestroyShaderModule(device, shaderStage.module, nullptr); + } + + // Render cubemap + VkClearValue clearValues[1]; + clearValues[0].color = {{0.0f, 0.0f, 0.2f, 0.0f}}; + + VkRenderPassBeginInfo renderPassBeginInfo{}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.renderPass = renderpass; + renderPassBeginInfo.framebuffer = offscreen.framebuffer; + renderPassBeginInfo.renderArea.extent.width = dim; + renderPassBeginInfo.renderArea.extent.height = dim; + renderPassBeginInfo.clearValueCount = 1; + renderPassBeginInfo.pClearValues = clearValues; + + std::vector matrices = { + glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)), + glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f)), + }; + + VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); + + VkViewport viewport{}; + viewport.width = (float)dim; + viewport.height = -(float)dim; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + viewport.x = 0; + viewport.y = -viewport.height; + + VkRect2D scissor{}; + scissor.extent.width = dim; + scissor.extent.height = dim; + + VkImageSubresourceRange subresourceRange{}; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = numMips; + subresourceRange.layerCount = 6; + + // Change image layout for all cubemap faces to transfer destination + { + vulkanDevice->beginCommandBuffer(cmdBuf); + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = cubemap.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.subresourceRange = subresourceRange; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + vulkanDevice->flushCommandBuffer(cmdBuf, queue, false); + } + + for (uint32_t m = 0; m < numMips; m++) + { + for (uint32_t f = 0; f < 6; f++) + { + + vulkanDevice->beginCommandBuffer(cmdBuf); + + viewport.width = static_cast(dim * std::pow(0.5f, m)); + viewport.height = -static_cast(dim * std::pow(0.5f, m)); + viewport.x = 0; + viewport.y = -viewport.height; + vkCmdSetViewport(cmdBuf, 0, 1, &viewport); + vkCmdSetScissor(cmdBuf, 0, 1, &scissor); + + // Render scene from cube face's point of view + vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + // Pass parameters for current pass using a push constant block + switch (target) + { + case IRRADIANCE: + irradiancePushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f]; + vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(IrradiancePushBlock), &irradiancePushBlock); + break; + case PREFILTEREDENV: + prefilterPushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f]; + prefilterPushBlock.roughness = 0.0; //(float)m / (float)(numMips - 1); + vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PrefilterPushBlock), &prefilterPushBlock); + break; + }; + + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 0, 1, &descriptorset, 0, NULL); + + VkDeviceSize offsets[1] = {0}; + + m_sceneModel.getSkyBox().draw(cmdBuf); + + vkCmdEndRenderPass(cmdBuf); + + VkImageSubresourceRange subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = numMips; + subresourceRange.layerCount = 6; + + { + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = offscreen.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + imageMemoryBarrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } + + // Copy region for transfer from framebuffer to cube face + VkImageCopy copyRegion{}; + + copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.srcSubresource.baseArrayLayer = 0; + copyRegion.srcSubresource.mipLevel = 0; + copyRegion.srcSubresource.layerCount = 1; + copyRegion.srcOffset = {0, 0, 0}; + + copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.dstSubresource.baseArrayLayer = f; + copyRegion.dstSubresource.mipLevel = m; + copyRegion.dstSubresource.layerCount = 1; + copyRegion.dstOffset = {0, 0, 0}; + + copyRegion.extent.width = static_cast(viewport.width); + copyRegion.extent.height = -static_cast(viewport.height); + copyRegion.extent.depth = 1; + + vkCmdCopyImage( + cmdBuf, + offscreen.image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + cubemap.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ©Region); + + { + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = offscreen.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imageMemoryBarrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } + + vulkanDevice->flushCommandBuffer(cmdBuf, queue, false); + } + } + + { + vulkanDevice->beginCommandBuffer(cmdBuf); + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.image = cubemap.image; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.subresourceRange = subresourceRange; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + vulkanDevice->flushCommandBuffer(cmdBuf, queue, false); + } + + vkDestroyRenderPass(device, renderpass, nullptr); + vkDestroyFramebuffer(device, offscreen.framebuffer, nullptr); + vkFreeMemory(device, offscreen.memory, nullptr); + vkDestroyImageView(device, offscreen.view, nullptr); + vkDestroyImage(device, offscreen.image, nullptr); + vkDestroyDescriptorPool(device, descriptorpool, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr); + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelinelayout, nullptr); + + cubemap.descriptor.imageView = cubemap.view; + cubemap.descriptor.sampler = cubemap.sampler; + cubemap.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + cubemap.device = vulkanDevice; + + switch (target) + { + case IRRADIANCE: + m_sceneTextures.getIrradianceCube() = cubemap; + break; + case PREFILTEREDENV: + m_sceneTextures.getPrefilteredCube() = cubemap; + m_shaderData.setPrefilteredCubeMipLevels(static_cast(numMips)); + break; + }; + + auto tEnd = std::chrono::high_resolution_clock::now(); + auto tDiff = std::chrono::duration(tEnd - tStart).count(); + std::cout << "Generating cube map with " << numMips << " mip levels took " << tDiff << " ms" << std::endl; + } +} +// generate BRDF integration map for roughness/NdotV +void PlumageRender::generateBRDFLUT() +{ + auto tStart = std::chrono::high_resolution_clock::now(); + + const VkFormat format = VK_FORMAT_R16G16_SFLOAT; + const int32_t dim = 2048; + vks::Texture2D RefLutBrdfTex = m_sceneTextures.getLutBrdf(); + + // Image + VkImageCreateInfo imageCI{}; + imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCI.imageType = VK_IMAGE_TYPE_2D; + imageCI.format = format; + imageCI.extent.width = dim; + imageCI.extent.height = dim; + imageCI.extent.depth = 1; + imageCI.mipLevels = 1; + imageCI.arrayLayers = 1; + imageCI.samples = VK_SAMPLE_COUNT_1_BIT; + imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &RefLutBrdfTex.image)); + VkMemoryRequirements memReqs; + + vkGetImageMemoryRequirements(device, RefLutBrdfTex.image, &memReqs); + VkMemoryAllocateInfo memAllocInfo{}; + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &RefLutBrdfTex.deviceMemory)); + VK_CHECK_RESULT(vkBindImageMemory(device, RefLutBrdfTex.image, RefLutBrdfTex.deviceMemory, 0)); + + // View + VkImageViewCreateInfo viewCI{}; + viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewCI.format = format; + viewCI.subresourceRange = {}; + viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewCI.subresourceRange.levelCount = 1; + viewCI.subresourceRange.layerCount = 1; + viewCI.image = RefLutBrdfTex.image; + VK_CHECK_RESULT(vkCreateImageView(device, &viewCI, nullptr, &RefLutBrdfTex.view)); + + // Sampler + VkSamplerCreateInfo samplerCI{}; + samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerCI.magFilter = VK_FILTER_LINEAR; + samplerCI.minFilter = VK_FILTER_LINEAR; + samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCI.minLod = 0.0f; + samplerCI.maxLod = 1.0f; + samplerCI.maxAnisotropy = 1.0f; + samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + VK_CHECK_RESULT(vkCreateSampler(device, &samplerCI, nullptr, &RefLutBrdfTex.sampler)); + + // FB, Att, RP, Pipe, etc. + VkAttachmentDescription attDesc{}; + // Color attachment + attDesc.format = format; + attDesc.samples = VK_SAMPLE_COUNT_1_BIT; + attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkAttachmentReference colorReference = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpassDescription{}; + subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDescription.colorAttachmentCount = 1; + subpassDescription.pColorAttachments = &colorReference; + + // Use subpass dependencies for layout transitions + std::array dependencies; + dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + dependencies[1].srcSubpass = 0; + dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; + dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + // Create the actual renderpass + VkRenderPassCreateInfo renderPassCI{}; + renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassCI.attachmentCount = 1; + renderPassCI.pAttachments = &attDesc; + renderPassCI.subpassCount = 1; + renderPassCI.pSubpasses = &subpassDescription; + renderPassCI.dependencyCount = 2; + renderPassCI.pDependencies = dependencies.data(); + + VkRenderPass renderpass; + VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderpass)); + + VkFramebufferCreateInfo framebufferCI{}; + framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferCI.renderPass = renderpass; + framebufferCI.attachmentCount = 1; + framebufferCI.pAttachments = &RefLutBrdfTex.view; + framebufferCI.width = dim; + framebufferCI.height = dim; + framebufferCI.layers = 1; + + VkFramebuffer framebuffer; + VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCI, nullptr, &framebuffer)); + + // Desriptors + VkDescriptorSetLayout descriptorsetlayout; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; + descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout)); + + // Pipeline layout + VkPipelineLayout pipelinelayout; + VkPipelineLayoutCreateInfo pipelineLayoutCI{}; + pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCI.setLayoutCount = 1; + pipelineLayoutCI.pSetLayouts = &descriptorsetlayout; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelinelayout)); + + // Pipeline + VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; + inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineRasterizationStateCreateInfo rasterizationStateCI{}; + rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL; + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizationStateCI.lineWidth = 1.0f; + + VkPipelineColorBlendAttachmentState blendAttachmentState{}; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendAttachmentState.blendEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo colorBlendStateCI{}; + colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlendStateCI.attachmentCount = 1; + colorBlendStateCI.pAttachments = &blendAttachmentState; + + VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{}; + depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencilStateCI.depthTestEnable = VK_FALSE; + depthStencilStateCI.depthWriteEnable = VK_FALSE; + depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencilStateCI.front = depthStencilStateCI.back; + depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS; + + VkPipelineViewportStateCreateInfo viewportStateCI{}; + viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportStateCI.viewportCount = 1; + viewportStateCI.scissorCount = 1; + + VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; + multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + std::vector dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + VkPipelineDynamicStateCreateInfo dynamicStateCI{}; + dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicStateCI.pDynamicStates = dynamicStateEnables.data(); + dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); + + VkPipelineVertexInputStateCreateInfo emptyInputStateCI{}; + emptyInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + + std::array shaderStages; + + VkGraphicsPipelineCreateInfo pipelineCI{}; + pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCI.layout = pipelinelayout; + pipelineCI.renderPass = renderpass; + pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; + pipelineCI.pVertexInputState = &emptyInputStateCI; + pipelineCI.pRasterizationState = &rasterizationStateCI; + pipelineCI.pColorBlendState = &colorBlendStateCI; + pipelineCI.pMultisampleState = &multisampleStateCI; + pipelineCI.pViewportState = &viewportStateCI; + pipelineCI.pDepthStencilState = &depthStencilStateCI; + pipelineCI.pDynamicState = &dynamicStateCI; + pipelineCI.stageCount = 2; + pipelineCI.pStages = shaderStages.data(); + + // Look-up-table (from BRDF) pipeline + shaderStages = { + loadShader(device, m_configFilePath.getBrdfVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT), + loadShader(device, m_configFilePath.getBrdfFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)}; + VkPipeline pipeline; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); + for (auto shaderStage : shaderStages) + { + vkDestroyShaderModule(device, shaderStage.module, nullptr); + } + + // Render + VkClearValue clearValues[1]; + clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; + + VkRenderPassBeginInfo renderPassBeginInfo{}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.renderPass = renderpass; + renderPassBeginInfo.renderArea.extent.width = dim; + renderPassBeginInfo.renderArea.extent.height = dim; + renderPassBeginInfo.clearValueCount = 1; + renderPassBeginInfo.pClearValues = clearValues; + renderPassBeginInfo.framebuffer = framebuffer; + + VkCommandBuffer cmdBuf = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport{}; + viewport.width = (float)dim; + viewport.height = (float)dim; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + // viewport.x = 0; + // viewport.y = -viewport.height; + + VkRect2D scissor{}; + scissor.extent.width = dim; + scissor.extent.height = dim; + + vkCmdSetViewport(cmdBuf, 0, 1, &viewport); + vkCmdSetScissor(cmdBuf, 0, 1, &scissor); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); + vkCmdEndRenderPass(cmdBuf); + vulkanDevice->flushCommandBuffer(cmdBuf, queue); + + vkQueueWaitIdle(queue); + + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelinelayout, nullptr); + vkDestroyRenderPass(device, renderpass, nullptr); + vkDestroyFramebuffer(device, framebuffer, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorsetlayout, nullptr); + + RefLutBrdfTex.descriptor.imageView = RefLutBrdfTex.view; + RefLutBrdfTex.descriptor.sampler = RefLutBrdfTex.sampler; + RefLutBrdfTex.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + RefLutBrdfTex.device = vulkanDevice; + + auto tEnd = std::chrono::high_resolution_clock::now(); + auto tDiff = std::chrono::duration(tEnd - tStart).count(); + std::cout << "Generating BRDF LUT took " << tDiff << " ms" << std::endl; +} + +// Prepare and initialize uniform buffer containing shader uniforms +void PlumageRender::prepareUniformBuffers() +{ + for (auto &uniformBuffer : uniformBuffers) + { + uniformBuffer.getScene().create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(m_shaderDataScene)); + uniformBuffer.getSkybox().create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(m_shaderDataSkybox)); + uniformBuffer.getParams().create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(m_shaderData)); + } + updateUniformBuffers(); +} + +void PlumageRender::updateUniformBuffers() +{ + // Scene + m_shaderDataScene.setProjection(camera.matrices.perspective); + m_shaderDataScene.setView(camera.matrices.view); + glTFModel::Model &models = m_sceneModel.getScene(); + + float modelSize = std::max(models.aabb[0][0], std::max(models.aabb[1][1], models.aabb[2][2])); + // Center and scale model + float scale = (1.0f / modelSize) * 0.5f; + glm::vec3 translate = -glm::vec3(models.aabb[3][0], models.aabb[3][1], models.aabb[3][2]); + translate += -0.5f * glm::vec3(models.aabb[0][0], models.aabb[1][1], models.aabb[2][2]); + + // camera.setPosition(glm::vec3(0, 0, -modelSize - 2)); + + m_shaderDataScene.setModel(glm::mat4(1.0f)); + m_shaderDataScene.setModel(glm::scale(m_shaderDataScene.getModel(), glm::vec3(scale))); + m_shaderDataScene.setModel(glm::translate(m_shaderDataScene.getModel(), translate)); + + if (settings.rotateModel) + { + // shaderDataScene.model = glm::mat4(1.0f); + m_shaderDataScene.setModel(glm::rotate(m_shaderDataScene.getModel(), glm::radians(modelrot), glm::vec3(0, 1, 0))); + } + + m_shaderDataScene.setCamPos(glm::vec3( + -camera.position.z * sin(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)), + -camera.position.z * sin(glm::radians(camera.rotation.x)), + camera.position.z * cos(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)))); + + // Skybox + m_shaderDataSkybox.setProjection(camera.matrices.perspective); + m_shaderDataSkybox.setView(camera.matrices.view); + m_shaderDataSkybox.setModel(glm::mat4(glm::mat3(camera.matrices.view))); +} + +void PlumageRender::updateShaderData() +{ + glm::vec4 currentLightDir = glm::vec4( + sin(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)), + sin(glm::radians(lightSource.rotation.y)), + cos(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)), + 0.0f); + m_shaderData.setLightDir(currentLightDir); +} + +void PlumageRender::windowResized() +{ + buildCommandBuffers(); + vkDeviceWaitIdle(device); + updateUniformBuffers(); + // update UI + updateUIOverlay(); +} + +void PlumageRender::prepare() +{ + VulkanExampleBase::prepare(); + + camera.type = Camera::CameraType::lookat; + + camera.setPerspective(45.0f, (float)width / (float)height, 0.1f, 256.0f); + camera.rotationSpeed = 0.25f; + camera.movementSpeed = 0.1f; + + waitFences.resize(renderAhead); + presentCompleteSemaphores.resize(renderAhead); + renderCompleteSemaphores.resize(renderAhead); + commandBuffers.resize(swapChain.imageCount); + uniformBuffers.resize(swapChain.imageCount); + descriptorSets.resize(swapChain.imageCount); + // Command buffer execution fences + for (auto &waitFence : waitFences) + { + VkFenceCreateInfo fenceCI{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT}; + VK_CHECK_RESULT(vkCreateFence(device, &fenceCI, nullptr, &waitFence)); + } + // Queue ordering semaphores + for (auto &semaphore : presentCompleteSemaphores) + { + VkSemaphoreCreateInfo semaphoreCI{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0}; + VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore)); + } + for (auto &semaphore : renderCompleteSemaphores) + { + VkSemaphoreCreateInfo semaphoreCI{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0}; + VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore)); + } + // Command buffers + { + VkCommandBufferAllocateInfo cmdBufAllocateInfo{}; + cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdBufAllocateInfo.commandPool = cmdPool; + cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmdBufAllocateInfo.commandBufferCount = static_cast(commandBuffers.size()); + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commandBuffers.data())); + } + + loadAssets(); + generateBRDFLUT(); + generateCubemaps(); + prepareUniformBuffers(); + setupDescriptors(); + preparePipelines(); + + gui = new UI(vulkanDevice, renderPass, queue, pipelineCache, settings.sampleCount); + updateUIOverlay(); + + buildCommandBuffers(); + + prepared = true; +} + +void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue) +{ + VkSubmitInfo submitInfo = vks::initializers::submitInfo(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &cmdBuffer; + VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(); + VkFence fence; + VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence)); + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence)); + VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX)); + vkDestroyFence(device, fence, nullptr); +} + +// todo :根据physicalDeviceIndex确定子文件夹路径,frameIndex确定fileName +void PlumageRender::writeImageToFile(std::string filePath) +{ + + bool screenshotSaved = false; + bool supportsBlit = true; + + // Check blit support for source and destination + VkFormatProperties formatProps; + + // Check if the device supports blitting from optimal images (the swapchain images are in optimal format) + vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChain.colorFormat, &formatProps); + if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) + { + std::cerr << "Device does not support blitting from optimal tiled images, using copy instead of blit!" << std::endl; + supportsBlit = false; + } + + // Check if the device supports blitting to linear images + vkGetPhysicalDeviceFormatProperties(physicalDevice, VK_FORMAT_R8G8B8A8_UNORM, &formatProps); + if (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) + { + std::cerr << "Device does not support blitting to linear tiled images, using copy instead of blit!" << std::endl; + supportsBlit = false; + } + + // Source for the copy is the last rendered swapchain image + VkImage srcImage = swapChain.images[currentBuffer]; + + // Create the linear tiled destination image to copy to and to read the memory from + VkImageCreateInfo imageCreateCI(vks::initializers::imageCreateInfo()); + imageCreateCI.imageType = VK_IMAGE_TYPE_2D; + // Note that vkCmdBlitImage (if supported) will also do format conversions if the swapchain color format would differ + imageCreateCI.format = VK_FORMAT_R8G8B8A8_UNORM; + imageCreateCI.extent.width = width; + imageCreateCI.extent.height = height; + imageCreateCI.extent.depth = 1; + imageCreateCI.arrayLayers = 1; + imageCreateCI.mipLevels = 1; + imageCreateCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCreateCI.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateCI.tiling = VK_IMAGE_TILING_LINEAR; + imageCreateCI.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + // Create the image + VkImage dstImage; + VK_CHECK_RESULT(vkCreateImage(device, &imageCreateCI, nullptr, &dstImage)); + // Create memory to back up the image + VkMemoryRequirements memRequirements; + VkMemoryAllocateInfo memAllocInfo(vks::initializers::memoryAllocateInfo()); + VkDeviceMemory dstImageMemory; + vkGetImageMemoryRequirements(device, dstImage, &memRequirements); + memAllocInfo.allocationSize = memRequirements.size; + // Memory must be host visible to copy from + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &dstImageMemory)); + VK_CHECK_RESULT(vkBindImageMemory(device, dstImage, dstImageMemory, 0)); + + // Do the actual blit from the swapchain image to our host visible destination image + VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + + // Transition destination image to transfer destination layout + vks::tools::insertImageMemoryBarrier( + copyCmd, + dstImage, + 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}); + + // Transition swapchain image from present to transfer source layout + vks::tools::insertImageMemoryBarrier( + copyCmd, + srcImage, + VK_ACCESS_MEMORY_READ_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}); + + // If source and destination support blit we'll blit as this also does automatic format conversion (e.g. from BGR to RGB) + if (supportsBlit) + { + // Define the region to blit (we will blit the whole swapchain image) + VkOffset3D blitSize; + blitSize.x = width; + blitSize.y = height; + blitSize.z = 1; + VkImageBlit imageBlitRegion{}; + imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageBlitRegion.srcSubresource.layerCount = 1; + imageBlitRegion.srcOffsets[1] = blitSize; + imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageBlitRegion.dstSubresource.layerCount = 1; + imageBlitRegion.dstOffsets[1] = blitSize; + + // Issue the blit command + vkCmdBlitImage( + copyCmd, + srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &imageBlitRegion, + VK_FILTER_NEAREST); + } + else + { + // Otherwise use image copy (requires us to manually flip components) + VkImageCopy imageCopyRegion{}; + imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageCopyRegion.srcSubresource.layerCount = 1; + imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageCopyRegion.dstSubresource.layerCount = 1; + imageCopyRegion.extent.width = width; + imageCopyRegion.extent.height = height; + imageCopyRegion.extent.depth = 1; + + // Issue the copy command + vkCmdCopyImage( + copyCmd, + srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &imageCopyRegion); + } + + // Transition destination image to general layout, which is the required layout for mapping the image memory later on + vks::tools::insertImageMemoryBarrier( + copyCmd, + dstImage, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_MEMORY_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_GENERAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}); + + // Transition back the swap chain image after the blit is done + vks::tools::insertImageMemoryBarrier( + copyCmd, + srcImage, + VK_ACCESS_TRANSFER_READ_BIT, + VK_ACCESS_MEMORY_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}); + + vulkanDevice->flushCommandBuffer(copyCmd, queue); + + // Get layout of the image (including row pitch) + VkImageSubresource subResource{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0}; + VkSubresourceLayout subResourceLayout; + vkGetImageSubresourceLayout(device, dstImage, &subResource, &subResourceLayout); + + // Map image memory so we can start copying from it + const char *data; + vkMapMemory(device, dstImageMemory, 0, VK_WHOLE_SIZE, 0, (void **)&data); + data += subResourceLayout.offset; + + if (settings.outputPNGimage) + { + stbi_write_png(filePath.c_str(), width, height, 4, data, static_cast(subResourceLayout.rowPitch)); + } + else + { + std::ofstream file(filePath, std::ios::out | std::ios::binary); + + // ppm header + file << "P6\n" + << width << "\n" + << height << "\n" + << 255 << "\n"; + + // If source is BGR (destination is always RGB) and we can't use blit (which does automatic conversion), we'll have to manually swizzle color components + bool colorSwizzle = false; + // Check if source is BGR + // Note: Not complete, only contains most common and basic BGR surface formats for demonstration purposes + if (!supportsBlit) + { + std::vector formatsBGR = {VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM}; + colorSwizzle = (std::find(formatsBGR.begin(), formatsBGR.end(), swapChain.colorFormat) != formatsBGR.end()); + } + // ppm binary pixel data + for (uint32_t y = 0; y < height; y++) + { + unsigned int *row = (unsigned int *)data; + for (uint32_t x = 0; x < width; x++) + { + if (colorSwizzle) + { + file.write((char *)row + 2, 1); + file.write((char *)row + 1, 1); + file.write((char *)row, 1); + } + else + { + file.write((char *)row, 3); + } + row++; + } + data += subResourceLayout.rowPitch; + } + file.close(); + } + + std::cout << "Screenshot saved to " << filePath << std::endl; + + // Clean up resources + vkUnmapMemory(device, dstImageMemory); + vkFreeMemory(device, dstImageMemory, nullptr); + vkDestroyImage(device, dstImage, nullptr); + + screenshotSaved = true; +} + +void PlumageRender::outputImageSequence() +{ + + if (savedFrameCounter == settings.startFrameCount) + { + std::cout << "clean up directory for image sequence generation" << std::endl; + removeImageSequence(); + } + + m_configFilePath.setDeviceSpecFilePath(m_configFilePath.getImageOutputPath() + "/device" + std::to_string(selectedPhysicalDeviceIndex)); + + if (savedFrameCounter > settings.outputFrameCount) + { + if (m_videoOutputState->getImageSequenceOutputComplete()) // 避免重复改变为true + { + return; + } + m_videoOutputState->setImageSequenceOutputComplete(true); + + std::string fileName; + + if (settings.outputPNGimage) + { + fileName = "/%dresult.png"; + } + else + { + fileName = "/%dresult.ppm"; + } + m_configFilePath.setTotalImageOutputPath(m_configFilePath.getDeviceSpecFilePath() + fileName); + return; + } + if (_access(m_configFilePath.getDeviceSpecFilePath().c_str(), 0) == -1) + { + std::filesystem::create_directories(m_configFilePath.getDeviceSpecFilePath().c_str()); + } + std::string fileNameSuffix; + if (settings.outputPNGimage) + { + fileNameSuffix = "result.png"; + } + else + { + fileNameSuffix = "result.ppm"; + } + std::string fileName = "/" + std::to_string(savedFrameCounter) + fileNameSuffix; + m_configFilePath.setTotalImageOutputPath(m_configFilePath.getDeviceSpecFilePath() + fileName); + + // std::cout << outputPath << std::endl; + writeImageToFile(m_configFilePath.getTotalImageOutputPath().c_str()); + savedFrameCounter++; +} + +void PlumageRender::imageSequenceToVideo() +{ + if (!m_videoOutputState->getImageSequenceOutputComplete()) + { + return; + } + if (m_videoOutputState->getImageSequenceToVideoComplete()) + { + return; + } + + std::string deviceFilePath = m_configFilePath.getVideoOutputPath() + "/device" + std::to_string(selectedPhysicalDeviceIndex); + if (_access(deviceFilePath.c_str(), 0) == -1) + { + std::filesystem::create_directories(deviceFilePath.c_str()); + } + + std::string resultVideoPath = deviceFilePath + "/result.mp4"; + + std::string commandLineImageSequencePath = m_configFilePath.getTotalImageOutputPath(); + // std::string commandLineCodecAndResultPath = resultVideoPath; + std::string commandLineFrameRate = std::to_string(settings.videoFrameRate); #if defined(_WIN32) - std::string commandLine = filePath.image2videoBatFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath; + std::string commandLine = m_configFilePath.getImage2videoBatFilePath() + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath; #else - std::string commandLine = filePath.image2videoShFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath; + std::string commandLine = filePath.image2videoShFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath; #endif - std::cout << commandLine << std::endl; - std::system(commandLine.c_str()); - - signal.imageSequenceToVideoComplete = true; - std::cout << "vidoe codec complete,saved in:" << resultVideoPath << std::endl; - std::cout << "star to clean up image sequence" << std::endl; - removeImageSequence(); - } + std::cout << commandLine << std::endl; + std::system(commandLine.c_str()); - void PlumageRender::removeImageSequence() - { - if (savedFrameCounter != settings.startFrameCount) - { - if (!signal.imageSequenceToVideoComplete) - { - return; - } - - } - if (std::filesystem::exists(filePath.deviceSpecFilePath)) - { - for (const auto& entry : std::filesystem::directory_iterator(filePath.deviceSpecFilePath)) - { - if (std::filesystem::is_directory(entry.path())) - { - std::filesystem::remove_all(entry.path()); - } - else - { - std::filesystem::remove(entry.path()); - } - } - std::filesystem::remove(filePath.deviceSpecFilePath); - std::cout << "clean up complete" << std::endl; - } - return; + m_videoOutputState->setImageSequenceToVideoComplete(true); + std::cout << "vidoe codec complete,saved in:" << resultVideoPath << std::endl; + std::cout << "star to clean up image sequence" << std::endl; + removeImageSequence(); +} - } +void PlumageRender::removeImageSequence() +{ + if (savedFrameCounter != settings.startFrameCount) + { + if (!m_videoOutputState->getImageSequenceToVideoComplete()) + { + return; + } + } + if (std::filesystem::exists(m_configFilePath.getDeviceSpecFilePath())) + { + for (const auto &entry : std::filesystem::directory_iterator(m_configFilePath.getDeviceSpecFilePath())) + { + if (std::filesystem::is_directory(entry.path())) + { + std::filesystem::remove_all(entry.path()); + } + else + { + std::filesystem::remove(entry.path()); + } + } + std::filesystem::remove(m_configFilePath.getDeviceSpecFilePath()); + std::cout << "clean up complete" << std::endl; + } + return; +} - uint32_t PlumageRender::getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties) - { - VkPhysicalDeviceMemoryProperties deviceMemoryProperties; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); - for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++) - { - if ((typeBits & 1) == 1) - { - if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties) - { - return i; - } - } - typeBits >>= 1; - } - return 0; - } +uint32_t PlumageRender::getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties) +{ + VkPhysicalDeviceMemoryProperties deviceMemoryProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); + for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++) + { + if ((typeBits & 1) == 1) + { + if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties) + { + return i; + } + } + typeBits >>= 1; + } + return 0; +} - void PlumageRender::render() - { - if (!prepared) { - return; - } +void PlumageRender::render() +{ + if (!prepared) + { + return; + } - updateUIOverlay(); - //加入写到文件的函数 - //swapChainImage = swapChain.images[frameIndex]; - //outputImageSequeue(swapChainImage,filePath.imageSequenceFilePath); + updateUIOverlay(); + // 加入写到文件的函数 + // swapChainImage = swapChain.images[frameIndex]; + // outputImageSequeue(swapChainImage,filePath.imageSequenceFilePath); - - //outputImageSequence(); - - VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX)); - - //imageSequenceToVideo(); - VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex])); + // outputImageSequence(); - VkResult acquire = swapChain.acquireNextImage(presentCompleteSemaphores[frameIndex], ¤tBuffer); - if ((acquire == VK_ERROR_OUT_OF_DATE_KHR) || (acquire == VK_SUBOPTIMAL_KHR)) { - windowResize(); - } - else { - VK_CHECK_RESULT(acquire); - - - } + VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX)); - // Update UBOs - updateUniformBuffers(); - UniformBufferSet currentUB = uniformBuffers[currentBuffer]; - memcpy(currentUB.scene.mapped, &shaderDataScene, sizeof(shaderDataScene)); - memcpy(currentUB.params.mapped, &shaderData, sizeof(shaderData)); - memcpy(currentUB.skybox.mapped, &shaderDataSkybox, sizeof(shaderDataSkybox)); + // imageSequenceToVideo(); + VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex])); - const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkSubmitInfo submitInfo{}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.pWaitDstStageMask = &waitDstStageMask; - submitInfo.pWaitSemaphores = &presentCompleteSemaphores[frameIndex]; - submitInfo.waitSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &renderCompleteSemaphores[frameIndex]; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pCommandBuffers = &commandBuffers[currentBuffer]; - submitInfo.commandBufferCount = 1; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, waitFences[frameIndex])); + VkResult acquire = swapChain.acquireNextImage(presentCompleteSemaphores[frameIndex], ¤tBuffer); + if ((acquire == VK_ERROR_OUT_OF_DATE_KHR) || (acquire == VK_SUBOPTIMAL_KHR)) + { + windowResize(); + } + else + { + VK_CHECK_RESULT(acquire); + } - //显示队列 - VkResult present = swapChain.queuePresent(queue, currentBuffer, renderCompleteSemaphores[frameIndex]); - if (!((present == VK_SUCCESS) || (present == VK_SUBOPTIMAL_KHR))) { - if (present == VK_ERROR_OUT_OF_DATE_KHR) { - windowResize(); - return; - } - else { - VK_CHECK_RESULT(present); - } - } + // Update UBOs + updateUniformBuffers(); + RenderUniformBufferSet currentUB = uniformBuffers[currentBuffer]; + memcpy(currentUB.getScene().mapped, &m_shaderDataScene, sizeof(m_shaderDataScene)); + memcpy(currentUB.getParams().mapped, &m_shaderData, sizeof(m_shaderData)); + memcpy(currentUB.getSkybox().mapped, &m_shaderDataSkybox, sizeof(m_shaderDataSkybox)); - frameIndex += 1; - frameIndex %= renderAhead; + const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pWaitDstStageMask = &waitDstStageMask; + submitInfo.pWaitSemaphores = &presentCompleteSemaphores[frameIndex]; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &renderCompleteSemaphores[frameIndex]; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pCommandBuffers = &commandBuffers[currentBuffer]; + submitInfo.commandBufferCount = 1; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, waitFences[frameIndex])); - - if (settings.rotateModel) { - modelrot += frameTimer * 2.0f; - if (modelrot > 360.0f) { - modelrot -= 360.0f; - } - } - if ((animate) && (models.scene.animations.size() > 0)) { - animationTimer += frameTimer; - if (animationTimer > models.scene.animations[animationIndex].end) { - animationTimer -= models.scene.animations[animationIndex].end; - } - models.scene.updateAnimation(animationIndex, animationTimer); - } - updateShaderData(); - if (settings.rotateModel) { - updateUniformBuffers(); - } - - if (camera.updated) { - updateUniformBuffers(); - } + // 显示队列 + VkResult present = swapChain.queuePresent(queue, currentBuffer, renderCompleteSemaphores[frameIndex]); + if (!((present == VK_SUCCESS) || (present == VK_SUBOPTIMAL_KHR))) + { + if (present == VK_ERROR_OUT_OF_DATE_KHR) + { + windowResize(); + return; + } + else + { + VK_CHECK_RESULT(present); + } + } - } + frameIndex += 1; + frameIndex %= renderAhead; - void PlumageRender::fileDropped(std::string filename) - { - vkDeviceWaitIdle(device); - loadScene(filename); - setupDescriptors(); - buildCommandBuffers(); + if (settings.rotateModel) + { + modelrot += frameTimer * 2.0f; + if (modelrot > 360.0f) + { + modelrot -= 360.0f; + } + } + if ((animate) && (m_sceneModel.getScene().animations.size() > 0)) + { + animationTimer += frameTimer; + if (animationTimer > m_sceneModel.getScene().animations[animationIndex].end) + { + animationTimer -= m_sceneModel.getScene().animations[animationIndex].end; + } + m_sceneModel.getScene().updateAnimation(animationIndex, animationTimer); + } + updateShaderData(); + if (settings.rotateModel) + { + updateUniformBuffers(); + } - } + if (camera.updated) + { + updateUniformBuffers(); + } +} - void PlumageRender::updateUIOverlay() - { - ImGuiIO& io = ImGui::GetIO(); +void PlumageRender::fileDropped(std::string filename) +{ + vkDeviceWaitIdle(device); + loadScene(filename); + setupDescriptors(); + buildCommandBuffers(); +} - ImVec2 lastDisplaySize = io.DisplaySize; - io.DisplaySize = ImVec2((float)width, (float)height); - io.DeltaTime = frameTimer; +void PlumageRender::updateUIOverlay() +{ + ImGuiIO &io = ImGui::GetIO(); - io.MousePos = ImVec2(mousePos.x, mousePos.y); - io.MouseDown[0] = mouseButtons.left; - io.MouseDown[1] = mouseButtons.right; + ImVec2 lastDisplaySize = io.DisplaySize; + io.DisplaySize = ImVec2((float)width, (float)height); + io.DeltaTime = frameTimer; - gui->pushConstBlock.scale = glm::vec2(2.0f / io.DisplaySize.x, 2.0f / io.DisplaySize.y); - gui->pushConstBlock.translate = glm::vec2(-1.0f); + io.MousePos = ImVec2(mousePos.x, mousePos.y); + io.MouseDown[0] = mouseButtons.left; + io.MouseDown[1] = mouseButtons.right; - bool updateShaderParams = false; - bool updateCBs = false; - float scale = 1.0f; - ImGui::NewFrame(); + gui->pushConstBlock.scale = glm::vec2(2.0f / io.DisplaySize.x, 2.0f / io.DisplaySize.y); + gui->pushConstBlock.translate = glm::vec2(-1.0f); - ImGui::SetNextWindowPos(ImVec2(10000, 10000)); - //ImGui::SetNextWindowSize(ImVec2(200 * scale, (models.scene.animations.size() > 0 ? 440 : 360) * scale), ImGuiSetCond_Always); - ImGui::Begin(title.c_str(), nullptr, ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoBringToFrontOnFocus); - - ImGui::PushItemWidth(100.0f * scale); + bool updateShaderParams = false; + bool updateCBs = false; + float scale = 1.0f; + ImGui::NewFrame(); - - + ImGui::SetNextWindowPos(ImVec2(10000, 10000)); + // ImGui::SetNextWindowSize(ImVec2(200 * scale, (models.scene.animations.size() > 0 ? 440 : 360) * scale), ImGuiSetCond_Always); + ImGui::Begin(title.c_str(), nullptr, ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoBringToFrontOnFocus); - if(gui->beginMainMenuBar()) { - if (gui->beginMenu(chineseUI.menuFile)) - { - if (gui->menuItem(chineseUI.menuOpenNewModel)) - { - std::wstring filename = L""; - wchar_t buffer[MAX_PATH]; - OPENFILENAMEW ofn; - ZeroMemory(&buffer, sizeof(buffer)); - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.lpstrFilter = L"glTF files\0*.gltf;*.glb\0"; - ofn.lpstrFile = buffer; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrTitle = L"Select a glTF file to load"; - ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; - if (GetOpenFileNameW(&ofn)) { - filename = buffer; + ImGui::PushItemWidth(100.0f * scale); - } + if (gui->beginMainMenuBar()) + { + if (gui->beginMenu(m_localizationStrings.getMenuFile())) + { + if (gui->menuItem(m_localizationStrings.getMenuOpenNewModel())) + { + std::wstring filename = L""; + wchar_t buffer[MAX_PATH]; + OPENFILENAMEW ofn; + ZeroMemory(&buffer, sizeof(buffer)); + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.lpstrFilter = L"glTF files\0*.gltf;*.glb\0"; + ofn.lpstrFile = buffer; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrTitle = L"Select a glTF file to load"; + ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; + if (GetOpenFileNameW(&ofn)) + { + filename = buffer; + } - if (!filename.empty()) { - vkDeviceWaitIdle(device); - std::wstring_convert> converter; - - std::string stringFilename = converter.to_bytes(filename); - loadScene(stringFilename); - setupDescriptors(); - updateCBs = true; - signal.imageSequenceOutputComplete = false; - signal.imageSequenceToVideoComplete = false; - savedFrameCounter = 1; - } - } - gui->endMenu(); - } - if (gui->beginMenu(chineseUI.menuEnvironment)) - { - if (gui->beginMenu(chineseUI.menuEnvironmentConfig)) - { - if (gui->combo(chineseUI.environmentMap, selectedEnvironment, environments)) { - vkDeviceWaitIdle(device); - loadEnvironment(environments[selectedEnvironment]); - setupDescriptors(); - updateCBs = true; - } - if (gui->checkbox("模型自转", &settings.rotateModel)) { - updateShaderParams = true; - } - if (gui->checkbox(chineseUI.environmentBackGround, &displayBackground)) { - updateShaderParams = true; - } - if (gui->slider("Exposure", &shaderData.exposure, 0.1f, 10.0f)) { - updateShaderParams = true; - } - if (gui->slider("Gamma", &shaderData.gamma, 0.1f, 4.0f)) { - updateShaderParams = true; - } - if (gui->slider("IBL", &shaderData.scaleIBLAmbient, 0.0f, 1.0f)) { - updateShaderParams = true; - } - gui->endMenu(); - } - gui->endMenu(); - } - if (gui->beginMenu("debug")) - { - if (gui->beginMenu(chineseUI.menuDebugInput)) - { - const std::vector debugNamesInputs = { - "none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness" - }; - if (gui->combo(chineseUI.debugInput, &debugViewInputs, debugNamesInputs)) { - shaderData.debugViewInputs = static_cast(debugViewInputs); - updateShaderParams = true; - } - gui->endMenu(); - } - if (gui->beginMenu("PBR")) - { - const std::vector debugNamesEquation = { - "none", "Diff (l,n)", "F (l,h)", "G (l,v,h)", "D (h)", "Specular" - }; - if (gui->combo(chineseUI.debugPBREquation, &debugViewEquation, debugNamesEquation)) { - shaderData.debugViewEquation = static_cast(debugViewEquation); - updateShaderParams = true; - } - gui->endMenu(); - } - - if (gui->beginMenu(chineseUI.menuDebugFrameRate)) - { - gui->text("%.1d fps (%.2f ms)", lastFPS, (1000.0f / lastFPS)); - gui->endMenu(); - } - gui->endMenu(); - } - if (gui->beginMenu(chineseUI.menuAnimation)) - { - if (models.scene.animations.size() > 0) - { - if (gui->beginMenu(chineseUI.menuAnimationActivation)) - { - gui->checkbox(chineseUI.pauseAnimation, &animate); - gui->endMenu(); - } - if (gui->beginMenu(chineseUI.menuAnimationAnimationSequence)) - { - std::vector animationNames; - for (auto animation : models.scene.animations) { - animationNames.push_back(animation.name); - } - gui->combo(chineseUI.animationSeq, &animationIndex, animationNames); - gui->endMenu(); - } - } - else - { - gui->text(chineseUI.menuAnimationNoAnimation); - } - gui->endMenu(); - } + if (!filename.empty()) + { + vkDeviceWaitIdle(device); + std::wstring_convert> converter; - gui->endMainMenuBar(); - } - + std::string stringFilename = converter.to_bytes(filename); + loadScene(stringFilename); + setupDescriptors(); + updateCBs = true; + m_videoOutputState->setImageSequenceOutputComplete(false); + m_videoOutputState->setImageSequenceToVideoComplete(false); + savedFrameCounter = 1; + } + } + gui->endMenu(); + } + if (gui->beginMenu(m_localizationStrings.getMenuEnvironment())) + { + if (gui->beginMenu(m_localizationStrings.getMenuEnvironmentConfig())) + { + if (gui->combo(m_localizationStrings.getEnvironmentMap(), selectedEnvironment, environments)) + { + vkDeviceWaitIdle(device); + loadEnvironment(environments[selectedEnvironment]); + setupDescriptors(); + updateCBs = true; + } + if (gui->checkbox("模型自转", &settings.rotateModel)) + { + updateShaderParams = true; + } + if (gui->checkbox(m_localizationStrings.getEnvironmentBackGround(), &displayBackground)) + { + updateShaderParams = true; + } + if (gui->slider("Exposure", &m_shaderData.getExposure(), 0.1f, 10.0f)) + { + updateShaderParams = true; + } + if (gui->slider("Gamma", &m_shaderData.getGamma(), 0.1f, 4.0f)) + { + updateShaderParams = true; + } + if (gui->slider("IBL", &m_shaderData.getScaleIBLAmbient(), 0.0f, 1.0f)) + { + updateShaderParams = true; + } + gui->endMenu(); + } + gui->endMenu(); + } + if (gui->beginMenu("debug")) + { + if (gui->beginMenu(m_localizationStrings.getMenuDebugInput())) + { + const std::vector debugNamesInputs = { + "none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness"}; + if (gui->combo(m_localizationStrings.getDebugInput(), &debugViewInputs, debugNamesInputs)) + { + m_shaderData.setDebugViewInputs(static_cast(debugViewInputs)); + updateShaderParams = true; + } + gui->endMenu(); + } + if (gui->beginMenu("PBR")) + { + const std::vector debugNamesEquation = { + "none", "Diff (l,n)", "F (l,h)", "G (l,v,h)", "D (h)", "Specular"}; + if (gui->combo(m_localizationStrings.getDebugPBREquation(), &debugViewEquation, debugNamesEquation)) + { + m_shaderData.setDebugViewEquation(static_cast(debugViewEquation)); + updateShaderParams = true; + } + gui->endMenu(); + } - ImGui::PopItemWidth(); - ImGui::End(); - ImGui::Render(); + if (gui->beginMenu(m_localizationStrings.getMenuDebugFrameRate())) + { + gui->text("%.1d fps (%.2f ms)", lastFPS, (1000.0f / lastFPS)); + gui->endMenu(); + } + gui->endMenu(); + } + if (gui->beginMenu(m_localizationStrings.getMenuAnimation())) + { + if (m_sceneModel.getScene().animations.size() > 0) + { + if (gui->beginMenu(m_localizationStrings.getMenuAnimationActivation())) + { + gui->checkbox(m_localizationStrings.getPauseAnimation(), &animate); + gui->endMenu(); + } + if (gui->beginMenu(m_localizationStrings.getMenuAnimationAnimationSequence())) + { + std::vector animationNames; + for (auto animation : m_sceneModel.getScene().animations) + { + animationNames.push_back(animation.name); + } + gui->combo(m_localizationStrings.getAnimationSeq(), &animationIndex, animationNames); + gui->endMenu(); + } + } + else + { + gui->text(m_localizationStrings.getMenuAnimationNoAnimation()); + } + gui->endMenu(); + } - ImDrawData* imDrawData = ImGui::GetDrawData(); + gui->endMainMenuBar(); + } - // Check if ui buffers need to be recreated - if (imDrawData) { - VkDeviceSize vertexBufferSize = imDrawData->TotalVtxCount * sizeof(ImDrawVert); - VkDeviceSize indexBufferSize = imDrawData->TotalIdxCount * sizeof(ImDrawIdx); + ImGui::PopItemWidth(); + ImGui::End(); + ImGui::Render(); - bool updateBuffers = (gui->vertexBuffer.buffer == VK_NULL_HANDLE) || (gui->vertexBuffer.count != imDrawData->TotalVtxCount) || (gui->indexBuffer.buffer == VK_NULL_HANDLE) || (gui->indexBuffer.count != imDrawData->TotalIdxCount); + ImDrawData *imDrawData = ImGui::GetDrawData(); - if (updateBuffers) { - vkDeviceWaitIdle(device); - if (gui->vertexBuffer.buffer) { - gui->vertexBuffer.destroy(); - } - gui->vertexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vertexBufferSize); - gui->vertexBuffer.count = imDrawData->TotalVtxCount; - if (gui->indexBuffer.buffer) { - gui->indexBuffer.destroy(); - } - gui->indexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indexBufferSize); - gui->indexBuffer.count = imDrawData->TotalIdxCount; - } + // Check if ui buffers need to be recreated + if (imDrawData) + { + VkDeviceSize vertexBufferSize = imDrawData->TotalVtxCount * sizeof(ImDrawVert); + VkDeviceSize indexBufferSize = imDrawData->TotalIdxCount * sizeof(ImDrawIdx); - // Upload data - ImDrawVert* vtxDst = (ImDrawVert*)gui->vertexBuffer.mapped; - ImDrawIdx* idxDst = (ImDrawIdx*)gui->indexBuffer.mapped; - for (int n = 0; n < imDrawData->CmdListsCount; n++) { - const ImDrawList* cmd_list = imDrawData->CmdLists[n]; - memcpy(vtxDst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idxDst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtxDst += cmd_list->VtxBuffer.Size; - idxDst += cmd_list->IdxBuffer.Size; - } + bool updateBuffers = (gui->vertexBuffer.buffer == VK_NULL_HANDLE) || (gui->vertexBuffer.count != imDrawData->TotalVtxCount) || (gui->indexBuffer.buffer == VK_NULL_HANDLE) || (gui->indexBuffer.count != imDrawData->TotalIdxCount); - gui->vertexBuffer.flush(); - gui->indexBuffer.flush(); + if (updateBuffers) + { + vkDeviceWaitIdle(device); + if (gui->vertexBuffer.buffer) + { + gui->vertexBuffer.destroy(); + } + gui->vertexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vertexBufferSize); + gui->vertexBuffer.count = imDrawData->TotalVtxCount; + if (gui->indexBuffer.buffer) + { + gui->indexBuffer.destroy(); + } + gui->indexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indexBufferSize); + gui->indexBuffer.count = imDrawData->TotalIdxCount; + } - updateCBs = updateCBs || updateBuffers; - } + // Upload data + ImDrawVert *vtxDst = (ImDrawVert *)gui->vertexBuffer.mapped; + ImDrawIdx *idxDst = (ImDrawIdx *)gui->indexBuffer.mapped; + for (int n = 0; n < imDrawData->CmdListsCount; n++) + { + const ImDrawList *cmd_list = imDrawData->CmdLists[n]; + memcpy(vtxDst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idxDst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtxDst += cmd_list->VtxBuffer.Size; + idxDst += cmd_list->IdxBuffer.Size; + } - if (lastDisplaySize.x != io.DisplaySize.x || lastDisplaySize.y != io.DisplaySize.y) { - updateCBs = true; - } + gui->vertexBuffer.flush(); + gui->indexBuffer.flush(); - if (updateCBs) { - vkDeviceWaitIdle(device); - buildCommandBuffers(); - vkDeviceWaitIdle(device); - } + updateCBs = updateCBs || updateBuffers; + } - if (updateShaderParams) { - updateShaderData(); - } + if (lastDisplaySize.x != io.DisplaySize.x || lastDisplaySize.y != io.DisplaySize.y) + { + updateCBs = true; + } - } + if (updateCBs) + { + vkDeviceWaitIdle(device); + buildCommandBuffers(); + vkDeviceWaitIdle(device); + } - + if (updateShaderParams) + { + updateShaderData(); + } +} - PlumageRender* plumageRender; - // OS specific macros for the example main entry points +PlumageRender *plumageRender; +// OS specific macros for the example main entry points #if defined(_WIN32) - LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - if (plumageRender != NULL) - { - plumageRender->handleMessages(hWnd, uMsg, wParam, lParam); - } - return (DefWindowProc(hWnd, uMsg, wParam, lParam)); - } - int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) - { - for (int32_t i = 0; i < __argc; i++) { PlumageRender::args.push_back(__argv[i]); }; - plumageRender = new PlumageRender(); - plumageRender->initVulkan(); - plumageRender->setupWindow(hInstance, WndProc); - plumageRender->prepare(); - plumageRender->renderLoop(); - delete(plumageRender); - return 0; - } +LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (plumageRender != NULL) + { + plumageRender->handleMessages(hWnd, uMsg, wParam, lParam); + } + return (DefWindowProc(hWnd, uMsg, wParam, lParam)); +} +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) +{ + for (int32_t i = 0; i < __argc; i++) + { + PlumageRender::args.push_back(__argv[i]); + }; + plumageRender = new PlumageRender(); + plumageRender->initVulkan(); + plumageRender->setupWindow(hInstance, WndProc); + plumageRender->prepare(); + plumageRender->renderLoop(); + delete (plumageRender); + return 0; +} #endif diff --git a/src/render/render.h b/src/render/render.h index 6bc379a..9387130 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -1,5 +1,8 @@ #pragma once +#include "ConfigFilePath.h" +#include "RenderSceneTextures.h" +#include "renderShaderData.h" #if defined(_WIN32) #include #include @@ -21,14 +24,12 @@ #include #include -#include "algorithm" #include #include #include #include #include -#include "VulkanDevice.hpp" #include "VulkanExampleBase.h" #include "glTFModel.h" #include "ui.hpp" @@ -37,152 +38,34 @@ #include #define ENABLE_VALIDATION false +#include "LocalizationStrings.h" +#include "ConfigFilePath.h" +#include "RenderSceneTextures.h" +#include "SceneUBOMatrices.h" +#include "SkyboxUBOMatrices.h" #include "renderEffectState.h" +#include "renderSceneModel.h" +#include "renderShaderData.h" +#include "renderUniformBufferSet.h" +#include "renderVideoOutputState.h" class PlumageRender : public VulkanExampleBase { private: RenderEffectState *m_effectState; + RenderVideoOutputState *m_videoOutputState; + RenderSceneModel m_sceneModel; + RenderSceneTextures m_sceneTextures; + RenderShaderData m_shaderData; + LocalizationStrings m_localizationStrings; + + SceneUBOMatrices m_shaderDataScene; + SkyboxUBOMatrices m_shaderDataSkybox; + + ConfigFilePath m_configFilePath; public: - struct Models - { - glTFModel::Model scene; - glTFModel::Model skybox; - } models; - - struct Textures - { - vks::TextureCubeMap environmentCube; - vks::Texture2D empty; - vks::Texture2D lutBrdf; - vks::TextureCubeMap irradianceCube; - vks::TextureCubeMap prefilteredCube; - } textures; - - struct ShaderData - { - glm::vec4 lightDir; - float exposure = 4.5f; - float gamma = 2.2f; - float prefilteredCubeMipLevels; - float scaleIBLAmbient = 2.0f; - float debugViewInputs = 0; - float debugViewEquation = 0; - } shaderData; - struct ChinesesUI - { - const char *model = "模型"; - - const char *environmentMap = "环境贴图"; - const char *environmentBackGround = "启用背景贴图"; - const char *debugInput = "输入"; - const char *debugPBREquation = "PBR计算参数"; - const char *animation = "动画"; - const char *pauseAnimation = "启用动画"; - const char *animationSeq = "动画序列"; - // menu item - const char *menuFile = "文件"; - const char *menuOpenNewModel = "新模型.."; - const char *menuEnvironment = "环境光照"; - const char *menuEnvironmentConfig = "设置"; - const char *menuAnimation = "动画"; - const char *menuDebugFrameRate = "fps"; - const char *menuDebugInput = "输入"; - const char *menuAnimationNoAnimation = "当前模型没有动画!"; - - const char *menuAnimationActivation = "开关"; - const char *menuAnimationAnimationSequence = "动画序列"; - - } chineseUI; - - struct UniformBufferSet - { - Buffer scene; - Buffer skybox; - Buffer params; - }; - - struct UBOMatrices - { - glm::mat4 projection; - glm::mat4 model; - glm::mat4 view; - glm::vec3 camPos; - } shaderDataScene, shaderDataSkybox; - - struct PushConstBlockMaterial - { - glm::vec4 baseColorFactor; - glm::vec4 emissiveFactor; - glm::vec4 diffuseFactor; - glm::vec4 specularFactor; - float workflow; - int colorTextureSet; - int PhysicalDescriptorTextureSet; - int normalTextureSet; - int occlusionTextureSet; - int emissiveTextureSet; - float metallicFactor; - float roughnessFactor; - float alphaMask; - float alphaMaskCutoff; - } pushConstBlockMaterial; - - struct FilePath - { // model path - std::string glTFModelFilePath = getAssetPath() + "models/DamagedHelmet/DamagedHelmet.gltf"; - std::string modelVertShaderPath = getAssetPath() + "buster_drone/shaders/glsl/mesh.vert.spv"; - std::string modelFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/mesh.frag.spv"; - - // ui - std::string uiVertShaderPath = getAssetPath() + "shaders/ui.vert.spv"; - std::string uiFragShaderPath = getAssetPath() + "shaders/ui.frag.spv"; - - // skybox path - std::string skyboxModleFilePath = getAssetPath() + "models/cube.gltf"; - std::string skyboxVertShaderPath = getAssetPath() + "shaders/skybox.vert.spv"; - std::string skyboxFragShaderPath = getAssetPath() + "shaders/skybox.frag.spv"; - - std::string iblTexturesFilePath = getAssetPath() + "textures/hdr/gcanyon_cube.ktx"; - // tonemapping - std::string tonemappingVertShaderPath = getAssetPath() + "buster_drone/shaders/glsl/genbrdflut.vert.spv"; - std::string tonemappingEnableFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/tonemapping_enable.frag.spv"; - std::string tonemappingDisableFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/tonemapping_disable.frag.spv"; - - // cube map - std::string irradianceFragShaderPath = getAssetPath() + "shaders/irradiancecube.frag.spv"; - - std::string filterVertShaderPath = getAssetPath() + "shaders/filtercube.vert.spv"; - - std::string prefilterEnvmapFragShaderPath = getAssetPath() + "shaders/prefilterenvmap.frag.spv"; - // brdf cube map - std::string brdfVertShaderPath = getAssetPath() + "shaders/genbrdflut.vert.spv"; - std::string brdfFragShaderPath = getAssetPath() + "shaders/genbrdflut.frag.spv"; - // environment map texture - std::string envMapFilePath = getAssetPath() + "environments/brown_photostudio_02_4k_hdr16f_cube.ktx"; - std::string emptyEnvmapFilePath = getAssetPath() + "textures/empty.ktx"; - // pbr shader - std::string pbrVertShaderPath = getAssetPath() + "shaders/pbr.vert.spv"; - std::string pbrFragShaderPath = getAssetPath() + "shaders/pbr_khr.frag.spv"; - - // ttf file path - std::string ttfFilePath = getAssetPath() + "/data/Roboto-Medium.ttf"; - - // output file path - - std::string imageOutputPath = getAssetPath() + "output/imageSequence"; - std::string videoOutputPath = getAssetPath() + "output/video"; - std::string totalImageOutputPath; - std::string deviceSpecFilePath; - - // script file path - std::string image2videoBatFilePath = getAssetPath() + "script/image2video.bat"; - std::string image2videoShFilePath = getAssetPath() + "script/image2video.sh"; - - } filePath; - float modelrot = 0.0f; glm::vec3 modelPos = glm::vec3(0.0f); @@ -246,7 +129,7 @@ public: std::vector descriptorSets; std::vector commandBuffers; - std::vector uniformBuffers; + std::vector uniformBuffers; std::vector waitFences; std::vector renderCompleteSemaphores; @@ -312,14 +195,14 @@ public: vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.material, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.node, nullptr); - models.scene.destroy(device); - models.skybox.destroy(device); + m_sceneModel.destroyScene(device); + m_sceneModel.destroySkyBox(device); for (auto buffer : uniformBuffers) { - buffer.params.destroy(); - buffer.scene.destroy(); - buffer.skybox.destroy(); + buffer.getParams().destroy(); + buffer.getScene().destroy(); + buffer.getSkybox().destroy(); } for (auto fence : waitFences) { @@ -334,11 +217,12 @@ public: vkDestroySemaphore(device, semaphore, nullptr); } - textures.environmentCube.destroy(); - textures.irradianceCube.destroy(); - textures.prefilteredCube.destroy(); - textures.lutBrdf.destroy(); - textures.empty.destroy(); + m_sceneTextures.destroyEnvironmentCube(); + m_sceneTextures.destroyIrradianceCube(); + m_sceneTextures.destroyPrefilteredCube(); + m_sceneTextures.destroyLutBrdf(); + m_sceneTextures.destroyEmpty(); + delete gui; } diff --git a/src/render/renderSceneModel.cpp b/src/render/renderSceneModel.cpp index a0d70cd..765f5df 100644 --- a/src/render/renderSceneModel.cpp +++ b/src/render/renderSceneModel.cpp @@ -11,21 +11,29 @@ RenderSceneModel::~RenderSceneModel() void RenderSceneModel::setScene(glTFModel::Model value) { - m_scene = value; + m_scene = value; } -glTFModel::Model RenderSceneModel::getScene() const +glTFModel::Model &RenderSceneModel::getScene() { - return m_scene; + return m_scene; } void RenderSceneModel::setSkyBox(glTFModel::Model value) { - m_skybox = value; + m_skybox = value; } -glTFModel::Model RenderSceneModel::getSkyBox() const +glTFModel::Model &RenderSceneModel::getSkyBox() { - return m_skybox; + return m_skybox; } +void RenderSceneModel::destroyScene(VkDevice device) +{ + m_scene.destroy(device); +} +void RenderSceneModel::destroySkyBox(VkDevice device) +{ + m_skybox.destroy(device); +} \ No newline at end of file diff --git a/src/render/renderSceneModel.h b/src/render/renderSceneModel.h index cb24547..6ca2e71 100644 --- a/src/render/renderSceneModel.h +++ b/src/render/renderSceneModel.h @@ -1,6 +1,7 @@ #pragma once #include "glTFModel.h" +#include "vulkan/vulkan.h" class RenderSceneModel { @@ -9,10 +10,13 @@ public: ~RenderSceneModel(); void setScene(glTFModel::Model value); - glTFModel::Model getScene() const; + glTFModel::Model &getScene(); void setSkyBox(glTFModel::Model value); - glTFModel::Model getSkyBox() const; + glTFModel::Model &getSkyBox(); + + void destroyScene(VkDevice device); + void destroySkyBox(VkDevice device); private: glTFModel::Model m_scene; diff --git a/src/render/renderShaderData.cpp b/src/render/renderShaderData.cpp index 3b54852..4dab528 100644 --- a/src/render/renderShaderData.cpp +++ b/src/render/renderShaderData.cpp @@ -9,43 +9,43 @@ RenderShaderData::~RenderShaderData() } // Getters -const glm::vec4 &RenderShaderData::getLightDir() const +glm::vec4 RenderShaderData::getLightDir() { return m_lightDir; } -float RenderShaderData::getExposure() const +float &RenderShaderData::getExposure() { return m_exposure; } -float RenderShaderData::getGamma() const +float &RenderShaderData::getGamma() { return m_gamma; } -float RenderShaderData::getPrefilteredCubeMipLevels() const +float RenderShaderData::getPrefilteredCubeMipLevels() { return m_prefilteredCubeMipLevels; } -float RenderShaderData::getScaleIBLAmbient() const +float &RenderShaderData::getScaleIBLAmbient() { return m_scaleIBLAmbient; } -float RenderShaderData::getDebugViewInputs() const +float &RenderShaderData::getDebugViewInputs() { return m_debugViewInputs; } -float RenderShaderData::getDebugViewEquation() const +float &RenderShaderData::getDebugViewEquation() { return m_debugViewEquation; } // Setters -void RenderShaderData::setLightDir(const glm::vec4 &dir) +void RenderShaderData::setLightDir(const glm::vec4 dir) { m_lightDir = dir; } diff --git a/src/render/renderShaderData.h b/src/render/renderShaderData.h index 0fb798f..edb4ad9 100644 --- a/src/render/renderShaderData.h +++ b/src/render/renderShaderData.h @@ -9,16 +9,16 @@ public: ~RenderShaderData(); // Getters - const glm::vec4 &getLightDir() const; - float getExposure() const; - float getGamma() const; - float getPrefilteredCubeMipLevels() const; - float getScaleIBLAmbient() const; - float getDebugViewInputs() const; - float getDebugViewEquation() const; + glm::vec4 getLightDir(); + float &getExposure(); + float &getGamma(); + float getPrefilteredCubeMipLevels(); + float &getScaleIBLAmbient(); + float &getDebugViewInputs(); + float &getDebugViewEquation(); // Setters - void setLightDir(const glm::vec4 &dir); + void setLightDir(const glm::vec4 dir); void setExposure(float exp); void setGamma(float g); void setPrefilteredCubeMipLevels(float levels); diff --git a/src/render/renderUniformBufferSet.cpp b/src/render/renderUniformBufferSet.cpp index 784cc46..25797a1 100644 --- a/src/render/renderUniformBufferSet.cpp +++ b/src/render/renderUniformBufferSet.cpp @@ -9,33 +9,33 @@ RenderUniformBufferSet::~RenderUniformBufferSet() } // Getter method definitions -const Buffer &RenderUniformBufferSet::getScene() const +Buffer &RenderUniformBufferSet::getScene() { return scene; } -const Buffer &RenderUniformBufferSet::getSkybox() const +Buffer &RenderUniformBufferSet::getSkybox() { return skybox; } -const Buffer &RenderUniformBufferSet::getParams() const +Buffer &RenderUniformBufferSet::getParams() { return params; } // Setter method definitions -void RenderUniformBufferSet::setScene(const Buffer &buffer) +void RenderUniformBufferSet::setScene(Buffer &buffer) { scene = buffer; } -void RenderUniformBufferSet::setSkybox(const Buffer &buffer) +void RenderUniformBufferSet::setSkybox(Buffer &buffer) { skybox = buffer; } -void RenderUniformBufferSet::setParams(const Buffer &buffer) +void RenderUniformBufferSet::setParams(Buffer &buffer) { params = buffer; } \ No newline at end of file diff --git a/src/render/renderUniformBufferSet.h b/src/render/renderUniformBufferSet.h index 52cce33..b0b0030 100644 --- a/src/render/renderUniformBufferSet.h +++ b/src/render/renderUniformBufferSet.h @@ -9,14 +9,14 @@ public: ~RenderUniformBufferSet(); // Getter methods - const Buffer &getScene() const; - const Buffer &getSkybox() const; - const Buffer &getParams() const; + Buffer &getScene(); + Buffer &getSkybox(); + Buffer &getParams(); // Setter methods - void setScene(const Buffer &buffer); - void setSkybox(const Buffer &buffer); - void setParams(const Buffer &buffer); + void setScene(Buffer &buffer); + void setSkybox(Buffer &buffer); + void setParams(Buffer &buffer); private: Buffer scene;