diff --git a/.cache/clangd/index/glTFModel.cpp.246B94A7A9CABEC6.idx b/.cache/clangd/index/glTFModel.cpp.246B94A7A9CABEC6.idx deleted file mode 100644 index add05ee..0000000 Binary files a/.cache/clangd/index/glTFModel.cpp.246B94A7A9CABEC6.idx and /dev/null differ diff --git a/.cache/clangd/index/glTFModel.h.18C204E02E1430C2.idx b/.cache/clangd/index/glTFModel.h.18C204E02E1430C2.idx deleted file mode 100644 index f4bcdee..0000000 Binary files a/.cache/clangd/index/glTFModel.h.18C204E02E1430C2.idx and /dev/null differ diff --git a/.cache/clangd/index/render.cpp.2517D1DB05BB2BAC.idx b/.cache/clangd/index/render.cpp.2517D1DB05BB2BAC.idx deleted file mode 100644 index 72a888b..0000000 Binary files a/.cache/clangd/index/render.cpp.2517D1DB05BB2BAC.idx and /dev/null differ diff --git a/.cache/clangd/index/render.h.AA34C5489F161A03.idx b/.cache/clangd/index/render.h.AA34C5489F161A03.idx deleted file mode 100644 index 3791d7a..0000000 Binary files a/.cache/clangd/index/render.h.AA34C5489F161A03.idx and /dev/null differ diff --git a/.cache/clangd/index/renderFoundation.cpp.A2C02532E8A340E2.idx b/.cache/clangd/index/renderFoundation.cpp.A2C02532E8A340E2.idx deleted file mode 100644 index d42bc5d..0000000 Binary files a/.cache/clangd/index/renderFoundation.cpp.A2C02532E8A340E2.idx and /dev/null differ 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;