From 199b75ab55722a3be5784e9d29e37d6bc8572bef Mon Sep 17 00:00:00 2001 From: Mateusz Kielan Date: Sat, 13 Sep 2025 20:52:04 +0200 Subject: [PATCH 01/61] Update CONTRIBUTING.md small change to make sure `ditt` doesn't autodelete --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f5a1d4595..24020210a7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ _I would really love to write a nice proper CONTRIBUTING.md, so excuse me for wh We would really love for you to tackle one of our burning issues, which you can view by clicking this link: -https://github.com/buildaworldnet/IrrlichtBAW/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc +https://github.com/Devsh-Graphics-Programming/Nabla/issues (sorted by the most recently updated) From 36d99431215297015c714e8de10ad83a127cd037 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 8 Oct 2025 15:16:33 +0200 Subject: [PATCH 02/61] Get IES cpps to compile --- include/nbl/asset/asset.h | 2 +- src/nbl/CMakeLists.txt | 5 ++ .../asset/interchange/CIESProfileLoader.cpp | 47 +++++++++++++++---- src/nbl/asset/interchange/CIESProfileLoader.h | 23 +-------- src/nbl/asset/utils/CIESProfile.cpp | 6 ++- src/nbl/asset/utils/CIESProfile.h | 1 - src/nbl/asset/utils/CIESProfileParser.h | 2 +- 7 files changed, 51 insertions(+), 35 deletions(-) diff --git a/include/nbl/asset/asset.h b/include/nbl/asset/asset.h index fe70e81646..f08844a182 100644 --- a/include/nbl/asset/asset.h +++ b/include/nbl/asset/asset.h @@ -67,6 +67,6 @@ #include "nbl/asset/metadata/CMTLMetadata.h" #include "nbl/asset/metadata/CPLYMetadata.h" #include "nbl/asset/metadata/CSTLMetadata.h" -//#include "nbl/asset/metadata/CIESProfileMetadata.h" +#include "nbl/asset/metadata/CIESProfileMetadata.h" #endif diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index 6bf9e9abdd..9105be3b41 100755 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -221,6 +221,11 @@ set(NBL_ASSET_SOURCES asset/interchange/CImageWriterTGA.cpp asset/interchange/CImageWriterOpenEXR.cpp # TODO: Nahim asset/interchange/CGLIWriter.cpp + +# IES profile loaders + asset/interchange/CIESProfileLoader.cpp + asset/utils/CIESProfileParser.cpp + asset/utils/CIESProfile.cpp ) set(NBL_VIDEO_SOURCES # Utilities diff --git a/src/nbl/asset/interchange/CIESProfileLoader.cpp b/src/nbl/asset/interchange/CIESProfileLoader.cpp index eecdde3190..744756b607 100644 --- a/src/nbl/asset/interchange/CIESProfileLoader.cpp +++ b/src/nbl/asset/interchange/CIESProfileLoader.cpp @@ -3,24 +3,53 @@ using namespace nbl; using namespace asset; -asset::SAssetBundle -CIESProfileLoader::loadAsset(io::IReadFile* _file, - const asset::IAssetLoader::SAssetLoadParams& _params, - asset::IAssetLoader::IAssetLoaderOverride* _override, - uint32_t _hierarchyLevel) { - if (!_file) +bool CIESProfileLoader::isALoadableFileFormat(system::IFile* _file, const system::logger_opt_ptr logger) const +{ + system::IFile::success_t success; + std::string versionBuffer(0x45, ' '); + const auto* fName = _file->getFileName().c_str(); + _file->read(success, versionBuffer.data(), 0, versionBuffer.size()); + + if (success) + { + for (const auto& it : CIESProfileParser::VALID_SIGNATURES) + if (versionBuffer.find(it.data()) != std::string::npos) + return true; + + logger.log("%s: Invalid IES signature for \"%s\" file!", system::ILogger::ELL_ERROR, __FUNCTION__, fName); + } + else + logger.log("%s: Failed to read \"%s\" file!", system::ILogger::ELL_ERROR, __FUNCTION__, fName); + + return false; +} + +asset::SAssetBundle CIESProfileLoader::loadAsset(system::IFile* _file, const asset::IAssetLoader::SAssetLoadParams& _params, asset::IAssetLoader::IAssetLoaderOverride* _override, uint32_t _hierarchyLevel) +{ + if (not _file) + { + _params.logger.log("%s: Nullptr system::IFile pointer!", system::ILogger::ELL_ERROR, __FUNCTION__); return {}; + } IAssetLoader::SAssetLoadContext loadContex(_params, _file); core::vector data(_file->getSize()); - _file->read(data.data(), _file->getSize()); + system::IFile::success_t success; + const auto* fName = _file->getFileName().c_str(); + _file->read(success, data.data(), 0, _file->getSize()); + + if (not success) + { + _params.logger.log("%s: Failed to read \"%s\" file!", system::ILogger::ELL_ERROR, __FUNCTION__, fName); + return {}; + } CIESProfileParser parser(data.data(), data.size()); CIESProfile profile; - if (!parser.parse(profile)) + if (not parser.parse(profile)) { - os::Printer::log("ERROR: Emission profile parsing error: " + std::string(parser.getErrorMsg()), ELL_ERROR); + _params.logger.log("%s: Failed to parse emission profile for \"%s\" file!", system::ILogger::ELL_ERROR, __FUNCTION__, fName); return {}; } diff --git a/src/nbl/asset/interchange/CIESProfileLoader.h b/src/nbl/asset/interchange/CIESProfileLoader.h index 64ef9688ee..5eb26c861b 100644 --- a/src/nbl/asset/interchange/CIESProfileLoader.h +++ b/src/nbl/asset/interchange/CIESProfileLoader.h @@ -5,8 +5,6 @@ #define __NBL_ASSET_C_IES_PROFILE_LOADER_H_INCLUDED__ #include "nbl/asset/ICPUImage.h" -#include "nbl/asset/ICPUShader.h" - #include "nbl/asset/IAssetManager.h" #include "nbl/asset/interchange/IAssetLoader.h" @@ -25,20 +23,7 @@ class CIESProfileLoader final : public asset::IAssetLoader \return True if file seems to be loadable. */ - bool isALoadableFileFormat(io::IReadFile *_file) const override - { - const size_t begginingOfFile = _file->getPos(); - _file->seek(0ull); - std::string versionBuffer(0x45, ' '); - _file->read(versionBuffer.data(), versionBuffer.size()); - _file->seek(begginingOfFile); - - for (const auto& it : CIESProfileParser::VALID_SIGNATURES) - if (versionBuffer.find(it.data()) != std::string::npos) - return true; - - return false; - } + bool isALoadableFileFormat(system::IFile* _file, const system::logger_opt_ptr logger) const override; //! Returns an array of string literals terminated by nullptr const char **getAssociatedFileExtensions() const override @@ -55,11 +40,7 @@ class CIESProfileLoader final : public asset::IAssetLoader uint64_t getSupportedAssetTypesBitfield() const override { return asset::IAsset::ET_IMAGE_VIEW; } //! Loads an asset from an opened file, returns nullptr in case of failure. - asset::SAssetBundle - loadAsset(io::IReadFile* _file, - const asset::IAssetLoader::SAssetLoadParams& _params, - asset::IAssetLoader::IAssetLoaderOverride* _override = nullptr, - uint32_t _hierarchyLevel = 0u) override; + asset::SAssetBundle loadAsset(system::IFile* _file, const asset::IAssetLoader::SAssetLoadParams& _params, asset::IAssetLoader::IAssetLoaderOverride* _override = nullptr, uint32_t _hierarchyLevel = 0u) override; }; } // namespace nbl::asset #endif // __NBL_ASSET_C_IES_PROFILE_LOADER_H_INCLUDED__ diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index b507ab0d45..5f89019ad7 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -139,7 +139,9 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu region.bufferImageHeight = 0u; region.bufferOffset = 0u; - auto buffer = core::make_smart_refctd_ptr(texelBytesz * bufferRowLength * height); + asset::ICPUBuffer::SCreationParams bParams; + bParams.size = texelBytesz * bufferRowLength * height; + auto buffer = asset::ICPUBuffer::create(std::move(bParams)); if (!outImg->setBufferAndRegions(std::move(buffer), core::make_refctd_dynamic_array>(1ull, region))) return {}; @@ -189,7 +191,7 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu CBasicImageFilterCommon::clip_region_functor_t clip(state.subresource, state.outRange, creationParams.format); const auto& regions = outImg->getRegions(state.subresource.mipLevel); - CBasicImageFilterCommon::executePerRegion(std::forward(policy), outImg.get(), fill, regions.begin(), regions.end(), clip); + CBasicImageFilterCommon::executePerRegion(std::forward(policy), outImg.get(), fill, regions, clip); } ICPUImageView::SCreationParams viewParams = {}; diff --git a/src/nbl/asset/utils/CIESProfile.h b/src/nbl/asset/utils/CIESProfile.h index ea3d539613..479483c052 100644 --- a/src/nbl/asset/utils/CIESProfile.h +++ b/src/nbl/asset/utils/CIESProfile.h @@ -6,7 +6,6 @@ #define __NBL_ASSET_C_IES_PROFILE_H_INCLUDED__ #include "nbl/asset/metadata/CIESProfileMetadata.h" -#include "nbl/core/Types.h" #include namespace nbl diff --git a/src/nbl/asset/utils/CIESProfileParser.h b/src/nbl/asset/utils/CIESProfileParser.h index cc613efc29..c5b57dd77b 100644 --- a/src/nbl/asset/utils/CIESProfileParser.h +++ b/src/nbl/asset/utils/CIESProfileParser.h @@ -99,7 +99,7 @@ namespace nbl if (!this->errorMsg) this->errorMsg = errorMsg; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) return -1.0; else return 0; From e3129939c8253ec04525bdb726578cfe61b754ac Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 10 Oct 2025 09:33:03 +0200 Subject: [PATCH 03/61] cap kind args --- cmake/common.cmake | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 645837aaaa..b7df2690e2 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1210,7 +1210,7 @@ struct DeviceConfigCaps get_target_property(HEADER_RULE_GENERATED ${IMPL_TARGET} NBL_HEADER_GENERATED_RULE) if(NOT HEADER_RULE_GENERATED) - set(INCLUDE_DIR "$/${IMPL_TARGET}/.cmake/include") + set(INCLUDE_DIR "$/${IMPL_TARGET}/.cmake/include") set(INCLUDE_FILE "${INCLUDE_DIR}/$") set(INCLUDE_CONTENT $) @@ -1323,12 +1323,27 @@ namespace @IMPL_NAMESPACE@ { set(CAP_NAMES "") set(CAP_TYPES "") + set(CAP_KINDS "") if(HAS_CAPS) math(EXPR LAST_CAP "${CAPS_LENGTH} - 1") foreach(CAP_IDX RANGE 0 ${LAST_CAP}) + string(JSON CAP_KIND ERROR_VARIABLE CAP_TYPE_ERROR GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} kind) string(JSON CAP_NAME GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} name) string(JSON CAP_TYPE GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} type) + # -> TODO: improve validation, input should be string + if(CAP_TYPE_ERROR) + set(CAP_KIND limits) # I assume its limit by default (or when invalid value present, currently) + else() + if(NOT CAP_KIND MATCHES "^(limits|features)$") + ERROR_WHILE_PARSING_ITEM( + "Invalid CAP kind \"${CAP_KIND}\" for ${CAP_NAME}\n" + "Allowed kinds are: limits, features" + ) + endif() + endif() + # <- + if(NOT CAP_TYPE MATCHES "^(bool|uint16_t|uint32_t|uint64_t)$") ERROR_WHILE_PARSING_ITEM( "Invalid CAP type \"${CAP_TYPE}\" for ${CAP_NAME}\n" @@ -1366,6 +1381,7 @@ namespace @IMPL_NAMESPACE@ { set(CAP_VALUES_${CAP_IDX} "${VALUES}") list(APPEND CAP_NAMES "${CAP_NAME}") list(APPEND CAP_TYPES "${CAP_TYPE}") + list(APPEND CAP_KINDS "${CAP_KIND}") endforeach() endif() @@ -1405,12 +1421,16 @@ namespace @IMPL_NAMESPACE@ { ]=]) unset(RETVAL_EVAL) - foreach(CAP ${CAP_NAMES}) + list(LENGTH CAP_NAMES CAP_COUNT) + math(EXPR CAP_COUNT "${CAP_COUNT} - 1") + foreach(i RANGE ${CAP_COUNT}) + list(GET CAP_NAMES ${i} CAP) + list(GET CAP_KINDS ${i} KIND) string(CONFIGURE [=[ - retval += ".@CAP@_" + std::to_string(limits.@CAP@); + retval += ".@CAP@_" + std::to_string(@KIND@.@CAP@); ]=] RETVALUE_VIEW @ONLY) string(APPEND RETVAL_EVAL "${RETVALUE_VIEW}") - endforeach(CAP) + endforeach() string(CONFIGURE "${HEADER_ITEM_VIEW}" HEADER_ITEM_EVAL @ONLY) set_property(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY NBL_HEADER_CONTENT "${HEADER_ITEM_EVAL}") @@ -1461,6 +1481,7 @@ namespace @IMPL_NAMESPACE@ { list(GET CAP_NAMES ${CAP_INDEX} CURRENT_CAP) list(GET CAP_TYPES ${CAP_INDEX} CURRENT_TYPE) + list(GET CAP_KINDS ${CAP_INDEX} CURRENT_KIND) set(VAR_NAME "CAP_VALUES_${CAP_INDEX}") set(VALUES "${${VAR_NAME}}") From 25c4bdcd157d0cfc418d36bddbd4a688ea07c4ad Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 10 Oct 2025 10:23:00 +0200 Subject: [PATCH 04/61] fix a bug after my NSC rules update --- cmake/common.cmake | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index b7df2690e2..92250a276b 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1422,15 +1422,18 @@ namespace @IMPL_NAMESPACE@ { ]=]) unset(RETVAL_EVAL) list(LENGTH CAP_NAMES CAP_COUNT) - math(EXPR CAP_COUNT "${CAP_COUNT} - 1") - foreach(i RANGE ${CAP_COUNT}) - list(GET CAP_NAMES ${i} CAP) - list(GET CAP_KINDS ${i} KIND) - string(CONFIGURE [=[ + if(CAP_COUNT GREATER 0) + math(EXPR LAST_CAP "${CAP_COUNT} - 1") + foreach(i RANGE ${LAST_CAP}) + list(GET CAP_NAMES ${i} CAP) + list(GET CAP_KINDS ${i} KIND) + string(CONFIGURE [=[ retval += ".@CAP@_" + std::to_string(@KIND@.@CAP@); -]=] RETVALUE_VIEW @ONLY) - string(APPEND RETVAL_EVAL "${RETVALUE_VIEW}") - endforeach() +]=] RETVALUE_VIEW @ONLY) + string(APPEND RETVAL_EVAL "${RETVALUE_VIEW}") + endforeach() + endif() + string(CONFIGURE "${HEADER_ITEM_VIEW}" HEADER_ITEM_EVAL @ONLY) set_property(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY NBL_HEADER_CONTENT "${HEADER_ITEM_EVAL}") From 3d18b585b6e3be2ea3e9c5b19527769738819c06 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 10 Oct 2025 13:36:38 +0200 Subject: [PATCH 05/61] update examples_tests submodule, we will first make CI pass with IES shaders --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 2b4db21239..c3b463a33f 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 2b4db2123918f380cc0a35f6889315a02f84ea73 +Subproject commit c3b463a33f864ddb9f9b4099b660b313cad6ab5c From 27de67f1a1a749e3f119170ef26be6fb48c65822 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 10 Oct 2025 15:31:58 +0200 Subject: [PATCH 06/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index c3b463a33f..29f64a283b 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit c3b463a33f864ddb9f9b4099b660b313cad6ab5c +Subproject commit 29f64a283b2ccaef76f169b997a47647631d84c9 From 0110f987b2430af7475be024e750239da2886605 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 14 Oct 2025 17:14:54 +0200 Subject: [PATCH 07/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 29f64a283b..59a996222d 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 29f64a283b2ccaef76f169b997a47647631d84c9 +Subproject commit 59a996222da2232348a1a9e31c4484161b340fb0 From 9ed5aee21aa409601a9670e69c1b3cc7a158c735 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 15 Oct 2025 13:39:30 +0200 Subject: [PATCH 08/61] ah IES was not added to asset manager, also correct some aspectMask subresource bitflags to not trigger asserts, update examples_tests submodule --- examples_tests | 2 +- src/nbl/asset/IAssetManager.cpp | 4 ++-- src/nbl/asset/utils/CIESProfile.cpp | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples_tests b/examples_tests index 59a996222d..02924fbac8 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 59a996222da2232348a1a9e31c4484161b340fb0 +Subproject commit 02924fbac84775596dd553b210016f5fb46834fc diff --git a/src/nbl/asset/IAssetManager.cpp b/src/nbl/asset/IAssetManager.cpp index dc67ed8d01..5f48170c37 100644 --- a/src/nbl/asset/IAssetManager.cpp +++ b/src/nbl/asset/IAssetManager.cpp @@ -84,7 +84,7 @@ #endif #include "nbl/asset/interchange/CBufferLoaderBIN.h" -//#include "nbl/asset/interchange/CIESProfileLoader.h" +#include "nbl/asset/interchange/CIESProfileLoader.h" #include "nbl/asset/utils/CGeometryCreator.h" @@ -181,7 +181,7 @@ void IAssetManager::addLoadersAndWriters() #ifdef _NBL_COMPILE_WITH_GLI_WRITER_ addAssetWriter(core::make_smart_refctd_ptr(core::smart_refctd_ptr(m_system))); #endif -// addAssetLoader(core::make_smart_refctd_ptr()); +addAssetLoader(core::make_smart_refctd_ptr()); for (auto& loader : m_loaders.vector) loader->initialize(); diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index 5f89019ad7..332e35fb87 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -136,6 +136,7 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu region.imageSubresource.baseArrayLayer = 0u; region.imageSubresource.layerCount = 1u; region.imageSubresource.mipLevel = 0u; + region.imageSubresource.aspectMask = core::bitflag(asset::IImage::EAF_COLOR_BIT); region.bufferImageHeight = 0u; region.bufferOffset = 0u; @@ -152,7 +153,7 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu CFillImageFilter::state_type state; state.outImage = outImg.get(); - state.subresource.aspectMask = static_cast(0); + state.subresource.aspectMask = core::bitflag(asset::IImage::EAF_COLOR_BIT); state.subresource.baseArrayLayer = 0u; state.subresource.layerCount = 1u; state.outRange.extent = creationParams.extent; @@ -199,7 +200,7 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu viewParams.flags = static_cast(0); viewParams.viewType = IImageView::ET_2D; viewParams.format = viewParams.image->getCreationParameters().format; - viewParams.subresourceRange.aspectMask = static_cast(0); + viewParams.subresourceRange.aspectMask = core::bitflag(asset::IImage::EAF_COLOR_BIT); viewParams.subresourceRange.levelCount = viewParams.image->getCreationParameters().mipLevels; viewParams.subresourceRange.layerCount = 1u; From 35931bd29a3fe66c1a76d644400cddd34a7d4718 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 15 Oct 2025 15:51:26 +0200 Subject: [PATCH 09/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 02924fbac8..7e4399a48b 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 02924fbac84775596dd553b210016f5fb46834fc +Subproject commit 7e4399a48b6f47892b8406ff7853489653a6acaf From a892678a067c1c19a23011cdcc4c4323cf0ee5c1 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 16 Oct 2025 18:19:14 +0200 Subject: [PATCH 10/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 7e4399a48b..1500ce014c 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 7e4399a48b6f47892b8406ff7853489653a6acaf +Subproject commit 1500ce014cceb14df35cd5009d8b126b34ef706f From 5e236e60ac71552b461e1971636f962c2b748a9d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 19 Oct 2025 12:58:40 +0200 Subject: [PATCH 11/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 1500ce014c..7d50d65b36 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 1500ce014cceb14df35cd5009d8b126b34ef706f +Subproject commit 7d50d65b36124ded561018ac8e86de41141c96a3 From 7b2716811c4e282dff61500a3e2fa7f9c4cc1118 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 20 Oct 2025 10:38:39 +0200 Subject: [PATCH 12/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 7d50d65b36..c46f8f8755 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 7d50d65b36124ded561018ac8e86de41141c96a3 +Subproject commit c46f8f8755a26d5e3d1ba9587769902e4025248a From 77e9e573a0dcf380f0e4cd4bbbdd60b73ba83a22 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 20 Oct 2025 16:13:23 +0200 Subject: [PATCH 13/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index c46f8f8755..ceada5e891 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit c46f8f8755a26d5e3d1ba9587769902e4025248a +Subproject commit ceada5e891a70b1fcc8d456c4bd50ef3106ee181 From 699e841a3841693088aa3d515bd3addef72589ce Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 21 Oct 2025 14:13:27 +0200 Subject: [PATCH 14/61] update ImGUI extension to allow hijacking precompiled SPIRV shaders (experimental, no real validation), update examples_tests submodule --- examples_tests | 2 +- include/nbl/ext/ImGui/ImGui.h | 8 ++++++ .../nbl/ext/ImGui/builtin/hlsl/fragment.hlsl | 1 + .../nbl/ext/ImGui/builtin/hlsl/vertex.hlsl | 1 + src/nbl/ext/ImGui/ImGui.cpp | 28 ++++++++++++------- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/examples_tests b/examples_tests index ceada5e891..349a850d4e 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit ceada5e891a70b1fcc8d456c4bd50ef3106ee181 +Subproject commit 349a850d4eb51619c33228c676eb1c84ac0f4a54 diff --git a/include/nbl/ext/ImGui/ImGui.h b/include/nbl/ext/ImGui/ImGui.h index 5f3c1d5f08..16f080d102 100644 --- a/include/nbl/ext/ImGui/ImGui.h +++ b/include/nbl/ext/ImGui/ImGui.h @@ -99,6 +99,14 @@ class UI final : public core::IReferenceCounted //! optional, no cache used if not provided core::smart_refctd_ptr pipelineCache = nullptr; + + struct PrecompiledShaders + { + core::smart_refctd_ptr vertex = nullptr, fragment = nullptr; + }; + + //! optional, precompiled spirv shaders (experimental) + std::optional spirv = std::nullopt; }; //! parameters which may change every frame, used with the .update call to interact with ImGuiIO; we require a very *required* minimum - if you need to cover more IO options simply get the IO with ImGui::GetIO() to customize them (they all have default values you can change before calling the .update) diff --git a/include/nbl/ext/ImGui/builtin/hlsl/fragment.hlsl b/include/nbl/ext/ImGui/builtin/hlsl/fragment.hlsl index 26e2b461a3..44ef6a0cb1 100644 --- a/include/nbl/ext/ImGui/builtin/hlsl/fragment.hlsl +++ b/include/nbl/ext/ImGui/builtin/hlsl/fragment.hlsl @@ -39,6 +39,7 @@ using namespace nbl::ext::imgui; to request per object data with BDA */ +[shader("pixel")] float4 PSMain(PSInput input) : SV_Target0 { // BDA for requesting object data diff --git a/include/nbl/ext/ImGui/builtin/hlsl/vertex.hlsl b/include/nbl/ext/ImGui/builtin/hlsl/vertex.hlsl index 1651060c58..78dbe10ac7 100644 --- a/include/nbl/ext/ImGui/builtin/hlsl/vertex.hlsl +++ b/include/nbl/ext/ImGui/builtin/hlsl/vertex.hlsl @@ -18,6 +18,7 @@ struct VSInput to request per object data with BDA */ +[shader("vertex")] PSInput VSMain(VSInput input, uint drawID : SV_InstanceID) { PSInput output; diff --git a/src/nbl/ext/ImGui/ImGui.cpp b/src/nbl/ext/ImGui/ImGui.cpp index f477e96cdf..fbb33f022f 100644 --- a/src/nbl/ext/ImGui/ImGui.cpp +++ b/src/nbl/ext/ImGui/ImGui.cpp @@ -154,6 +154,14 @@ core::smart_refctd_ptr UI::createPipeline(SCreation smart_refctd_ptr vertex, fragment; } shaders; + if (creationParams.spirv.has_value()) + { + // TODO: since prebuild is experminetal currently I don't validate anything + auto& spirv = creationParams.spirv.value(); + shaders.vertex = spirv.vertex; + shaders.fragment = spirv.fragment; + } + else { //! proxy the system, we will touch it gently auto system = smart_refctd_ptr(creationParams.assetManager->getSystem()); @@ -269,18 +277,18 @@ core::smart_refctd_ptr UI::createPipeline(SCreation shaders.vertex = createShader.template operator() < NBL_CORE_UNIQUE_STRING_LITERAL_TYPE("vertex.hlsl"), IShader::E_SHADER_STAGE::ESS_VERTEX > (); shaders.fragment = createShader.template operator() < NBL_CORE_UNIQUE_STRING_LITERAL_TYPE("fragment.hlsl"), IShader::E_SHADER_STAGE::ESS_FRAGMENT > (); + } - if (!shaders.vertex) - { - creationParams.utilities->getLogger()->log("Failed to compile vertex shader!", ILogger::ELL_ERROR); - return nullptr; - } + if (!shaders.vertex) + { + creationParams.utilities->getLogger()->log("Failed to create vertex shader!", ILogger::ELL_ERROR); + return nullptr; + } - if (!shaders.fragment) - { - creationParams.utilities->getLogger()->log("Failed to compile fragment shader!", ILogger::ELL_ERROR); - return nullptr; - } + if (!shaders.fragment) + { + creationParams.utilities->getLogger()->log("Failed to create fragment shader!", ILogger::ELL_ERROR); + return nullptr; } SVertexInputParams vertexInputParams{}; From bd6cc4dff57af3516bcff4ce1bb5cc72017300b0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 22 Oct 2025 12:16:03 +0200 Subject: [PATCH 15/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 349a850d4e..bdbae93a63 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 349a850d4eb51619c33228c676eb1c84ac0f4a54 +Subproject commit bdbae93a6389414dac1e47f59fb5bb74d99e68ec From 93814913e84eb86e4c625d9e32d83221c62965c9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 22 Oct 2025 14:58:21 +0200 Subject: [PATCH 16/61] a few minor updates to NBL_CREATE_NSC_COMPILE_RULES to skip optional arguments in json payload, CI should pass now --- cmake/common.cmake | 23 ++++++++++++++--------- examples_tests | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 92250a276b..ab215a59e3 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1277,17 +1277,22 @@ namespace @IMPL_NAMESPACE@ { foreach(INDEX RANGE ${LAST_INDEX}) string(JSON INPUT GET "${IMPL_INPUTS}" ${INDEX} INPUT) string(JSON BASE_KEY GET "${IMPL_INPUTS}" ${INDEX} KEY) - string(JSON COMPILE_OPTIONS_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} COMPILE_OPTIONS) - + set(COMPILE_OPTIONS "") - math(EXPR LAST_CO "${COMPILE_OPTIONS_LENGTH} - 1") - foreach(COMP_IDX RANGE 0 ${LAST_CO}) - string(JSON COMP_ITEM GET "${IMPL_INPUTS}" ${INDEX} COMPILE_OPTIONS ${COMP_IDX}) - list(APPEND COMPILE_OPTIONS "${COMP_ITEM}") - endforeach() + string(JSON HAS_COMPILE_OPTIONS ERROR_VARIABLE ERROR_VAR TYPE "${IMPL_INPUTS}" ${INDEX} COMPILE_OPTIONS) + if(HAS_COMPILE_OPTIONS STREQUAL "ARRAY") + string(JSON COMPILE_OPTIONS_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} COMPILE_OPTIONS) + if(NOT COMPILE_OPTIONS_LENGTH EQUAL 0) + math(EXPR LAST_CO "${COMPILE_OPTIONS_LENGTH} - 1") + foreach(COMP_IDX RANGE 0 ${LAST_CO}) + string(JSON COMP_ITEM GET "${IMPL_INPUTS}" ${INDEX} COMPILE_OPTIONS ${COMP_IDX}) + list(APPEND COMPILE_OPTIONS "${COMP_ITEM}") + endforeach() + endif() + endif() set(DEPENDS_ON "") - string(JSON HAS_DEPENDS TYPE "${IMPL_INPUTS}" ${INDEX} DEPENDS) + string(JSON HAS_DEPENDS ERROR_VARIABLE ERROR_VAR TYPE "${IMPL_INPUTS}" ${INDEX} DEPENDS) if(HAS_DEPENDS STREQUAL "ARRAY") string(JSON DEPENDS_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} DEPENDS) if(NOT DEPENDS_LENGTH EQUAL 0) @@ -1305,7 +1310,7 @@ namespace @IMPL_NAMESPACE@ { set(HAS_CAPS FALSE) set(CAPS_LENGTH 0) - string(JSON CAPS_TYPE TYPE "${IMPL_INPUTS}" ${INDEX} CAPS) + string(JSON CAPS_TYPE ERROR_VARIABLE ERROR_VAR TYPE "${IMPL_INPUTS}" ${INDEX} CAPS) if(CAPS_TYPE STREQUAL "ARRAY") string(JSON CAPS_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} CAPS) if(NOT CAPS_LENGTH EQUAL 0) diff --git a/examples_tests b/examples_tests index bdbae93a63..ac85bdb781 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit bdbae93a6389414dac1e47f59fb5bb74d99e68ec +Subproject commit ac85bdb781c77fdde694a3da81a8f5831d17e96d From ae0b1604869ecb3f41d118078de5cd22c7662a2b Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 24 Oct 2025 14:58:31 +0200 Subject: [PATCH 17/61] CP_UTF8 for dxc source buffer's encoding just like code page (experimental) --- .../nbl/builtin/hlsl/ext/FullScreenTriangle/default.vert.hlsl | 3 ++- include/nbl/builtin/hlsl/surface_transform.h | 4 +++- src/nbl/asset/utils/CHLSLCompiler.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/nbl/builtin/hlsl/ext/FullScreenTriangle/default.vert.hlsl b/include/nbl/builtin/hlsl/ext/FullScreenTriangle/default.vert.hlsl index a48d9b4623..7a2aef1cbf 100644 --- a/include/nbl/builtin/hlsl/ext/FullScreenTriangle/default.vert.hlsl +++ b/include/nbl/builtin/hlsl/ext/FullScreenTriangle/default.vert.hlsl @@ -33,4 +33,5 @@ SVertexAttributes main() SVertexAttributes retval; retval.uv = tc[gl_VertexIndex()]; return retval; -} \ No newline at end of file +} + diff --git a/include/nbl/builtin/hlsl/surface_transform.h b/include/nbl/builtin/hlsl/surface_transform.h index a681ecf0bb..2d7afa7add 100644 --- a/include/nbl/builtin/hlsl/surface_transform.h +++ b/include/nbl/builtin/hlsl/surface_transform.h @@ -181,4 +181,6 @@ TwoColumns applyToDerivatives(const FLAG_BITS transform, TwoColumns dDx_dDy) } } } -#endif \ No newline at end of file + +#endif // _NBL_BUILTIN_HLSL_SURFACE_TRANSFORM_INCLUDED_ + diff --git a/src/nbl/asset/utils/CHLSLCompiler.cpp b/src/nbl/asset/utils/CHLSLCompiler.cpp index 306d2f60de..51609c4039 100644 --- a/src/nbl/asset/utils/CHLSLCompiler.cpp +++ b/src/nbl/asset/utils/CHLSLCompiler.cpp @@ -301,7 +301,7 @@ static DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset DxcBuffer sourceBuffer; sourceBuffer.Ptr = src->GetBufferPointer(); sourceBuffer.Size = src->GetBufferSize(); - sourceBuffer.Encoding = 0; + sourceBuffer.Encoding = CP_UTF8; ComPtr compileResult; res = dxc->m_dxcCompiler->Compile(&sourceBuffer, args, argCount, nullptr, IID_PPV_ARGS(compileResult.GetAddressOf())); From d45e3a7f7b8cead31283e5cdbcb8e6bd2bb81875 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 27 Oct 2025 13:48:50 +0100 Subject: [PATCH 18/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index ac85bdb781..776f925b8f 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit ac85bdb781c77fdde694a3da81a8f5831d17e96d +Subproject commit 776f925b8fa72348aa41a687089af280a5a8f57c From 5ecf50e68429a7dca39751efa5851a8fb2fca96a Mon Sep 17 00:00:00 2001 From: devsh Date: Tue, 28 Oct 2025 12:37:48 +0100 Subject: [PATCH 19/61] fix IES Profile average emission and domain calculations --- examples_tests | 2 +- src/nbl/asset/utils/CIESProfile.h | 7 ++++- src/nbl/asset/utils/CIESProfileParser.cpp | 38 ++++++++++++----------- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/examples_tests b/examples_tests index 332e8d72cf..1fe9697453 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 332e8d72cf776dd78e4cf707d87c25f0aeeb6342 +Subproject commit 1fe969745304a3492b04c3d1902561d92f467827 diff --git a/src/nbl/asset/utils/CIESProfile.h b/src/nbl/asset/utils/CIESProfile.h index ea3d539613..1da2c60b79 100644 --- a/src/nbl/asset/utils/CIESProfile.h +++ b/src/nbl/asset/utils/CIESProfile.h @@ -72,7 +72,12 @@ namespace nbl inline IES_STORAGE_FORMAT getAvgEmmision(const bool fullDomain=false) const { if (fullDomain) - return totalEmissionIntegral*0.25/core::radians(vAngles.back()-vAngles.front()); + { + const float cosLo = std::cos(core::radians(vAngles.front())); + const float cosHi = std::cos(core::radians(vAngles.back())); + const float dsinTheta = cosLo - cosHi; + return totalEmissionIntegral*(0.5/core::PI())/dsinTheta; + } return avgEmmision; } diff --git a/src/nbl/asset/utils/CIESProfileParser.cpp b/src/nbl/asset/utils/CIESProfileParser.cpp index e0593cd7f2..2c6ce873be 100644 --- a/src/nbl/asset/utils/CIESProfileParser.cpp +++ b/src/nbl/asset/utils/CIESProfileParser.cpp @@ -180,15 +180,23 @@ bool CIESProfileParser::parse(CIESProfile& result) float totalEmissionIntegral = 0.0, nonZeroEmissionDomainSize = 0.0; constexpr auto FULL_SOLID_ANGLE = 4.0f * core::PI(); + // TODO: this code could have two separate inner for loops for `result.symmetry != CIESProfile::ISOTROPIC` cases const auto H_ANGLES_I_RANGE = result.symmetry != CIESProfile::ISOTROPIC ? result.hAngles.size() - 1 : 1; const auto V_ANGLES_I_RANGE = result.vAngles.size() - 1; - for (size_t i = 0; i < H_ANGLES_I_RANGE; i++) + for (size_t j = 0; j < V_ANGLES_I_RANGE; j++) { - const float dPhiRad = result.symmetry != CIESProfile::ISOTROPIC ? (hAngles[i + 1] - hAngles[i]) : core::PI() * 2.0f; - - for (size_t j = 0; j < V_ANGLES_I_RANGE; j++) + const float thetaRad = core::radians(result.vAngles[j]); + const float cosLo = std::cos(thetaRad); + const float cosHi = std::cos(core::radians(result.vAngles[j+1])); + const float dsinTheta = cosLo - cosHi; + + float stripIntegral = 0.f; + float nonZeroStripDomain = 0.f; + for (size_t i = 0; i < H_ANGLES_I_RANGE; i++) { + const float dPhiRad = result.symmetry != CIESProfile::ISOTROPIC ? core::radians(hAngles[i + 1] - hAngles[i]) : (core::PI() * 2.0f); + const auto candelaValue = result.getCandelaValue(i, j); // interpolate candela value spanned onto a solid angle @@ -199,23 +207,17 @@ bool CIESProfileParser::parse(CIESProfile& result) if (result.maxCandelaValue < candelaValue) result.maxCandelaValue = candelaValue; - const float thetaRad = core::radians(result.vAngles[j]); - const float cosLo = std::cos(core::radians(result.vAngles[j])); - const float cosHi = std::cos(core::radians(result.vAngles[j + 1])); - - const auto differentialSolidAngle = dPhiRad*(cosLo - cosHi); - const auto integralV = candelaAverage * differentialSolidAngle; - - if (integralV > 0.0) - { - totalEmissionIntegral += integralV; - nonZeroEmissionDomainSize += differentialSolidAngle; - } + stripIntegral += candelaAverage*dPhiRad; + if (candelaAverage>0.f) + nonZeroStripDomain += dPhiRad; } + totalEmissionIntegral += stripIntegral*dsinTheta; + nonZeroEmissionDomainSize += nonZeroStripDomain*dsinTheta; } - nonZeroEmissionDomainSize = std::clamp(nonZeroEmissionDomainSize, 0.0, FULL_SOLID_ANGLE); - if (nonZeroEmissionDomainSize <= 0) // protect us from division by 0 (just in case, we should never hit it) + assert(nonZeroEmissionDomainSize >= 0.f); + //assert(nonZeroEmissionDomainSize*fluxMultiplier =approx= 2.f*(cosBack-cosFront)*PI); + if (nonZeroEmissionDomainSize <= std::numeric_limits::min()) // protect us from division by small numbers (just in case, we should never hit it) return false; result.avgEmmision = totalEmissionIntegral / static_cast(nonZeroEmissionDomainSize); From 07feaff4b6f3a2696e2dae6d1c707822109f1a3d Mon Sep 17 00:00:00 2001 From: root Date: Tue, 28 Oct 2025 16:14:04 +0100 Subject: [PATCH 20/61] Update CI references --- ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci b/ci index 043f8a0aa0..606901755b 160000 --- a/ci +++ b/ci @@ -1 +1 @@ -Subproject commit 043f8a0aa074f134b3230d56f27ed7d0c645f6b3 +Subproject commit 606901755b9ba13715c796ac8b303c57732a7581 From e8ea1194403c1b2f3d4e0af507dae56faffbb8ba Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 28 Oct 2025 16:28:38 +0100 Subject: [PATCH 21/61] `-Wno-local-type-template-args` for NBL_CREATE_NSC_COMPILE_RULES, update examples_tests --- cmake/common.cmake | 1 + examples_tests | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index ab215a59e3..c1ab2aa3e1 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1179,6 +1179,7 @@ struct DeviceConfigCaps -Zpr -spirv -fspv-target-env=vulkan1.3 + -Wno-local-type-template-args ) if(NOT NBL_EMBED_BUILTIN_RESOURCES) diff --git a/examples_tests b/examples_tests index 776f925b8f..06b2d09bbc 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 776f925b8fa72348aa41a687089af280a5a8f57c +Subproject commit 06b2d09bbc338ee3f57d27587d099bbf1ad22949 From 1e9138e441ac2a1d4afdca71fa5eb390d0d218e5 Mon Sep 17 00:00:00 2001 From: devsh Date: Tue, 28 Oct 2025 16:41:26 +0100 Subject: [PATCH 22/61] make the IES octahedral maps corner sampled --- examples_tests | 2 +- include/nbl/builtin/glsl/ies/functions.glsl | 36 +++++++++++-------- .../glsl/material_compiler/common.glsl | 3 +- src/nbl/asset/utils/CIESProfile.cpp | 16 ++++++--- 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/examples_tests b/examples_tests index 1fe9697453..b742c70c5a 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 1fe969745304a3492b04c3d1902561d92f467827 +Subproject commit b742c70c5abc6feaf22ebb56cbae8a2bbcfa12f9 diff --git a/include/nbl/builtin/glsl/ies/functions.glsl b/include/nbl/builtin/glsl/ies/functions.glsl index 70f5165f98..54c266d114 100644 --- a/include/nbl/builtin/glsl/ies/functions.glsl +++ b/include/nbl/builtin/glsl/ies/functions.glsl @@ -6,25 +6,33 @@ #include -// TODO: implement proper mirroing -// MIRROR_180_BITS = 0b001, Last Angle is 180, so map V slightly differently -// MIRROR_90_BITS = 0b010, Last Angle is 90, so map both U and V slightly differently -// ISOTROPIC_BITS = 0b011, texture to sample is Nx1, pretend v=middle always -// FULL_THETA_BIT = 0b100, handle extended domain and rotate by 45 degrees for anisotropic - -vec2 nbl_glsl_IES_convert_dir_to_uv(vec3 dir) { - float sum = dot(vec3(1.0f), abs(dir)); +// TODO: when rewriting to HLSL this is not IES namespace or folder, this should be octahedral mapping sitting somewhere where the spherical/polar sits +// NOTE: I changed it to return NDC [-1,1]^2 instead of UV coords [0,1]^2 +vec2 nbl_glsl_TODOnamespace_octahedral_mapping(vec3 dir) +{ + float sum = dot(vec3(1.0f), abs(dir)); vec3 s = dir / sum; - if(s.z < 0.0f) { - s.xy = sign(s.xy) * (1.0f - abs(s.yx)); + if(s.z < 0.0f) + { + const uvec2 flipSignMask = floatBitsToUint(s.xy)&0x80000000u; + s.xy = uintBitsToFloat(floatBitsToUint(1.0f - abs(s.yx))^flipSignMask); } - return s.xy * 0.5f + 0.5f; + return s.xy; } -// vec2 nbl_glsl_IES_convert_dir_to_uv(vec3 dir) { -// return vec2((atan(dir.x, dir.y) + nbl_glsl_PI) / (2.0*nbl_glsl_PI), acos(dir.z) / nbl_glsl_PI); -// } +// TODO: implement proper mirroing +// MIRROR_180_BITS = 0b001, Last Angle is 180, so map V with MIRROR and corner sampling off +// MIRROR_90_BITS = 0b010, Last Angle is 90, so map both U and V with MIRROR and corner sampling off +// ISOTROPIC_BITS = 0b011, texture to sample is Nx1, pretend v=middle always , and make u REPEAT or CLAMP_TO_BORDER +// FULL_THETA_BIT = 0b100, handle truncated domain and rotate by 45 degrees for anisotropic +// (certain combos wont work like 90 degree 2 symmetry domain & half theta), it really needs to be an 8 case label thing explicitly enumerated +vec2 nbl_glsl_IES_convert_dir_to_uv(vec3 dir, vec2 halfMinusHalfPixel) +{ + // halfMinusHalfPixel = 0.5-0.5/texSize + // believe it or not, cornerSampled(NDC*0.5+0.5) = NDC*0.5*(1-1/texSize)+0.5 + return nbl_glsl_TODOnamespace_octahedral_mapping(dir)*halfMinusHalfPixel+0.5; +} #endif \ No newline at end of file diff --git a/include/nbl/builtin/glsl/material_compiler/common.glsl b/include/nbl/builtin/glsl/material_compiler/common.glsl index da67b12cbf..ba3c95d5e2 100644 --- a/include/nbl/builtin/glsl/material_compiler/common.glsl +++ b/include/nbl/builtin/glsl/material_compiler/common.glsl @@ -601,7 +601,8 @@ vec3 nbl_glsl_MC_oriented_material_t_getEmissive(in nbl_glsl_MC_oriented_materia if ((floatBitsToInt(emitter.orientation[0])&1u) != 1u) { right *= -1; } - return emissive * nbl_glsl_vTextureGrad(emitter.emissionProfile, nbl_glsl_IES_convert_dir_to_uv(mat3(right, up, view)*dir), mat2(0.0)).r; + vec2 halfMinusHalfPixel = 0.5-0.5/vec2(nbl_glsl_unpackSize(emitter.emissionProfile)); + return emissive * nbl_glsl_vTextureGrad(emitter.emissionProfile, nbl_glsl_IES_convert_dir_to_uv(mat3(right, up, view)*dir,halfMinusHalfPixel), mat2(0.0)).r; } #endif return emissive; diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index b507ab0d45..59829b9c71 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -88,8 +88,8 @@ inline core::vectorSIMDf CIESProfile::octahdronUVToDir(const float& u, const flo float abs_x = core::abs(pos.x), abs_y = core::abs(pos.y); pos.z = 1.0 - abs_x - abs_y; if (pos.z < 0.0) { - pos.x = core::sign(pos.x) * (1.0 - abs_y); - pos.y = core::sign(pos.y) * (1.0 - abs_x); + pos.x = (pos.x<0.f ? (-1.f):1.f) * (1.0 - abs_y); + pos.y = (pos.y<0.f ? (-1.f):1.f) * (1.0 - abs_x); } return core::normalize(pos); @@ -116,6 +116,8 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu if (height > CDC_MAX_TEXTURE_HEIGHT) height = CDC_MAX_TEXTURE_HEIGHT; + // TODO: If no symmetry (no folding in half and abuse of mirror sampler) make dimensions odd-sized so middle texel taps the south pole + asset::ICPUImage::SCreationParams imgInfo; imgInfo.type = asset::ICPUImage::ET_2D; imgInfo.extent.width = width; @@ -161,15 +163,19 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu const double maxValue = getMaxCandelaValue(); const double maxValueRecip = 1.0 / maxValue; - const double vertInv = 1.0 / height; - const double horiInv = 1.0 / width; + // There is one huge issue, the IES files love to give us values for degrees 0, 90, 180 an 360 + // So standard octahedral mapping won't work, because for above data points you need corner sampled images. + const float vertInv = 1.0 / (height-1); + const float horiInv = 1.0 / (width-1); const double flattenTarget = getAvgEmmision(fullDomainFlatten); const double domainLo = core::radians(vAngles.front()); const double domainHi = core::radians(vAngles.back()); auto fill = [&](uint32_t blockArrayOffset, core::vectorSIMDu32 position) -> void { - const auto dir = octahdronUVToDir(((float)position.x + 0.5) * vertInv, ((float)position.y + 0.5) * horiInv); + // We don't currently support generating IES images that exploit symmetries or reduced domains, all are full octahederal mappings of a sphere. + // If we did, we'd rely on MIRROR and CLAMP samplers to do some of the work for us while handling the discontinuity due to corner sampling. + const auto dir = octahdronUVToDir(position.x * vertInv, position.y * horiInv); const auto [theta, phi] = sphericalDirToRadians(dir); const auto intensity = sample(theta, phi); From be62e3ac5716e93794423efbbdd7e0d34a00683b Mon Sep 17 00:00:00 2001 From: devsh Date: Tue, 28 Oct 2025 17:36:32 +0100 Subject: [PATCH 23/61] improve how the resolution of an IES is calculated but also leave a TODO on how to improve it even more --- examples_tests | 2 +- .../glsl/material_compiler/common.glsl | 2 +- src/nbl/asset/utils/CIESProfile.cpp | 5 +++++ src/nbl/asset/utils/CIESProfileParser.cpp | 19 +++++++++++++------ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/examples_tests b/examples_tests index b742c70c5a..cd3efce0ac 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit b742c70c5abc6feaf22ebb56cbae8a2bbcfa12f9 +Subproject commit cd3efce0ac9b498bd8569a68fb9ddef0f6f19332 diff --git a/include/nbl/builtin/glsl/material_compiler/common.glsl b/include/nbl/builtin/glsl/material_compiler/common.glsl index ba3c95d5e2..f6b7d97c46 100644 --- a/include/nbl/builtin/glsl/material_compiler/common.glsl +++ b/include/nbl/builtin/glsl/material_compiler/common.glsl @@ -601,7 +601,7 @@ vec3 nbl_glsl_MC_oriented_material_t_getEmissive(in nbl_glsl_MC_oriented_materia if ((floatBitsToInt(emitter.orientation[0])&1u) != 1u) { right *= -1; } - vec2 halfMinusHalfPixel = 0.5-0.5/vec2(nbl_glsl_unpackSize(emitter.emissionProfile)); + vec2 halfMinusHalfPixel = vec2(0.5)-vec2(0.5)/vec2(nbl_glsl_unpackSize(emitter.emissionProfile)); return emissive * nbl_glsl_vTextureGrad(emitter.emissionProfile, nbl_glsl_IES_convert_dir_to_uv(mat3(right, up, view)*dir,halfMinusHalfPixel), mat2(0.0)).r; } #endif diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index 59829b9c71..431cc14eba 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -118,6 +118,11 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu // TODO: If no symmetry (no folding in half and abuse of mirror sampler) make dimensions odd-sized so middle texel taps the south pole + // TODO: This is hack because the mitsuba loader and its material compiler use Virtual Texturing, and there's some bug with IES not sampling sub 128x128 mip levels + // don't want to spend time to fix this since we'll be using descriptor indexing for the next iteration + width = core::max(width,128); + height = core::max(height,128); + asset::ICPUImage::SCreationParams imgInfo; imgInfo.type = asset::ICPUImage::ET_2D; imgInfo.extent.width = width; diff --git a/src/nbl/asset/utils/CIESProfileParser.cpp b/src/nbl/asset/utils/CIESProfileParser.cpp index 2c6ce873be..dd6b321414 100644 --- a/src/nbl/asset/utils/CIESProfileParser.cpp +++ b/src/nbl/asset/utils/CIESProfileParser.cpp @@ -106,12 +106,6 @@ bool CIESProfileParser::parse(CIESProfile& result) if (vSize < 2) return false; - { - const uint32_t maxDimMeasureSize = core::max(hSize, vSize); - result.optimalIESResolution = decltype(result.optimalIESResolution){ maxDimMeasureSize, maxDimMeasureSize }; - result.optimalIESResolution *= 2u; // safe bias for our bilinear interpolation to work nicely and increase resolution of a profile - } - auto& vAngles = result.vAngles; for (int i = 0; i < vSize; i++) { vAngles[i] = getDouble("vertical angle truncated"); @@ -184,6 +178,7 @@ bool CIESProfileParser::parse(CIESProfile& result) const auto H_ANGLES_I_RANGE = result.symmetry != CIESProfile::ISOTROPIC ? result.hAngles.size() - 1 : 1; const auto V_ANGLES_I_RANGE = result.vAngles.size() - 1; + float smallestRangeSolidAngle = FULL_SOLID_ANGLE; for (size_t j = 0; j < V_ANGLES_I_RANGE; j++) { const float thetaRad = core::radians(result.vAngles[j]); @@ -196,6 +191,11 @@ bool CIESProfileParser::parse(CIESProfile& result) for (size_t i = 0; i < H_ANGLES_I_RANGE; i++) { const float dPhiRad = result.symmetry != CIESProfile::ISOTROPIC ? core::radians(hAngles[i + 1] - hAngles[i]) : (core::PI() * 2.0f); + // TODO: in reality one should transform the 4 vertices (or 3) into octahedral map, work out the dUV/dPhi and dUV/dTheta vectors as-if for Anisotropic Filtering + // then choose the minor axis length, and use that as a pixel size (since looking for smallest thing, dont have to worry about handling discont) + const float solidAngle = dsinTheta * dPhiRad; + if (solidAngle= 0.f); //assert(nonZeroEmissionDomainSize*fluxMultiplier =approx= 2.f*(cosBack-cosFront)*PI); if (nonZeroEmissionDomainSize <= std::numeric_limits::min()) // protect us from division by small numbers (just in case, we should never hit it) From 0c03e2f7517c6cd8cfff2dfb5c874a3da41c27e7 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 28 Oct 2025 19:37:17 +0100 Subject: [PATCH 24/61] Update CI references --- ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci b/ci index 606901755b..8c3e98c651 160000 --- a/ci +++ b/ci @@ -1 +1 @@ -Subproject commit 606901755b9ba13715c796ac8b303c57732a7581 +Subproject commit 8c3e98c651e55a9e0e9c6121d055d483b2f90618 From 80de6aaa741b908cab2c9c2ade3e04ce049f3204 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 29 Oct 2025 11:58:52 +0100 Subject: [PATCH 25/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 06b2d09bbc..7d0b0db615 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 06b2d09bbc338ee3f57d27587d099bbf1ad22949 +Subproject commit 7d0b0db6159ee194c8d9a2f094a03f85fc0c7f8c From e05478d676faf15c4b61d8ddf541d8a80fcc785b Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 29 Oct 2025 15:12:00 +0100 Subject: [PATCH 26/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 7d0b0db615..6d2c3d4f32 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 7d0b0db6159ee194c8d9a2f094a03f85fc0c7f8c +Subproject commit 6d2c3d4f32383eaeb706bef30b47e68292e7f24f From 8d0c2375aa79e617200ee738dc65ad3890f14f76 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 30 Oct 2025 15:21:36 +0100 Subject: [PATCH 27/61] add createGrid to geometry creator --- include/nbl/asset/utils/CGeometryCreator.h | 8 +- src/nbl/asset/utils/CGeometryCreator.cpp | 97 ++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/include/nbl/asset/utils/CGeometryCreator.h b/include/nbl/asset/utils/CGeometryCreator.h index 5c669b9510..290c81b239 100644 --- a/include/nbl/asset/utils/CGeometryCreator.h +++ b/include/nbl/asset/utils/CGeometryCreator.h @@ -115,9 +115,15 @@ class NBL_API2 CGeometryCreator final : public core::IReferenceCounted \param subdivision Specifies subdivision level of the icosphere. \param smooth Specifies whether vertecies should be built for smooth or flat shading. */ - core::smart_refctd_ptr createIcoSphere(float radius=1.f, uint32_t subdivision=1, bool smooth=false) const; + //! Create a grid geometry + /** + No vertex buffer, only index in triangle strip topology without reset, "snake" with degenerates + \param "resolution" Specifies resolution of grid + */ + core::smart_refctd_ptr createGrid(const hlsl::uint16_t2 resolution = { 128u, 128u }) const; + private: SCreationParams m_params; }; diff --git a/src/nbl/asset/utils/CGeometryCreator.cpp b/src/nbl/asset/utils/CGeometryCreator.cpp index 9dc8cdd42a..8bf0a7521b 100644 --- a/src/nbl/asset/utils/CGeometryCreator.cpp +++ b/src/nbl/asset/utils/CGeometryCreator.cpp @@ -498,6 +498,15 @@ core::smart_refctd_ptr CGeometryCreator::createSphere(float memcpy(normals + vertex_i, &quantizedBottomNormal, sizeof(quantizedBottomNormal)); } + for (auto i = 0u; i < vertexCount; ++i) + { + auto position = positions[i]; + auto len = glm::length(position); + + auto ok = len >= 1.f - 0.01f; + assert(ok); + } + CPolygonGeometryManipulator::recomputeContentHashes(retval.get()); return retval; } @@ -1889,5 +1898,93 @@ core::smart_refctd_ptr CGeometryCreator::createIcoSphere(fl return retval; } +core::smart_refctd_ptr CGeometryCreator::createGrid(const hlsl::uint16_t2 resolution) const +{ + if (resolution.x < 2 || resolution.y < 2) + return nullptr; + + auto retval = core::make_smart_refctd_ptr(); + retval->setIndexing(IPolygonGeometryBase::TriangleStrip()); + + //! Create indices + /* + i \in [0, resolution.x - 1], j \in [0, resolution.y - 1] + logical vertex id : V(i, j) + + Eg. resolution = {5u, 4u}: + + j=3 15--16--17--18--19 + | \ | \ | \ | \ | + j=2 10--11--12--13--14 + | \ | \ | \ | \ | + j=1 5-- 6-- 7-- 8-- 9 + | \ | \ | \ | \ | + j=0 0-- 1-- 2-- 3-- 4 + i=0 1 2 3 4 + + Strip order (one draw), rows linked by 2 degenerate indices: + row 0 -> 1 (L->R): 0,5, 1,6, 2,7, 3,8, 4,9, 9,9 + row 1 -> 2 (R->L): 9,14, 8,13, 7,12, 6,11, 5,10, 5,5 + row 2 -> 3 (L->R): 5,10, 6,11, 7,12, 8,13, 9,14, 14,14 + */ + + const size_t indexCount = 2ull * resolution.x * (resolution.y - 1) + 2ull * (resolution.y - 2); + const size_t maxIndex = resolution.x * resolution.y - 1u; + + auto createIndices = [&]() -> void + { + auto indexView = createIndexView(indexCount, maxIndex); + + auto V = [&](IndexT i, IndexT j) { return IndexT(j * resolution.x + i); }; + auto* index = static_cast(indexView.src.buffer->getPointer()); + #define PUSH_INDEX(value) *index = value; ++index; + + for (IndexT j = 0u; j < resolution.y - 1; ++j) + { + if ((j & 1u) == 0) + { + for (IndexT i = 0u; i < resolution.x; ++i) + { + PUSH_INDEX(V(i, j)) + PUSH_INDEX(V(i, j + 1)) + } + + if (j + 1 < resolution.y - 1) + { + IndexT last = V(resolution.x - 1, j + 1); + PUSH_INDEX(last) + PUSH_INDEX(last) + } + } + else + { + for (int i = int(resolution.x) - 1; i >= 0; --i) + { + PUSH_INDEX(V(uint32_t(i), j)) + PUSH_INDEX(V(uint32_t(i), j + 1)) + } + + if (j + 1 < resolution.y - 1) + { + IndexT first = V(0, j + 1); + PUSH_INDEX(first) + PUSH_INDEX(first) + } + } + } + retval->setIndexView(std::move(indexView)); + }; + + if (maxIndex <= std::numeric_limits::max()) + createIndices.template operator() < uint16_t > (); + else if (maxIndex <= std::numeric_limits::max()) + createIndices.template operator() < uint32_t > (); + else + return nullptr; + + CPolygonGeometryManipulator::recomputeContentHashes(retval.get()); + return retval; +} + } // end namespace nbl::asset From dbd28055bba525730ba7fc3cfbc45cbc4c76b181 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 30 Oct 2025 15:24:36 +0100 Subject: [PATCH 28/61] remove debug code I forgot about --- src/nbl/asset/utils/CGeometryCreator.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/nbl/asset/utils/CGeometryCreator.cpp b/src/nbl/asset/utils/CGeometryCreator.cpp index 8bf0a7521b..ae1995aa0e 100644 --- a/src/nbl/asset/utils/CGeometryCreator.cpp +++ b/src/nbl/asset/utils/CGeometryCreator.cpp @@ -498,15 +498,6 @@ core::smart_refctd_ptr CGeometryCreator::createSphere(float memcpy(normals + vertex_i, &quantizedBottomNormal, sizeof(quantizedBottomNormal)); } - for (auto i = 0u; i < vertexCount; ++i) - { - auto position = positions[i]; - auto len = glm::length(position); - - auto ok = len >= 1.f - 0.01f; - assert(ok); - } - CPolygonGeometryManipulator::recomputeContentHashes(retval.get()); return retval; } From 054038ffd81a660c36b6ceb596cd6bc8e6116f89 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 31 Oct 2025 12:40:04 +0100 Subject: [PATCH 29/61] add positions to geometry creator's grid for the polygon to be usable with GPU converter, encode to EF_A2R10G10B10_UNORM_PACK32, update examples_tests submodule --- examples_tests | 2 +- src/nbl/asset/utils/CGeometryCreator.cpp | 39 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 6d2c3d4f32..86a50c5a2b 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 6d2c3d4f32383eaeb706bef30b47e68292e7f24f +Subproject commit 86a50c5a2b9b07aee676cc92d70b1910b4da46d4 diff --git a/src/nbl/asset/utils/CGeometryCreator.cpp b/src/nbl/asset/utils/CGeometryCreator.cpp index ae1995aa0e..be37ec640a 100644 --- a/src/nbl/asset/utils/CGeometryCreator.cpp +++ b/src/nbl/asset/utils/CGeometryCreator.cpp @@ -1891,6 +1891,8 @@ core::smart_refctd_ptr CGeometryCreator::createIcoSphere(fl core::smart_refctd_ptr CGeometryCreator::createGrid(const hlsl::uint16_t2 resolution) const { + using namespace hlsl; + if (resolution.x < 2 || resolution.y < 2) return nullptr; @@ -1973,6 +1975,43 @@ core::smart_refctd_ptr CGeometryCreator::createGrid(const h else return nullptr; + //! Create positions + const size_t vertexCount = resolution.x * resolution.y; + { + shapes::AABB<4, float32_t> aabb; + aabb.maxVx = float32_t4((resolution.x - 0.5f) / float(resolution.x), 0.5f, (resolution.y - 0.5f) / float(resolution.y), 1.f); + aabb.minVx = float32_t4(0.5f / float(resolution.x), 0.5f, 0.5f / float(resolution.y), 1.f); + + const auto stride = getTexelOrBlockBytesize(); + const auto bytes = stride * vertexCount; + auto buffer = ICPUBuffer::create({ bytes, IBuffer::EUF_NONE }); + ICPUPolygonGeometry::SDataView positionView = { + .composed = { + .encodedDataRange = {.f32 = aabb}, + .stride = stride, + .format = EF_A2R10G10B10_UNORM_PACK32, + .rangeFormat = IGeometryBase::EAABBFormat::F32 + }, + .src = {.offset = 0,.size = buffer->getSize(),.buffer = core::smart_refctd_ptr(buffer)} + }; + + auto* packed = reinterpret_cast(buffer->getPointer()); + for (uint32_t j = 0; j < resolution.y; ++j) + for (uint32_t i = 0; i < resolution.x; ++i) + { + const double u = (i + 0.5) / double(resolution.x); + const double v = (j + 0.5) / double(resolution.y); + + float64_t4 rgbaunorm = { u, 0.5, v, 1.0 }; + + *packed = {}; + encodePixels(packed, (double*)&rgbaunorm); + ++packed; + } + + retval->setPositionView(std::move(positionView)); + } + CPolygonGeometryManipulator::recomputeContentHashes(retval.get()); return retval; } From f64a8f34edc5abf338d72a3042fa0b370d7554ce Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 3 Nov 2025 10:29:36 +0100 Subject: [PATCH 30/61] update examples_tests submodule --- examples_tests | 2 +- src/nbl/asset/utils/CGeometryCreator.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples_tests b/examples_tests index 86a50c5a2b..d0156858be 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 86a50c5a2b9b07aee676cc92d70b1910b4da46d4 +Subproject commit d0156858bedf2b985316184a73ac0a889350fdc2 diff --git a/src/nbl/asset/utils/CGeometryCreator.cpp b/src/nbl/asset/utils/CGeometryCreator.cpp index be37ec640a..30a9eea7af 100644 --- a/src/nbl/asset/utils/CGeometryCreator.cpp +++ b/src/nbl/asset/utils/CGeometryCreator.cpp @@ -1982,7 +1982,7 @@ core::smart_refctd_ptr CGeometryCreator::createGrid(const h aabb.maxVx = float32_t4((resolution.x - 0.5f) / float(resolution.x), 0.5f, (resolution.y - 0.5f) / float(resolution.y), 1.f); aabb.minVx = float32_t4(0.5f / float(resolution.x), 0.5f, 0.5f / float(resolution.y), 1.f); - const auto stride = getTexelOrBlockBytesize(); + static constexpr auto stride = getTexelOrBlockBytesize(); const auto bytes = stride * vertexCount; auto buffer = ICPUBuffer::create({ bytes, IBuffer::EUF_NONE }); ICPUPolygonGeometry::SDataView positionView = { From c94199199856e3b5d89d6998d641080e14c511c7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 3 Nov 2025 16:30:16 +0100 Subject: [PATCH 31/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index d0156858be..462bb549f6 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit d0156858bedf2b985316184a73ac0a889350fdc2 +Subproject commit 462bb549f642fe0c02da384416766e8cc049adab From 95246c48adfd4f20bad093c93961e2fa8447860d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 5 Nov 2025 15:07:09 +0100 Subject: [PATCH 32/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 462bb549f6..4cd5f027ea 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 462bb549f642fe0c02da384416766e8cc049adab +Subproject commit 4cd5f027eabdf88f84e16d47f8fdc6acdd1d36b4 From 4bb28642c39ecf3f21cfb87a4653183900ecee28 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sat, 8 Nov 2025 10:21:23 +0100 Subject: [PATCH 33/61] add include/nbl/builtin/hlsl/math/octahedral.hlsl --- include/nbl/builtin/hlsl/math/octahedral.hlsl | 69 +++++++++++++++++++ src/nbl/builtin/CMakeLists.txt | 1 + 2 files changed, 70 insertions(+) create mode 100644 include/nbl/builtin/hlsl/math/octahedral.hlsl diff --git a/include/nbl/builtin/hlsl/math/octahedral.hlsl b/include/nbl/builtin/hlsl/math/octahedral.hlsl new file mode 100644 index 0000000000..55f845a0c8 --- /dev/null +++ b/include/nbl/builtin/hlsl/math/octahedral.hlsl @@ -0,0 +1,69 @@ +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h + +#ifndef _NBL_BUILTIN_HLSL_MATH_OCTAHEDRAL_INCLUDED_ +#define _NBL_BUILTIN_HLSL_MATH_OCTAHEDRAL_INCLUDED_ + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#include "nbl/builtin/hlsl/numbers.hlsl" + +namespace nbl +{ +namespace hlsl +{ +namespace math +{ + +// Octahedral Transform, maps 3D direction vectors to 2D square and vice versa +template +struct OctahedralTransform +{ + using scalar_type = T; + using vector2_type = vector; + using vector3_type = vector; + + // F : [-1, 1]^2 -> S^2 + static vector3_type eval(const vector2_type ndc) + { + vector3_type p = vector3_type(ndc.xy, scalar_type(0)); + const vector2_type a = abs(p.xy); + + p.z = scalar_type(1) - a.x - a.y; + + if (p.z < scalar_type(0)) + p.xy = hlsl::sign(p.xy) * (scalar_type(1) - abs(p.yx)); + + return hlsl::normalize(p); + } + + // F^-1 : S^2 -> [-1, 1]^2 + static vector2_type inverse(vector3_type dir) + { + dir = hlsl::normalize(dir); + const scalar_type sum = hlsl::dot(vector3_type(scalar_type(1), scalar_type(1), scalar_type(1)), abs(dir)); + vector3_type s = dir / sum; + + if (s.z < scalar_type(0)) + s.xy = hlsl::sign(s.xy) * (scalar_type(1) - abs(s.yx)); + + return s.xy; + } + + // transforms direction vector into UV (for corner sampling) + // dir in S^2, halfMinusHalfPixel in [0, 0.5)^2, + // where halfMinusHalfPixel = 0.5-0.5/texSize + // and texSize.x >= 1, texSize.y >= 1 + // NOTE/TODO: not best place to keep it here imo + static vector2_type toCornerSampledUV(vector3_type dir, vector2_type halfMinusHalfPixel) + { + // note: cornerSampled(NDC*0.5+0.5) = NDC*0.5*(1-1/texSize)+0.5 + return inverse(dir) * halfMinusHalfPixel + scalar_type(0.5); + } +}; + +} +} +} + +#endif // _NBL_BUILTIN_HLSL_MATH_OCTAHEDRAL_INCLUDED_ \ No newline at end of file diff --git a/src/nbl/builtin/CMakeLists.txt b/src/nbl/builtin/CMakeLists.txt index cc81b093a2..e15c1458da 100644 --- a/src/nbl/builtin/CMakeLists.txt +++ b/src/nbl/builtin/CMakeLists.txt @@ -224,6 +224,7 @@ LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/functions.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/geometry.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/intutil.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/angle_adding.hlsl") +LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/octahedral.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/equations/quadratic.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/equations/cubic.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/equations/quartic.hlsl") From 12d608fbb805a24e597cea091c3da32ba090af9f Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sat, 8 Nov 2025 10:23:55 +0100 Subject: [PATCH 34/61] CONTRIBUTING.md post update --- CONTRIBUTING.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52130bd445..7078612541 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,6 @@ Thank you for your interest in contributing to the Nabla Engine! Nabla is a high ## Table of Contents -<<<<<<< HEAD - [How Can I Contribute?](#how-can-i-contribute) - [Reporting Bugs](#reporting-bugs) - [Suggesting Enhancements](#suggesting-enhancements) @@ -13,9 +12,6 @@ Thank you for your interest in contributing to the Nabla Engine! Nabla is a high - [Pull Request Process](#pull-request-process) - [Connect with Other Project Contributors](#connect-with-other-project-contributors) - [License](#license) -======= -https://github.com/Devsh-Graphics-Programming/Nabla/issues ->>>>>>> 0c03e2f7517c6cd8cfff2dfb5c874a3da41c27e7 ## How Can I Contribute? From 2eadc3bf9b3fbf8708404589d7abe17fbb7b4719 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sat, 8 Nov 2025 11:54:43 +0100 Subject: [PATCH 35/61] wipe CIESProfile::octahdronUVToDir and use HLSL version --- include/nbl/builtin/hlsl/math/octahedral.hlsl | 32 +++++++++++-------- src/nbl/asset/utils/CIESProfile.cpp | 23 ++++--------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/octahedral.hlsl b/include/nbl/builtin/hlsl/math/octahedral.hlsl index 55f845a0c8..1f3c34d6f5 100644 --- a/include/nbl/builtin/hlsl/math/octahedral.hlsl +++ b/include/nbl/builtin/hlsl/math/octahedral.hlsl @@ -16,49 +16,55 @@ namespace math { // Octahedral Transform, maps 3D direction vectors to 2D square and vice versa -template +template struct OctahedralTransform { using scalar_type = T; using vector2_type = vector; using vector3_type = vector; - // F : [-1, 1]^2 -> S^2 - static vector3_type eval(const vector2_type ndc) + // F : [0, 1]^2 -> S^2 + static vector3_type uvToDir(const vector2_type uv) { - vector3_type p = vector3_type(ndc.xy, scalar_type(0)); - const vector2_type a = abs(p.xy); + vector3_type p = vector3_type((uv * scalar_type(2) - scalar_type(1)), scalar_type(0)); + const scalar_type a_x = abs(p.x); const scalar_type a_y = abs(p.y); - p.z = scalar_type(1) - a.x - a.y; + p.z = scalar_type(1) - a_x - a_y; - if (p.z < scalar_type(0)) - p.xy = hlsl::sign(p.xy) * (scalar_type(1) - abs(p.yx)); + if (p.z < scalar_type(0)) + { + p.x = (p.x < scalar_type(0) ? scalar_type(-1) : scalar_type(1)) * (scalar_type(1) - a_y); + p.y = (p.y < scalar_type(0) ? scalar_type(-1) : scalar_type(1)) * (scalar_type(1) - a_x); + } return hlsl::normalize(p); } // F^-1 : S^2 -> [-1, 1]^2 - static vector2_type inverse(vector3_type dir) + static vector2_type dirToNDC(vector3_type dir) { dir = hlsl::normalize(dir); const scalar_type sum = hlsl::dot(vector3_type(scalar_type(1), scalar_type(1), scalar_type(1)), abs(dir)); vector3_type s = dir / sum; if (s.z < scalar_type(0)) - s.xy = hlsl::sign(s.xy) * (scalar_type(1) - abs(s.yx)); + { + s.x = (s.x < scalar_type(0) ? scalar_type(-1) : scalar_type(1)) * (scalar_type(1) - abs(s.y)); + s.y = (s.y < scalar_type(0) ? scalar_type(-1) : scalar_type(1)) * (scalar_type(1) - abs(s.x)); + } return s.xy; } - // transforms direction vector into UV (for corner sampling) + // transforms direction vector into UV for corner sampling // dir in S^2, halfMinusHalfPixel in [0, 0.5)^2, // where halfMinusHalfPixel = 0.5-0.5/texSize // and texSize.x >= 1, texSize.y >= 1 - // NOTE/TODO: not best place to keep it here imo + // NOTE/TODO: not best place to keep it here static vector2_type toCornerSampledUV(vector3_type dir, vector2_type halfMinusHalfPixel) { // note: cornerSampled(NDC*0.5+0.5) = NDC*0.5*(1-1/texSize)+0.5 - return inverse(dir) * halfMinusHalfPixel + scalar_type(0.5); + return dirToNDC(dir) * halfMinusHalfPixel + scalar_type(0.5); } }; diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index 2cb79aa9f1..c981cd3208 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -2,6 +2,7 @@ #include #include "nbl/asset/filters/CBasicImageFilterCommon.h" +#include "nbl/builtin/hlsl/math/octahedral.hlsl" using namespace nbl; using namespace asset; @@ -82,20 +83,6 @@ const CIESProfile::IES_STORAGE_FORMAT CIESProfile::sample(IES_STORAGE_FORMAT the return s0 * (1.0 - u) + s1 * u; } -inline core::vectorSIMDf CIESProfile::octahdronUVToDir(const float& u, const float& v) -{ - core::vectorSIMDf pos = core::vectorSIMDf(2 * (u - 0.5), 2 * (v - 0.5), 0.0); - float abs_x = core::abs(pos.x), abs_y = core::abs(pos.y); - pos.z = 1.0 - abs_x - abs_y; - if (pos.z < 0.0) { - pos.x = (pos.x<0.f ? (-1.f):1.f) * (1.0 - abs_y); - pos.y = (pos.y<0.f ? (-1.f):1.f) * (1.0 - abs_x); - } - - return core::normalize(pos); -} - - inline std::pair CIESProfile::sphericalDirToRadians(const core::vectorSIMDf& dir) { const float theta = std::acos(std::clamp(dir.z, -1.f, 1.f)); @@ -183,8 +170,12 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu { // We don't currently support generating IES images that exploit symmetries or reduced domains, all are full octahederal mappings of a sphere. // If we did, we'd rely on MIRROR and CLAMP samplers to do some of the work for us while handling the discontinuity due to corner sampling. - const auto dir = octahdronUVToDir(position.x * vertInv, position.y * horiInv); - const auto [theta, phi] = sphericalDirToRadians(dir); + + using Octahedral = hlsl::math::OctahedralTransform; + const auto uv = Octahedral::vector2_type(position.x * vertInv, position.y * horiInv); + const auto dir = Octahedral::uvToDir(uv); + const auto tmp = core::vectorSIMDf(dir.x, dir.y, dir.z); + const auto [theta, phi] = sphericalDirToRadians(tmp); const auto intensity = sample(theta, phi); //! blend the IES texture with "flatten" From 1d8aa312f7cb044e31fb48f3bf419cb872ffc37a Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sat, 8 Nov 2025 12:40:12 +0100 Subject: [PATCH 36/61] wipe CIESProfile::sphericalDirToRadians and use polar.hlsl --- include/nbl/builtin/hlsl/math/octahedral.hlsl | 8 +++--- include/nbl/builtin/hlsl/math/polar.hlsl | 24 ++++++++-------- src/nbl/asset/utils/CIESProfile.cpp | 19 ++++--------- src/nbl/asset/utils/CIESProfile.h | 28 ------------------- 4 files changed, 23 insertions(+), 56 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/octahedral.hlsl b/include/nbl/builtin/hlsl/math/octahedral.hlsl index 1f3c34d6f5..8e32d60cb0 100644 --- a/include/nbl/builtin/hlsl/math/octahedral.hlsl +++ b/include/nbl/builtin/hlsl/math/octahedral.hlsl @@ -24,7 +24,7 @@ struct OctahedralTransform using vector3_type = vector; // F : [0, 1]^2 -> S^2 - static vector3_type uvToDir(const vector2_type uv) + static vector3_type uvToDir(NBL_CONST_REF_ARG(vector2_type) uv) { vector3_type p = vector3_type((uv * scalar_type(2) - scalar_type(1)), scalar_type(0)); const scalar_type a_x = abs(p.x); const scalar_type a_y = abs(p.y); @@ -41,9 +41,9 @@ struct OctahedralTransform } // F^-1 : S^2 -> [-1, 1]^2 - static vector2_type dirToNDC(vector3_type dir) + static vector2_type dirToNDC(NBL_CONST_REF_ARG(vector3_type) d) { - dir = hlsl::normalize(dir); + scalar_type dir = hlsl::normalize(d); const scalar_type sum = hlsl::dot(vector3_type(scalar_type(1), scalar_type(1), scalar_type(1)), abs(dir)); vector3_type s = dir / sum; @@ -61,7 +61,7 @@ struct OctahedralTransform // where halfMinusHalfPixel = 0.5-0.5/texSize // and texSize.x >= 1, texSize.y >= 1 // NOTE/TODO: not best place to keep it here - static vector2_type toCornerSampledUV(vector3_type dir, vector2_type halfMinusHalfPixel) + static vector2_type toCornerSampledUV(NBL_CONST_REF_ARG(vector3_type) dir, NBL_CONST_REF_ARG(vector2_type) halfMinusHalfPixel) { // note: cornerSampled(NDC*0.5+0.5) = NDC*0.5*(1-1/texSize)+0.5 return dirToNDC(dir) * halfMinusHalfPixel + scalar_type(0.5); diff --git a/include/nbl/builtin/hlsl/math/polar.hlsl b/include/nbl/builtin/hlsl/math/polar.hlsl index 7b30e3bb8f..59454e27e6 100644 --- a/include/nbl/builtin/hlsl/math/polar.hlsl +++ b/include/nbl/builtin/hlsl/math/polar.hlsl @@ -14,27 +14,29 @@ namespace hlsl namespace math { -template +template struct Polar { using scalar_type = T; using vector2_type = vector; using vector3_type = vector; - // should be normalized - static Polar createFromCartesian(const vector3_type coords) + // input must be normalized + static Polar createFromCartesian(NBL_CONST_REF_ARG(vector3_type) dir) { Polar retval; - retval.theta = hlsl::acos(coords.z); - retval.phi = hlsl::atan2(coords.y, coords.x); + retval.theta = acos(dir.z); + retval.phi = atan2(dir.y, dir.x); return retval; } - static vector3_type ToCartesian(const scalar_type theta, const scalar_type phi) + static vector3_type ToCartesian(NBL_CONST_REF_ARG(scalar_type) theta, NBL_CONST_REF_ARG(scalar_type) phi) { - return vector(hlsl::cos(phi) * hlsl::cos(theta), - hlsl::sin(phi) * hlsl::cos(theta), - hlsl::sin(theta)); + return vector( + cos(phi) * cos(theta), + sin(phi) * cos(theta), + sin(theta) + ); } vector3_type getCartesian() @@ -42,8 +44,8 @@ struct Polar return ToCartesian(theta, phi); } - scalar_type theta; - scalar_type phi; + scalar_type theta; //! polar angle in range [0, PI] + scalar_type phi; //! azimuthal angle in range [-PI, PI] }; } diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index c981cd3208..55b8b18fc8 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -3,6 +3,7 @@ #include #include "nbl/asset/filters/CBasicImageFilterCommon.h" #include "nbl/builtin/hlsl/math/octahedral.hlsl" +#include "nbl/builtin/hlsl/math/polar.hlsl" using namespace nbl; using namespace asset; @@ -83,14 +84,6 @@ const CIESProfile::IES_STORAGE_FORMAT CIESProfile::sample(IES_STORAGE_FORMAT the return s0 * (1.0 - u) + s1 * u; } -inline std::pair CIESProfile::sphericalDirToRadians(const core::vectorSIMDf& dir) -{ - const float theta = std::acos(std::clamp(dir.z, -1.f, 1.f)); - const float phi = std::atan2(dir.y, dir.x); - - return { theta, phi }; -} - template core::smart_refctd_ptr CIESProfile::createIESTexture(ExecutionPolicy&& policy, const float flatten, const bool fullDomainFlatten, uint32_t width, uint32_t height) const { @@ -172,15 +165,15 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu // If we did, we'd rely on MIRROR and CLAMP samplers to do some of the work for us while handling the discontinuity due to corner sampling. using Octahedral = hlsl::math::OctahedralTransform; + using Polar = hlsl::math::Polar; const auto uv = Octahedral::vector2_type(position.x * vertInv, position.y * horiInv); const auto dir = Octahedral::uvToDir(uv); - const auto tmp = core::vectorSIMDf(dir.x, dir.y, dir.z); - const auto [theta, phi] = sphericalDirToRadians(tmp); - const auto intensity = sample(theta, phi); - + const auto polar = Polar::createFromCartesian(dir); + const auto intensity = sample(polar.theta, polar.phi); + //! blend the IES texture with "flatten" double blendV = intensity * (1.0 - flatten); - if (fullDomainFlatten && domainLo<=theta && theta<=domainHi || intensity >0.0) + if (fullDomainFlatten && domainLo<= polar.theta && polar.theta<=domainHi || intensity >0.0) blendV += flattenTarget * flatten; blendV *= maxValueRecip; diff --git a/src/nbl/asset/utils/CIESProfile.h b/src/nbl/asset/utils/CIESProfile.h index 266b8435ec..1f6b2833e5 100644 --- a/src/nbl/asset/utils/CIESProfile.h +++ b/src/nbl/asset/utils/CIESProfile.h @@ -89,34 +89,6 @@ namespace nbl private: CIESProfile(PhotometricType type, size_t hSize, size_t vSize) : type(type), version(V_SIZE), hAngles(hSize), vAngles(vSize), data(hSize* vSize) {} - - // TODO for @Hazard, I would move it into separate file, we may use this abstraction somewhere too - //! Returns spherical coordinates with physics convention in radians - /* - https://en.wikipedia.org/wiki/Spherical_coordinate_system#/media/File:3D_Spherical.svg - Retval.first is "theta" polar angle in range [0, PI] & Retval.second "phi" is azimuthal angle - in range [-PI, PI] range - - Cartesian coordinates obtained from the spherical coordinates in Nabla - are assumed to have radius equal to 1 and therefore always are - - x = cos(phi)*sin(theta) - y = sin(phi)*sin(theta) - z = cos(theta) - */ - - static inline std::pair sphericalDirToRadians(const core::vectorSIMDf& dir); - - //! Octahedral coordinate mapping is following - /* - center is Z- - U+ from center is X+ - V+ from center is Y+ - - when viewed as a texture, the net folds, and the apex where the seams join is Z+ - */ - - static inline core::vectorSIMDf octahdronUVToDir(const float& u, const float& v); void setCandelaValue(size_t i, size_t j, IES_STORAGE_FORMAT val) { data[vAngles.size() * i + j] = val; } From 7105b0c5594c53f2cc5294cf950a956dd457b2c8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 14 Nov 2025 14:32:48 +0100 Subject: [PATCH 37/61] add include/nbl/builtin/hlsl/ies/profile.hlsl and include/nbl/builtin/hlsl/ies/sampler.hlsl, wipe CIESProfile::sample, save work (won't compile!) --- include/nbl/builtin/hlsl/ies/profile.hlsl | 66 +++++++++ include/nbl/builtin/hlsl/ies/sampler.hlsl | 156 ++++++++++++++++++++++ src/nbl/asset/utils/CIESProfile.cpp | 78 +---------- src/nbl/asset/utils/CIESProfile.h | 111 ++++++--------- 4 files changed, 263 insertions(+), 148 deletions(-) create mode 100644 include/nbl/builtin/hlsl/ies/profile.hlsl create mode 100644 include/nbl/builtin/hlsl/ies/sampler.hlsl diff --git a/include/nbl/builtin/hlsl/ies/profile.hlsl b/include/nbl/builtin/hlsl/ies/profile.hlsl new file mode 100644 index 0000000000..440fe84a98 --- /dev/null +++ b/include/nbl/builtin/hlsl/ies/profile.hlsl @@ -0,0 +1,66 @@ +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h + +#ifndef _NBL_BUILTIN_HLSL_IES_PROFILE_INCLUDED_ +#define _NBL_BUILTIN_HLSL_IES_PROFILE_INCLUDED_ + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" + +namespace nbl +{ +namespace hlsl +{ +namespace ies +{ + +struct ProfileProperties +{ + //! max 16K resolution + NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MAX_TEXTURE_SIZE = 15360u; + NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MAX_TEXTURE_HEIGHT = 8640u; + + NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_DEFAULT_TEXTURE_WIDTH = 1024u; + NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_DEFAULT_TEXTURE_HEIGHT = 1024u; + + NBL_CONSTEXPR_STATIC_INLINE float32_t MAX_VANGLE = 180.f; + NBL_CONSTEXPR_STATIC_INLINE float32_t MAX_HANGLE = 360.f; + + enum Version : uint16_t + { + V_1995, + V_2002, + V_SIZE + }; + + enum PhotometricType : uint16_t + { + TYPE_NONE, + TYPE_C, + TYPE_B, + TYPE_A + }; + + enum LuminairePlanesSymmetry : uint16_t + { + ISOTROPIC, //! Only one horizontal angle present and a luminaire is assumed to be laterally axial symmetric + QUAD_SYMETRIC, //! The luminaire is assumed to be symmetric in each quadrant + HALF_SYMETRIC, //! The luminaire is assumed to be symmetric about the 0 to 180 degree plane + OTHER_HALF_SYMMETRIC, //! HALF_SYMETRIC case for legacy V_1995 version where horizontal angles are in range [90, 270], in that case the parser patches horizontal angles to be HALF_SYMETRIC + NO_LATERAL_SYMMET //! The luminaire is assumed to exhibit no lateral symmet + }; + + PhotometricType type; + Version version; + LuminairePlanesSymmetry symmetry; + + float32_t maxCandelaValue; //! Max value from this->data vector + float32_t totalEmissionIntegral; //! Total energy emitted + float32_t avgEmmision; //! totalEmissionIntegral / +}; + +} +} +} + +#endif // _NBL_BUILTIN_HLSL_IES_PROFILE_INCLUDED_ \ No newline at end of file diff --git a/include/nbl/builtin/hlsl/ies/sampler.hlsl b/include/nbl/builtin/hlsl/ies/sampler.hlsl new file mode 100644 index 0000000000..b8ee40b84f --- /dev/null +++ b/include/nbl/builtin/hlsl/ies/sampler.hlsl @@ -0,0 +1,156 @@ +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h + +#ifndef _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_ +#define _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_ + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#include "nbl/builtin/hlsl/numbers.hlsl" +#include "nbl/builtin/hlsl/concepts.hlsl" +#include "nbl/builtin/hlsl/ies/profile.hlsl" + +namespace nbl +{ +namespace hlsl +{ +namespace ies +{ +namespace concepts +{ +#define NBL_CONCEPT_NAME IESAccessor +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename) +#define NBL_CONCEPT_TPLT_PRM_NAMES (accessor_t) +NBL_CONCEPT_BEGIN(0) +#define req_key_t uint32_t +#define req_key_t2 uint32_t2 +#define req_value_t float32_t +NBL_CONCEPT_END( + ((NBL_CONCEPT_REQ_TYPE)(accessor_t::key_t)) + ((NBL_CONCEPT_REQ_TYPE)(accessor_t::key_t2)) + ((NBL_CONCEPT_REQ_TYPE)(accessor_t::value_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_key_t(0)), is_same_v, typename accessor_t::key_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_key_t2(0, 0)), is_same_v, typename accessor_t::key_t2)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_value_t(0)), is_same_v, typename accessor_t::value_t)) + + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().vAnglesCount()), is_same_v, req_key_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().hAnglesCount()), is_same_v, req_key_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().symmetry()), is_same_v, ProfileProperties::LuminairePlanesSymmetry)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().template vAngle((req_key_t)0)), is_same_v, req_value_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().template hAngle((req_key_t)0)), is_same_v, req_value_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().template value((req_key_t2)0)), is_same_v, req_value_t)) +); +#undef req_key_t +#undef req_key_t2 +#undef req_value_t +#include + +template +NBL_BOOL_CONCEPT IsIESAccessor = IESAccessor; +} + +template) + struct CandelaSampler +{ + using accessor_t = Accessor; + using value_t = typename accessor_t::value_t; + using symmetry_t = ProfileProperties::LuminairePlanesSymmetry; + + static value_t sample(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t2 polar) + { + const float32_t vAngle = degrees(polar.x); + const float32_t hAngle = degrees(wrapPhi(polar.y, symmetry)); + + const float32_t vABack = accessor.vAngle(accessor.vAnglesCount() - 1u); + if (vAngle > vABack) + return 0.f; + + const symmetry_t symmetry = accessor.symmetry(); + const uint32_t j0 = getVLB(accessor, vAngle); + const uint32_t j1 = getVUB(accessor, vAngle); + const uint32_t i0 = (symmetry == ISOTROPIC) ? 0u : getHLB(accessor, hAngle); + const uint32_t i1 = (symmetry == ISOTROPIC) ? 0u : getHUB(accessor, hAngle); + + const float32_t uReciprocal = ((i1 == i0) ? 1.f : 1.f / (accessor.hAngle(i1) - accessor.hAngle(i0))); + const float32_t vReciprocal = ((j1 == j0) ? 1.f : 1.f / (accessor.vAngle(j1) - accessor.vAngle(j0))); + + const float32_t u = ((hAngle - accessor.hAngle(i0)) * uReciprocal); + const float32_t v = ((vAngle - accessor.vAngle(j0)) * vReciprocal); + + const float32_t s0 = (accessor.value(uint32_t2(i0, j0)) * (1.f - v) + accessor.value(uint32_t2(i0, j1)) * v); + const float32_t s1 = (accessor.value(uint32_t2(i1, j0)) * (1.f - v) + accessor.value(uint32_t2(i1, j1)) * v); + + return s0 * (1.f - u) + s1 * u; + } + + static float32_t wrapPhi(const float32_t phi, const symmetry_t symmetry) + { + switch (symmetry) + { + case ISOTROPIC: //! axial symmetry + return 0.0f; + case QUAD_SYMETRIC: //! phi MIRROR_REPEAT wrap onto [0, 90] degrees range + { + NBL_CONSTEXPR float32_t M_HALF_PI = numbers::pi *0.5f; + float32_t wrapPhi = abs(phi); //! first MIRROR + if (wrapPhi > M_HALF_PI) //! then REPEAT + wrapPhi = hlsl::clamp(M_HALF_PI - (wrapPhi - M_HALF_PI), 0.f, M_HALF_PI); + return wrapPhi; //! eg. maps (in degrees) 91,269,271 -> 89 and 179,181,359 -> 1 + } + case HALF_SYMETRIC: //! phi MIRROR wrap onto [0, 180] degrees range + case OTHER_HALF_SYMMETRIC: //! eg. maps (in degress) 181 -> 179 or 359 -> 1 + return abs(phi); + case NO_LATERAL_SYMMET: //! plot onto whole (in degress) [0, 360] range + { + NBL_CONSTEXPR float32_t M_TWICE_PI = numbers::pi *2.f; + return (phi < 0.f) ? (phi + M_TWICE_PI) : phi; + } + } + return 69.f; + } + + struct impl_t + { + static uint32_t getVUB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle) + { + for (uint32_t i = 0u; i < accessor.vAnglesCount(); ++i) + if (accessor.vAngle(i) > angle) + return i; + return accessor.vAnglesCount(); + } + + static uint32_t getHUB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle) + { + for (uint32_t i = 0u; i < accessor.hAnglesCount(); ++i) + if (accessor.hAngle(i) > angle) + return i; + return accessor.hAnglesCount(); + } + }; + + static uint32_t getVLB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle) + { + return (uint32_t)hlsl::max((int64_t)impl_t::getVUB(accessor, angle) - 1ll, 0ll); + } + + static uint32_t getHLB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle) + { + return (uint32_t)hlsl::max((int64_t)impl_t::getHUB(accessor, angle) - 1ll, 0ll); + } + + static uint32_t getVUB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle) + { + return (uint32_t)hlsl::min((int64_t)impl_t::getVUB(accessor, angle), (int64_t)(accessor.vAnglesCount() - 1u)); + } + + static uint32_t getHUB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle) + { + return (uint32_t)hlsl::min((int64_t)impl_t::getHUB(accessor, angle), (int64_t)(accessor.hAnglesCount() - 1u)); + } +}; + +} +} +} + +#endif // _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_ \ No newline at end of file diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index 55b8b18fc8..0a7d72b731 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -8,82 +8,6 @@ using namespace nbl; using namespace asset; -const CIESProfile::IES_STORAGE_FORMAT CIESProfile::sample(IES_STORAGE_FORMAT theta, IES_STORAGE_FORMAT phi) const -{ - auto wrapPhi = [&](const IES_STORAGE_FORMAT& _phi) -> IES_STORAGE_FORMAT - { - constexpr auto M_HALF_PI =core::HALF_PI(); - constexpr auto M_TWICE_PI = core::PI() * 2.0; - - switch (symmetry) - { - case ISOTROPIC: //! axial symmetry - return 0.0; - case QUAD_SYMETRIC: //! phi MIRROR_REPEAT wrap onto [0, 90] degrees range - { - float wrapPhi = abs(_phi); //! first MIRROR - - if (wrapPhi > M_HALF_PI) //! then REPEAT - wrapPhi = std::clamp(M_HALF_PI - (wrapPhi - M_HALF_PI), 0, M_HALF_PI); - - return wrapPhi; //! eg. maps (in degrees) 91,269,271 -> 89 and 179,181,359 -> 1 - } - case HALF_SYMETRIC: //! phi MIRROR wrap onto [0, 180] degrees range - case OTHER_HALF_SYMMETRIC: - return abs(_phi); //! eg. maps (in degress) 181 -> 179 or 359 -> 1 - case NO_LATERAL_SYMMET: //! plot onto whole (in degress) [0, 360] range - { - if (_phi < 0) - return _phi + M_TWICE_PI; - else - return _phi; - } - default: - assert(false); - return 69; - } - }; - - const float vAngle = core::degrees(theta), hAngle = core::degrees(wrapPhi(phi)); - - assert(vAngle >= 0.0 && vAngle <= 180.0); - assert(hAngle >= 0.0 && hAngle <= 360.0); - - if (vAngle > vAngles.back()) - return 0.0; - - // bilinear interpolation - auto lb = [](const core::vector& angles, double angle) -> size_t - { - assert(!angles.empty()); - const size_t idx = std::upper_bound(std::begin(angles), std::end(angles), angle) - std::begin(angles); - return (size_t)std::max((int64_t)idx - 1, (int64_t)0); - }; - - auto ub = [](const core::vector& angles, double angle) -> size_t - { - assert(!angles.empty()); - const size_t idx = std::upper_bound(std::begin(angles), std::end(angles), angle) - std::begin(angles); - return std::min(idx, angles.size() - 1); - }; - - const size_t j0 = lb(vAngles, vAngle); - const size_t j1 = ub(vAngles, vAngle); - const size_t i0 = symmetry == ISOTROPIC ? 0 : lb(hAngles, hAngle); - const size_t i1 = symmetry == ISOTROPIC ? 0 : ub(hAngles, hAngle); - - double uResp = i1 == i0 ? 1.0 : 1.0 / (hAngles[i1] - hAngles[i0]); - double vResp = j1 == j0 ? 1.0 : 1.0 / (vAngles[j1] - vAngles[j0]); - - double u = (hAngle - hAngles[i0]) * uResp; - double v = (vAngle - vAngles[j0]) * vResp; - - double s0 = getCandelaValue(i0, j0) * (1.0 - v) + getCandelaValue(i0, j1) * (v); - double s1 = getCandelaValue(i1, j0) * (1.0 - v) + getCandelaValue(i1, j1) * (v); - - return s0 * (1.0 - u) + s1 * u; -} - template core::smart_refctd_ptr CIESProfile::createIESTexture(ExecutionPolicy&& policy, const float flatten, const bool fullDomainFlatten, uint32_t width, uint32_t height) const { @@ -169,7 +93,7 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu const auto uv = Octahedral::vector2_type(position.x * vertInv, position.y * horiInv); const auto dir = Octahedral::uvToDir(uv); const auto polar = Polar::createFromCartesian(dir); - const auto intensity = sample(polar.theta, polar.phi); + const auto intensity = sampler_t::sample(accessor, hlsl::uint32_t(polar.theta, polar.phi)); //! blend the IES texture with "flatten" double blendV = intensity * (1.0 - flatten); diff --git a/src/nbl/asset/utils/CIESProfile.h b/src/nbl/asset/utils/CIESProfile.h index 1f6b2833e5..1584f17006 100644 --- a/src/nbl/asset/utils/CIESProfile.h +++ b/src/nbl/asset/utils/CIESProfile.h @@ -6,6 +6,7 @@ #define __NBL_ASSET_C_IES_PROFILE_H_INCLUDED__ #include "nbl/asset/metadata/CIESProfileMetadata.h" +#include "nbl/builtin/hlsl/ies/sampler.hlsl" #include namespace nbl @@ -15,99 +16,67 @@ namespace nbl class CIESProfile { public: - using IES_STORAGE_FORMAT = double; + struct properties_t : public nbl::hlsl::ies::ProfileProperties + { + hlsl::uint32_t2 optimalIESResolution; //! Optimal resolution for IES CDC texture + }; - //! max 16K resolution - _NBL_STATIC_INLINE_CONSTEXPR size_t CDC_MAX_TEXTURE_WIDTH = 15360; - _NBL_STATIC_INLINE_CONSTEXPR size_t CDC_MAX_TEXTURE_HEIGHT = 8640; + struct accessor_t + { + using key_t = uint32_t; + using key_t2 = hlsl::uint32_t2; + using value_t = hlsl::float32_t; - _NBL_STATIC_INLINE_CONSTEXPR size_t CDC_DEFAULT_TEXTURE_WIDTH = 1024; - _NBL_STATIC_INLINE_CONSTEXPR size_t CDC_DEFAULT_TEXTURE_HEIGHT = 1024; + accessor_t(const key_t2& resolution, const properties_t& props) : hAngles(resolution.x), vAngles(resolution.y), data(resolution.x * resolution.y), properties(props) {} - _NBL_STATIC_INLINE_CONSTEXPR IES_STORAGE_FORMAT MAX_VANGLE = 180.0; - _NBL_STATIC_INLINE_CONSTEXPR IES_STORAGE_FORMAT MAX_HANGLE = 360.0; + template) + inline value_t vAngle(T j) const { return (value_t)vAngles[j]; } - _NBL_STATIC_INLINE_CONSTEXPR auto UI16_MAX_D = 65535.0; - _NBL_STATIC_INLINE_CONSTEXPR auto IES_TEXTURE_STORAGE_FORMAT = asset::EF_R16_UNORM; + template) + inline value_t hAngle(T i) const { return (value_t)hAngles[i]; } - enum Version : uint8_t - { - V_1995, - V_2002, - V_SIZE - }; + template) + inline value_t value(T ij) const { return (value_t)data[vAnglesCount() * ij.x + ij.y]; } - enum PhotometricType : uint8_t - { - TYPE_NONE, - TYPE_C, - TYPE_B, - TYPE_A - }; + template) + inline void setValue(T ij, value_t val) { data[vAnglesCount() * ij.x + ij.y] = val; } - enum LuminairePlanesSymmetry : uint8_t - { - ISOTROPIC, //! Only one horizontal angle present and a luminaire is assumed to be laterally axial symmetric - QUAD_SYMETRIC, //! The luminaire is assumed to be symmetric in each quadrant - HALF_SYMETRIC, //! The luminaire is assumed to be symmetric about the 0 to 180 degree plane - OTHER_HALF_SYMMETRIC, //! HALF_SYMETRIC case for legacy V_1995 version where horizontal angles are in range [90, 270], in that case the parser patches horizontal angles to be HALF_SYMETRIC - NO_LATERAL_SYMMET //! The luminaire is assumed to exhibit no lateral symmet + inline key_t vAnglesCount() { return (key_t)vAngles.size(); } + inline key_t hAnglesCount() { return (key_t)hAngles.size(); } + inline properties_t::LuminairePlanesSymmetry symmetry() { return properties.symmetry; } + + core::vector hAngles; //! The angular displacement indegreesfrom straight down, a value represents spherical coordinate "theta" with physics convention. Note that if symmetry is OTHER_HALF_SYMMETRIC then real horizontal angle provided by IES data is (hAngles[index] + 90) - the reason behind it is we patch 1995 IES OTHER_HALF_SYMETRIC case to be HALF_SYMETRIC + core::vector vAngles; //! Measurements in degrees of angular displacement measured counterclockwise in a horizontal plane for Type C photometry and clockwise for Type A and B photometry, a value represents spherical coordinate "phi" with physics convention + core::vector data; //! Candela scalar values + properties_t properties; //! Profile properties }; + using sampler_t = nbl::hlsl::ies::CandelaSampler; + CIESProfile() = default; ~CIESProfile() = default; + + inline const accessor_t& getAccessor() const { return accessor; } - auto getType() const { return type; } - auto getVersion() const { return version; } - auto getSymmetry() const { return symmetry; } - - const core::vector& getHoriAngles() const { return hAngles; } - const core::vector& getVertAngles() const { return vAngles; } - const core::vector& getData() const { return data; } - IES_STORAGE_FORMAT getCandelaValue(size_t i, size_t j) const { return data[vAngles.size() * i + j]; } - - IES_STORAGE_FORMAT getMaxCandelaValue() const { return maxCandelaValue; } - IES_STORAGE_FORMAT getTotalEmission() const { return totalEmissionIntegral; } - inline IES_STORAGE_FORMAT getAvgEmmision(const bool fullDomain=false) const + inline hlsl::float32_t getAvgEmmision(const bool fullDomain=false) const { if (fullDomain) { - const float cosLo = std::cos(core::radians(vAngles.front())); - const float cosHi = std::cos(core::radians(vAngles.back())); + const float cosLo = std::cos(core::radians(accessor.vAngles.front())); + const float cosHi = std::cos(core::radians(accessor.vAngles.back())); const float dsinTheta = cosLo - cosHi; - return totalEmissionIntegral*(0.5/core::PI())/dsinTheta; + return accessor.properties.totalEmissionIntegral*(0.5/core::PI())/dsinTheta; } - return avgEmmision; + return accessor.properties.avgEmmision; } - auto getOptimalIESResolution() const { return optimalIESResolution; } - template - core::smart_refctd_ptr createIESTexture(ExecutionPolicy&& policy, const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = CDC_DEFAULT_TEXTURE_HEIGHT) const; - core::smart_refctd_ptr createIESTexture(const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = CDC_DEFAULT_TEXTURE_HEIGHT) const; + core::smart_refctd_ptr createIESTexture(ExecutionPolicy&& policy, const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = properties_t::CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = properties_t::CDC_DEFAULT_TEXTURE_HEIGHT) const; + core::smart_refctd_ptr createIESTexture(const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = properties_t::CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = properties_t::CDC_DEFAULT_TEXTURE_HEIGHT) const; private: - CIESProfile(PhotometricType type, size_t hSize, size_t vSize) - : type(type), version(V_SIZE), hAngles(hSize), vAngles(vSize), data(hSize* vSize) {} - - void setCandelaValue(size_t i, size_t j, IES_STORAGE_FORMAT val) { data[vAngles.size() * i + j] = val; } - - const IES_STORAGE_FORMAT sample(IES_STORAGE_FORMAT vAngle, IES_STORAGE_FORMAT hAngle) const; - - PhotometricType type; - Version version; - LuminairePlanesSymmetry symmetry; - - core::vector hAngles; //! The angular displacement indegreesfrom straight down, a value represents spherical coordinate "theta" with physics convention. Note that if symmetry is OTHER_HALF_SYMMETRIC then real horizontal angle provided by IES data is (hAngles[index] + 90) - the reason behind it is we patch 1995 IES OTHER_HALF_SYMETRIC case to be HALF_SYMETRIC - core::vector vAngles; //! Measurements in degrees of angular displacement measured counterclockwise in a horizontal plane for Type C photometry and clockwise for Type A and B photometry, a value represents spherical coordinate "phi" with physics convention - core::vector data; //! Candela values - - IES_STORAGE_FORMAT maxCandelaValue = {}; //! Max value from this->data vector - IES_STORAGE_FORMAT totalEmissionIntegral = {}; //! Total energy emitted - IES_STORAGE_FORMAT avgEmmision = {}; //! this->totalEmissionIntegral / - - core::vector2du32_SIMD optimalIESResolution; //! optimal resolution for IES profile texture - + CIESProfile(const properties_t& props, const hlsl::uint32_t2& resolution) : accessor(resolution, props) {} + accessor_t accessor; //! IES profile data accessor friend class CIESProfileParser; }; } From 811ced6b75475fc4285447fd1222fd49141adfa3 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 16 Nov 2025 13:59:23 +0100 Subject: [PATCH 38/61] update IES .cpp files, downgrade IES internal scalar storage to float32_t & make Nabla compile again --- include/nbl/builtin/hlsl/ies/profile.hlsl | 4 +- include/nbl/builtin/hlsl/ies/sampler.hlsl | 45 +++++---- include/nbl/builtin/hlsl/math/polar.hlsl | 4 +- .../asset/interchange/CIESProfileLoader.cpp | 2 +- src/nbl/asset/utils/CIESProfile.cpp | 27 +++--- src/nbl/asset/utils/CIESProfile.h | 11 ++- src/nbl/asset/utils/CIESProfileParser.cpp | 96 ++++++++++--------- 7 files changed, 101 insertions(+), 88 deletions(-) diff --git a/include/nbl/builtin/hlsl/ies/profile.hlsl b/include/nbl/builtin/hlsl/ies/profile.hlsl index 440fe84a98..c4b12b3211 100644 --- a/include/nbl/builtin/hlsl/ies/profile.hlsl +++ b/include/nbl/builtin/hlsl/ies/profile.hlsl @@ -17,7 +17,7 @@ namespace ies struct ProfileProperties { //! max 16K resolution - NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MAX_TEXTURE_SIZE = 15360u; + NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MAX_TEXTURE_WIDTH = 15360u; NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MAX_TEXTURE_HEIGHT = 8640u; NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_DEFAULT_TEXTURE_WIDTH = 1024u; @@ -54,7 +54,7 @@ struct ProfileProperties Version version; LuminairePlanesSymmetry symmetry; - float32_t maxCandelaValue; //! Max value from this->data vector + float32_t maxCandelaValue; //! Max scalar value from candela data vector float32_t totalEmissionIntegral; //! Total energy emitted float32_t avgEmmision; //! totalEmissionIntegral / }; diff --git a/include/nbl/builtin/hlsl/ies/sampler.hlsl b/include/nbl/builtin/hlsl/ies/sampler.hlsl index b8ee40b84f..e38bc53551 100644 --- a/include/nbl/builtin/hlsl/ies/sampler.hlsl +++ b/include/nbl/builtin/hlsl/ies/sampler.hlsl @@ -6,7 +6,7 @@ #define _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_ #include "nbl/builtin/hlsl/cpp_compat.hlsl" -#include "nbl/builtin/hlsl/numbers.hlsl" +#include "nbl/builtin/hlsl/math/polar.hlsl" #include "nbl/builtin/hlsl/concepts.hlsl" #include "nbl/builtin/hlsl/ies/profile.hlsl" @@ -21,7 +21,9 @@ namespace concepts #define NBL_CONCEPT_NAME IESAccessor #define NBL_CONCEPT_TPLT_PRM_KINDS (typename) #define NBL_CONCEPT_TPLT_PRM_NAMES (accessor_t) -NBL_CONCEPT_BEGIN(0) +#define NBL_CONCEPT_PARAM_0 (accessor, accessor_t) +NBL_CONCEPT_BEGIN(1) +#define accessor NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 #define req_key_t uint32_t #define req_key_t2 uint32_t2 #define req_value_t float32_t @@ -33,13 +35,14 @@ NBL_CONCEPT_END( ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_key_t2(0, 0)), is_same_v, typename accessor_t::key_t2)) ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_value_t(0)), is_same_v, typename accessor_t::value_t)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().vAnglesCount()), is_same_v, req_key_t)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().hAnglesCount()), is_same_v, req_key_t)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().symmetry()), is_same_v, ProfileProperties::LuminairePlanesSymmetry)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().template vAngle((req_key_t)0)), is_same_v, req_value_t)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().template hAngle((req_key_t)0)), is_same_v, req_value_t)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval().template value((req_key_t2)0)), is_same_v, req_value_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.vAnglesCount()), is_same_v, req_key_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.hAnglesCount()), is_same_v, req_key_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.symmetry()), is_same_v, ProfileProperties::LuminairePlanesSymmetry)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.template vAngle((req_key_t)0)), is_same_v, req_value_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.template hAngle((req_key_t)0)), is_same_v, req_value_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.template value((req_key_t2)0)), is_same_v, req_value_t)) ); +#undef accessor #undef req_key_t #undef req_key_t2 #undef req_value_t @@ -50,26 +53,26 @@ NBL_BOOL_CONCEPT IsIESAccessor = IESAccessor; } template) - struct CandelaSampler +struct CandelaSampler { using accessor_t = Accessor; using value_t = typename accessor_t::value_t; using symmetry_t = ProfileProperties::LuminairePlanesSymmetry; - static value_t sample(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t2 polar) + static value_t sample(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(math::Polar) polar) { - const float32_t vAngle = degrees(polar.x); - const float32_t hAngle = degrees(wrapPhi(polar.y, symmetry)); + const symmetry_t symmetry = accessor.symmetry(); + const float32_t vAngle = degrees(polar.theta); + const float32_t hAngle = degrees(wrapPhi(polar.phi, symmetry)); const float32_t vABack = accessor.vAngle(accessor.vAnglesCount() - 1u); if (vAngle > vABack) return 0.f; - const symmetry_t symmetry = accessor.symmetry(); const uint32_t j0 = getVLB(accessor, vAngle); const uint32_t j1 = getVUB(accessor, vAngle); - const uint32_t i0 = (symmetry == ISOTROPIC) ? 0u : getHLB(accessor, hAngle); - const uint32_t i1 = (symmetry == ISOTROPIC) ? 0u : getHUB(accessor, hAngle); + const uint32_t i0 = (symmetry == symmetry_t::ISOTROPIC) ? 0u : getHLB(accessor, hAngle); + const uint32_t i1 = (symmetry == symmetry_t::ISOTROPIC) ? 0u : getHUB(accessor, hAngle); const float32_t uReciprocal = ((i1 == i0) ? 1.f : 1.f / (accessor.hAngle(i1) - accessor.hAngle(i0))); const float32_t vReciprocal = ((j1 == j0) ? 1.f : 1.f / (accessor.vAngle(j1) - accessor.vAngle(j0))); @@ -87,20 +90,20 @@ template) { switch (symmetry) { - case ISOTROPIC: //! axial symmetry + case symmetry_t::ISOTROPIC: //! axial symmetry return 0.0f; - case QUAD_SYMETRIC: //! phi MIRROR_REPEAT wrap onto [0, 90] degrees range + case symmetry_t::QUAD_SYMETRIC: //! phi MIRROR_REPEAT wrap onto [0, 90] degrees range { - NBL_CONSTEXPR float32_t M_HALF_PI = numbers::pi *0.5f; + NBL_CONSTEXPR float32_t M_HALF_PI = numbers::pi * 0.5f; float32_t wrapPhi = abs(phi); //! first MIRROR if (wrapPhi > M_HALF_PI) //! then REPEAT wrapPhi = hlsl::clamp(M_HALF_PI - (wrapPhi - M_HALF_PI), 0.f, M_HALF_PI); return wrapPhi; //! eg. maps (in degrees) 91,269,271 -> 89 and 179,181,359 -> 1 } - case HALF_SYMETRIC: //! phi MIRROR wrap onto [0, 180] degrees range - case OTHER_HALF_SYMMETRIC: //! eg. maps (in degress) 181 -> 179 or 359 -> 1 + case symmetry_t::HALF_SYMETRIC: //! phi MIRROR wrap onto [0, 180] degrees range + case symmetry_t::OTHER_HALF_SYMMETRIC: //! eg. maps (in degress) 181 -> 179 or 359 -> 1 return abs(phi); - case NO_LATERAL_SYMMET: //! plot onto whole (in degress) [0, 360] range + case symmetry_t::NO_LATERAL_SYMMET: //! plot onto whole (in degress) [0, 360] range { NBL_CONSTEXPR float32_t M_TWICE_PI = numbers::pi *2.f; return (phi < 0.f) ? (phi + M_TWICE_PI) : phi; diff --git a/include/nbl/builtin/hlsl/math/polar.hlsl b/include/nbl/builtin/hlsl/math/polar.hlsl index 59454e27e6..01a95f61ef 100644 --- a/include/nbl/builtin/hlsl/math/polar.hlsl +++ b/include/nbl/builtin/hlsl/math/polar.hlsl @@ -44,8 +44,8 @@ struct Polar return ToCartesian(theta, phi); } - scalar_type theta; //! polar angle in range [0, PI] - scalar_type phi; //! azimuthal angle in range [-PI, PI] + scalar_type theta; //! polar angle + scalar_type phi; //! azimuthal angle }; } diff --git a/src/nbl/asset/interchange/CIESProfileLoader.cpp b/src/nbl/asset/interchange/CIESProfileLoader.cpp index 744756b607..a78c9af0a2 100644 --- a/src/nbl/asset/interchange/CIESProfileLoader.cpp +++ b/src/nbl/asset/interchange/CIESProfileLoader.cpp @@ -60,7 +60,7 @@ asset::SAssetBundle CIESProfileLoader::loadAsset(system::IFile* _file, const ass cpuImageView = _override->findDefaultAsset("nbl/builtin/image_view/dummy2d", loadContex, _hierarchyLevel).first; // note: we could also pass empty content, but this would require adjusting IAssetLoader source to not attempt to use all loaders to find the asset else { - const auto optimalResolution = profile.getOptimalIESResolution(); + const auto optimalResolution = profile.getAccessor().properties.optimalIESResolution; cpuImageView = profile.createIESTexture(0.f, false, optimalResolution.x, optimalResolution.y); } diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index 0a7d72b731..dc66c9693a 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -14,11 +14,11 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu const bool inFlattenDomain = flatten >= 0.0 && flatten <= 1.0; // [0, 1] range for blend equation, 1 is normally invalid but we use it to for special implied domain flatten mode assert(inFlattenDomain); - if (width > CDC_MAX_TEXTURE_WIDTH) - width = CDC_MAX_TEXTURE_WIDTH; + if (width > properties_t::CDC_MAX_TEXTURE_WIDTH) + width = properties_t::CDC_MAX_TEXTURE_WIDTH; - if (height > CDC_MAX_TEXTURE_HEIGHT) - height = CDC_MAX_TEXTURE_HEIGHT; + if (height > properties_t::CDC_MAX_TEXTURE_HEIGHT) + height = properties_t::CDC_MAX_TEXTURE_HEIGHT; // TODO: If no symmetry (no folding in half and abuse of mirror sampler) make dimensions odd-sized so middle texel taps the south pole @@ -36,11 +36,11 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu imgInfo.arrayLayers = 1u; imgInfo.samples = asset::ICPUImage::ESCF_1_BIT; imgInfo.flags = static_cast(0u); - imgInfo.format = IES_TEXTURE_STORAGE_FORMAT; + imgInfo.format = properties_t::IES_TEXTURE_STORAGE_FORMAT; auto outImg = asset::ICPUImage::create(std::move(imgInfo)); asset::ICPUImage::SBufferCopy region; - constexpr auto texelBytesz = asset::getTexelOrBlockBytesize(); + constexpr auto texelBytesz = asset::getTexelOrBlockBytesize(); const size_t bufferRowLength = asset::IImageAssetHandlerBase::calcPitchInBlocks(width, texelBytesz); region.bufferRowLength = bufferRowLength; region.imageExtent = imgInfo.extent; @@ -72,8 +72,8 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu const IImageFilter::IState::ColorValue::WriteMemoryInfo wInfo(creationParams.format, outImg->getBuffer()->getPointer()); // Late Optimization TODO: Modify the Max Value for the UNORM texture to be the Max Value after flatten blending - const double maxValue = getMaxCandelaValue(); - const double maxValueRecip = 1.0 / maxValue; + const auto maxValue = accessor.properties.maxCandelaValue; + const auto maxValueRecip = 1.f / maxValue; // There is one huge issue, the IES files love to give us values for degrees 0, 90, 180 an 360 // So standard octahedral mapping won't work, because for above data points you need corner sampled images. @@ -81,8 +81,8 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu const float horiInv = 1.0 / (width-1); const double flattenTarget = getAvgEmmision(fullDomainFlatten); - const double domainLo = core::radians(vAngles.front()); - const double domainHi = core::radians(vAngles.back()); + const double domainLo = core::radians(accessor.vAngles.front()); + const double domainHi = core::radians(accessor.vAngles.back()); auto fill = [&](uint32_t blockArrayOffset, core::vectorSIMDu32 position) -> void { // We don't currently support generating IES images that exploit symmetries or reduced domains, all are full octahederal mappings of a sphere. @@ -93,10 +93,10 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu const auto uv = Octahedral::vector2_type(position.x * vertInv, position.y * horiInv); const auto dir = Octahedral::uvToDir(uv); const auto polar = Polar::createFromCartesian(dir); - const auto intensity = sampler_t::sample(accessor, hlsl::uint32_t(polar.theta, polar.phi)); + const auto intensity = sampler_t::sample(accessor, polar); //! blend the IES texture with "flatten" - double blendV = intensity * (1.0 - flatten); + float blendV = intensity * (1.f - flatten); if (fullDomainFlatten && domainLo<= polar.theta && polar.theta<=domainHi || intensity >0.0) blendV += flattenTarget * flatten; @@ -104,7 +104,8 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu asset::IImageFilter::IState::ColorValue color; //asset::encodePixels(color.asDouble, &blendV); TODO: FIX THIS ENCODE, GIVES ARTIFACTS - const uint16_t encodeV = static_cast(std::clamp(blendV * UI16_MAX_D + 0.5, 0.0, UI16_MAX_D)); + constexpr float UI16_MAX_D = static_cast(std::numeric_limits::max()); + const uint16_t encodeV = static_cast(std::clamp(blendV * UI16_MAX_D + 0.5f, 0.f, UI16_MAX_D)); *color.asUShort = encodeV; color.writeMemory(wInfo, blockArrayOffset); }; diff --git a/src/nbl/asset/utils/CIESProfile.h b/src/nbl/asset/utils/CIESProfile.h index 1584f17006..a165b0ae49 100644 --- a/src/nbl/asset/utils/CIESProfile.h +++ b/src/nbl/asset/utils/CIESProfile.h @@ -18,6 +18,7 @@ namespace nbl public: struct properties_t : public nbl::hlsl::ies::ProfileProperties { + NBL_CONSTEXPR_STATIC_INLINE auto IES_TEXTURE_STORAGE_FORMAT = asset::EF_R16_UNORM; hlsl::uint32_t2 optimalIESResolution; //! Optimal resolution for IES CDC texture }; @@ -27,7 +28,9 @@ namespace nbl using key_t2 = hlsl::uint32_t2; using value_t = hlsl::float32_t; + accessor_t() = default; accessor_t(const key_t2& resolution, const properties_t& props) : hAngles(resolution.x), vAngles(resolution.y), data(resolution.x * resolution.y), properties(props) {} + ~accessor_t() = default; template) inline value_t vAngle(T j) const { return (value_t)vAngles[j]; } @@ -41,9 +44,9 @@ namespace nbl template) inline void setValue(T ij, value_t val) { data[vAnglesCount() * ij.x + ij.y] = val; } - inline key_t vAnglesCount() { return (key_t)vAngles.size(); } - inline key_t hAnglesCount() { return (key_t)hAngles.size(); } - inline properties_t::LuminairePlanesSymmetry symmetry() { return properties.symmetry; } + inline key_t vAnglesCount() const { return (key_t)vAngles.size(); } + inline key_t hAnglesCount() const { return (key_t)hAngles.size(); } + inline properties_t::LuminairePlanesSymmetry symmetry() const { return properties.symmetry; } core::vector hAngles; //! The angular displacement indegreesfrom straight down, a value represents spherical coordinate "theta" with physics convention. Note that if symmetry is OTHER_HALF_SYMMETRIC then real horizontal angle provided by IES data is (hAngles[index] + 90) - the reason behind it is we patch 1995 IES OTHER_HALF_SYMETRIC case to be HALF_SYMETRIC core::vector vAngles; //! Measurements in degrees of angular displacement measured counterclockwise in a horizontal plane for Type C photometry and clockwise for Type A and B photometry, a value represents spherical coordinate "phi" with physics convention @@ -76,7 +79,7 @@ namespace nbl private: CIESProfile(const properties_t& props, const hlsl::uint32_t2& resolution) : accessor(resolution, props) {} - accessor_t accessor; //! IES profile data accessor + accessor_t accessor; friend class CIESProfileParser; }; } diff --git a/src/nbl/asset/utils/CIESProfileParser.cpp b/src/nbl/asset/utils/CIESProfileParser.cpp index dd6b321414..96285b6a6d 100644 --- a/src/nbl/asset/utils/CIESProfileParser.cpp +++ b/src/nbl/asset/utils/CIESProfileParser.cpp @@ -33,16 +33,16 @@ bool CIESProfileParser::parse(CIESProfile& result) std::getline(ss, line); removeTrailingWhiteChars(line); - CIESProfile::Version iesVersion; - + + CIESProfile::properties_t::Version iesVersion; if (line.find(SIG_LM63_1995.data()) != std::string::npos) - iesVersion = CIESProfile::V_1995; + iesVersion = CIESProfile::properties_t::V_1995; else if (line.find(SIG_LM63_2002.data()) != std::string::npos) - iesVersion = CIESProfile::V_2002; + iesVersion = CIESProfile::properties_t::V_2002; else if (line.find(SIG_IESNA91.data()) != std::string::npos) - iesVersion = CIESProfile::V_1995; + iesVersion = CIESProfile::properties_t::V_1995; else if (line.find(SIG_ERCO_LG.data()) != std::string::npos) - iesVersion = CIESProfile::V_1995; + iesVersion = CIESProfile::properties_t::V_1995; else { errorMsg = "Unknown IESNA:LM-63 version, the IES input being parsed is invalid!"; @@ -82,9 +82,8 @@ bool CIESProfileParser::parse(CIESProfile& result) errorMsg = "unrecognized type"; return false; } - CIESProfile::PhotometricType type = - static_cast(type_); - if (type != CIESProfile::PhotometricType::TYPE_C) { + auto type = static_cast(type_); + if (type != CIESProfile::properties_t::TYPE_C) { errorMsg = "Only type C is supported for now"; return false; } @@ -100,32 +99,39 @@ bool CIESProfileParser::parse(CIESProfile& result) if (error) return false; - result = CIESProfile(type, hSize, vSize); - result.version = iesVersion; + { + CIESProfile::properties_t init; + init.type = type; + init.version = iesVersion; + init.maxCandelaValue = 0.f; + init.totalEmissionIntegral = 0.f; + init.avgEmmision = 0.f; + result = CIESProfile(init, hlsl::uint32_t2(hSize, vSize)); + } if (vSize < 2) return false; - auto& vAngles = result.vAngles; + auto& vAngles = result.accessor.vAngles; for (int i = 0; i < vSize; i++) { - vAngles[i] = getDouble("vertical angle truncated"); + vAngles[i] = static_cast(getDouble("vertical angle truncated")); } if (!std::is_sorted(vAngles.begin(), vAngles.end())) { errorMsg = "Vertical angles should be sorted"; return false; } - if (vAngles[0] != 0.0 && vAngles[0] != 90.0) { + if (vAngles[0] != 0.f && vAngles[0] != 90.f) { errorMsg = "First vertical angle must be 0 or 90 in type C"; return false; } - if (vAngles[vSize - 1] != 90.0 && vAngles[vSize - 1] != 180.0) { + if (vAngles[vSize - 1] != 90.f && vAngles[vSize - 1] != 180.f) { errorMsg = "Last vertical angle must be 90 or 180 in type C"; return false; } - auto& hAngles = result.hAngles; + auto& hAngles = result.accessor.hAngles; for (int i = 0; i < hSize; i++) { - hAngles[i] = getDouble("horizontal angle truncated"); + hAngles[i] = static_cast(getDouble("horizontal angle truncated")); if (i != 0 && hAngles[i - 1] > hAngles[i]) return false; // Angles should be sorted } @@ -135,26 +141,26 @@ bool CIESProfileParser::parse(CIESProfile& result) const auto firstHAngle = hAngles.front(); const auto lastHAngle = hAngles.back(); - if (lastHAngle == 0) - result.symmetry = CIESProfile::ISOTROPIC; - else if (lastHAngle == 90) + if (lastHAngle == 0.f) + result.accessor.properties.symmetry = CIESProfile::properties_t::ISOTROPIC; + else if (lastHAngle == 90.f) { - result.symmetry = CIESProfile::QUAD_SYMETRIC; - fluxMultiplier = 4.0; + result.accessor.properties.symmetry = CIESProfile::properties_t::QUAD_SYMETRIC; + fluxMultiplier = 4.f; } - else if (lastHAngle == 180) + else if (lastHAngle == 180.f) { - result.symmetry = CIESProfile::HALF_SYMETRIC; + result.accessor.properties.symmetry = CIESProfile::properties_t::HALF_SYMETRIC; fluxMultiplier = 2.0; } - else if (lastHAngle == 360) - result.symmetry = CIESProfile::NO_LATERAL_SYMMET; + else if (lastHAngle == 360.f) + result.accessor.properties.symmetry = CIESProfile::properties_t::NO_LATERAL_SYMMET; else { - if (firstHAngle == 90 && lastHAngle == 270 && result.version == CIESProfile::V_1995) + if (firstHAngle == 90.f && lastHAngle == 270.f && result.accessor.properties.version == CIESProfile::properties_t::V_1995) { - result.symmetry = CIESProfile::OTHER_HALF_SYMMETRIC; - fluxMultiplier = 2.0; + result.accessor.properties.symmetry = CIESProfile::properties_t::OTHER_HALF_SYMMETRIC; + fluxMultiplier = 2.f; for (auto& angle : hAngles) angle -= firstHAngle; // patch the profile to HALF_SYMETRIC by shifting [90,270] range to [0, 180] @@ -168,44 +174,44 @@ bool CIESProfileParser::parse(CIESProfile& result) const double factor = ballastFactor * candelaMultiplier; for (int i = 0; i < hSize; i++) for (int j = 0; j < vSize; j++) - result.setCandelaValue(i, j, factor * getDouble("intensity value truncated")); + result.accessor.setValue(hlsl::uint32_t2(i, j), static_cast(factor * getDouble("intensity value truncated"))); } float totalEmissionIntegral = 0.0, nonZeroEmissionDomainSize = 0.0; constexpr auto FULL_SOLID_ANGLE = 4.0f * core::PI(); // TODO: this code could have two separate inner for loops for `result.symmetry != CIESProfile::ISOTROPIC` cases - const auto H_ANGLES_I_RANGE = result.symmetry != CIESProfile::ISOTROPIC ? result.hAngles.size() - 1 : 1; - const auto V_ANGLES_I_RANGE = result.vAngles.size() - 1; + const auto H_ANGLES_I_RANGE = result.accessor.properties.symmetry != CIESProfile::properties_t::ISOTROPIC ? result.accessor.hAngles.size() - 1 : 1; + const auto V_ANGLES_I_RANGE = result.accessor.vAngles.size() - 1; float smallestRangeSolidAngle = FULL_SOLID_ANGLE; for (size_t j = 0; j < V_ANGLES_I_RANGE; j++) { - const float thetaRad = core::radians(result.vAngles[j]); + const float thetaRad = core::radians(result.accessor.vAngles[j]); const float cosLo = std::cos(thetaRad); - const float cosHi = std::cos(core::radians(result.vAngles[j+1])); + const float cosHi = std::cos(core::radians(result.accessor.vAngles[j+1])); const float dsinTheta = cosLo - cosHi; float stripIntegral = 0.f; float nonZeroStripDomain = 0.f; for (size_t i = 0; i < H_ANGLES_I_RANGE; i++) { - const float dPhiRad = result.symmetry != CIESProfile::ISOTROPIC ? core::radians(hAngles[i + 1] - hAngles[i]) : (core::PI() * 2.0f); + const float dPhiRad = result.accessor.properties.symmetry != CIESProfile::properties_t::ISOTROPIC ? core::radians(hAngles[i + 1] - hAngles[i]) : (core::PI() * 2.0f); // TODO: in reality one should transform the 4 vertices (or 3) into octahedral map, work out the dUV/dPhi and dUV/dTheta vectors as-if for Anisotropic Filtering // then choose the minor axis length, and use that as a pixel size (since looking for smallest thing, dont have to worry about handling discont) const float solidAngle = dsinTheta * dPhiRad; if (solidAngle0.f) @@ -218,8 +224,8 @@ bool CIESProfileParser::parse(CIESProfile& result) // assuming octahedral map { const uint32_t maxDimMeasureSize = core::sqrt(FULL_SOLID_ANGLE/smallestRangeSolidAngle); - result.optimalIESResolution = decltype(result.optimalIESResolution){ maxDimMeasureSize, maxDimMeasureSize }; - result.optimalIESResolution *= 2u; // safe bias for our bilinear interpolation to work nicely and increase resolution of a profile + result.accessor.properties.optimalIESResolution = decltype(result.accessor.properties.optimalIESResolution){ maxDimMeasureSize, maxDimMeasureSize }; + result.accessor.properties.optimalIESResolution *= 2u; // safe bias for our bilinear interpolation to work nicely and increase resolution of a profile } assert(nonZeroEmissionDomainSize >= 0.f); @@ -227,8 +233,8 @@ bool CIESProfileParser::parse(CIESProfile& result) if (nonZeroEmissionDomainSize <= std::numeric_limits::min()) // protect us from division by small numbers (just in case, we should never hit it) return false; - result.avgEmmision = totalEmissionIntegral / static_cast(nonZeroEmissionDomainSize); - result.totalEmissionIntegral = totalEmissionIntegral * fluxMultiplier; // we use fluxMultiplier to calculate final total emission for case where we have some symmetry between planes (fluxMultiplier is 1.0f if ISOTROPIC or NO_LATERAL_SYMMET because they already have correct total emission integral calculated), also note it doesn't affect average emission at all + result.accessor.properties.avgEmmision = totalEmissionIntegral / static_cast(nonZeroEmissionDomainSize); + result.accessor.properties.totalEmissionIntegral = totalEmissionIntegral * fluxMultiplier; // we use fluxMultiplier to calculate final total emission for case where we have some symmetry between planes (fluxMultiplier is 1.0f if ISOTROPIC or NO_LATERAL_SYMMET because they already have correct total emission integral calculated), also note it doesn't affect average emission at all return !error; } \ No newline at end of file From 80d4479b1b9c01d8fd8a213dd1575f7203278d41 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 24 Nov 2025 16:50:45 +0100 Subject: [PATCH 39/61] a few updates due to WAVE, ambiguity and DXC bugs, new ImGui/builtin/hlsl/pc.hlsl to allow me precompile unified uber shader, a little formatting, update examples_tests submodule --- examples_tests | 2 +- include/nbl/builtin/hlsl/ies/profile.hlsl | 2 +- include/nbl/builtin/hlsl/ies/sampler.hlsl | 9 +- include/nbl/builtin/hlsl/math/octahedral.hlsl | 6 +- .../nbl/ext/ImGui/builtin/hlsl/fragment.hlsl | 4 +- include/nbl/ext/ImGui/builtin/hlsl/pc.hlsl | 8 ++ .../nbl/ext/ImGui/builtin/hlsl/vertex.hlsl | 4 +- src/nbl/asset/utils/CIESProfile.h | 121 +++++++++--------- src/nbl/ext/ImGui/CMakeLists.txt | 7 +- 9 files changed, 84 insertions(+), 79 deletions(-) create mode 100644 include/nbl/ext/ImGui/builtin/hlsl/pc.hlsl diff --git a/examples_tests b/examples_tests index 4cd5f027ea..65e0126cac 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 4cd5f027eabdf88f84e16d47f8fdc6acdd1d36b4 +Subproject commit 65e0126cac320c10efe34ebbc144da45d587a54e diff --git a/include/nbl/builtin/hlsl/ies/profile.hlsl b/include/nbl/builtin/hlsl/ies/profile.hlsl index c4b12b3211..88e212f069 100644 --- a/include/nbl/builtin/hlsl/ies/profile.hlsl +++ b/include/nbl/builtin/hlsl/ies/profile.hlsl @@ -63,4 +63,4 @@ struct ProfileProperties } } -#endif // _NBL_BUILTIN_HLSL_IES_PROFILE_INCLUDED_ \ No newline at end of file +#endif // _NBL_BUILTIN_HLSL_IES_PROFILE_INCLUDED_ diff --git a/include/nbl/builtin/hlsl/ies/sampler.hlsl b/include/nbl/builtin/hlsl/ies/sampler.hlsl index e38bc53551..3f518ff21a 100644 --- a/include/nbl/builtin/hlsl/ies/sampler.hlsl +++ b/include/nbl/builtin/hlsl/ies/sampler.hlsl @@ -61,7 +61,8 @@ struct CandelaSampler static value_t sample(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(math::Polar) polar) { - const symmetry_t symmetry = accessor.symmetry(); + // TODO: DXC seems to have a bug and cannot use symmetry_t directly with == operator https://godbolt.devsh.eu/z/P9Kc5x + const ProfileProperties::LuminairePlanesSymmetry symmetry = accessor.symmetry(); const float32_t vAngle = degrees(polar.theta); const float32_t hAngle = degrees(wrapPhi(polar.phi, symmetry)); @@ -71,8 +72,8 @@ struct CandelaSampler const uint32_t j0 = getVLB(accessor, vAngle); const uint32_t j1 = getVUB(accessor, vAngle); - const uint32_t i0 = (symmetry == symmetry_t::ISOTROPIC) ? 0u : getHLB(accessor, hAngle); - const uint32_t i1 = (symmetry == symmetry_t::ISOTROPIC) ? 0u : getHUB(accessor, hAngle); + const uint32_t i0 = (symmetry == ProfileProperties::LuminairePlanesSymmetry::ISOTROPIC) ? 0u : getHLB(accessor, hAngle); + const uint32_t i1 = (symmetry == ProfileProperties::LuminairePlanesSymmetry::ISOTROPIC) ? 0u : getHUB(accessor, hAngle); const float32_t uReciprocal = ((i1 == i0) ? 1.f : 1.f / (accessor.hAngle(i1) - accessor.hAngle(i0))); const float32_t vReciprocal = ((j1 == j0) ? 1.f : 1.f / (accessor.vAngle(j1) - accessor.vAngle(j0))); @@ -156,4 +157,4 @@ struct CandelaSampler } } -#endif // _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_ \ No newline at end of file +#endif // _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_ diff --git a/include/nbl/builtin/hlsl/math/octahedral.hlsl b/include/nbl/builtin/hlsl/math/octahedral.hlsl index 8e32d60cb0..45fe35b2d8 100644 --- a/include/nbl/builtin/hlsl/math/octahedral.hlsl +++ b/include/nbl/builtin/hlsl/math/octahedral.hlsl @@ -43,8 +43,8 @@ struct OctahedralTransform // F^-1 : S^2 -> [-1, 1]^2 static vector2_type dirToNDC(NBL_CONST_REF_ARG(vector3_type) d) { - scalar_type dir = hlsl::normalize(d); - const scalar_type sum = hlsl::dot(vector3_type(scalar_type(1), scalar_type(1), scalar_type(1)), abs(dir)); + vector3_type dir = hlsl::normalize(d); + const scalar_type sum = dot(vector3_type(scalar_type(1), scalar_type(1), scalar_type(1)), abs(dir)); vector3_type s = dir / sum; if (s.z < scalar_type(0)) @@ -72,4 +72,4 @@ struct OctahedralTransform } } -#endif // _NBL_BUILTIN_HLSL_MATH_OCTAHEDRAL_INCLUDED_ \ No newline at end of file +#endif // _NBL_BUILTIN_HLSL_MATH_OCTAHEDRAL_INCLUDED_ diff --git a/include/nbl/ext/ImGui/builtin/hlsl/fragment.hlsl b/include/nbl/ext/ImGui/builtin/hlsl/fragment.hlsl index 44ef6a0cb1..a0e70dfebd 100644 --- a/include/nbl/ext/ImGui/builtin/hlsl/fragment.hlsl +++ b/include/nbl/ext/ImGui/builtin/hlsl/fragment.hlsl @@ -22,13 +22,11 @@ #error "NBL_SAMPLERS_COUNT must be defined!" #endif -#include "common.hlsl" +#include "pc.hlsl" #include "psinput.hlsl" using namespace nbl::ext::imgui; -[[vk::push_constant]] struct PushConstants pc; - // separable image samplers to handle textures we do descriptor-index [[vk::binding(NBL_TEXTURES_BINDING_IX, NBL_TEXTURES_SET_IX)]] Texture2D textures[NBL_TEXTURES_COUNT]; [[vk::binding(NBL_SAMPLER_STATES_BINDING_IX, NBL_SAMPLER_STATES_SET_IX)]] SamplerState samplerStates[NBL_SAMPLERS_COUNT]; diff --git a/include/nbl/ext/ImGui/builtin/hlsl/pc.hlsl b/include/nbl/ext/ImGui/builtin/hlsl/pc.hlsl new file mode 100644 index 0000000000..103ce5b6c1 --- /dev/null +++ b/include/nbl/ext/ImGui/builtin/hlsl/pc.hlsl @@ -0,0 +1,8 @@ +#ifndef _NBL_IMGUI_EXT_PC_HLSL_ +#define _NBL_IMGUI_EXT_PC_HLSL_ + +// TODO: have only unified.hlsl uber shader and common.hlsl then update imgui cpp files, doing a quick workaround for my prebuilds +#include "common.hlsl" +[[vk::push_constant]] struct nbl::ext::imgui::PushConstants pc; + +#endif // _NBL_IMGUI_EXT_PC_HLSL_ diff --git a/include/nbl/ext/ImGui/builtin/hlsl/vertex.hlsl b/include/nbl/ext/ImGui/builtin/hlsl/vertex.hlsl index 78dbe10ac7..ef4582146e 100644 --- a/include/nbl/ext/ImGui/builtin/hlsl/vertex.hlsl +++ b/include/nbl/ext/ImGui/builtin/hlsl/vertex.hlsl @@ -1,10 +1,8 @@ -#include "common.hlsl" +#include "pc.hlsl" #include "psinput.hlsl" using namespace nbl::ext::imgui; -[[vk::push_constant]] struct PushConstants pc; - struct VSInput { [[vk::location(0)]] float2 position : POSITION; diff --git a/src/nbl/asset/utils/CIESProfile.h b/src/nbl/asset/utils/CIESProfile.h index a165b0ae49..c09f2fd760 100644 --- a/src/nbl/asset/utils/CIESProfile.h +++ b/src/nbl/asset/utils/CIESProfile.h @@ -7,82 +7,81 @@ #include "nbl/asset/metadata/CIESProfileMetadata.h" #include "nbl/builtin/hlsl/ies/sampler.hlsl" -#include namespace nbl { - namespace asset - { - class CIESProfile +namespace asset +{ +class CIESProfile +{ + public: + struct properties_t : public nbl::hlsl::ies::ProfileProperties { - public: - struct properties_t : public nbl::hlsl::ies::ProfileProperties - { - NBL_CONSTEXPR_STATIC_INLINE auto IES_TEXTURE_STORAGE_FORMAT = asset::EF_R16_UNORM; - hlsl::uint32_t2 optimalIESResolution; //! Optimal resolution for IES CDC texture - }; + NBL_CONSTEXPR_STATIC_INLINE auto IES_TEXTURE_STORAGE_FORMAT = asset::EF_R16_UNORM; + hlsl::uint32_t2 optimalIESResolution; //! Optimal resolution for IES CDC texture + }; - struct accessor_t - { - using key_t = uint32_t; - using key_t2 = hlsl::uint32_t2; - using value_t = hlsl::float32_t; + struct accessor_t + { + using key_t = uint32_t; + using key_t2 = hlsl::uint32_t2; + using value_t = hlsl::float32_t; - accessor_t() = default; - accessor_t(const key_t2& resolution, const properties_t& props) : hAngles(resolution.x), vAngles(resolution.y), data(resolution.x * resolution.y), properties(props) {} - ~accessor_t() = default; + accessor_t() = default; + accessor_t(const key_t2& resolution, const properties_t& props) : hAngles(resolution.x), vAngles(resolution.y), data(resolution.x * resolution.y), properties(props) {} + ~accessor_t() = default; - template) - inline value_t vAngle(T j) const { return (value_t)vAngles[j]; } + template) + inline value_t vAngle(T j) const { return (value_t)vAngles[j]; } - template) - inline value_t hAngle(T i) const { return (value_t)hAngles[i]; } + template) + inline value_t hAngle(T i) const { return (value_t)hAngles[i]; } - template) - inline value_t value(T ij) const { return (value_t)data[vAnglesCount() * ij.x + ij.y]; } + template) + inline value_t value(T ij) const { return (value_t)data[vAnglesCount() * ij.x + ij.y]; } - template) - inline void setValue(T ij, value_t val) { data[vAnglesCount() * ij.x + ij.y] = val; } + template) + inline void setValue(T ij, value_t val) { data[vAnglesCount() * ij.x + ij.y] = val; } - inline key_t vAnglesCount() const { return (key_t)vAngles.size(); } - inline key_t hAnglesCount() const { return (key_t)hAngles.size(); } - inline properties_t::LuminairePlanesSymmetry symmetry() const { return properties.symmetry; } + inline key_t vAnglesCount() const { return (key_t)vAngles.size(); } + inline key_t hAnglesCount() const { return (key_t)hAngles.size(); } + inline properties_t::LuminairePlanesSymmetry symmetry() const { return properties.symmetry; } - core::vector hAngles; //! The angular displacement indegreesfrom straight down, a value represents spherical coordinate "theta" with physics convention. Note that if symmetry is OTHER_HALF_SYMMETRIC then real horizontal angle provided by IES data is (hAngles[index] + 90) - the reason behind it is we patch 1995 IES OTHER_HALF_SYMETRIC case to be HALF_SYMETRIC - core::vector vAngles; //! Measurements in degrees of angular displacement measured counterclockwise in a horizontal plane for Type C photometry and clockwise for Type A and B photometry, a value represents spherical coordinate "phi" with physics convention - core::vector data; //! Candela scalar values - properties_t properties; //! Profile properties - }; + core::vector hAngles; //! The angular displacement indegreesfrom straight down, a value represents spherical coordinate "theta" with physics convention. Note that if symmetry is OTHER_HALF_SYMMETRIC then real horizontal angle provided by IES data is (hAngles[index] + 90) - the reason behind it is we patch 1995 IES OTHER_HALF_SYMETRIC case to be HALF_SYMETRIC + core::vector vAngles; //! Measurements in degrees of angular displacement measured counterclockwise in a horizontal plane for Type C photometry and clockwise for Type A and B photometry, a value represents spherical coordinate "phi" with physics convention + core::vector data; //! Candela scalar values + properties_t properties; //! Profile properties + }; - using sampler_t = nbl::hlsl::ies::CandelaSampler; + using sampler_t = nbl::hlsl::ies::CandelaSampler; - CIESProfile() = default; - ~CIESProfile() = default; + CIESProfile() = default; + ~CIESProfile() = default; - inline const accessor_t& getAccessor() const { return accessor; } - - inline hlsl::float32_t getAvgEmmision(const bool fullDomain=false) const - { - if (fullDomain) - { - const float cosLo = std::cos(core::radians(accessor.vAngles.front())); - const float cosHi = std::cos(core::radians(accessor.vAngles.back())); - const float dsinTheta = cosLo - cosHi; - return accessor.properties.totalEmissionIntegral*(0.5/core::PI())/dsinTheta; - } - return accessor.properties.avgEmmision; - } - - template - core::smart_refctd_ptr createIESTexture(ExecutionPolicy&& policy, const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = properties_t::CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = properties_t::CDC_DEFAULT_TEXTURE_HEIGHT) const; - core::smart_refctd_ptr createIESTexture(const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = properties_t::CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = properties_t::CDC_DEFAULT_TEXTURE_HEIGHT) const; - - private: - CIESProfile(const properties_t& props, const hlsl::uint32_t2& resolution) : accessor(resolution, props) {} - accessor_t accessor; - friend class CIESProfileParser; - }; - } + inline const accessor_t& getAccessor() const { return accessor; } + + inline hlsl::float32_t getAvgEmmision(const bool fullDomain=false) const + { + if (fullDomain) + { + const float cosLo = std::cos(core::radians(accessor.vAngles.front())); + const float cosHi = std::cos(core::radians(accessor.vAngles.back())); + const float dsinTheta = cosLo - cosHi; + return accessor.properties.totalEmissionIntegral*(0.5/core::PI())/dsinTheta; + } + return accessor.properties.avgEmmision; + } + + template + core::smart_refctd_ptr createIESTexture(ExecutionPolicy&& policy, const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = properties_t::CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = properties_t::CDC_DEFAULT_TEXTURE_HEIGHT) const; + core::smart_refctd_ptr createIESTexture(const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = properties_t::CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = properties_t::CDC_DEFAULT_TEXTURE_HEIGHT) const; + + private: + CIESProfile(const properties_t& props, const hlsl::uint32_t2& resolution) : accessor(resolution, props) {} + accessor_t accessor; + friend class CIESProfileParser; +}; +} } #endif // __NBL_ASSET_C_IES_PROFILE_H_INCLUDED__ \ No newline at end of file diff --git a/src/nbl/ext/ImGui/CMakeLists.txt b/src/nbl/ext/ImGui/CMakeLists.txt index 2c339b2b00..e46d93b952 100644 --- a/src/nbl/ext/ImGui/CMakeLists.txt +++ b/src/nbl/ext/ImGui/CMakeLists.txt @@ -33,13 +33,14 @@ target_compile_definitions(${LIB_NAME} PRIVATE _ARCHIVE_ABSOLUTE_ENTRY_PATH_="${ target_compile_definitions(${LIB_NAME} PRIVATE _ARCHIVE_ENTRY_KEY_="${_ARCHIVE_ENTRY_KEY_}") if(NBL_EMBED_BUILTIN_RESOURCES) - # (*) -> I wish we could just take NSC, offline-precompile to SPIRV, embed into builtin resource library (as we did!) but then be smart & adjust at runtime OpDecorate of our resources according to wishes - unfortunately no linker yet we have and we are not going to make one ourselves so we compile imgui shaders at runtime set(_BR_TARGET_ extImguibuiltinResourceData) + # TODO: one uber shader and common.hlsl LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "common.hlsl") + LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "pc.hlsl") LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "psinput.hlsl") - LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "vertex.hlsl") # (*) -> this we could precompile [no resources for which set/binding Ixs could be adjusted] but I'm not going to mix stuff - LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "fragment.hlsl") # (*) -> but this we could not since we let users to provide external descriptor set layout + ImGUI textures & sampler state set/binding Ixs (for pipeline layout) at runtime + LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "vertex.hlsl") + LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "fragment.hlsl") ADD_CUSTOM_BUILTIN_RESOURCES(${_BR_TARGET_} RESOURCES_TO_EMBED "${_ARCHIVE_ABSOLUTE_ENTRY_PATH_}" "${_ARCHIVE_ENTRY_KEY_}" "nbl::ext::imgui::builtin" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}") LINK_BUILTIN_RESOURCES_TO_TARGET(${LIB_NAME} ${_BR_TARGET_}) From 1a25fc0800786ad2a55201f97e1ee384db6fcf66 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 25 Nov 2025 09:54:15 +0100 Subject: [PATCH 40/61] fix another ambiguity, finally my unified IES shader compiled --- include/nbl/builtin/hlsl/surface_transform.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/nbl/builtin/hlsl/surface_transform.h b/include/nbl/builtin/hlsl/surface_transform.h index 2d7afa7add..bfe2f2cbba 100644 --- a/include/nbl/builtin/hlsl/surface_transform.h +++ b/include/nbl/builtin/hlsl/surface_transform.h @@ -174,8 +174,7 @@ inline float32_t2 applyToNDC(const FLAG_BITS transform, const float32_t2 ndc) template TwoColumns applyToDerivatives(const FLAG_BITS transform, TwoColumns dDx_dDy) { - using namespace glsl; // IN HLSL mode, C++ doens't need this to access `inverse` - return mul(inverse(transformMatrix(transform)),dDx_dDy); + return mul(glsl::inverse(transformMatrix(transform)),dDx_dDy); } } From 83da9c59c8c4ae0584872f99f1ce95c3abea5dab Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 25 Nov 2025 10:40:47 +0100 Subject: [PATCH 41/61] ah I broke nabla build, this one fixes the ambiguity and compiles for both cpp and hlsl --- include/nbl/builtin/hlsl/surface_transform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/builtin/hlsl/surface_transform.h b/include/nbl/builtin/hlsl/surface_transform.h index bfe2f2cbba..0b93434fe0 100644 --- a/include/nbl/builtin/hlsl/surface_transform.h +++ b/include/nbl/builtin/hlsl/surface_transform.h @@ -174,7 +174,7 @@ inline float32_t2 applyToNDC(const FLAG_BITS transform, const float32_t2 ndc) template TwoColumns applyToDerivatives(const FLAG_BITS transform, TwoColumns dDx_dDy) { - return mul(glsl::inverse(transformMatrix(transform)),dDx_dDy); + return mul(inverse(transformMatrix(transform)),dDx_dDy); } } From 7c5b658d310cd0a6a0357a5450bb4e157cd2cf2a Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 25 Nov 2025 11:17:25 +0100 Subject: [PATCH 42/61] add source groups, include HLSL files in solution --- src/nbl/CMakeLists.txt | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index 5ab4061eb8..3ebecfbb28 100644 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -103,7 +103,7 @@ if (NBL_COMPILE_WITH_CUDA) endif() endif() -# => TODO: clean +# => TODO: clean! # a little bit of globbing for headers never hurt anyone file(GLOB_RECURSE TEMP_GLOB_RES "${NBL_ROOT_PATH}/include/*.h") set(NABLA_HEADERS_PUBLIC ${NABLA_HEADERS_PUBLIC} ${TEMP_GLOB_RES}) @@ -112,6 +112,9 @@ set(NABLA_HEADERS_PUBLIC ${NABLA_HEADERS_PUBLIC} ${TEMP_GLOB_RES}) file(GLOB_RECURSE TEMP_GLOB_RES "${NBL_ROOT_PATH}/src/*.h") set(NABLA_HEADERS_PUBLIC2 ${NABLA_HEADERS_PUBLIC2} ${TEMP_GLOB_RES}) # TODO: we should have moved all headers from src directory to /include, but we need it for install target +file(GLOB_RECURSE NABLA_HLSL_PUBLIC "${NBL_ROOT_PATH}/include/*.hlsl") +list(APPEND NABLA_HEADERS_PUBLIC ${NABLA_HLSL_PUBLIC}) + foreach(NBL_CURRENT_HEADER IN LISTS NABLA_HEADERS_PUBLIC2) cmake_path(GET NBL_CURRENT_HEADER PARENT_PATH NBL_CURRENT_HEADER_DIR) file(RELATIVE_PATH NBL_TMP_REL_DESTINATION "${NBL_ROOT_PATH}/src" ${NBL_CURRENT_HEADER_DIR}) @@ -355,6 +358,7 @@ else() ) endif() add_library(Nabla::Nabla ALIAS Nabla) +set_source_files_properties(${NABLA_HLSL_PUBLIC} PROPERTIES HEADER_FILE_ONLY ON) # from old build config template: # @@ -851,4 +855,29 @@ target_compile_definitions(Nabla INTERFACE NBL_CPACK_PACKAGE_DXC_DLL_DIR_ABS_KEY="${_NBL_DXC_PACKAGE_RUNTIME_DLL_DIR_PATH_}" ) -NBL_ADJUST_FOLDERS(src) \ No newline at end of file +NBL_ADJUST_FOLDERS(src) +function(EXTRACT_BY_REGEX OUT REGEX) + set(tmp "${ARGN}") + list(FILTER tmp INCLUDE REGEX "${REGEX}") + set(${OUT} "${tmp}" PARENT_SCOPE) +endfunction() + +get_target_property(SRC Nabla SOURCES) +EXTRACT_BY_REGEX(NABLA_HLSL_FILES ".*\\.hlsl$" ${SRC}) +EXTRACT_BY_REGEX(NABLA_HEADER_FILES ".*\\.(h|hpp|tcc)$" ${SRC}) +EXTRACT_BY_REGEX(NABLA_SOURCE_FILES ".*\\.(c|cpp)$" ${SRC}) + +source_group(TREE "${NBL_ROOT_PATH}" + PREFIX "HLSL Files" + FILES ${NABLA_HLSL_FILES} +) + +source_group(TREE "${NBL_ROOT_PATH}" + PREFIX "Header Files" + FILES ${NABLA_HEADER_FILES} +) + +source_group(TREE "${NBL_ROOT_PATH}" + PREFIX "Source Files" + FILES ${NABLA_SOURCE_FILES} +) \ No newline at end of file From 67518feab7f409c3aa2bcb6ccd0058f727a531d8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 25 Nov 2025 12:33:32 +0100 Subject: [PATCH 43/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 65e0126cac..e00a669c1f 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 65e0126cac320c10efe34ebbc144da45d587a54e +Subproject commit e00a669c1f9914a850f13f8a0659edccb6350831 From 1ed5d82a43fbf77b060f36de2672f079ba66254d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 25 Nov 2025 15:42:46 +0100 Subject: [PATCH 44/61] add shadertoolsconfig.json, include in source group, leave some comments after my R&D --- include/shadertoolsconfig.json | 8 ++++++++ src/nbl/CMakeLists.txt | 14 ++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 include/shadertoolsconfig.json diff --git a/include/shadertoolsconfig.json b/include/shadertoolsconfig.json new file mode 100644 index 0000000000..4c16b1f743 --- /dev/null +++ b/include/shadertoolsconfig.json @@ -0,0 +1,8 @@ +{ + "root": true, + "hlsl.preprocessorDefinitions": { + }, + "hlsl.additionalIncludeDirectories": [ + "." + ] +} \ No newline at end of file diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index 3ebecfbb28..3b9fd0d3fd 100644 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -880,4 +880,18 @@ source_group(TREE "${NBL_ROOT_PATH}" source_group(TREE "${NBL_ROOT_PATH}" PREFIX "Source Files" FILES ${NABLA_SOURCE_FILES} +) + +# we want HLSL intelisense with all fancy features +# https://marketplace.visualstudio.com/items?itemName=TimGJones.HLSLToolsforVisualStudio +# but intellisense doesn't work in VS2026 with the ext even tho I seem to have correct config, +# there is syntax highlighting however it cannot resolve any #include file and +# in VS2022 this ext literally breaks the IDE making it unresponsive. +# One could not use it at all and rely on C++ intellisense for .hlsl files, +# but then I found I must right click in a .hlsl file -> Rescan -> Rescan File +# to resolve include files, "Rescan solution" doesn't work +target_sources(Nabla PRIVATE "${NBL_ROOT_PATH}/include/shadertoolsconfig.json") +source_group(TREE "${NBL_ROOT_PATH}" + PREFIX "HLSL Tools" + FILES "${NBL_ROOT_PATH}/include/shadertoolsconfig.json" ) \ No newline at end of file From 9814b88a082d2b62dda559d5662237a2e6d7b7f3 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 26 Nov 2025 12:38:54 +0100 Subject: [PATCH 45/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index e00a669c1f..06bad177bd 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit e00a669c1f9914a850f13f8a0659edccb6350831 +Subproject commit 06bad177bdb18772c8b4c6c4289a22159e7c97c0 From e60596975286c8ba927d3e14105987bf8dce7f2c Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 26 Nov 2025 18:36:29 +0100 Subject: [PATCH 46/61] update dxc submodule, pull microsoft:main and s-perron:i7945 --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index dafad1d9a3..155f57ad15 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit dafad1d9a370d17ac9ce69928ef518f842cb5191 +Subproject commit 155f57ad15ca7eabeaa5e5a892cfdeb7bffe8fc3 From 53e4ab1855b1474d35888e84a9b23d1636e12177 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 26 Nov 2025 19:30:28 +0100 Subject: [PATCH 47/61] update dxc submodule, it crashes! --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index 155f57ad15..dafad1d9a3 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit 155f57ad15ca7eabeaa5e5a892cfdeb7bffe8fc3 +Subproject commit dafad1d9a370d17ac9ce69928ef518f842cb5191 From 5b79bb4c9d77f1c605d2e8371b8efb8b2944b2ed Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 30 Nov 2025 15:42:06 +0100 Subject: [PATCH 48/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 06bad177bd..b659f1a3e6 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 06bad177bdb18772c8b4c6c4289a22159e7c97c0 +Subproject commit b659f1a3e624bd4d6b87629f2740d048c2db8b17 From 0db984bf7a371d967fcd7a60ef94e4e39d98c406 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 30 Nov 2025 16:21:43 +0100 Subject: [PATCH 49/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index b659f1a3e6..d8f82f0d59 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit b659f1a3e624bd4d6b87629f2740d048c2db8b17 +Subproject commit d8f82f0d593d04b437ca64ddece9c32112ed5b12 From 5ce6fa26bef0b7c8d329fdc75177ad769b19db17 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 30 Nov 2025 18:05:50 +0100 Subject: [PATCH 50/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index d8f82f0d59..9c83531c63 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit d8f82f0d593d04b437ca64ddece9c32112ed5b12 +Subproject commit 9c83531c63490bf743dee9bddcfbd5d729e1c916 From 83a83a489cf338d95653653371579e76cb70c6e9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 3 Dec 2025 10:53:07 +0100 Subject: [PATCH 51/61] update ProfileProperties to tightly pack version, type and symmetry, add sample function overload to sampler.hlsl, create include/nbl/builtin/hlsl/ies/texture.hlsl to share texel write method between C++ & HLSL (the correct one including blending and corner sampling) TODO: need to update IES viewer example to compile again and clean bindings a bit (keep only octahedral image to write and sample from + add new ies::Texture::SInfo) --- include/nbl/builtin/hlsl/ies/profile.hlsl | 64 +++++++++++++--- include/nbl/builtin/hlsl/ies/sampler.hlsl | 14 +++- include/nbl/builtin/hlsl/ies/texture.hlsl | 90 +++++++++++++++++++++++ src/nbl/asset/utils/CIESProfile.cpp | 35 +-------- src/nbl/asset/utils/CIESProfile.h | 28 ++----- src/nbl/asset/utils/CIESProfileParser.cpp | 29 +++++--- 6 files changed, 186 insertions(+), 74 deletions(-) create mode 100644 include/nbl/builtin/hlsl/ies/texture.hlsl diff --git a/include/nbl/builtin/hlsl/ies/profile.hlsl b/include/nbl/builtin/hlsl/ies/profile.hlsl index 88e212f069..35210fedda 100644 --- a/include/nbl/builtin/hlsl/ies/profile.hlsl +++ b/include/nbl/builtin/hlsl/ies/profile.hlsl @@ -26,14 +26,25 @@ struct ProfileProperties NBL_CONSTEXPR_STATIC_INLINE float32_t MAX_VANGLE = 180.f; NBL_CONSTEXPR_STATIC_INLINE float32_t MAX_HANGLE = 360.f; - enum Version : uint16_t + // TODO: could change to uint8_t once we get implemented + // https://github.com/microsoft/hlsl-specs/pull/538 + using packed_flags_t = uint16_t; + + NBL_CONSTEXPR_STATIC_INLINE packed_flags_t VERSION_BITS = 2u; + NBL_CONSTEXPR_STATIC_INLINE packed_flags_t TYPE_BITS = 2u; + NBL_CONSTEXPR_STATIC_INLINE packed_flags_t SYMM_BITS = 3u; + NBL_CONSTEXPR_STATIC_INLINE packed_flags_t VERSION_MASK = (packed_flags_t(1u) << VERSION_BITS) - packed_flags_t(1u); + NBL_CONSTEXPR_STATIC_INLINE packed_flags_t TYPE_MASK = (packed_flags_t(1u) << TYPE_BITS) - packed_flags_t(1u); + NBL_CONSTEXPR_STATIC_INLINE packed_flags_t SYMM_MASK = (packed_flags_t(1u) << SYMM_BITS) - packed_flags_t(1u); + + enum Version : packed_flags_t { V_1995, V_2002, V_SIZE }; - enum PhotometricType : uint16_t + enum PhotometricType : packed_flags_t { TYPE_NONE, TYPE_C, @@ -41,7 +52,7 @@ struct ProfileProperties TYPE_A }; - enum LuminairePlanesSymmetry : uint16_t + enum LuminairePlanesSymmetry : packed_flags_t { ISOTROPIC, //! Only one horizontal angle present and a luminaire is assumed to be laterally axial symmetric QUAD_SYMETRIC, //! The luminaire is assumed to be symmetric in each quadrant @@ -50,13 +61,48 @@ struct ProfileProperties NO_LATERAL_SYMMET //! The luminaire is assumed to exhibit no lateral symmet }; - PhotometricType type; - Version version; - LuminairePlanesSymmetry symmetry; + Version getVersion() const + { + return static_cast( packed & VERSION_MASK ); + } + + PhotometricType getType() const + { + const packed_flags_t shift = VERSION_BITS; + return static_cast( (packed >> shift) & TYPE_MASK ); + } + + LuminairePlanesSymmetry getSymmetry() const + { + const packed_flags_t shift = VERSION_BITS + TYPE_BITS; + return static_cast( (packed >> shift) & SYMM_MASK ); + } + + void setVersion(Version v) + { + packed_flags_t vBits = static_cast(v) & VERSION_MASK; + packed = (packed & ~VERSION_MASK) | vBits; + } + + void setType(PhotometricType t) + { + const packed_flags_t shift = VERSION_BITS; + packed_flags_t tBits = (static_cast(t) & TYPE_MASK) << shift; + packed = (packed & ~(TYPE_MASK << shift)) | tBits; + } + + void setSymmetry(LuminairePlanesSymmetry s) + { + const packed_flags_t shift = VERSION_BITS + TYPE_BITS; + packed_flags_t sBits = (static_cast(s) & SYMM_MASK) << shift; + packed = (packed & ~(SYMM_MASK << shift)) | sBits; + } - float32_t maxCandelaValue; //! Max scalar value from candela data vector - float32_t totalEmissionIntegral; //! Total energy emitted - float32_t avgEmmision; //! totalEmissionIntegral / + float32_t maxCandelaValue; //! Max candela sample value + float32_t totalEmissionIntegral; //! Total emitted intensity (integral over full angular domain) + float32_t fullDomainAvgEmission; //! Mean intensity over full angular domain (including I == 0) + float32_t avgEmmision; //! Mean intensity over emitting solid angle (I > 0) + packed_flags_t packed = 0u; //! Packed version, type and symmetry flags }; } diff --git a/include/nbl/builtin/hlsl/ies/sampler.hlsl b/include/nbl/builtin/hlsl/ies/sampler.hlsl index 3f518ff21a..41f273e82c 100644 --- a/include/nbl/builtin/hlsl/ies/sampler.hlsl +++ b/include/nbl/builtin/hlsl/ies/sampler.hlsl @@ -7,6 +7,7 @@ #include "nbl/builtin/hlsl/cpp_compat.hlsl" #include "nbl/builtin/hlsl/math/polar.hlsl" +#include "nbl/builtin/hlsl/math/octahedral.hlsl" #include "nbl/builtin/hlsl/concepts.hlsl" #include "nbl/builtin/hlsl/ies/profile.hlsl" @@ -37,7 +38,7 @@ NBL_CONCEPT_END( ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.vAnglesCount()), is_same_v, req_key_t)) ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.hAnglesCount()), is_same_v, req_key_t)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.symmetry()), is_same_v, ProfileProperties::LuminairePlanesSymmetry)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.getProperties()), is_same_v, ProfileProperties)) ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.template vAngle((req_key_t)0)), is_same_v, req_value_t)) ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.template hAngle((req_key_t)0)), is_same_v, req_value_t)) ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.template value((req_key_t2)0)), is_same_v, req_value_t)) @@ -58,11 +59,13 @@ struct CandelaSampler using accessor_t = Accessor; using value_t = typename accessor_t::value_t; using symmetry_t = ProfileProperties::LuminairePlanesSymmetry; + using polar_t = math::Polar; + using octahedral_t = math::OctahedralTransform; static value_t sample(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(math::Polar) polar) { // TODO: DXC seems to have a bug and cannot use symmetry_t directly with == operator https://godbolt.devsh.eu/z/P9Kc5x - const ProfileProperties::LuminairePlanesSymmetry symmetry = accessor.symmetry(); + const ProfileProperties::LuminairePlanesSymmetry symmetry = accessor.getProperties().getSymmetry(); const float32_t vAngle = degrees(polar.theta); const float32_t hAngle = degrees(wrapPhi(polar.phi, symmetry)); @@ -87,6 +90,13 @@ struct CandelaSampler return s0 * (1.f - u) + s1 * u; } + static value_t sample(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(float32_t2) uv) + { + const float32_t3 dir = octahedral_t::uvToDir(uv); + const polar_t polar = polar_t::createFromCartesian(dir); + return sample(accessor, polar); + } + static float32_t wrapPhi(const float32_t phi, const symmetry_t symmetry) { switch (symmetry) diff --git a/include/nbl/builtin/hlsl/ies/texture.hlsl b/include/nbl/builtin/hlsl/ies/texture.hlsl new file mode 100644 index 0000000000..4372bb5544 --- /dev/null +++ b/include/nbl/builtin/hlsl/ies/texture.hlsl @@ -0,0 +1,90 @@ +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h + +#ifndef _NBL_BUILTIN_HLSL_IES_TEXTURE_INCLUDED_ +#define _NBL_BUILTIN_HLSL_IES_TEXTURE_INCLUDED_ + +#include "nbl/builtin/hlsl/ies/sampler.hlsl" + +namespace nbl +{ +namespace hlsl +{ +namespace ies +{ + +template) +struct Texture +{ + using accessor_t = Accessor; + using value_t = typename accessor_t::value_t; + using sampler_t = CandelaSampler; + using polar_t = math::Polar; + using octahedral_t = math::OctahedralTransform; + + struct SInfo + { + float32_t2 inv; + float32_t flatten; + float32_t maxValueRecip; + float32_t flattenTarget; + float32_t domainLo; + float32_t domainHi; + bool fullDomainFlatten; + }; + + static SInfo createInfo(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(uint32_t2) size, float32_t flatten, bool fullDomainFlatten) + { + SInfo retval; + const ProfileProperties props = accessor.getProperties(); + + // There is one huge issue, the IES files love to give us values for degrees 0, 90, 180 an 360 + // So standard octahedral mapping won't work, because for above data points you need corner sampled images. + + retval.inv = float32_t2(1.f, 1.f) / float32_t2(size - 1u); + retval.flatten = flatten; + retval.maxValueRecip = 1.0f / props.maxCandelaValue; // Late Optimization TODO: Modify the Max Value for the UNORM texture to be the Max Value after flatten blending + retval.domainLo = radians(accessor.vAngle(0u)); + retval.domainHi = radians(accessor.vAngle(accessor.vAnglesCount() - 1u)); + retval.fullDomainFlatten = fullDomainFlatten; + + if(fullDomainFlatten) + retval.flattenTarget = props.fullDomainAvgEmission; + else + retval.flattenTarget = props.avgEmmision; + + return retval; + } + + static float32_t eval(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(SInfo) info, NBL_CONST_REF_ARG(uint32_t2) position) + { + // We don't currently support generating IES images that exploit symmetries or reduced domains, all are full octahederal mappings of a sphere. + // If we did, we'd rely on MIRROR and CLAMP samplers to do some of the work for us while handling the discontinuity due to corner sampling. + + const float32_t2 uv = float32_t2(position) * info.inv; + const float32_t3 dir = octahedral_t::uvToDir(uv); + const polar_t polar = polar_t::createFromCartesian(dir); + + sampler_t sampler; + const float32_t intensity = sampler.sample(accessor, polar); + + //! blend the IES texture with "flatten" + float32_t blendV = intensity * (1.f - info.flatten); + + const bool inDomain = (info.domainLo <= polar.theta) && (polar.theta <= info.domainHi); + + if ((info.fullDomainFlatten && inDomain) || intensity > 0.0f) + blendV += info.flattenTarget * info.flatten; + + blendV *= info.maxValueRecip; + + return blendV; + } +}; + +} +} +} + +#endif // _NBL_BUILTIN_HLSL_IES_TEXTURE_INCLUDED_ diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index dc66c9693a..b595f5a415 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -2,8 +2,6 @@ #include #include "nbl/asset/filters/CBasicImageFilterCommon.h" -#include "nbl/builtin/hlsl/math/octahedral.hlsl" -#include "nbl/builtin/hlsl/math/polar.hlsl" using namespace nbl; using namespace asset; @@ -70,42 +68,15 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu state.outRange.extent = creationParams.extent; const IImageFilter::IState::ColorValue::WriteMemoryInfo wInfo(creationParams.format, outImg->getBuffer()->getPointer()); + const auto tInfo = texture_t::createInfo(accessor, hlsl::uint32_t2(width, height), flatten, fullDomainFlatten); - // Late Optimization TODO: Modify the Max Value for the UNORM texture to be the Max Value after flatten blending - const auto maxValue = accessor.properties.maxCandelaValue; - const auto maxValueRecip = 1.f / maxValue; - - // There is one huge issue, the IES files love to give us values for degrees 0, 90, 180 an 360 - // So standard octahedral mapping won't work, because for above data points you need corner sampled images. - const float vertInv = 1.0 / (height-1); - const float horiInv = 1.0 / (width-1); - - const double flattenTarget = getAvgEmmision(fullDomainFlatten); - const double domainLo = core::radians(accessor.vAngles.front()); - const double domainHi = core::radians(accessor.vAngles.back()); auto fill = [&](uint32_t blockArrayOffset, core::vectorSIMDu32 position) -> void { - // We don't currently support generating IES images that exploit symmetries or reduced domains, all are full octahederal mappings of a sphere. - // If we did, we'd rely on MIRROR and CLAMP samplers to do some of the work for us while handling the discontinuity due to corner sampling. - - using Octahedral = hlsl::math::OctahedralTransform; - using Polar = hlsl::math::Polar; - const auto uv = Octahedral::vector2_type(position.x * vertInv, position.y * horiInv); - const auto dir = Octahedral::uvToDir(uv); - const auto polar = Polar::createFromCartesian(dir); - const auto intensity = sampler_t::sample(accessor, polar); - - //! blend the IES texture with "flatten" - float blendV = intensity * (1.f - flatten); - if (fullDomainFlatten && domainLo<= polar.theta && polar.theta<=domainHi || intensity >0.0) - blendV += flattenTarget * flatten; - - blendV *= maxValueRecip; + auto texel = texture_t::eval(accessor, tInfo, hlsl::uint32_t2(position.x, position.y)); asset::IImageFilter::IState::ColorValue color; - //asset::encodePixels(color.asDouble, &blendV); TODO: FIX THIS ENCODE, GIVES ARTIFACTS constexpr float UI16_MAX_D = static_cast(std::numeric_limits::max()); - const uint16_t encodeV = static_cast(std::clamp(blendV * UI16_MAX_D + 0.5f, 0.f, UI16_MAX_D)); + const uint16_t encodeV = static_cast(std::clamp(texel * UI16_MAX_D + 0.5f, 0.f, UI16_MAX_D)); // TODO: use asset::encodePixels when its fixed (no artifacts) *color.asUShort = encodeV; color.writeMemory(wInfo, blockArrayOffset); }; diff --git a/src/nbl/asset/utils/CIESProfile.h b/src/nbl/asset/utils/CIESProfile.h index c09f2fd760..2a063e7b15 100644 --- a/src/nbl/asset/utils/CIESProfile.h +++ b/src/nbl/asset/utils/CIESProfile.h @@ -6,7 +6,7 @@ #define __NBL_ASSET_C_IES_PROFILE_H_INCLUDED__ #include "nbl/asset/metadata/CIESProfileMetadata.h" -#include "nbl/builtin/hlsl/ies/sampler.hlsl" +#include "nbl/builtin/hlsl/ies/texture.hlsl" namespace nbl { @@ -15,10 +15,14 @@ namespace asset class CIESProfile { public: + CIESProfile() = default; + ~CIESProfile() = default; + struct properties_t : public nbl::hlsl::ies::ProfileProperties { + using base_t = nbl::hlsl::ies::ProfileProperties; NBL_CONSTEXPR_STATIC_INLINE auto IES_TEXTURE_STORAGE_FORMAT = asset::EF_R16_UNORM; - hlsl::uint32_t2 optimalIESResolution; //! Optimal resolution for IES CDC texture + hlsl::uint32_t2 optimalIESResolution; //! Optimal resolution for IES Octahedral Candela Map texture }; struct accessor_t @@ -45,33 +49,17 @@ class CIESProfile inline key_t vAnglesCount() const { return (key_t)vAngles.size(); } inline key_t hAnglesCount() const { return (key_t)hAngles.size(); } - inline properties_t::LuminairePlanesSymmetry symmetry() const { return properties.symmetry; } + inline const properties_t::base_t& getProperties() const { return static_cast(properties); } core::vector hAngles; //! The angular displacement indegreesfrom straight down, a value represents spherical coordinate "theta" with physics convention. Note that if symmetry is OTHER_HALF_SYMMETRIC then real horizontal angle provided by IES data is (hAngles[index] + 90) - the reason behind it is we patch 1995 IES OTHER_HALF_SYMETRIC case to be HALF_SYMETRIC core::vector vAngles; //! Measurements in degrees of angular displacement measured counterclockwise in a horizontal plane for Type C photometry and clockwise for Type A and B photometry, a value represents spherical coordinate "phi" with physics convention core::vector data; //! Candela scalar values properties_t properties; //! Profile properties }; - - using sampler_t = nbl::hlsl::ies::CandelaSampler; - - CIESProfile() = default; - ~CIESProfile() = default; + using texture_t = nbl::hlsl::ies::Texture; inline const accessor_t& getAccessor() const { return accessor; } - inline hlsl::float32_t getAvgEmmision(const bool fullDomain=false) const - { - if (fullDomain) - { - const float cosLo = std::cos(core::radians(accessor.vAngles.front())); - const float cosHi = std::cos(core::radians(accessor.vAngles.back())); - const float dsinTheta = cosLo - cosHi; - return accessor.properties.totalEmissionIntegral*(0.5/core::PI())/dsinTheta; - } - return accessor.properties.avgEmmision; - } - template core::smart_refctd_ptr createIESTexture(ExecutionPolicy&& policy, const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = properties_t::CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = properties_t::CDC_DEFAULT_TEXTURE_HEIGHT) const; core::smart_refctd_ptr createIESTexture(const float flatten = 0.0, const bool fullDomainFlatten=false, uint32_t width = properties_t::CDC_DEFAULT_TEXTURE_WIDTH, uint32_t height = properties_t::CDC_DEFAULT_TEXTURE_HEIGHT) const; diff --git a/src/nbl/asset/utils/CIESProfileParser.cpp b/src/nbl/asset/utils/CIESProfileParser.cpp index 96285b6a6d..4a5bc89969 100644 --- a/src/nbl/asset/utils/CIESProfileParser.cpp +++ b/src/nbl/asset/utils/CIESProfileParser.cpp @@ -101,8 +101,8 @@ bool CIESProfileParser::parse(CIESProfile& result) { CIESProfile::properties_t init; - init.type = type; - init.version = iesVersion; + init.setType(type); + init.setVersion(iesVersion); init.maxCandelaValue = 0.f; init.totalEmissionIntegral = 0.f; init.avgEmmision = 0.f; @@ -142,24 +142,24 @@ bool CIESProfileParser::parse(CIESProfile& result) const auto lastHAngle = hAngles.back(); if (lastHAngle == 0.f) - result.accessor.properties.symmetry = CIESProfile::properties_t::ISOTROPIC; + result.accessor.properties.setSymmetry(CIESProfile::properties_t::ISOTROPIC); else if (lastHAngle == 90.f) { - result.accessor.properties.symmetry = CIESProfile::properties_t::QUAD_SYMETRIC; + result.accessor.properties.setSymmetry(CIESProfile::properties_t::QUAD_SYMETRIC); fluxMultiplier = 4.f; } else if (lastHAngle == 180.f) { - result.accessor.properties.symmetry = CIESProfile::properties_t::HALF_SYMETRIC; + result.accessor.properties.setSymmetry(CIESProfile::properties_t::HALF_SYMETRIC); fluxMultiplier = 2.0; } else if (lastHAngle == 360.f) - result.accessor.properties.symmetry = CIESProfile::properties_t::NO_LATERAL_SYMMET; + result.accessor.properties.setSymmetry(CIESProfile::properties_t::NO_LATERAL_SYMMET); else { - if (firstHAngle == 90.f && lastHAngle == 270.f && result.accessor.properties.version == CIESProfile::properties_t::V_1995) + if (firstHAngle == 90.f && lastHAngle == 270.f && iesVersion == CIESProfile::properties_t::V_1995) { - result.accessor.properties.symmetry = CIESProfile::properties_t::OTHER_HALF_SYMMETRIC; + result.accessor.properties.setSymmetry(CIESProfile::properties_t::OTHER_HALF_SYMMETRIC); fluxMultiplier = 2.f; for (auto& angle : hAngles) @@ -169,6 +169,7 @@ bool CIESProfileParser::parse(CIESProfile& result) return false; } } + const auto symmetry = result.accessor.properties.getSymmetry(); { const double factor = ballastFactor * candelaMultiplier; @@ -181,7 +182,7 @@ bool CIESProfileParser::parse(CIESProfile& result) constexpr auto FULL_SOLID_ANGLE = 4.0f * core::PI(); // TODO: this code could have two separate inner for loops for `result.symmetry != CIESProfile::ISOTROPIC` cases - const auto H_ANGLES_I_RANGE = result.accessor.properties.symmetry != CIESProfile::properties_t::ISOTROPIC ? result.accessor.hAngles.size() - 1 : 1; + const auto H_ANGLES_I_RANGE = symmetry != CIESProfile::properties_t::ISOTROPIC ? result.accessor.hAngles.size() - 1 : 1; const auto V_ANGLES_I_RANGE = result.accessor.vAngles.size() - 1; float smallestRangeSolidAngle = FULL_SOLID_ANGLE; @@ -196,7 +197,7 @@ bool CIESProfileParser::parse(CIESProfile& result) float nonZeroStripDomain = 0.f; for (size_t i = 0; i < H_ANGLES_I_RANGE; i++) { - const float dPhiRad = result.accessor.properties.symmetry != CIESProfile::properties_t::ISOTROPIC ? core::radians(hAngles[i + 1] - hAngles[i]) : (core::PI() * 2.0f); + const float dPhiRad = symmetry != CIESProfile::properties_t::ISOTROPIC ? core::radians(hAngles[i + 1] - hAngles[i]) : (core::PI() * 2.0f); // TODO: in reality one should transform the 4 vertices (or 3) into octahedral map, work out the dUV/dPhi and dUV/dTheta vectors as-if for Anisotropic Filtering // then choose the minor axis length, and use that as a pixel size (since looking for smallest thing, dont have to worry about handling discont) const float solidAngle = dsinTheta * dPhiRad; @@ -206,7 +207,7 @@ bool CIESProfileParser::parse(CIESProfile& result) const auto candelaValue = result.accessor.value(hlsl::uint32_t2(i, j)); // interpolate candela value spanned onto a solid angle - const auto candelaAverage = result.accessor.properties.symmetry != CIESProfile::properties_t::ISOTROPIC ? + const auto candelaAverage = symmetry != CIESProfile::properties_t::ISOTROPIC ? 0.25f * (candelaValue + result.accessor.value(hlsl::uint32_t2(i + 1, j)) + result.accessor.value(hlsl::uint32_t2(i, j + 1)) + result.accessor.value(hlsl::uint32_t2(i + 1, j + 1))) : 0.5f * (candelaValue + result.accessor.value(hlsl::uint32_t2(i, j + 1))); @@ -235,6 +236,12 @@ bool CIESProfileParser::parse(CIESProfile& result) result.accessor.properties.avgEmmision = totalEmissionIntegral / static_cast(nonZeroEmissionDomainSize); result.accessor.properties.totalEmissionIntegral = totalEmissionIntegral * fluxMultiplier; // we use fluxMultiplier to calculate final total emission for case where we have some symmetry between planes (fluxMultiplier is 1.0f if ISOTROPIC or NO_LATERAL_SYMMET because they already have correct total emission integral calculated), also note it doesn't affect average emission at all + { + const float cosLo = std::cos(core::radians(result.accessor.vAngles.front())); + const float cosHi = std::cos(core::radians(result.accessor.vAngles.back())); + const float dsinTheta = cosLo - cosHi; + result.accessor.properties.fullDomainAvgEmission = result.accessor.properties.totalEmissionIntegral*(0.5f/core::PI())/dsinTheta; + } return !error; } \ No newline at end of file From b855e1c0761cdd4992f2a163e72aeb3aaddc8327 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 3 Dec 2025 15:03:59 +0100 Subject: [PATCH 52/61] NBL_HLSL_DEFINE_STRUCT for IESTextureInfo, update ies/profile.hlsl casts & use NBL_CONST_MEMBER_FUNC, update examples_tests submodule --- examples_tests | 2 +- include/nbl/builtin/hlsl/ies/profile.hlsl | 20 +++++++------- include/nbl/builtin/hlsl/ies/texture.hlsl | 33 ++++++++++++++--------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/examples_tests b/examples_tests index 9c83531c63..92784f38d7 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 9c83531c63490bf743dee9bddcfbd5d729e1c916 +Subproject commit 92784f38d708b3577cfdff39341cd519052cfe9d diff --git a/include/nbl/builtin/hlsl/ies/profile.hlsl b/include/nbl/builtin/hlsl/ies/profile.hlsl index 35210fedda..50c370947e 100644 --- a/include/nbl/builtin/hlsl/ies/profile.hlsl +++ b/include/nbl/builtin/hlsl/ies/profile.hlsl @@ -61,40 +61,40 @@ struct ProfileProperties NO_LATERAL_SYMMET //! The luminaire is assumed to exhibit no lateral symmet }; - Version getVersion() const + Version getVersion() NBL_CONST_MEMBER_FUNC { - return static_cast( packed & VERSION_MASK ); + return (Version)( packed & VERSION_MASK ); } - PhotometricType getType() const + PhotometricType getType() NBL_CONST_MEMBER_FUNC { const packed_flags_t shift = VERSION_BITS; - return static_cast( (packed >> shift) & TYPE_MASK ); + return (PhotometricType)((packed >> shift) & TYPE_MASK); } - LuminairePlanesSymmetry getSymmetry() const + LuminairePlanesSymmetry getSymmetry() NBL_CONST_MEMBER_FUNC { const packed_flags_t shift = VERSION_BITS + TYPE_BITS; - return static_cast( (packed >> shift) & SYMM_MASK ); + return (LuminairePlanesSymmetry)((packed >> shift) & SYMM_MASK); } void setVersion(Version v) { - packed_flags_t vBits = static_cast(v) & VERSION_MASK; + packed_flags_t vBits = (packed_flags_t)(v) & VERSION_MASK; packed = (packed & ~VERSION_MASK) | vBits; } void setType(PhotometricType t) { const packed_flags_t shift = VERSION_BITS; - packed_flags_t tBits = (static_cast(t) & TYPE_MASK) << shift; + packed_flags_t tBits = ((packed_flags_t)(t) & TYPE_MASK) << shift; packed = (packed & ~(TYPE_MASK << shift)) | tBits; } void setSymmetry(LuminairePlanesSymmetry s) { const packed_flags_t shift = VERSION_BITS + TYPE_BITS; - packed_flags_t sBits = (static_cast(s) & SYMM_MASK) << shift; + packed_flags_t sBits = ((packed_flags_t)(s) & SYMM_MASK) << shift; packed = (packed & ~(SYMM_MASK << shift)) | sBits; } @@ -102,7 +102,7 @@ struct ProfileProperties float32_t totalEmissionIntegral; //! Total emitted intensity (integral over full angular domain) float32_t fullDomainAvgEmission; //! Mean intensity over full angular domain (including I == 0) float32_t avgEmmision; //! Mean intensity over emitting solid angle (I > 0) - packed_flags_t packed = 0u; //! Packed version, type and symmetry flags + packed_flags_t packed; //! Packed version, type and symmetry flags }; } diff --git a/include/nbl/builtin/hlsl/ies/texture.hlsl b/include/nbl/builtin/hlsl/ies/texture.hlsl index 4372bb5544..7f02290506 100644 --- a/include/nbl/builtin/hlsl/ies/texture.hlsl +++ b/include/nbl/builtin/hlsl/ies/texture.hlsl @@ -6,11 +6,28 @@ #define _NBL_BUILTIN_HLSL_IES_TEXTURE_INCLUDED_ #include "nbl/builtin/hlsl/ies/sampler.hlsl" +#include "nbl/builtin/hlsl/bda/struct_declare.hlsl" namespace nbl { namespace hlsl { + +// TODO(?): should be in nbl::hlsl::ies (or in the Texutre struct) but I get +// error GA3909C62: class template specialization of 'member_count' not in a namespace enclosing 'bda' +// which I don't want to deal with rn to not (eventually) break stuff + +struct IESTextureInfo; +NBL_HLSL_DEFINE_STRUCT((IESTextureInfo), + ((inv, float32_t2)) + ((flatten, float32_t)) + ((maxValueRecip, float32_t)) + ((flattenTarget, float32_t)) + ((domainLo, float32_t)) + ((domainHi, float32_t)) + ((fullDomainFlatten, uint16_t)) // bool +); + namespace ies { @@ -22,19 +39,9 @@ struct Texture using sampler_t = CandelaSampler; using polar_t = math::Polar; using octahedral_t = math::OctahedralTransform; + using SInfo = nbl::hlsl::IESTextureInfo; - struct SInfo - { - float32_t2 inv; - float32_t flatten; - float32_t maxValueRecip; - float32_t flattenTarget; - float32_t domainLo; - float32_t domainHi; - bool fullDomainFlatten; - }; - - static SInfo createInfo(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(uint32_t2) size, float32_t flatten, bool fullDomainFlatten) + static inline SInfo createInfo(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(uint32_t2) size, float32_t flatten, bool fullDomainFlatten) { SInfo retval; const ProfileProperties props = accessor.getProperties(); @@ -57,7 +64,7 @@ struct Texture return retval; } - static float32_t eval(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(SInfo) info, NBL_CONST_REF_ARG(uint32_t2) position) + static inline float32_t eval(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(SInfo) info, NBL_CONST_REF_ARG(uint32_t2) position) { // We don't currently support generating IES images that exploit symmetries or reduced domains, all are full octahederal mappings of a sphere. // If we did, we'd rely on MIRROR and CLAMP samplers to do some of the work for us while handling the discontinuity due to corner sampling. From 2c5974e994203aa00c6755e7a636a9142336e695 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 4 Dec 2025 15:32:18 +0100 Subject: [PATCH 53/61] fix optimal resolution bug, update examples_tests submodule --- examples_tests | 2 +- include/nbl/builtin/hlsl/ies/profile.hlsl | 5 +++++ src/nbl/asset/utils/CIESProfile.cpp | 7 ++----- src/nbl/asset/utils/CIESProfileParser.cpp | 4 +++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/examples_tests b/examples_tests index 92784f38d7..49b18aa4ec 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 92784f38d708b3577cfdff39341cd519052cfe9d +Subproject commit 49b18aa4ec453fb53cf9bab6f28f83860818ff67 diff --git a/include/nbl/builtin/hlsl/ies/profile.hlsl b/include/nbl/builtin/hlsl/ies/profile.hlsl index 50c370947e..a85141aebd 100644 --- a/include/nbl/builtin/hlsl/ies/profile.hlsl +++ b/include/nbl/builtin/hlsl/ies/profile.hlsl @@ -20,6 +20,11 @@ struct ProfileProperties NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MAX_TEXTURE_WIDTH = 15360u; NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MAX_TEXTURE_HEIGHT = 8640u; + // TODO: This constraint is hack because the mitsuba loader and its material compiler use Virtual Texturing, and there's some bug with IES not sampling sub 128x128 mip levels + // don't want to spend time to fix this since we'll be using descriptor indexing for the next iteration + NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MIN_TEXTURE_WIDTH = 128u; + NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MIN_TEXTURE_HEIGHT = 128u; + NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_DEFAULT_TEXTURE_WIDTH = 1024u; NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_DEFAULT_TEXTURE_HEIGHT = 1024u; diff --git a/src/nbl/asset/utils/CIESProfile.cpp b/src/nbl/asset/utils/CIESProfile.cpp index b595f5a415..d4289191f6 100644 --- a/src/nbl/asset/utils/CIESProfile.cpp +++ b/src/nbl/asset/utils/CIESProfile.cpp @@ -19,11 +19,8 @@ core::smart_refctd_ptr CIESProfile::createIESTexture(Execu height = properties_t::CDC_MAX_TEXTURE_HEIGHT; // TODO: If no symmetry (no folding in half and abuse of mirror sampler) make dimensions odd-sized so middle texel taps the south pole - - // TODO: This is hack because the mitsuba loader and its material compiler use Virtual Texturing, and there's some bug with IES not sampling sub 128x128 mip levels - // don't want to spend time to fix this since we'll be using descriptor indexing for the next iteration - width = core::max(width,128); - height = core::max(height,128); + width = core::max(width,properties_t::CDC_MIN_TEXTURE_WIDTH); + height = core::max(height,properties_t::CDC_MIN_TEXTURE_HEIGHT); asset::ICPUImage::SCreationParams imgInfo; imgInfo.type = asset::ICPUImage::ET_2D; diff --git a/src/nbl/asset/utils/CIESProfileParser.cpp b/src/nbl/asset/utils/CIESProfileParser.cpp index 4a5bc89969..6d9bf1ea32 100644 --- a/src/nbl/asset/utils/CIESProfileParser.cpp +++ b/src/nbl/asset/utils/CIESProfileParser.cpp @@ -226,7 +226,9 @@ bool CIESProfileParser::parse(CIESProfile& result) { const uint32_t maxDimMeasureSize = core::sqrt(FULL_SOLID_ANGLE/smallestRangeSolidAngle); result.accessor.properties.optimalIESResolution = decltype(result.accessor.properties.optimalIESResolution){ maxDimMeasureSize, maxDimMeasureSize }; - result.accessor.properties.optimalIESResolution *= 2u; // safe bias for our bilinear interpolation to work nicely and increase resolution of a profile + auto& res = result.accessor.properties.optimalIESResolution *= 2u; // safe bias for our bilinear interpolation to work nicely and increase resolution of a profile + res.x = core::max(res.x,CIESProfile::properties_t::CDC_MIN_TEXTURE_WIDTH); + res.y = core::max(res.y,CIESProfile::properties_t::CDC_MIN_TEXTURE_HEIGHT); } assert(nonZeroEmissionDomainSize >= 0.f); From 777e443de6bdaff29c08d70b7265d60d16c12aaa Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 4 Dec 2025 16:28:30 +0100 Subject: [PATCH 54/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 49b18aa4ec..57bcf32016 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 49b18aa4ec453fb53cf9bab6f28f83860818ff67 +Subproject commit 57bcf320167405e32c4ad54f9e37106c1cd3a428 From cab896a44474809f31b8711a7deec91def50b64b Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 5 Dec 2025 14:53:25 +0100 Subject: [PATCH 55/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 57bcf32016..fa797e4e17 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 57bcf320167405e32c4ad54f9e37106c1cd3a428 +Subproject commit fa797e4e17eb02c203227c58f805896cd65997c4 From e7a0ef4b3bf2f982ee922164bfddc5a263dbd0ae Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 28 Dec 2025 18:51:13 +0100 Subject: [PATCH 56/61] add IES texture eval overload, remove some old code, update examples_tests submodule --- examples_tests | 2 +- .../builtin/glsl/material_compiler/common.glsl | 3 ++- include/nbl/builtin/hlsl/ies/texture.hlsl | 10 +++++++--- src/nbl/CMakeLists.txt | 17 ----------------- 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/examples_tests b/examples_tests index b7b796189a..59a434cc64 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit b7b796189a70270a681c35e3e5c1de7517533ed6 +Subproject commit 59a434cc64179b223663a6ca6543a4e85a9f58e1 diff --git a/include/nbl/builtin/glsl/material_compiler/common.glsl b/include/nbl/builtin/glsl/material_compiler/common.glsl index f6b7d97c46..c0a52a4f0d 100644 --- a/include/nbl/builtin/glsl/material_compiler/common.glsl +++ b/include/nbl/builtin/glsl/material_compiler/common.glsl @@ -215,6 +215,7 @@ bool nbl_glsl_MC_op_isDelta(in uint op) #ifdef TEX_PREFETCH_STREAM #include #endif +// TODO: once rewritten to HLSL, shall use new API #include // OptiX likes this one better @@ -1499,4 +1500,4 @@ nbl_glsl_MC_quot_pdf_aov_t nbl_glsl_MC_runGenerateAndRemainderStream( } #endif //GEN_CHOICE_STREAM -#endif \ No newline at end of file +#endif diff --git a/include/nbl/builtin/hlsl/ies/texture.hlsl b/include/nbl/builtin/hlsl/ies/texture.hlsl index 7f02290506..4ea04755df 100644 --- a/include/nbl/builtin/hlsl/ies/texture.hlsl +++ b/include/nbl/builtin/hlsl/ies/texture.hlsl @@ -64,12 +64,10 @@ struct Texture return retval; } - static inline float32_t eval(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(SInfo) info, NBL_CONST_REF_ARG(uint32_t2) position) + static inline float32_t eval(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(SInfo) info, NBL_CONST_REF_ARG(float32_t2) uv) { // We don't currently support generating IES images that exploit symmetries or reduced domains, all are full octahederal mappings of a sphere. // If we did, we'd rely on MIRROR and CLAMP samplers to do some of the work for us while handling the discontinuity due to corner sampling. - - const float32_t2 uv = float32_t2(position) * info.inv; const float32_t3 dir = octahedral_t::uvToDir(uv); const polar_t polar = polar_t::createFromCartesian(dir); @@ -88,6 +86,12 @@ struct Texture return blendV; } + + static inline float32_t eval(NBL_CONST_REF_ARG(accessor_t) accessor, NBL_CONST_REF_ARG(SInfo) info, NBL_CONST_REF_ARG(uint32_t2) position) + { + const float32_t2 uv = float32_t2(position) * info.inv; + return eval(accessor, info, uv); + } }; } diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index 53cd256205..8603d8935f 100644 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -881,20 +881,3 @@ source_group(TREE "${NBL_ROOT_PATH}" PREFIX "Source Files" FILES ${NABLA_SOURCE_FILES} ) - -# we want HLSL intelisense with all fancy features -# NOTE: don't use HLSL Tools component but map .hlsl -# file ext to C++ intellisense in VS settings - -# https://marketplace.visualstudio.com/items?itemName=TimGJones.HLSLToolsforVisualStudio -# intellisense doesn't work in VS2026 with the ext even tho I seem to have correct config, -# there is syntax highlighting however it cannot resolve any #include file and -# in VS2022 this ext literally breaks the IDE making it unresponsive. -# One could not use it at all and rely on C++ intellisense for .hlsl files, -# but then I found I must right click in a .hlsl file -> Rescan -> Rescan File -# to resolve include files, "Rescan solution" doesn't work -target_sources(Nabla PRIVATE "${NBL_ROOT_PATH}/include/shadertoolsconfig.json") -source_group(TREE "${NBL_ROOT_PATH}" - PREFIX "HLSL Tools" - FILES "${NBL_ROOT_PATH}/include/shadertoolsconfig.json" -) \ No newline at end of file From 3e5f8d039d46e302f51029a291c69d1a21e2395d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 28 Dec 2025 21:12:08 +0100 Subject: [PATCH 57/61] awful nsc tooling bug I didn't notice while merging https://github.com/Devsh-Graphics-Programming/Nabla/pull/944 - upgrade builtins API to support config-genex, fix .spv custom command it was building all configs per single config (and embedding all 3 into single archive) --- cmake/common.cmake | 71 ++++++++++++++++++------------------- src/nbl/builtin/utils.cmake | 6 ++-- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index d1b9c5eb5d..10741c9a94 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1485,42 +1485,41 @@ namespace @IMPL_NAMESPACE@ { file(WRITE "${CONFIG_FILE}" "${CONFIG_CONTENT}") # generate keys and commands for compiling shaders - foreach(BUILD_CONFIGURATION ${CMAKE_CONFIGURATION_TYPES}) - set(FINAL_KEY_REL_PATH "${BUILD_CONFIGURATION}/${FINAL_KEY}") - set(TARGET_OUTPUT "${IMPL_BINARY_DIR}/${FINAL_KEY_REL_PATH}") - - set(NBL_NSC_COMPILE_COMMAND - "$" - -Fc "${TARGET_OUTPUT}" - ${COMPILE_OPTIONS} ${REQUIRED_OPTIONS} ${IMPL_COMMON_OPTIONS} - "${CONFIG_FILE}" - ) - - add_custom_command(OUTPUT "${TARGET_OUTPUT}" - COMMAND ${NBL_NSC_COMPILE_COMMAND} - DEPENDS ${DEPENDS_ON} - COMMENT "Creating \"${TARGET_OUTPUT}\"" - VERBATIM - COMMAND_EXPAND_LISTS - ) - - set(HEADER_ONLY_LIKE "${CONFIG_FILE}" "${TARGET_INPUT}" "${TARGET_OUTPUT}") - target_sources(${IMPL_TARGET} PRIVATE ${HEADER_ONLY_LIKE}) - - set_source_files_properties(${HEADER_ONLY_LIKE} PROPERTIES - HEADER_FILE_ONLY ON - VS_TOOL_OVERRIDE None - ) - - set_source_files_properties("${TARGET_OUTPUT}" PROPERTIES - NBL_SPIRV_REGISTERED_INPUT "${TARGET_INPUT}" - NBL_SPIRV_PERMUTATION_CONFIG "${CONFIG_FILE}" - NBL_SPIRV_BINARY_DIR "${IMPL_BINARY_DIR}" - NBL_SPIRV_ACCESS_KEY "${FINAL_KEY_REL_PATH}" - ) - - set_property(TARGET ${IMPL_TARGET} APPEND PROPERTY NBL_SPIRV_OUTPUTS "${TARGET_OUTPUT}") - endforeach() + set(FINAL_KEY_REL_PATH "$/${FINAL_KEY}") + set(TARGET_OUTPUT "${IMPL_BINARY_DIR}/${FINAL_KEY_REL_PATH}") + + set(NBL_NSC_COMPILE_COMMAND + "$" + -Fc "${TARGET_OUTPUT}" + ${COMPILE_OPTIONS} ${REQUIRED_OPTIONS} ${IMPL_COMMON_OPTIONS} + "${CONFIG_FILE}" + ) + + add_custom_command(OUTPUT "${TARGET_OUTPUT}" + COMMAND ${NBL_NSC_COMPILE_COMMAND} + DEPENDS ${DEPENDS_ON} + COMMENT "Creating \"${TARGET_OUTPUT}\"" + VERBATIM + COMMAND_EXPAND_LISTS + ) + set_source_files_properties("${TARGET_OUTPUT}" PROPERTIES GENERATED TRUE) + + set(HEADER_ONLY_LIKE "${CONFIG_FILE}" "${TARGET_INPUT}" "${TARGET_OUTPUT}") + target_sources(${IMPL_TARGET} PRIVATE ${HEADER_ONLY_LIKE}) + + set_source_files_properties(${HEADER_ONLY_LIKE} PROPERTIES + HEADER_FILE_ONLY ON + VS_TOOL_OVERRIDE None + ) + + set_source_files_properties("${TARGET_OUTPUT}" PROPERTIES + NBL_SPIRV_REGISTERED_INPUT "${TARGET_INPUT}" + NBL_SPIRV_PERMUTATION_CONFIG "${CONFIG_FILE}" + NBL_SPIRV_BINARY_DIR "${IMPL_BINARY_DIR}" + NBL_SPIRV_ACCESS_KEY "${FINAL_KEY_REL_PATH}" + ) + + set_property(TARGET ${IMPL_TARGET} APPEND PROPERTY NBL_SPIRV_OUTPUTS "${TARGET_OUTPUT}") return() endif() diff --git a/src/nbl/builtin/utils.cmake b/src/nbl/builtin/utils.cmake index d791cd3aa4..26499dfc76 100644 --- a/src/nbl/builtin/utils.cmake +++ b/src/nbl/builtin/utils.cmake @@ -119,10 +119,10 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH list(APPEND NBL_DEPENDENCY_FILES "${NBL_BUILTIN_HEADER_GEN_PY}") list(APPEND NBL_DEPENDENCY_FILES "${NBL_BUILTIN_DATA_GEN_PY}") - set(NBL_RESOURCES_LIST_FILE "${_OUTPUT_SOURCE_DIRECTORY_}/resources.txt") + set(NBL_RESOURCES_LIST_FILE "${_OUTPUT_SOURCE_DIRECTORY_}/resources-$.txt") string(REPLACE ";" "\n" RESOURCES_ARGS "${_LBR_${_BUNDLE_NAME_}_}") - file(WRITE "${NBL_RESOURCES_LIST_FILE}" "${RESOURCES_ARGS}") + file(GENERATE OUTPUT "${NBL_RESOURCES_LIST_FILE}" CONTENT "${RESOURCES_ARGS}") set(NBL_BUILTIN_RESOURCES_H "${_OUTPUT_HEADER_DIRECTORY_}/${NBL_BS_HEADER_FILENAME}") set(NBL_BUILTIN_RESOURCE_DATA_CPP "${_OUTPUT_SOURCE_DIRECTORY_}/${NBL_BS_DATA_SOURCE_FILENAME}") @@ -247,4 +247,4 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH if(MSVC AND NBL_SANITIZE_ADDRESS) set_property(TARGET ${_TARGET_NAME_} PROPERTY COMPILE_OPTIONS /fsanitize=address) endif() -endfunction() \ No newline at end of file +endfunction() From f95f163d37f26fe8a07b06a33e901bf7d9b9fb83 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 28 Dec 2025 22:37:07 +0100 Subject: [PATCH 58/61] update examples_tests submodule --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 59a434cc64..81449834f4 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 59a434cc64179b223663a6ca6543a4e85a9f58e1 +Subproject commit 81449834f4efd4fe649f7dc706ab202ca92c45f3 From 575136ee1546ea5849a97af286ff3b7f419c98e8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 28 Dec 2025 22:40:06 +0100 Subject: [PATCH 59/61] builtin sources & headers per configuration --- src/nbl/builtin/utils.cmake | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/nbl/builtin/utils.cmake b/src/nbl/builtin/utils.cmake index 26499dfc76..17fce1e8a6 100644 --- a/src/nbl/builtin/utils.cmake +++ b/src/nbl/builtin/utils.cmake @@ -82,10 +82,18 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH string(MAKE_C_IDENTIFIER ${_GUARD_SUFFIX_} _GUARD_SUFFIX_) set(_OUTPUT_INCLUDE_SEARCH_DIRECTORY_ "${_OUTPUT_INCLUDE_SEARCH_DIRECTORY_}") - set(_OUTPUT_HEADER_DIRECTORY_ "${_OUTPUT_INCLUDE_SEARCH_DIRECTORY_}/${_NAMESPACE_PREFIX_}") + set(_OUTPUT_HEADER_DIRECTORY_BASE "${_OUTPUT_INCLUDE_SEARCH_DIRECTORY_}/${_NAMESPACE_PREFIX_}") + set(_OUTPUT_SOURCE_DIRECTORY_BASE "${_OUTPUT_SOURCE_DIRECTORY_}") + set(_OUTPUT_INCLUDE_SEARCH_DIRECTORY_CONFIG "${_OUTPUT_INCLUDE_SEARCH_DIRECTORY_}/$") + set(_OUTPUT_HEADER_DIRECTORY_ "${_OUTPUT_INCLUDE_SEARCH_DIRECTORY_CONFIG}/${_NAMESPACE_PREFIX_}") + set(_OUTPUT_SOURCE_DIRECTORY_ "${_OUTPUT_SOURCE_DIRECTORY_BASE}/$") + set(_OUTPUT_INCLUDE_DIRECTORIES_ + "${_OUTPUT_HEADER_DIRECTORY_}" + "${_OUTPUT_INCLUDE_SEARCH_DIRECTORY_CONFIG}" + ) - file(MAKE_DIRECTORY "${_OUTPUT_HEADER_DIRECTORY_}") - file(MAKE_DIRECTORY "${_OUTPUT_SOURCE_DIRECTORY_}") + file(MAKE_DIRECTORY "${_OUTPUT_HEADER_DIRECTORY_BASE}") + file(MAKE_DIRECTORY "${_OUTPUT_SOURCE_DIRECTORY_BASE}") set(_ITR_ 0) foreach(X IN LISTS _LBR_${_BUNDLE_NAME_}_) # iterate over builtin resources bundle list given bundle name @@ -119,7 +127,7 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH list(APPEND NBL_DEPENDENCY_FILES "${NBL_BUILTIN_HEADER_GEN_PY}") list(APPEND NBL_DEPENDENCY_FILES "${NBL_BUILTIN_DATA_GEN_PY}") - set(NBL_RESOURCES_LIST_FILE "${_OUTPUT_SOURCE_DIRECTORY_}/resources-$.txt") + set(NBL_RESOURCES_LIST_FILE "${_OUTPUT_SOURCE_DIRECTORY_BASE}/resources-$.txt") string(REPLACE ";" "\n" RESOURCES_ARGS "${_LBR_${_BUNDLE_NAME_}_}") file(GENERATE OUTPUT "${NBL_RESOURCES_LIST_FILE}" CONTENT "${RESOURCES_ARGS}") @@ -139,6 +147,7 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH ) add_custom_command(OUTPUT "${NBL_BUILTIN_RESOURCES_H}" "${NBL_BUILTIN_RESOURCE_DATA_CPP}" "${NBL_BUILTIN_DATA_ARCHIVE_H}" "${NBL_BUILTIN_DATA_ARCHIVE_CPP}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${_OUTPUT_HEADER_DIRECTORY_}" "${_OUTPUT_SOURCE_DIRECTORY_}" COMMAND "${_Python3_EXECUTABLE}" "${NBL_BUILTIN_HEADER_GEN_PY}" ${NBL_BUILTIN_RESOURCES_COMMON_ARGS} --outputBuiltinPath "${NBL_BUILTIN_RESOURCES_H}" --outputArchivePath "${NBL_BUILTIN_DATA_ARCHIVE_H}" --archiveBundlePath "${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" --guardSuffix "${_GUARD_SUFFIX_}" --isSharedLibrary "${_SHARED_}" COMMAND "${_Python3_EXECUTABLE}" "${NBL_BUILTIN_DATA_GEN_PY}" ${NBL_BUILTIN_RESOURCES_COMMON_ARGS} --outputBuiltinPath "${NBL_BUILTIN_RESOURCE_DATA_CPP}" --outputArchivePath "${NBL_BUILTIN_DATA_ARCHIVE_CPP}" --bundleAbsoluteEntryPath "${_BUNDLE_SEARCH_DIRECTORY_}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" --correspondingHeaderFile "${NBL_BS_HEADER_FILENAME}" --xxHash256Exe "$<${_NBL_BR_RUNTIME_HASH_}:$>" COMMENT "Generating \"${_TARGET_NAME_}\"'s sources & headers" @@ -204,8 +213,8 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH endif() target_include_directories(${_TARGET_NAME_} PUBLIC + ${_OUTPUT_INCLUDE_DIRECTORIES_} "${_NABLA_INCLUDE_DIRECTORIES_}" - "${_OUTPUT_HEADER_DIRECTORY_}" ) set_target_properties(${_TARGET_NAME_} PROPERTIES CXX_STANDARD 20) @@ -242,7 +251,7 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH _ADD_PROPERTY_(BUILTIN_RESOURCES_HEADER_DIRECTORY _OUTPUT_HEADER_DIRECTORY_) _ADD_PROPERTY_(BUILTIN_RESOURCES_SOURCE_DIRECTORY _OUTPUT_SOURCE_DIRECTORY_) _ADD_PROPERTY_(BUILTIN_RESOURCES_HEADERS NBL_BUILTIN_RESOURCES_HEADERS) - _ADD_PROPERTY_(BUILTIN_RESOURCES_INCLUDE_SEARCH_DIRECTORY _OUTPUT_INCLUDE_SEARCH_DIRECTORY_) + _ADD_PROPERTY_(BUILTIN_RESOURCES_INCLUDE_SEARCH_DIRECTORY _OUTPUT_HEADER_DIRECTORY_) if(MSVC AND NBL_SANITIZE_ADDRESS) set_property(TARGET ${_TARGET_NAME_} PROPERTY COMPILE_OPTIONS /fsanitize=address) From 2f5de5d91185825a1dc1438c6197ec8128289041 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 29 Dec 2025 10:33:08 +0100 Subject: [PATCH 60/61] wipe installation rules of builtin resource headers, they are not included in headers, not exported and its private interface actually they might be installed but then shall be exported and it requires polishing what content they include as they should hide all info about keys to keep our install single prefix --- cmake/common.cmake | 7 ------- src/nbl/CMakeLists.txt | 8 -------- 2 files changed, 15 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 10741c9a94..4ee0e705ca 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -350,13 +350,6 @@ function(nbl_install_media _FILE) nbl_install_lib_spec("${_FILE}" "") endfunction() -function(nbl_install_builtin_resources _TARGET_) - get_target_property(_BUILTIN_RESOURCES_INCLUDE_SEARCH_DIRECTORY_ ${_TARGET_} BUILTIN_RESOURCES_INCLUDE_SEARCH_DIRECTORY) - get_target_property(_BUILTIN_RESOURCES_HEADERS_ ${_TARGET_} BUILTIN_RESOURCES_HEADERS) - - nbl_install_headers_spec("${_BUILTIN_RESOURCES_HEADERS_}" "${_BUILTIN_RESOURCES_INCLUDE_SEARCH_DIRECTORY_}") -endfunction() - function(NBL_TEST_MODULE_INSTALL_FILE _NBL_FILEPATH_) file(RELATIVE_PATH _NBL_REL_INSTALL_DEST_ "${NBL_ROOT_PATH}" "${_NBL_FILEPATH_}") cmake_path(GET _NBL_REL_INSTALL_DEST_ PARENT_PATH _NBL_REL_INSTALL_DEST_) diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index 8603d8935f..6a7e144f36 100644 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -785,14 +785,6 @@ add_subdirectory(ext EXCLUDE_FROM_ALL) propagate_changed_variables_to_parent_scope() nbl_install_headers("${NABLA_HEADERS_PUBLIC}") -nbl_install_file_spec("${NBL_ROOT_PATH_BINARY}/include/nbl/builtin/builtinResources.h" "nbl/builtin") - -if(NBL_EMBED_BUILTIN_RESOURCES) - nbl_install_builtin_resources(nblBuiltinResourceData) - nbl_install_builtin_resources(spirvBuiltinResourceData) - nbl_install_builtin_resources(boostBuiltinResourceData) -endif() - set_target_properties(Nabla PROPERTIES DEBUG_POSTFIX _debug) set_target_properties(Nabla PROPERTIES RELWITHDEBINFO_POSTFIX _relwithdebinfo) From c71762e336026bcdcd9fdf8e936e4b55810ca4e8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 29 Dec 2025 12:30:25 +0100 Subject: [PATCH 61/61] BUILD_INTERFACE for builtin auto-gen include search directories --- src/nbl/CMakeLists.txt | 1 + src/nbl/builtin/utils.cmake | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index 6a7e144f36..895488cf45 100644 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -694,6 +694,7 @@ if(NBL_EMBED_BUILTIN_RESOURCES) target_compile_definitions(${NBL_TARGET} PUBLIC "$") # workaround because must use Nabla headers without linking Nabla to itself.. target_include_directories(${NBL_TARGET} PUBLIC "$") target_include_directories(Nabla PRIVATE "${_INTERNAL_BR_OUTPUT_INCLUDE_SEARCH_DIRECTORY_}") + target_include_directories(Nabla INTERFACE "$") endforeach() add_dependencies(Nabla ${NBL_TARGETS}) diff --git a/src/nbl/builtin/utils.cmake b/src/nbl/builtin/utils.cmake index 17fce1e8a6..6465c2ac6d 100644 --- a/src/nbl/builtin/utils.cmake +++ b/src/nbl/builtin/utils.cmake @@ -251,7 +251,7 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH _ADD_PROPERTY_(BUILTIN_RESOURCES_HEADER_DIRECTORY _OUTPUT_HEADER_DIRECTORY_) _ADD_PROPERTY_(BUILTIN_RESOURCES_SOURCE_DIRECTORY _OUTPUT_SOURCE_DIRECTORY_) _ADD_PROPERTY_(BUILTIN_RESOURCES_HEADERS NBL_BUILTIN_RESOURCES_HEADERS) - _ADD_PROPERTY_(BUILTIN_RESOURCES_INCLUDE_SEARCH_DIRECTORY _OUTPUT_HEADER_DIRECTORY_) + _ADD_PROPERTY_(BUILTIN_RESOURCES_INCLUDE_SEARCH_DIRECTORY _OUTPUT_INCLUDE_SEARCH_DIRECTORY_CONFIG) if(MSVC AND NBL_SANITIZE_ADDRESS) set_property(TARGET ${_TARGET_NAME_} PROPERTY COMPILE_OPTIONS /fsanitize=address)