IBL Specular complete.
This commit is contained in:
parent
b9d5ba56d4
commit
e82b37b2d9
|
|
@ -40,6 +40,24 @@
|
||||||
"name": "windows-reldebug",
|
"name": "windows-reldebug",
|
||||||
"generator": "Ninja",
|
"generator": "Ninja",
|
||||||
"binaryDir": "${sourceDir}/build/reldebug/",
|
"binaryDir": "${sourceDir}/build/reldebug/",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||||
|
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
||||||
|
"CMAKE_MAKE_PROGRAM": "ninja",
|
||||||
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
|
||||||
|
"DXC_SHADER_FLAGS": "-Zi",
|
||||||
|
"GLSLC_SHADER_FLAGS": "-g"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-reldebug-nobreak",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"binaryDir": "${sourceDir}/build/reldebug/",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||||
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ Failed(const vk::Result result)
|
||||||
using NameString = eastl::fixed_string<char, 32, false>;
|
using NameString = eastl::fixed_string<char, 32, false>;
|
||||||
|
|
||||||
template <typename TFlagBits>
|
template <typename TFlagBits>
|
||||||
struct std::hash<vk::Flags<TFlagBits>> // NOLINT(*-dcl58-cpp)
|
struct eastl::hash<vk::Flags<TFlagBits>> // NOLINT(*-dcl58-cpp)
|
||||||
{
|
{
|
||||||
[[nodiscard]] usize
|
[[nodiscard]] usize
|
||||||
operator()(const vk::Flags<TFlagBits> &val)
|
operator()(const vk::Flags<TFlagBits> &val)
|
||||||
|
|
@ -66,7 +66,7 @@ template <typename T>
|
||||||
[[nodiscard]] usize
|
[[nodiscard]] usize
|
||||||
HashAny(const T &val)
|
HashAny(const T &val)
|
||||||
{
|
{
|
||||||
return std::hash<std::remove_cvref_t<T>>()(val);
|
return eastl::hash<std::remove_cvref_t<T>>()(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline usize
|
[[nodiscard]] inline usize
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,79 @@ StorageTextureManager::Release(const Device *device, const StorageTextureHandle
|
||||||
TextureManager::Release(device, {handle.m_Index});
|
TextureManager::Release(device, {handle.m_Index});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usize
|
||||||
|
HashSamplerCreateInfo(const vk::SamplerCreateInfo *createInfo)
|
||||||
|
{
|
||||||
|
usize hash = HashAny(createInfo->flags);
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->magFilter));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->minFilter));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->mipmapMode));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->addressModeU));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->addressModeV));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->addressModeW));
|
||||||
|
hash = HashCombine(hash, HashAny(Cast<usize>(createInfo->mipLodBias * 1000))); // Resolution of 10^-3
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->anisotropyEnable));
|
||||||
|
hash = HashCombine(hash,
|
||||||
|
HashAny(Cast<usize>(createInfo->maxAnisotropy * 0x10))); // 16:1 Anisotropy is enough resolution
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->compareEnable));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->compareOp));
|
||||||
|
hash = HashCombine(hash, HashAny(Cast<usize>(createInfo->minLod * 1000))); // 0.001 resolution is enough.
|
||||||
|
hash = HashCombine(hash,
|
||||||
|
HashAny(Cast<usize>(createInfo->maxLod * 1000))); // 0.001 resolution is enough. (1 == NO Clamp)
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->borderColor));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->unnormalizedCoordinates));
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SamplerManager::Init(usize size)
|
||||||
|
{
|
||||||
|
m_Samplers.reserve(size);
|
||||||
|
m_SamplerHashes.reserve(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
SamplerHandle
|
||||||
|
SamplerManager::Create(const Device *device, const vk::SamplerCreateInfo *createInfo)
|
||||||
|
{
|
||||||
|
const usize hash = HashSamplerCreateInfo(createInfo);
|
||||||
|
|
||||||
|
for (u32 index = 0; usize samplerHash : m_SamplerHashes)
|
||||||
|
{
|
||||||
|
if (samplerHash == hash)
|
||||||
|
{
|
||||||
|
return {index};
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Sampler sampler;
|
||||||
|
AbortIfFailed(device->m_Device.createSampler(createInfo, nullptr, &sampler));
|
||||||
|
const u32 index = Cast<u32>(m_SamplerHashes.size());
|
||||||
|
m_SamplerHashes.push_back(hash);
|
||||||
|
m_Samplers.push_back(sampler);
|
||||||
|
return {index};
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Sampler
|
||||||
|
SamplerManager::Fetch(const SamplerHandle handle)
|
||||||
|
{
|
||||||
|
assert(!handle.IsInvalid());
|
||||||
|
|
||||||
|
return m_Samplers[handle.m_Index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SamplerManager::Destroy(const Device *device)
|
||||||
|
{
|
||||||
|
for (const auto &sampler : m_Samplers)
|
||||||
|
{
|
||||||
|
device->m_Device.destroy(sampler, nullptr);
|
||||||
|
}
|
||||||
|
m_Samplers.clear();
|
||||||
|
m_SamplerHashes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorBufferInfo info)
|
GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorBufferInfo info)
|
||||||
: uBufferInfo(info)
|
: uBufferInfo(info)
|
||||||
{
|
{
|
||||||
|
|
@ -323,12 +396,14 @@ GpuResourceManager::Release(Texture *texture, TextureHandle handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureHandle
|
TextureHandle
|
||||||
GpuResourceManager::CommitTexture(Texture *texture)
|
GpuResourceManager::CommitTexture(Texture *texture, const SamplerHandle sampler)
|
||||||
{
|
{
|
||||||
TextureHandle handle = m_TextureManager.Commit(texture);
|
TextureHandle handle = m_TextureManager.Commit(texture);
|
||||||
|
|
||||||
|
const vk::Sampler samplerImpl = sampler.IsInvalid() ? m_DefaultSampler : m_SamplerManager.Fetch(sampler);
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||||
.sampler = nullptr,
|
.sampler = samplerImpl,
|
||||||
.imageView = texture->m_View,
|
.imageView = texture->m_View,
|
||||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
});
|
});
|
||||||
|
|
@ -352,12 +427,14 @@ GpuResourceManager::CommitTexture(Texture *texture)
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageTextureHandle
|
StorageTextureHandle
|
||||||
GpuResourceManager::CommitStorageTexture(StorageTexture *storageTexture)
|
GpuResourceManager::CommitStorageTexture(StorageTexture *storageTexture, SamplerHandle sampler)
|
||||||
{
|
{
|
||||||
StorageTextureHandle handle = m_StorageTextureManager.Commit(storageTexture);
|
StorageTextureHandle handle = m_StorageTextureManager.Commit(storageTexture);
|
||||||
|
|
||||||
|
vk::Sampler samplerImpl = sampler.IsInvalid() ? m_DefaultSampler : m_SamplerManager.Fetch(sampler);
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||||
.sampler = nullptr,
|
.sampler = samplerImpl,
|
||||||
.imageView = storageTexture->m_View,
|
.imageView = storageTexture->m_View,
|
||||||
.imageLayout = vk::ImageLayout::eGeneral,
|
.imageLayout = vk::ImageLayout::eGeneral,
|
||||||
});
|
});
|
||||||
|
|
@ -432,8 +509,16 @@ GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||||
u32 storageTexturesCount =
|
u32 storageTexturesCount =
|
||||||
eastl::min(properties.limits.maxPerStageDescriptorStorageImages - 1024, Cast<u32>(maxSize));
|
eastl::min(properties.limits.maxPerStageDescriptorStorageImages - 1024, Cast<u32>(maxSize));
|
||||||
|
|
||||||
// TODO: Switch to bindless samplers / multiple sampler configurations
|
INFO("Max Buffer Count: {}", buffersCount);
|
||||||
vk::SamplerCreateInfo samplerCreateInfo = {
|
INFO("Max Texture Count: {}", texturesCount);
|
||||||
|
INFO("Max Storage Texture Count: {}", storageTexturesCount);
|
||||||
|
|
||||||
|
m_BufferManager.Init(buffersCount);
|
||||||
|
m_TextureManager.Init(texturesCount);
|
||||||
|
m_StorageTextureManager.Init(storageTexturesCount);
|
||||||
|
m_SamplerManager.Init(storageTexturesCount);
|
||||||
|
|
||||||
|
m_DefaultSamplerCreateInfo = {
|
||||||
.magFilter = vk::Filter::eLinear,
|
.magFilter = vk::Filter::eLinear,
|
||||||
.minFilter = vk::Filter::eLinear,
|
.minFilter = vk::Filter::eLinear,
|
||||||
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||||
|
|
@ -449,15 +534,8 @@ GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||||
.borderColor = vk::BorderColor::eFloatOpaqueBlack,
|
.borderColor = vk::BorderColor::eFloatOpaqueBlack,
|
||||||
.unnormalizedCoordinates = false,
|
.unnormalizedCoordinates = false,
|
||||||
};
|
};
|
||||||
AbortIfFailed(device->m_Device.createSampler(&samplerCreateInfo, nullptr, &m_ImmutableSampler));
|
|
||||||
|
|
||||||
INFO("Max Buffer Count: {}", buffersCount);
|
m_DefaultSampler = m_SamplerManager.Fetch(m_SamplerManager.Create(device, &m_DefaultSamplerCreateInfo));
|
||||||
INFO("Max Texture Count: {}", texturesCount);
|
|
||||||
INFO("Max Storage Texture Count: {}", storageTexturesCount);
|
|
||||||
|
|
||||||
m_BufferManager.Init(buffersCount);
|
|
||||||
m_TextureManager.Init(texturesCount);
|
|
||||||
m_StorageTextureManager.Init(storageTexturesCount);
|
|
||||||
|
|
||||||
eastl::array poolSizes = {
|
eastl::array poolSizes = {
|
||||||
vk::DescriptorPoolSize{
|
vk::DescriptorPoolSize{
|
||||||
|
|
@ -495,7 +573,6 @@ GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||||
.pBindingFlags = layoutBindingFlags.data(),
|
.pBindingFlags = layoutBindingFlags.data(),
|
||||||
};
|
};
|
||||||
|
|
||||||
eastl::vector immutableSamplers(texturesCount, m_ImmutableSampler);
|
|
||||||
eastl::array descriptorLayoutBindings = {
|
eastl::array descriptorLayoutBindings = {
|
||||||
vk::DescriptorSetLayoutBinding{
|
vk::DescriptorSetLayoutBinding{
|
||||||
.binding = BUFFER_BINDING_INDEX,
|
.binding = BUFFER_BINDING_INDEX,
|
||||||
|
|
@ -508,7 +585,6 @@ GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.descriptorCount = Cast<u32>(texturesCount),
|
.descriptorCount = Cast<u32>(texturesCount),
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
.pImmutableSamplers = immutableSamplers.data(),
|
|
||||||
},
|
},
|
||||||
vk::DescriptorSetLayoutBinding{
|
vk::DescriptorSetLayoutBinding{
|
||||||
.binding = STORAGE_TEXTURE_BINDING_INDEX,
|
.binding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||||
|
|
@ -552,7 +628,7 @@ GpuResourceManager::~GpuResourceManager()
|
||||||
m_BufferManager.Destroy(m_Device);
|
m_BufferManager.Destroy(m_Device);
|
||||||
m_TextureManager.Destroy(m_Device);
|
m_TextureManager.Destroy(m_Device);
|
||||||
m_StorageTextureManager.Destroy(m_Device);
|
m_StorageTextureManager.Destroy(m_Device);
|
||||||
m_Device->m_Device.destroy(m_ImmutableSampler, nullptr);
|
m_SamplerManager.Destroy(m_Device);
|
||||||
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
||||||
m_Device->m_Device.destroy(m_SetLayout, nullptr);
|
m_Device->m_Device.destroy(m_SetLayout, nullptr);
|
||||||
}
|
}
|
||||||
|
|
@ -561,10 +637,10 @@ GpuResourceManager::GpuResourceManager(GpuResourceManager &&other) noexcept
|
||||||
: m_WriteInfos(std::move(other.m_WriteInfos))
|
: m_WriteInfos(std::move(other.m_WriteInfos))
|
||||||
, m_Writes(std::move(other.m_Writes))
|
, m_Writes(std::move(other.m_Writes))
|
||||||
, m_WriteOwner(std::move(other.m_WriteOwner))
|
, m_WriteOwner(std::move(other.m_WriteOwner))
|
||||||
, m_ImmutableSampler(other.m_ImmutableSampler)
|
|
||||||
, m_BufferManager(std::move(other.m_BufferManager))
|
, m_BufferManager(std::move(other.m_BufferManager))
|
||||||
, m_TextureManager(std::move(other.m_TextureManager))
|
, m_TextureManager(std::move(other.m_TextureManager))
|
||||||
, m_StorageTextureManager(std::move(other.m_StorageTextureManager))
|
, m_StorageTextureManager(std::move(other.m_StorageTextureManager))
|
||||||
|
, m_SamplerManager(std::move(other.m_SamplerManager))
|
||||||
, m_Device(Take(other.m_Device))
|
, m_Device(Take(other.m_Device))
|
||||||
, m_DescriptorPool(other.m_DescriptorPool)
|
, m_DescriptorPool(other.m_DescriptorPool)
|
||||||
, m_SetLayout(other.m_SetLayout)
|
, m_SetLayout(other.m_SetLayout)
|
||||||
|
|
@ -586,10 +662,10 @@ GpuResourceManager::operator=(GpuResourceManager &&other) noexcept
|
||||||
m_WriteInfos = std::move(other.m_WriteInfos);
|
m_WriteInfos = std::move(other.m_WriteInfos);
|
||||||
m_Writes = std::move(other.m_Writes);
|
m_Writes = std::move(other.m_Writes);
|
||||||
m_WriteOwner = std::move(other.m_WriteOwner);
|
m_WriteOwner = std::move(other.m_WriteOwner);
|
||||||
m_ImmutableSampler = other.m_ImmutableSampler;
|
|
||||||
m_BufferManager = std::move(other.m_BufferManager);
|
m_BufferManager = std::move(other.m_BufferManager);
|
||||||
m_TextureManager = std::move(other.m_TextureManager);
|
m_TextureManager = std::move(other.m_TextureManager);
|
||||||
m_StorageTextureManager = std::move(other.m_StorageTextureManager);
|
m_StorageTextureManager = std::move(other.m_StorageTextureManager);
|
||||||
|
m_SamplerManager = std::move(other.m_SamplerManager);
|
||||||
m_Device = Take(other.m_Device); // Ensure taken.
|
m_Device = Take(other.m_Device); // Ensure taken.
|
||||||
m_DescriptorPool = other.m_DescriptorPool;
|
m_DescriptorPool = other.m_DescriptorPool;
|
||||||
m_SetLayout = other.m_SetLayout;
|
m_SetLayout = other.m_SetLayout;
|
||||||
|
|
@ -603,3 +679,9 @@ GpuResourceManager::operator=(GpuResourceManager &&other) noexcept
|
||||||
assert(!other.m_Device);
|
assert(!other.m_Device);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SamplerHandle
|
||||||
|
GpuResourceManager::CreateSampler(const vk::SamplerCreateInfo *samplerCreateInfo)
|
||||||
|
{
|
||||||
|
return m_SamplerManager.Create(m_Device, samplerCreateInfo);
|
||||||
|
}
|
||||||
|
|
@ -39,6 +39,10 @@ struct StorageTextureHandle : GpuResourceHandle
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SamplerHandle : GpuResourceHandle
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
struct TextureManager
|
struct TextureManager
|
||||||
{
|
{
|
||||||
eastl::vector<Texture> m_Textures;
|
eastl::vector<Texture> m_Textures;
|
||||||
|
|
@ -72,6 +76,18 @@ struct StorageTextureManager : TextureManager
|
||||||
void Release(const Device *device, StorageTextureHandle handle);
|
void Release(const Device *device, StorageTextureHandle handle);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SamplerManager
|
||||||
|
{
|
||||||
|
// There can only be so many samplers.
|
||||||
|
eastl::vector<vk::Sampler> m_Samplers;
|
||||||
|
eastl::vector<usize> m_SamplerHashes;
|
||||||
|
|
||||||
|
void Init(usize size);
|
||||||
|
SamplerHandle Create(const Device *device, const vk::SamplerCreateInfo *createInfo);
|
||||||
|
vk::Sampler Fetch(SamplerHandle handle);
|
||||||
|
void Destroy(const Device *device);
|
||||||
|
};
|
||||||
|
|
||||||
struct GpuResourceManager
|
struct GpuResourceManager
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
@ -102,11 +118,12 @@ struct GpuResourceManager
|
||||||
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
||||||
eastl::vector<WriteOwner> m_WriteOwner;
|
eastl::vector<WriteOwner> m_WriteOwner;
|
||||||
|
|
||||||
vk::Sampler m_ImmutableSampler;
|
vk::Sampler m_DefaultSampler;
|
||||||
|
|
||||||
BufferManager m_BufferManager;
|
BufferManager m_BufferManager;
|
||||||
TextureManager m_TextureManager;
|
TextureManager m_TextureManager;
|
||||||
StorageTextureManager m_StorageTextureManager;
|
StorageTextureManager m_StorageTextureManager;
|
||||||
|
SamplerManager m_SamplerManager;
|
||||||
|
|
||||||
void EraseWrites(u32 handleIndex, HandleType handleType);
|
void EraseWrites(u32 handleIndex, HandleType handleType);
|
||||||
|
|
||||||
|
|
@ -117,6 +134,8 @@ struct GpuResourceManager
|
||||||
constexpr static u32 TEXTURE_BINDING_INDEX = 1;
|
constexpr static u32 TEXTURE_BINDING_INDEX = 1;
|
||||||
constexpr static u32 STORAGE_TEXTURE_BINDING_INDEX = 2;
|
constexpr static u32 STORAGE_TEXTURE_BINDING_INDEX = 2;
|
||||||
|
|
||||||
|
vk::SamplerCreateInfo m_DefaultSamplerCreateInfo;
|
||||||
|
|
||||||
vk::DescriptorPool m_DescriptorPool;
|
vk::DescriptorPool m_DescriptorPool;
|
||||||
vk::DescriptorSetLayout m_SetLayout;
|
vk::DescriptorSetLayout m_SetLayout;
|
||||||
vk::DescriptorSet m_DescriptorSet;
|
vk::DescriptorSet m_DescriptorSet;
|
||||||
|
|
@ -126,13 +145,16 @@ struct GpuResourceManager
|
||||||
void Release(BufferHandle handle); // Release and Destroy
|
void Release(BufferHandle handle); // Release and Destroy
|
||||||
void Release(StorageBuffer *storageBuffer, BufferHandle handle); // Release and Return
|
void Release(StorageBuffer *storageBuffer, BufferHandle handle); // Release and Return
|
||||||
|
|
||||||
TextureHandle CommitTexture(Texture *texture); // Commit to GPU and take Ownership
|
TextureHandle CommitTexture(Texture *texture, SamplerHandle sampler = {}); // Commit to GPU and take Ownership
|
||||||
void Release(TextureHandle handle); // Release and Destroy
|
void Release(TextureHandle handle); // Release and Destroy
|
||||||
void Release(Texture *texture, TextureHandle handle); // Release and Return
|
void Release(Texture *texture, TextureHandle handle); // Release and Return
|
||||||
|
|
||||||
StorageTextureHandle CommitStorageTexture(StorageTexture *storageTexture); // Commit to GPU and take Ownership
|
StorageTextureHandle
|
||||||
void Release(StorageTextureHandle handle); // Release and Destroy
|
CommitStorageTexture(StorageTexture *storageTexture, SamplerHandle sampler = {}); // Commit to GPU and take Ownership
|
||||||
void Release(StorageTexture *texture, StorageTextureHandle handle); // Release and Return
|
void Release(StorageTextureHandle handle); // Release and Destroy
|
||||||
|
void Release(StorageTexture *texture, StorageTextureHandle handle); // Release and Return
|
||||||
|
|
||||||
|
SamplerHandle CreateSampler(const vk::SamplerCreateInfo *samplerCreateInfo);
|
||||||
|
|
||||||
void Update(); // Update all the descriptors required.
|
void Update(); // Update all the descriptors required.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ add_shader(model_render shader/background.vs.hlsl)
|
||||||
add_shader(model_render shader/background.ps.hlsl)
|
add_shader(model_render shader/background.ps.hlsl)
|
||||||
add_shader(model_render shader/diffuse_irradiance.cs.hlsl)
|
add_shader(model_render shader/diffuse_irradiance.cs.hlsl)
|
||||||
add_shader(model_render shader/prefilter.cs.hlsl)
|
add_shader(model_render shader/prefilter.cs.hlsl)
|
||||||
|
add_shader(model_render shader/brdf_lut.cs.hlsl)
|
||||||
|
|
||||||
target_link_libraries(model_render PRIVATE aster_core)
|
target_link_libraries(model_render PRIVATE aster_core)
|
||||||
target_link_libraries(model_render PRIVATE util_helper)
|
target_link_libraries(model_render PRIVATE util_helper)
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@ GenerateMipMaps(vk::CommandBuffer commandBuffer, Texture *texture, vk::ImageLayo
|
||||||
vk::ImageMemoryBarrier2 imageReadyBarrier = {
|
vk::ImageMemoryBarrier2 imageReadyBarrier = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
|
.dstStageMask = finalStage,
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
||||||
.oldLayout = vk::ImageLayout::eTransferSrcOptimal,
|
.oldLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||||
.newLayout = finalLayout,
|
.newLayout = finalLayout,
|
||||||
|
|
|
||||||
|
|
@ -17,25 +17,43 @@
|
||||||
constexpr cstr EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrect_to_cube.cs.hlsl.spv";
|
constexpr cstr EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrect_to_cube.cs.hlsl.spv";
|
||||||
constexpr cstr DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
constexpr cstr DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
||||||
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
||||||
|
constexpr cstr BRDF_LUT_SHADER_FILE = "shader/brdf_lut.cs.hlsl.spv";
|
||||||
|
|
||||||
eastl::tuple<TextureHandle, TextureHandle, TextureHandle>
|
void
|
||||||
|
Environment::Destroy(GpuResourceManager *resourceManager)
|
||||||
|
{
|
||||||
|
resourceManager->Release(Take(m_Skybox));
|
||||||
|
resourceManager->Release(Take(m_Diffuse));
|
||||||
|
resourceManager->Release(Take(m_Prefilter));
|
||||||
|
resourceManager->Release(Take(m_BrdfLut));
|
||||||
|
}
|
||||||
|
|
||||||
|
Environment
|
||||||
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cubeSide, TextureHandle hdrEnv,
|
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cubeSide, TextureHandle hdrEnv,
|
||||||
const cstr name)
|
const cstr name)
|
||||||
{
|
{
|
||||||
GpuResourceManager *resMan = assetLoader->m_ResourceManager;
|
GpuResourceManager *resMan = assetLoader->m_ResourceManager;
|
||||||
const Device *pDevice = resMan->m_Device;
|
const Device *pDevice = resMan->m_Device;
|
||||||
|
|
||||||
|
vk::SamplerCreateInfo brdfLutSamplerCreateInfo = resMan->m_DefaultSamplerCreateInfo;
|
||||||
|
brdfLutSamplerCreateInfo.addressModeU = vk::SamplerAddressMode::eClampToEdge;
|
||||||
|
brdfLutSamplerCreateInfo.addressModeV = vk::SamplerAddressMode::eClampToEdge;
|
||||||
|
brdfLutSamplerCreateInfo.addressModeW = vk::SamplerAddressMode::eClampToEdge;
|
||||||
|
|
||||||
StorageTextureCube skybox;
|
StorageTextureCube skybox;
|
||||||
|
StorageTextureCube diffuseIrradiance;
|
||||||
|
StorageTextureCube prefilterCube;
|
||||||
|
StorageTexture brdfLut;
|
||||||
|
SamplerHandle brdfLutSampler;
|
||||||
|
|
||||||
skybox.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, true, true, "Skybox");
|
skybox.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, true, true, "Skybox");
|
||||||
TextureHandle skyboxHandle = resMan->CommitTexture(&skybox);
|
TextureHandle skyboxHandle = resMan->CommitTexture(&skybox);
|
||||||
StorageTextureHandle skyboxStorageHandle = resMan->CommitStorageTexture(&skybox);
|
StorageTextureHandle skyboxStorageHandle = resMan->CommitStorageTexture(&skybox);
|
||||||
|
|
||||||
StorageTextureCube diffuseIrradiance;
|
|
||||||
diffuseIrradiance.Init(pDevice, 64, vk::Format::eR16G16B16A16Sfloat, true, false, "Diffuse Irradiance");
|
diffuseIrradiance.Init(pDevice, 64, vk::Format::eR16G16B16A16Sfloat, true, false, "Diffuse Irradiance");
|
||||||
TextureHandle diffuseIrradianceHandle = resMan->CommitTexture(&diffuseIrradiance);
|
TextureHandle diffuseIrradianceHandle = resMan->CommitTexture(&diffuseIrradiance);
|
||||||
StorageTextureHandle diffuseIrradianceStorageHandle = resMan->CommitStorageTexture(&diffuseIrradiance);
|
StorageTextureHandle diffuseIrradianceStorageHandle = resMan->CommitStorageTexture(&diffuseIrradiance);
|
||||||
|
|
||||||
StorageTextureCube prefilterCube;
|
|
||||||
prefilterCube.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, true, true, "Prefilter");
|
prefilterCube.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, true, true, "Prefilter");
|
||||||
TextureHandle prefilterHandle = resMan->CommitTexture(&prefilterCube); // This stores the original view for us.
|
TextureHandle prefilterHandle = resMan->CommitTexture(&prefilterCube); // This stores the original view for us.
|
||||||
constexpr u32 prefilterMipCountMax = 6;
|
constexpr u32 prefilterMipCountMax = 6;
|
||||||
|
|
@ -61,6 +79,11 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
tex = resMan->CommitStorageTexture(&prefilterCube);
|
tex = resMan->CommitStorageTexture(&prefilterCube);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
brdfLut.Init(pDevice, {512, 512}, vk::Format::eR16G16Sfloat, true, "BRDF LUT");
|
||||||
|
brdfLutSampler = resMan->CreateSampler(&brdfLutSamplerCreateInfo);
|
||||||
|
TextureHandle brdfLutHandle = resMan->CommitTexture(&brdfLut, brdfLutSampler);
|
||||||
|
StorageTextureHandle brdfLutStorageHandle = resMan->CommitStorageTexture(&brdfLut);
|
||||||
|
|
||||||
#pragma region Dependencies and Copies
|
#pragma region Dependencies and Copies
|
||||||
vk::ImageSubresourceRange cubeSubresRange = {
|
vk::ImageSubresourceRange cubeSubresRange = {
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
|
@ -69,6 +92,13 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 6,
|
.layerCount = 6,
|
||||||
};
|
};
|
||||||
|
vk::ImageSubresourceRange lutSubresRange = {
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 readyToWriteBarrierTemplate = {
|
vk::ImageMemoryBarrier2 readyToWriteBarrierTemplate = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe,
|
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe,
|
||||||
|
|
@ -81,48 +111,57 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.subresourceRange = cubeSubresRange,
|
.subresourceRange = cubeSubresRange,
|
||||||
};
|
};
|
||||||
eastl::fixed_vector<vk::ImageMemoryBarrier2, 3> readyToWriteBarriers(2, readyToWriteBarrierTemplate);
|
eastl::fixed_vector<vk::ImageMemoryBarrier2, 4> readyToWriteBarriers(4, readyToWriteBarrierTemplate);
|
||||||
readyToWriteBarriers[0].image = skybox.m_Image;
|
readyToWriteBarriers[0].image = skybox.m_Image;
|
||||||
readyToWriteBarriers[1].image = diffuseIrradiance.m_Image;
|
readyToWriteBarriers[1].image = diffuseIrradiance.m_Image;
|
||||||
|
readyToWriteBarriers[2].image = prefilterCube.m_Image;
|
||||||
|
readyToWriteBarriers[3].image = brdfLut.m_Image;
|
||||||
|
readyToWriteBarriers[3].subresourceRange = lutSubresRange;
|
||||||
|
|
||||||
vk::DependencyInfo readyToWriteDependency = {
|
vk::DependencyInfo readyToWriteDependency = {
|
||||||
.imageMemoryBarrierCount = Cast<u32>(readyToWriteBarriers.size()),
|
.imageMemoryBarrierCount = Cast<u32>(readyToWriteBarriers.size()),
|
||||||
.pImageMemoryBarriers = readyToWriteBarriers.data(),
|
.pImageMemoryBarriers = readyToWriteBarriers.data(),
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 skyboxWriteToReadBarrier = {
|
vk::ImageMemoryBarrier2 readyToSampleBarrierTemplate = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eComputeShader,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eShaderStorageWrite,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eComputeShader,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eShaderStorageRead,
|
|
||||||
.oldLayout = vk::ImageLayout::eGeneral,
|
|
||||||
.newLayout = vk::ImageLayout::eGeneral,
|
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.image = skybox.m_Image,
|
|
||||||
.subresourceRange = cubeSubresRange,
|
|
||||||
};
|
|
||||||
vk::DependencyInfo skyboxWriteToReadDependency = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &skyboxWriteToReadBarrier,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 skyboxToSampleBarrier = {
|
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eComputeShader,
|
.srcStageMask = vk::PipelineStageFlagBits2::eComputeShader,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eShaderStorageWrite | vk::AccessFlagBits2::eShaderStorageRead,
|
.srcAccessMask = vk::AccessFlagBits2::eShaderStorageWrite | vk::AccessFlagBits2::eShaderStorageRead,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
|
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eShaderSampledRead,
|
|
||||||
.oldLayout = vk::ImageLayout::eGeneral,
|
.oldLayout = vk::ImageLayout::eGeneral,
|
||||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.image = skybox.m_Image,
|
|
||||||
.subresourceRange = cubeSubresRange,
|
.subresourceRange = cubeSubresRange,
|
||||||
};
|
};
|
||||||
|
auto skyboxToSampleBarrier = readyToSampleBarrierTemplate;
|
||||||
|
skyboxToSampleBarrier.image = skybox.m_Image;
|
||||||
|
|
||||||
|
auto diffIrrToSampleBarrier = readyToSampleBarrierTemplate;
|
||||||
|
diffIrrToSampleBarrier.image = diffuseIrradiance.m_Image;
|
||||||
|
|
||||||
|
auto prefilterToSampleBarrier = readyToSampleBarrierTemplate;
|
||||||
|
prefilterToSampleBarrier.image = prefilterCube.m_Image;
|
||||||
|
|
||||||
|
auto brdfToSampleBarrier = readyToSampleBarrierTemplate;
|
||||||
|
prefilterToSampleBarrier.image = brdfLut.m_Image;
|
||||||
|
prefilterToSampleBarrier.subresourceRange = lutSubresRange;
|
||||||
|
|
||||||
vk::DependencyInfo skyboxToSampleDependency = {
|
vk::DependencyInfo skyboxToSampleDependency = {
|
||||||
.imageMemoryBarrierCount = 1,
|
.imageMemoryBarrierCount = 1,
|
||||||
.pImageMemoryBarriers = &skyboxToSampleBarrier,
|
.pImageMemoryBarriers = &skyboxToSampleBarrier,
|
||||||
};
|
};
|
||||||
|
vk::DependencyInfo diffIrrToSampleDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &diffIrrToSampleBarrier,
|
||||||
|
};
|
||||||
|
vk::DependencyInfo prefilterToSampleDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &prefilterToSampleBarrier,
|
||||||
|
};
|
||||||
|
vk::DependencyInfo brdfToSampleDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &brdfToSampleBarrier,
|
||||||
|
};
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
|
@ -146,13 +185,17 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
f32 m_Roughness;
|
f32 m_Roughness;
|
||||||
u32 m_EnvSide;
|
u32 m_EnvSide;
|
||||||
};
|
};
|
||||||
|
struct BrdfLutPushConstants
|
||||||
|
{
|
||||||
|
StorageTextureHandle m_OutputTexture;
|
||||||
|
};
|
||||||
|
|
||||||
#pragma region Pipeline Creation etc
|
#pragma region Pipeline Creation etc
|
||||||
|
|
||||||
vk::PushConstantRange pcr = {
|
vk::PushConstantRange pcr = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = eastl::max(sizeof(SkyboxPushConstants),
|
.size = eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants))),
|
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants))),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -168,6 +211,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
const auto eqRectToCubeShader = CreateShader(pDevice, EQUIRECT_TO_CUBE_SHADER_FILE);
|
const auto eqRectToCubeShader = CreateShader(pDevice, EQUIRECT_TO_CUBE_SHADER_FILE);
|
||||||
const auto diffuseRadianceShader = CreateShader(pDevice, DIFFUSE_IRRADIANCE_SHADER_FILE);
|
const auto diffuseRadianceShader = CreateShader(pDevice, DIFFUSE_IRRADIANCE_SHADER_FILE);
|
||||||
const auto prefilterShader = CreateShader(pDevice, PREFILTER_SHADER_FILE);
|
const auto prefilterShader = CreateShader(pDevice, PREFILTER_SHADER_FILE);
|
||||||
|
const auto brdfLutShader = CreateShader(pDevice, BRDF_LUT_SHADER_FILE);
|
||||||
eastl::array computePipelineCreateInfo = {
|
eastl::array computePipelineCreateInfo = {
|
||||||
vk::ComputePipelineCreateInfo{
|
vk::ComputePipelineCreateInfo{
|
||||||
.stage =
|
.stage =
|
||||||
|
|
@ -196,6 +240,15 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
},
|
},
|
||||||
.layout = pipelineLayout,
|
.layout = pipelineLayout,
|
||||||
},
|
},
|
||||||
|
vk::ComputePipelineCreateInfo{
|
||||||
|
.stage =
|
||||||
|
{
|
||||||
|
.stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
|
.module = brdfLutShader,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
.layout = pipelineLayout,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||||
|
|
@ -206,6 +259,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
vk::Pipeline eqRectToCubePipeline = pipelines[0];
|
vk::Pipeline eqRectToCubePipeline = pipelines[0];
|
||||||
vk::Pipeline diffuseIrradiancePipeline = pipelines[1];
|
vk::Pipeline diffuseIrradiancePipeline = pipelines[1];
|
||||||
vk::Pipeline prefilterPipeline = pipelines[2];
|
vk::Pipeline prefilterPipeline = pipelines[2];
|
||||||
|
vk::Pipeline brdfLutPipeline = pipelines[3];
|
||||||
|
|
||||||
for (auto &createInfos : computePipelineCreateInfo)
|
for (auto &createInfos : computePipelineCreateInfo)
|
||||||
{
|
{
|
||||||
|
|
@ -228,6 +282,9 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
.m_SkyboxHandle = skyboxHandle,
|
.m_SkyboxHandle = skyboxHandle,
|
||||||
.m_EnvSide = cubeSide,
|
.m_EnvSide = cubeSide,
|
||||||
};
|
};
|
||||||
|
BrdfLutPushConstants brdfLutPushConstants = {
|
||||||
|
.m_OutputTexture = brdfLutStorageHandle,
|
||||||
|
};
|
||||||
|
|
||||||
resMan->Update();
|
resMan->Update();
|
||||||
|
|
||||||
|
|
@ -251,6 +308,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, eqRectToCubePipeline);
|
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, eqRectToCubePipeline);
|
||||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
||||||
&skyboxPushConstant);
|
&skyboxPushConstant);
|
||||||
|
assert(skybox.m_Extent.width % 16 == 0 && skybox.m_Extent.height % 16 == 0);
|
||||||
cmd.dispatch(skybox.m_Extent.width / 16, skybox.m_Extent.height / 16, 6);
|
cmd.dispatch(skybox.m_Extent.width / 16, skybox.m_Extent.height / 16, 6);
|
||||||
|
|
||||||
GenerateMipMaps(cmd, &skybox, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral,
|
GenerateMipMaps(cmd, &skybox, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral,
|
||||||
|
|
@ -259,10 +317,14 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, diffuseIrradiancePipeline);
|
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, diffuseIrradiancePipeline);
|
||||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
||||||
&diffuseIrradiancePushConstants);
|
&diffuseIrradiancePushConstants);
|
||||||
|
assert(diffuseIrradiance.m_Extent.width % 16 == 0 && diffuseIrradiance.m_Extent.height % 16 == 0);
|
||||||
cmd.dispatch(diffuseIrradiance.m_Extent.width / 16, diffuseIrradiance.m_Extent.width / 16, 6);
|
cmd.dispatch(diffuseIrradiance.m_Extent.width / 16, diffuseIrradiance.m_Extent.width / 16, 6);
|
||||||
|
|
||||||
|
cmd.pipelineBarrier2(&diffIrrToSampleDependency);
|
||||||
|
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, prefilterPipeline);
|
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, prefilterPipeline);
|
||||||
u32 mipSize = prefilterCube.m_Extent.width;
|
u32 mipSize = prefilterCube.m_Extent.width;
|
||||||
|
assert(mipSize % 16 == 0);
|
||||||
for (u32 mipCount = 0; auto &tex : prefilterStorageHandles)
|
for (u32 mipCount = 0; auto &tex : prefilterStorageHandles)
|
||||||
{
|
{
|
||||||
prefilterPushConstants.m_OutputTexture = tex;
|
prefilterPushConstants.m_OutputTexture = tex;
|
||||||
|
|
@ -278,6 +340,13 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&skyboxToSampleDependency);
|
cmd.pipelineBarrier2(&skyboxToSampleDependency);
|
||||||
|
cmd.pipelineBarrier2(&prefilterToSampleDependency);
|
||||||
|
|
||||||
|
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, brdfLutPipeline);
|
||||||
|
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof brdfLutPushConstants,
|
||||||
|
&brdfLutPushConstants);
|
||||||
|
assert(brdfLut.m_Extent.width % 16 == 0 && brdfLut.m_Extent.height % 16 == 0);
|
||||||
|
cmd.dispatch(brdfLut.m_Extent.width / 16, brdfLut.m_Extent.height / 16, 1);
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
cmd.endDebugUtilsLabelEXT();
|
cmd.endDebugUtilsLabelEXT();
|
||||||
|
|
@ -304,6 +373,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
skybox = {};
|
skybox = {};
|
||||||
resMan->Release(skyboxStorageHandle);
|
resMan->Release(skyboxStorageHandle);
|
||||||
resMan->Release(diffuseIrradianceStorageHandle);
|
resMan->Release(diffuseIrradianceStorageHandle);
|
||||||
|
resMan->Release(brdfLutStorageHandle);
|
||||||
for (auto &texHandles : prefilterStorageHandles)
|
for (auto &texHandles : prefilterStorageHandles)
|
||||||
{
|
{
|
||||||
StorageTextureCube st;
|
StorageTextureCube st;
|
||||||
|
|
@ -316,5 +386,10 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
}
|
}
|
||||||
pDevice->m_Device.destroy(pipelineLayout, nullptr);
|
pDevice->m_Device.destroy(pipelineLayout, nullptr);
|
||||||
|
|
||||||
return {skyboxHandle, diffuseIrradianceHandle, prefilterHandle};
|
return {
|
||||||
|
.m_Skybox = skyboxHandle,
|
||||||
|
.m_Diffuse = diffuseIrradianceHandle,
|
||||||
|
.m_Prefilter = prefilterHandle,
|
||||||
|
.m_BrdfLut = brdfLutHandle,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -15,6 +15,16 @@ struct Texture;
|
||||||
struct TextureCube;
|
struct TextureCube;
|
||||||
struct AssetLoader;
|
struct AssetLoader;
|
||||||
|
|
||||||
eastl::tuple<TextureHandle, TextureHandle, TextureHandle>
|
struct Environment
|
||||||
|
{
|
||||||
|
TextureHandle m_Skybox;
|
||||||
|
TextureHandle m_Diffuse;
|
||||||
|
TextureHandle m_Prefilter;
|
||||||
|
TextureHandle m_BrdfLut;
|
||||||
|
|
||||||
|
void Destroy(GpuResourceManager *resourceManager);
|
||||||
|
};
|
||||||
|
|
||||||
|
Environment
|
||||||
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, u32 cubeSide, TextureHandle hdrEnv,
|
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, u32 cubeSide, TextureHandle hdrEnv,
|
||||||
cstr name = nullptr);
|
cstr name = nullptr);
|
||||||
|
|
@ -176,13 +176,13 @@ main(int, char **)
|
||||||
LightManager lightManager = LightManager{&resourceManager};
|
LightManager lightManager = LightManager{&resourceManager};
|
||||||
|
|
||||||
Model model = assetLoader.LoadModelToGpu(MODEL_FILE);
|
Model model = assetLoader.LoadModelToGpu(MODEL_FILE);
|
||||||
Texture environment;
|
Texture environmentHdri;
|
||||||
assetLoader.LoadHdrImage(&environment, BACKDROP_FILE);
|
assetLoader.LoadHdrImage(&environmentHdri, BACKDROP_FILE);
|
||||||
auto envHandle = resourceManager.CommitTexture(&environment);
|
auto envHdriHandle = resourceManager.CommitTexture(&environmentHdri);
|
||||||
|
|
||||||
auto [texCube, diffuseIrr, prefilter] = CreateCubeFromHdrEnv(&assetLoader, graphicsQueue, 512, envHandle, "Cube Env");
|
auto environment = CreateCubeFromHdrEnv(&assetLoader, graphicsQueue, 512, envHdriHandle, "Cube Env");
|
||||||
|
|
||||||
resourceManager.Release(envHandle);
|
resourceManager.Release(envHdriHandle);
|
||||||
|
|
||||||
vk::Format attachmentFormat = vk::Format::eR8G8B8A8Srgb;
|
vk::Format attachmentFormat = vk::Format::eR8G8B8A8Srgb;
|
||||||
|
|
||||||
|
|
@ -374,6 +374,8 @@ main(int, char **)
|
||||||
bool showDiffuse = false;
|
bool showDiffuse = false;
|
||||||
bool useDiffuse = true;
|
bool useDiffuse = true;
|
||||||
bool showPrefilter = false;
|
bool showPrefilter = false;
|
||||||
|
bool useSpecular = true;
|
||||||
|
|
||||||
i32 height = Cast<i32>(internalResolution.height);
|
i32 height = Cast<i32>(internalResolution.height);
|
||||||
f32 camPitch = glm::degrees(cameraController.m_Pitch);
|
f32 camPitch = glm::degrees(cameraController.m_Pitch);
|
||||||
f32 camYaw = glm::degrees(cameraController.m_Yaw);
|
f32 camYaw = glm::degrees(cameraController.m_Yaw);
|
||||||
|
|
@ -453,6 +455,7 @@ main(int, char **)
|
||||||
gui::Checkbox("Show DiffIrr", &showDiffuse);
|
gui::Checkbox("Show DiffIrr", &showDiffuse);
|
||||||
gui::Checkbox("Use DiffIrr", &useDiffuse);
|
gui::Checkbox("Use DiffIrr", &useDiffuse);
|
||||||
gui::Checkbox("Show Prefilter", &showPrefilter);
|
gui::Checkbox("Show Prefilter", &showPrefilter);
|
||||||
|
gui::Checkbox("Use Specular", &useSpecular);
|
||||||
gui::Separator();
|
gui::Separator();
|
||||||
gui::Checkbox("Rotate", &rotating);
|
gui::Checkbox("Rotate", &rotating);
|
||||||
gui::PopItemWidth();
|
gui::PopItemWidth();
|
||||||
|
|
@ -556,37 +559,31 @@ main(int, char **)
|
||||||
&model.m_Handles);
|
&model.m_Handles);
|
||||||
pcbOffset += sizeof model.m_Handles;
|
pcbOffset += sizeof model.m_Handles;
|
||||||
|
|
||||||
|
Environment thisFrameEnvBuffers = environment;
|
||||||
if (showDiffuse)
|
if (showDiffuse)
|
||||||
{
|
{
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof diffuseIrr,
|
thisFrameEnvBuffers.m_Skybox = environment.m_Diffuse;
|
||||||
&diffuseIrr);
|
|
||||||
pcbOffset += sizeof diffuseIrr;
|
|
||||||
}
|
}
|
||||||
else if (showPrefilter)
|
else if (showPrefilter)
|
||||||
{
|
{
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof prefilter,
|
thisFrameEnvBuffers.m_Skybox = environment.m_Prefilter;
|
||||||
&prefilter);
|
|
||||||
pcbOffset += sizeof prefilter;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof texCube, &texCube);
|
|
||||||
pcbOffset += sizeof texCube;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useDiffuse)
|
if (!useDiffuse)
|
||||||
{
|
{
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof diffuseIrr,
|
thisFrameEnvBuffers.m_Diffuse = {};
|
||||||
&diffuseIrr);
|
|
||||||
pcbOffset += sizeof diffuseIrr;
|
|
||||||
}
|
}
|
||||||
else
|
if (!useSpecular)
|
||||||
{
|
{
|
||||||
TextureHandle invalid;
|
thisFrameEnvBuffers.m_BrdfLut = {};
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof invalid, &invalid);
|
thisFrameEnvBuffers.m_Prefilter = {};
|
||||||
pcbOffset += sizeof invalid;
|
|
||||||
}
|
}
|
||||||
static_assert(sizeof texCube == sizeof diffuseIrr);
|
|
||||||
|
assert(pcbOffset == 16);
|
||||||
|
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof thisFrameEnvBuffers,
|
||||||
|
&thisFrameEnvBuffers);
|
||||||
|
pcbOffset += sizeof thisFrameEnvBuffers;
|
||||||
|
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof lightManager.m_MetaInfo,
|
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof lightManager.m_MetaInfo,
|
||||||
&lightManager.m_MetaInfo);
|
&lightManager.m_MetaInfo);
|
||||||
pcbOffset += sizeof lightManager.m_MetaInfo;
|
pcbOffset += sizeof lightManager.m_MetaInfo;
|
||||||
|
|
@ -664,9 +661,7 @@ main(int, char **)
|
||||||
|
|
||||||
AbortIfFailed(device.m_Device.waitIdle());
|
AbortIfFailed(device.m_Device.waitIdle());
|
||||||
|
|
||||||
resourceManager.Release(texCube);
|
environment.Destroy(&resourceManager);
|
||||||
resourceManager.Release(diffuseIrr);
|
|
||||||
resourceManager.Release(prefilter);
|
|
||||||
|
|
||||||
pipelineCacheData = device.DumpPipelineCache();
|
pipelineCacheData = device.DumpPipelineCache();
|
||||||
ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written");
|
ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written");
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResou
|
||||||
vk::PushConstantRange pushConstantRange = {
|
vk::PushConstantRange pushConstantRange = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = 44,
|
.size = 52,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||||
|
|
@ -206,7 +206,7 @@ CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, cons
|
||||||
vk::PushConstantRange pushConstantRange = {
|
vk::PushConstantRange pushConstantRange = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = 44,
|
.size = 52,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,10 @@ static const float TAU = 6.28318530f;
|
||||||
[[vk::binding(0, 0)]] StructuredBuffer<DirectionalLight> DirectionalLightBuffer[];
|
[[vk::binding(0, 0)]] StructuredBuffer<DirectionalLight> DirectionalLightBuffer[];
|
||||||
|
|
||||||
[[vk::binding(1, 0)]] Texture2D<float4> Textures[];
|
[[vk::binding(1, 0)]] Texture2D<float4> Textures[];
|
||||||
|
[[vk::binding(1, 0)]] Texture2D<float2> TexturesRG[];
|
||||||
[[vk::binding(1, 0)]] TextureCube<float4> TextureCubes[];
|
[[vk::binding(1, 0)]] TextureCube<float4> TextureCubes[];
|
||||||
[[vk::binding(1, 0)]] SamplerState ImmutableSamplers[];
|
[[vk::binding(1, 0)]] SamplerState ImmutableSamplers[];
|
||||||
|
|
||||||
[[vk::binding(2, 0)]] RWTexture2D<float4> StorageTextures[];
|
[[vk::binding(2, 0)]] RWTexture2D<float4> StorageTextures[];
|
||||||
|
[[vk::binding(2, 0)]] RWTexture2D<float2> StorageTexturesRG[];
|
||||||
[[vk::binding(2, 0)]] RWTexture2DArray<float4> StorageTextureArrays[];
|
[[vk::binding(2, 0)]] RWTexture2DArray<float4> StorageTextureArrays[];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include "ibl_common.hlsli"
|
||||||
|
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
uint OutputTextureHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[vk::push_constant]]
|
||||||
|
Block Pcb;
|
||||||
|
|
||||||
|
float GeometrySchlickGGX(float NdotV, float Roughness)
|
||||||
|
{
|
||||||
|
float R = Roughness;
|
||||||
|
// (Rough + 1)^2 / 8 for Punctual Lights
|
||||||
|
// Rough^2 / 2 for IBL
|
||||||
|
float K = (R * R) / 2.0;
|
||||||
|
|
||||||
|
float Numerator = NdotV;
|
||||||
|
float Denominator = NdotV * (1.0f - K) + K;
|
||||||
|
|
||||||
|
return Numerator / Denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GeometrySmith(float NdotV, float NdotL, float Roughness)
|
||||||
|
{
|
||||||
|
float GGX1 = GeometrySchlickGGX(NdotV, Roughness);
|
||||||
|
float GGX2 = GeometrySchlickGGX(NdotL, Roughness);
|
||||||
|
|
||||||
|
return GGX1 * GGX2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 IntegrateBRDF(float NdotV, float Roughness)
|
||||||
|
{
|
||||||
|
float3 ViewDir;
|
||||||
|
ViewDir.x = sqrt(1.0f - NdotV * NdotV);
|
||||||
|
ViewDir.y = 0.0f;
|
||||||
|
ViewDir.z = NdotV;
|
||||||
|
|
||||||
|
float A = 0.0f;
|
||||||
|
float B = 0.0f;
|
||||||
|
|
||||||
|
float3 Normal = float3(0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
const uint SAMPLE_COUNT = 1024u;
|
||||||
|
|
||||||
|
for (uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
float2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||||
|
float3 Halfway = ImportanceSampleGGX(Xi, Normal, Roughness);
|
||||||
|
float3 LightDir = normalize(2.0f * dot(ViewDir, Halfway) * Halfway - ViewDir);
|
||||||
|
|
||||||
|
float NdotL = max(LightDir.z, 0.0f);
|
||||||
|
float NdotH = max(Halfway.z, 0.0f);
|
||||||
|
float VdotH = max(dot(ViewDir, Halfway), 0.0f);
|
||||||
|
|
||||||
|
if (NdotL > 0.0f)
|
||||||
|
{
|
||||||
|
float G = GeometrySmith(NdotV, NdotL, Roughness);
|
||||||
|
float G_Vis = (G * VdotH) / max((NdotH * NdotV), 0.0001f);
|
||||||
|
float Fc = pow(1.0f - VdotH, 5.0f);
|
||||||
|
|
||||||
|
A += (1.0f - Fc) * G_Vis;
|
||||||
|
B += Fc * G_Vis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
A /= float(SAMPLE_COUNT);
|
||||||
|
B /= float(SAMPLE_COUNT);
|
||||||
|
|
||||||
|
return float2(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
[numthreads(16, 16, 1)]
|
||||||
|
void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
|
||||||
|
{
|
||||||
|
float Width, Height;
|
||||||
|
StorageTexturesRG[Pcb.OutputTextureHandle].GetDimensions(Width, Height);
|
||||||
|
|
||||||
|
float2 UV = GlobalInvocationID.xy / float2(Width, Height);
|
||||||
|
|
||||||
|
float2 IntegratedBRDF = IntegrateBRDF(UV.x, UV.y);
|
||||||
|
StorageTexturesRG[Pcb.OutputTextureHandle][GlobalInvocationID.xy] = IntegratedBRDF;
|
||||||
|
}
|
||||||
|
|
@ -27,7 +27,7 @@ void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
|
||||||
float3 Forward, Up, Right;
|
float3 Forward, Up, Right;
|
||||||
|
|
||||||
Forward = GetCubeDir(GlobalInvocationID, pcb.CubeSide);
|
Forward = GetCubeDir(GlobalInvocationID, pcb.CubeSide);
|
||||||
Up = float3(0.0f, 1.0f, 0.0f); // 0.01f offset to
|
Up = abs(Forward.y) < 1.0f ? float3(0.0f, 1.0f, 0.0f) : float3(1.0f, 0.0f, 0.0f); // 0.01f offset to
|
||||||
Right = normalize(cross(Up, Forward));
|
Right = normalize(cross(Up, Forward));
|
||||||
Up = normalize(cross(Forward, Right));
|
Up = normalize(cross(Forward, Right));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,16 @@ struct Block
|
||||||
uint VertexDataHandle;
|
uint VertexDataHandle;
|
||||||
uint MaterialBufferHandle;
|
uint MaterialBufferHandle;
|
||||||
uint NodeBufferHandle;
|
uint NodeBufferHandle;
|
||||||
|
|
||||||
uint EnvCubeHandle;
|
uint EnvCubeHandle;
|
||||||
uint DiffuseIrradianceHandle;
|
uint DiffuseIrradianceHandle;
|
||||||
|
uint PrefilterHandle;
|
||||||
|
uint BrdfLutHandle;
|
||||||
|
|
||||||
uint LightHandle;
|
uint LightHandle;
|
||||||
uint PointLightIndexer;
|
uint PointLightIndexer;
|
||||||
uint DirectionalLightIndexer;
|
uint DirectionalLightIndexer;
|
||||||
|
|
||||||
int MaterialIdx;
|
int MaterialIdx;
|
||||||
uint NodeIdx;
|
uint NodeIdx;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -37,3 +37,41 @@ float3 GetCubeDir(uint3 GlobalInvocationID, float SideLength)
|
||||||
return 0.0f.xxx;
|
return 0.0f.xxx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float RadicalInverse_VdC(uint Bits)
|
||||||
|
{
|
||||||
|
Bits = (Bits << 16u) | (Bits >> 16u);
|
||||||
|
Bits = ((Bits & 0x55555555u) << 1u) | ((Bits & 0xAAAAAAAAu) >> 1u);
|
||||||
|
Bits = ((Bits & 0x33333333u) << 2u) | ((Bits & 0xCCCCCCCCu) >> 2u);
|
||||||
|
Bits = ((Bits & 0x0F0F0F0Fu) << 4u) | ((Bits & 0xF0F0F0F0u) >> 4u);
|
||||||
|
Bits = ((Bits & 0x00FF00FFu) << 8u) | ((Bits & 0xFF00FF00u) >> 8u);
|
||||||
|
return float(Bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 Hammersley(uint SampleIndex, uint SampleCount)
|
||||||
|
{
|
||||||
|
return float2(float(SampleIndex) / float(SampleCount), RadicalInverse_VdC(SampleIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 ImportanceSampleGGX(float2 Xi, float3 Normal, float Roughness)
|
||||||
|
{
|
||||||
|
float A = Roughness * Roughness;
|
||||||
|
|
||||||
|
float Phi = 2.0f * PI * Xi.x;
|
||||||
|
float CosTheta = sqrt((1.0f - Xi.y) / (1.0f + (A * A - 1.0f) * Xi.y));
|
||||||
|
float SinTheta = sqrt(1.0f - CosTheta * CosTheta);
|
||||||
|
|
||||||
|
// from spherical coordinates to cartesian coordinates
|
||||||
|
float3 H;
|
||||||
|
H.x = cos(Phi) * SinTheta;
|
||||||
|
H.y = sin(Phi) * SinTheta;
|
||||||
|
H.z = CosTheta;
|
||||||
|
|
||||||
|
// from tangent-space vector to world-space sample vector
|
||||||
|
float3 Up = abs(Normal.z) < 0.999f ? float3(0.0f, 0.0f, 1.0f) : float3(1.0f, 0.0f, 0.0f);
|
||||||
|
float3 Tangent = normalize(cross(Up, Normal));
|
||||||
|
float3 Bitangent = cross(Normal, Tangent);
|
||||||
|
|
||||||
|
float3 SampleVec = Tangent * H.x + Bitangent * H.y + Normal * H.z;
|
||||||
|
return normalize(SampleVec);
|
||||||
|
}
|
||||||
|
|
@ -77,6 +77,26 @@ float3 SampleIrradiance(float3 Direction)
|
||||||
return 0.04f.xxx;
|
return 0.04f.xxx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float3 SamplePrefiltered(float3 Direction, float Roughness)
|
||||||
|
{
|
||||||
|
const float MAX_MIP_LEVEL = 5.0f;
|
||||||
|
float Mip = MAX_MIP_LEVEL * Roughness;
|
||||||
|
if (PushConstant.PrefilterHandle != INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
return TextureCubes[PushConstant.PrefilterHandle].SampleLevel(ImmutableSamplers[PushConstant.PrefilterHandle], Direction, Mip).rgb;
|
||||||
|
}
|
||||||
|
return 0.0f.xxx;
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 SampleBrdfLut(float NdotV, float Roughness)
|
||||||
|
{
|
||||||
|
if (PushConstant.BrdfLutHandle != INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
return TexturesRG[PushConstant.BrdfLutHandle].Sample(ImmutableSamplers[PushConstant.BrdfLutHandle], float2(NdotV, Roughness));
|
||||||
|
}
|
||||||
|
return 0.0f.xx;
|
||||||
|
}
|
||||||
|
|
||||||
float TrowbridgeReitzGGX(float3 Normal, float3 Halfway, float Roughness)
|
float TrowbridgeReitzGGX(float3 Normal, float3 Halfway, float Roughness)
|
||||||
{
|
{
|
||||||
float Coeff = Roughness * Roughness;
|
float Coeff = Roughness * Roughness;
|
||||||
|
|
@ -196,7 +216,6 @@ float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position,
|
||||||
return Contrib;
|
return Contrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal)
|
float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal)
|
||||||
{
|
{
|
||||||
if (PushConstant.LightHandle == INVALID_HANDLE)
|
if (PushConstant.LightHandle == INVALID_HANDLE)
|
||||||
|
|
@ -240,18 +259,28 @@ float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Pos
|
||||||
float3 GetAmbientInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal, float Occlusion)
|
float3 GetAmbientInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal, float Occlusion)
|
||||||
{
|
{
|
||||||
float3 ViewDir = normalize(Camera.Position.xyz - Position);
|
float3 ViewDir = normalize(Camera.Position.xyz - Position);
|
||||||
float CosineFactor = max(dot(Normal, ViewDir), 0.0f); // TODO: Is Normal or is it Halfway?
|
float CosineFactor = max(dot(Normal, ViewDir), 0.0f); // Normal instead of Halfway since there's no halfway in ambient.
|
||||||
|
|
||||||
|
float Metal = MetalRough.r;
|
||||||
|
float Roughness = MetalRough.g;
|
||||||
|
|
||||||
float3 F_0 = 0.04f.xxx;
|
float3 F_0 = 0.04f.xxx;
|
||||||
F_0 = lerp(F_0, Albedo, MetalRough.r);
|
F_0 = lerp(F_0, Albedo, MetalRough.r);
|
||||||
float3 K_Specular = FresnelSchlickRoughness(CosineFactor, F_0, MetalRough.g);
|
float3 K_Specular = FresnelSchlickRoughness(CosineFactor, F_0, Roughness);
|
||||||
float3 K_Diffuse = 1.0f.xxx - K_Specular;
|
float3 K_Diffuse = 1.0f.xxx - K_Specular;
|
||||||
|
|
||||||
K_Diffuse *= 1.0f - MetalRough.r; // Metals don't have diffuse/refractions.
|
K_Diffuse *= 1.0f - Metal; // Metals don't have diffuse/refractions.
|
||||||
|
|
||||||
float3 DiffuseIrradiance = K_Diffuse * Albedo * SampleIrradiance(Normal) * Occlusion;
|
float3 ReflectionDir = reflect(-ViewDir, Normal);
|
||||||
|
|
||||||
return DiffuseIrradiance;
|
float NdotV = max(dot(Normal, ViewDir), 0.0f);
|
||||||
|
float3 PrefilteredColor = SamplePrefiltered(ReflectionDir, Roughness).rgb;
|
||||||
|
float2 EnvBRDF = SampleBrdfLut(NdotV, Roughness);
|
||||||
|
float3 Specular = PrefilteredColor * (K_Specular * EnvBRDF.x + EnvBRDF.y);
|
||||||
|
|
||||||
|
float3 DiffuseIrradiance = Albedo * SampleIrradiance(Normal);
|
||||||
|
|
||||||
|
return (K_Diffuse * DiffuseIrradiance + Specular) * Occlusion;
|
||||||
}
|
}
|
||||||
|
|
||||||
FS_Output main(FS_Input StageInput)
|
FS_Output main(FS_Input StageInput)
|
||||||
|
|
|
||||||
|
|
@ -12,44 +12,6 @@ struct Block
|
||||||
[[vk::push_constant]]
|
[[vk::push_constant]]
|
||||||
Block Pcb;
|
Block Pcb;
|
||||||
|
|
||||||
float RadicalInverse_VdC(uint Bits)
|
|
||||||
{
|
|
||||||
Bits = (Bits << 16u) | (Bits >> 16u);
|
|
||||||
Bits = ((Bits & 0x55555555u) << 1u) | ((Bits & 0xAAAAAAAAu) >> 1u);
|
|
||||||
Bits = ((Bits & 0x33333333u) << 2u) | ((Bits & 0xCCCCCCCCu) >> 2u);
|
|
||||||
Bits = ((Bits & 0x0F0F0F0Fu) << 4u) | ((Bits & 0xF0F0F0F0u) >> 4u);
|
|
||||||
Bits = ((Bits & 0x00FF00FFu) << 8u) | ((Bits & 0xFF00FF00u) >> 8u);
|
|
||||||
return float(Bits) * 2.3283064365386963e-10; // / 0x100000000
|
|
||||||
}
|
|
||||||
|
|
||||||
float2 Hammersley(uint SampleIndex, uint SampleCount)
|
|
||||||
{
|
|
||||||
return float2(float(SampleIndex) / float(SampleCount), RadicalInverse_VdC(SampleIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
float3 ImportanceSampleGGX(float2 Xi, float3 Normal, float Roughness)
|
|
||||||
{
|
|
||||||
float A = Roughness * Roughness;
|
|
||||||
|
|
||||||
float Phi = 2.0f * PI * Xi.x;
|
|
||||||
float CosTheta = sqrt((1.0f - Xi.y) / (1.0f + (A * A - 1.0f) * Xi.y));
|
|
||||||
float SinTheta = sqrt(1.0f - CosTheta * CosTheta);
|
|
||||||
|
|
||||||
// from spherical coordinates to cartesian coordinates
|
|
||||||
float3 H;
|
|
||||||
H.x = cos(Phi) * SinTheta;
|
|
||||||
H.y = sin(Phi) * SinTheta;
|
|
||||||
H.z = CosTheta;
|
|
||||||
|
|
||||||
// from tangent-space vector to world-space sample vector
|
|
||||||
float3 Up = abs(Normal.z) < 0.999f ? float3(0.0f, 0.0f, 1.0f) : float3(1.0f, 0.0f, 0.0f);
|
|
||||||
float3 Tangent = normalize(cross(Up, Normal));
|
|
||||||
float3 Bitangent = cross(Normal, Tangent);
|
|
||||||
|
|
||||||
float3 SampleVec = Tangent * H.x + Bitangent * H.y + Normal * H.z;
|
|
||||||
return normalize(SampleVec);
|
|
||||||
}
|
|
||||||
|
|
||||||
float TrowbridgeReitzGGX(float NdotH, float Roughness)
|
float TrowbridgeReitzGGX(float NdotH, float Roughness)
|
||||||
{
|
{
|
||||||
float Coeff = Roughness * Roughness;
|
float Coeff = Roughness * Roughness;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue