From 1157ba8330461d33fc6c723a13f4e88c1b6d3e2a Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 24 Sep 2017 21:17:59 -0700 Subject: [PATCH 01/43] Fixed validation errors from writing to UNORM textures --- BakingLab/DepthReduction.hlsl | 296 +++---- SampleFramework11/v1.02/Graphics/Textures.cpp | 753 +++++++++--------- .../v1.02/Shaders/DecodeTextureCS.hlsl | 77 +- 3 files changed, 580 insertions(+), 546 deletions(-) diff --git a/BakingLab/DepthReduction.hlsl b/BakingLab/DepthReduction.hlsl index 7a05e3e..6c7ad00 100644 --- a/BakingLab/DepthReduction.hlsl +++ b/BakingLab/DepthReduction.hlsl @@ -1,149 +1,149 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -//================================================================================================= -// Includes -//================================================================================================= -#include "SharedConstants.h" - -//================================================================================================= -// Constants -//================================================================================================= -static const uint NumThreads = ReductionTGSize * ReductionTGSize; - -//================================================================================================= -// Resources -//================================================================================================= -#if MSAA_ - Texture2DMS DepthMap : register(t0); -#else - Texture2D DepthMap : register(t0); -#endif - -Texture2D ReductionMap : register(t0); - -RWTexture2D OutputMap : register(u0); - -cbuffer ReductionConstants : register(b0) -{ - float4x4 Projection; - float NearClip; - float FarClip; - uint2 TextureSize; - uint NumSamples; -} - -// -- shared memory -groupshared float2 depthsamples[NumThreads]; - -//================================================================================================= -// Depth reduction, intial pass -//================================================================================================= -[numthreads(ReductionTGSize, ReductionTGSize, 1)] -void DepthReductionInitialCS(in uint3 GroupID : SV_GroupID, - in uint3 GroupThreadID : SV_GroupThreadID, - uint ThreadIndex : SV_GroupIndex) -{ - float minDepth = 1.0f; - float maxDepth = 0.0f; - - uint2 samplePos = GroupID.xy * ReductionTGSize + GroupThreadID.xy; - samplePos = min(samplePos, TextureSize - 1); - - #if MSAA_ - for(uint sIdx = 0; sIdx < NumSamples; ++sIdx) - { - float depthSample = DepthMap.Load(samplePos, sIdx); - - if(depthSample < 1.0f) - { - // Convert to linear Z - depthSample = Projection._43 / (depthSample - Projection._33); - depthSample = saturate((depthSample - NearClip) / (FarClip - NearClip)); - minDepth = min(minDepth, depthSample); - maxDepth = max(maxDepth, depthSample); - } - } - #else - float depthSample = DepthMap[samplePos]; - - if(depthSample < 1.0f) - { - // Convert to linear Z - depthSample = Projection._43 / (depthSample - Projection._33); - depthSample = saturate((depthSample - NearClip) / (FarClip - NearClip)); - minDepth = min(minDepth, depthSample); - maxDepth = max(maxDepth, depthSample); - } - #endif - - // Store in shared memory - depthsamples[ThreadIndex] = float2(minDepth, maxDepth); - GroupMemoryBarrierWithGroupSync(); - - // Reduce - [unroll] - for(uint s = NumThreads / 2; s > 0; s >>= 1) - { - if(ThreadIndex < s) - { - depthsamples[ThreadIndex].x = min(depthsamples[ThreadIndex].x, depthsamples[ThreadIndex + s].x); - depthsamples[ThreadIndex].y = max(depthsamples[ThreadIndex].y, depthsamples[ThreadIndex + s].y); - } - - GroupMemoryBarrierWithGroupSync(); - } - - if(ThreadIndex == 0) - { - minDepth = depthsamples[0].x; - maxDepth = depthsamples[0].y; - OutputMap[GroupID.xy] = float2(minDepth, maxDepth); - } -} - -//================================================================================================= -// Depth reduction, 2nd pass onwards -//================================================================================================= -[numthreads(ReductionTGSize, ReductionTGSize, 1)] -void DepthReductionCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID, - in uint ThreadIndex : SV_GroupIndex) -{ - uint2 samplePos = GroupID.xy * ReductionTGSize + GroupThreadID.xy; - samplePos = min(samplePos, TextureSize - 1); - - float minDepth = ReductionMap[samplePos].x; - float maxDepth = ReductionMap[samplePos].y; - - - // Store in shared memory - depthsamples[ThreadIndex] = float2(minDepth, maxDepth); - GroupMemoryBarrierWithGroupSync(); - - // Reduce - [unroll] - for(uint s = NumThreads / 2; s > 0; s >>= 1) - { - if(ThreadIndex < s) - { - depthsamples[ThreadIndex].x = min(depthsamples[ThreadIndex].x, depthsamples[ThreadIndex + s].x); - depthsamples[ThreadIndex].y = max(depthsamples[ThreadIndex].y, depthsamples[ThreadIndex + s].y); - } - - GroupMemoryBarrierWithGroupSync(); - } - - if(ThreadIndex == 0) - { - minDepth = depthsamples[0].x; - maxDepth = depthsamples[0].y; - OutputMap[GroupID.xy] = float2(minDepth, maxDepth); - } +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include "SharedConstants.h" + +//================================================================================================= +// Constants +//================================================================================================= +static const uint NumThreads = ReductionTGSize * ReductionTGSize; + +//================================================================================================= +// Resources +//================================================================================================= +#if MSAA_ + Texture2DMS DepthMap : register(t0); +#else + Texture2D DepthMap : register(t0); +#endif + +Texture2D ReductionMap : register(t0); + +RWTexture2D OutputMap : register(u0); + +cbuffer ReductionConstants : register(b0) +{ + float4x4 Projection; + float NearClip; + float FarClip; + uint2 TextureSize; + uint NumSamples; +} + +// -- shared memory +groupshared float2 depthsamples[NumThreads]; + +//================================================================================================= +// Depth reduction, intial pass +//================================================================================================= +[numthreads(ReductionTGSize, ReductionTGSize, 1)] +void DepthReductionInitialCS(in uint3 GroupID : SV_GroupID, + in uint3 GroupThreadID : SV_GroupThreadID, + uint ThreadIndex : SV_GroupIndex) +{ + float minDepth = 1.0f; + float maxDepth = 0.0f; + + uint2 samplePos = GroupID.xy * ReductionTGSize + GroupThreadID.xy; + samplePos = min(samplePos, TextureSize - 1); + + #if MSAA_ + for(uint sIdx = 0; sIdx < NumSamples; ++sIdx) + { + float depthSample = DepthMap.Load(samplePos, sIdx); + + if(depthSample < 1.0f) + { + // Convert to linear Z + depthSample = Projection._43 / (depthSample - Projection._33); + depthSample = saturate((depthSample - NearClip) / (FarClip - NearClip)); + minDepth = min(minDepth, depthSample); + maxDepth = max(maxDepth, depthSample); + } + } + #else + float depthSample = DepthMap[samplePos]; + + if(depthSample < 1.0f) + { + // Convert to linear Z + depthSample = Projection._43 / (depthSample - Projection._33); + depthSample = saturate((depthSample - NearClip) / (FarClip - NearClip)); + minDepth = min(minDepth, depthSample); + maxDepth = max(maxDepth, depthSample); + } + #endif + + // Store in shared memory + depthsamples[ThreadIndex] = float2(minDepth, maxDepth); + GroupMemoryBarrierWithGroupSync(); + + // Reduce + [unroll] + for(uint s = NumThreads / 2; s > 0; s >>= 1) + { + if(ThreadIndex < s) + { + depthsamples[ThreadIndex].x = min(depthsamples[ThreadIndex].x, depthsamples[ThreadIndex + s].x); + depthsamples[ThreadIndex].y = max(depthsamples[ThreadIndex].y, depthsamples[ThreadIndex + s].y); + } + + GroupMemoryBarrierWithGroupSync(); + } + + if(ThreadIndex == 0) + { + minDepth = depthsamples[0].x; + maxDepth = depthsamples[0].y; + OutputMap[GroupID.xy] = float2(minDepth, maxDepth); + } +} + +//================================================================================================= +// Depth reduction, 2nd pass onwards +//================================================================================================= +[numthreads(ReductionTGSize, ReductionTGSize, 1)] +void DepthReductionCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID, + in uint ThreadIndex : SV_GroupIndex) +{ + uint2 samplePos = GroupID.xy * ReductionTGSize + GroupThreadID.xy; + samplePos = min(samplePos, TextureSize - 1); + + float minDepth = ReductionMap[samplePos].x; + float maxDepth = ReductionMap[samplePos].y; + + + // Store in shared memory + depthsamples[ThreadIndex] = float2(minDepth, maxDepth); + GroupMemoryBarrierWithGroupSync(); + + // Reduce + [unroll] + for(uint s = NumThreads / 2; s > 0; s >>= 1) + { + if(ThreadIndex < s) + { + depthsamples[ThreadIndex].x = min(depthsamples[ThreadIndex].x, depthsamples[ThreadIndex + s].x); + depthsamples[ThreadIndex].y = max(depthsamples[ThreadIndex].y, depthsamples[ThreadIndex + s].y); + } + + GroupMemoryBarrierWithGroupSync(); + } + + if(ThreadIndex == 0) + { + minDepth = depthsamples[0].x; + maxDepth = depthsamples[0].y; + OutputMap[GroupID.xy] = float2(minDepth, maxDepth); + } } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/Textures.cpp b/SampleFramework11/v1.02/Graphics/Textures.cpp index 56dde8a..83ccf7c 100644 --- a/SampleFramework11/v1.02/Graphics/Textures.cpp +++ b/SampleFramework11/v1.02/Graphics/Textures.cpp @@ -1,363 +1,392 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include "PCH.h" - -#include "..\\Utility.h" -#include "..\\Exceptions.h" -#include "Textures.h" -#include "DDSTextureLoader.h" -#include "WICTextureLoader.h" -#include "..\\FileIO.h" -#include "ShaderCompilation.h" -#include "GraphicsTypes.h" -#include "TinyEXR.h" - -namespace SampleFramework11 -{ - - // Loads a texture, using either the DDS loader or the WIC loader -ID3D11ShaderResourceViewPtr LoadTexture(ID3D11Device* device, const wchar* filePath, bool forceSRGB) -{ - ID3D11DeviceContextPtr context; - device->GetImmediateContext(&context); - - ID3D11ResourcePtr resource; - ID3D11ShaderResourceViewPtr srv; - - const std::wstring extension = GetFileExtension(filePath); - if(extension == L"DDS" || extension == L"dds") - { - DXCall(DirectX::CreateDDSTextureFromFileEx(device, filePath, 0, D3D11_USAGE_DEFAULT, - D3D11_BIND_SHADER_RESOURCE, 0, 0, forceSRGB, - &resource, &srv, nullptr)); - return srv; - } - else - { - DXCall(DirectX:: CreateWICTextureFromFileEx(device, context, filePath, 0, D3D11_USAGE_DEFAULT, - D3D11_BIND_SHADER_RESOURCE, 0, 0, forceSRGB, &resource, &srv)); - - return srv; - } -} - -template -static void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, - DXGI_FORMAT outFormat, TextureData& texData) -{ - static ComputeShaderPtr decodeTextureCS; - static ComputeShaderPtr decodeTextureArrayCS; - - static const uint32 TGSize = 16; - - if(decodeTextureCS.Valid() == false) - { - CompileOptions opts; - opts.Add("TGSize_", TGSize); - const std::wstring shaderPath = SampleFrameworkDir() + L"Shaders\\DecodeTextureCS.hlsl"; - decodeTextureCS = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureCS", "cs_5_0", opts); - - decodeTextureArrayCS = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureArrayCS", "cs_5_0", opts); - } - - ID3D11Texture2DPtr texture; - textureSRV->GetResource(reinterpret_cast(&texture)); - - D3D11_TEXTURE2D_DESC texDesc; - texture->GetDesc(&texDesc); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - textureSRV->GetDesc(&srvDesc); - - ID3D11ShaderResourceViewPtr sourceSRV = textureSRV; - uint32 arraySize = texDesc.ArraySize; - if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBE - || srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.ArraySize = arraySize; - srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.MostDetailedMip = 0; - srvDesc.Texture2DArray.MipLevels = -1; - DXCall(device->CreateShaderResourceView(texture, &srvDesc, &sourceSRV)); - } - - D3D11_TEXTURE2D_DESC decodeTextureDesc; - decodeTextureDesc.Width = texDesc.Width; - decodeTextureDesc.Height = texDesc.Height; - decodeTextureDesc.ArraySize = arraySize; - decodeTextureDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; - decodeTextureDesc.Format = outFormat; - decodeTextureDesc.MipLevels = 1; - decodeTextureDesc.MiscFlags = 0; - decodeTextureDesc.SampleDesc.Count = 1; - decodeTextureDesc.SampleDesc.Quality = 0; - decodeTextureDesc.Usage = D3D11_USAGE_DEFAULT; - decodeTextureDesc.CPUAccessFlags = 0; - - ID3D11Texture2DPtr decodeTexture; - DXCall(device->CreateTexture2D(&decodeTextureDesc, nullptr, &decodeTexture)); - - ID3D11UnorderedAccessViewPtr decodeTextureUAV; - DXCall(device->CreateUnorderedAccessView(decodeTexture, nullptr, &decodeTextureUAV)); - - ID3D11DeviceContextPtr context; - device->GetImmediateContext(&context); - - SetCSInputs(context, sourceSRV); - SetCSOutputs(context, decodeTextureUAV); - SetCSShader(context, arraySize > 1 ? decodeTextureArrayCS : decodeTextureCS); - - context->Dispatch(DispatchSize(TGSize, texDesc.Width), DispatchSize(TGSize, texDesc.Height), arraySize); - - ClearCSInputs(context); - ClearCSOutputs(context); - - StagingTexture2D stagingTexture; - stagingTexture.Initialize(device, texDesc.Width, texDesc.Height, outFormat, 1, 1, 0, arraySize); - context->CopyResource(stagingTexture.Texture, decodeTexture); - - texData.Init(texDesc.Width, texDesc.Height, arraySize); - - for(uint32 slice = 0; slice < arraySize; ++slice) - { - uint32 pitch = 0; - const uint8* srcData = reinterpret_cast(stagingTexture.Map(context, slice, pitch)); - Assert_(pitch >= texDesc.Width * sizeof(T)); - - const uint32 sliceOffset = texDesc.Width * texDesc.Height * slice; - - for(uint32 y = 0; y < texDesc.Height; ++y) - { - const T* rowData = reinterpret_cast(srcData); - - for(uint32 x = 0; x < texDesc.Width; ++x) - texData.Texels[y * texDesc.Width + x + sliceOffset] = rowData[x]; - - srcData += pitch; - } - } -} - -// Decode a texture into 32-bit floats and copies it to the CPU -void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, - TextureData& textureData) -{ - GetTextureData(device, textureSRV, DXGI_FORMAT_R32G32B32A32_FLOAT, textureData); -} - -// Decode a texture into 16-bit floats and copies it to the CPU -void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, - TextureData& textureData) -{ - GetTextureData(device, textureSRV, DXGI_FORMAT_R16G16B16A16_FLOAT, textureData); -} - -// Decode a texture into 32-bit floats and copies it to the CPU -void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, - TextureData& textureData) -{ - GetTextureData(device, textureSRV, DXGI_FORMAT_R8G8B8A8_UNORM, textureData); -} - -template -static ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) -{ - DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; - if(typeid(T) == typeid(UByte4N)) - format = DXGI_FORMAT_R8G8B8A8_UNORM; - else if(typeid(T) == typeid(Half4)) - format = DXGI_FORMAT_R16G16B16A16_FLOAT; - else if(typeid(T) == typeid(Float4)) - format = DXGI_FORMAT_R32G32B32A32_FLOAT; - - Assert_(format != DXGI_FORMAT_UNKNOWN); - - const uint64 elemSize = sizeof(T); - Assert_(textureData.Texels.size() > 0); - Assert_(textureData.Width * textureData.Height * textureData.NumSlices == textureData.Texels.size()); - - std::vector subResources; - subResources.resize(textureData.NumSlices); - for(uint64 i = 0; i < textureData.NumSlices; ++i) - { - subResources[i].pSysMem = &textureData.Texels[textureData.Width * textureData.Height * i]; - subResources[i].SysMemPitch = elemSize * textureData.Width; - subResources[i].SysMemSlicePitch = 0; - } - - D3D11_TEXTURE2D_DESC texDesc; - texDesc.Width = textureData.Width; - texDesc.Height = textureData.Height; - texDesc.MipLevels = 1; - texDesc.ArraySize = textureData.NumSlices; - texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - texDesc.SampleDesc.Count = 1; - texDesc.SampleDesc.Quality = 0; - texDesc.Usage = D3D11_USAGE_IMMUTABLE; - texDesc.CPUAccessFlags = 0; - texDesc.MiscFlags = 0; - texDesc.Format = format; - ID3D11Texture2DPtr texture; - DXCall(device->CreateTexture2D(&texDesc, subResources.data(), &texture)); - - ID3D11ShaderResourceViewPtr srv; - DXCall(device->CreateShaderResourceView(texture, nullptr, &srv)); - - return srv; -} - -ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) -{ - return CreateSRVFromTextureData(device, textureData); -} - -ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) -{ - return CreateSRVFromTextureData(device, textureData); -} - -ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) -{ - return CreateSRVFromTextureData(device, textureData); -} - -void SaveTextureAsDDS(ID3D11ShaderResourceView* srv, const wchar* filePath) -{ - ID3D11ResourcePtr texture; - srv->GetResource(&texture); - - SaveTextureAsDDS(texture, filePath); -} - -void SaveTextureAsDDS(ID3D11Resource* texture, const wchar* filePath) -{ - ID3D11DevicePtr device; - texture->GetDevice(&device); - - ID3D11DeviceContextPtr context; - device->GetImmediateContext(&context); - - ScratchImage scratchImage; - DXCall(CaptureTexture(device, context, texture, scratchImage)); - DXCall(SaveToDDSFile(scratchImage.GetImages(), scratchImage.GetImageCount(), - scratchImage.GetMetadata(), DDS_FLAGS_FORCE_DX10_EXT, filePath)); -} - -void SaveTextureAsEXR(ID3D11ShaderResourceView* srv, const wchar* filePath) -{ - ID3D11DevicePtr device; - srv->GetDevice(&device); - - TextureData textureData; - GetTextureData(device, srv, textureData); - - SaveTextureAsEXR(textureData, filePath); -} - -void SaveTextureAsEXR(const TextureData& texture, const wchar* filePath) -{ - Assert_(texture.Texels.size() > 0); - Assert_(texture.Width > 0 && texture.Height > 0); - Assert_(texture.NumSlices == 1); - - const uint64 numTexels = texture.Texels.size(); - std::vector channelDataR; - std::vector channelDataG; - std::vector channelDataB; - channelDataR.resize(numTexels); - channelDataG.resize(numTexels); - channelDataB.resize(numTexels); - for(uint64 i = 0; i < numTexels; ++i) - { - channelDataR[i] = texture.Texels[i].x; - channelDataG[i] = texture.Texels[i].y; - channelDataB[i] = texture.Texels[i].z; - } - - float* imageChannels[3] = { channelDataB.data(), channelDataG.data(), channelDataR.data() }; - const char* channelNames[3] = { "B", "G", "R" }; - - EXRImage exrImage; - exrImage.num_channels = 3; - exrImage.width = texture.Width; - exrImage.height = texture.Height; - exrImage.channel_names = channelNames; - exrImage.images = imageChannels; - - std::string filePathAnsi = WStringToAnsi(filePath); - - const char* errorString = nullptr; - int returnCode = SaveMultiChannelEXR(&exrImage, filePathAnsi.c_str(), &errorString); - if(returnCode != 0) - { - AssertFail_("%s", errorString); - throw Exception(AnsiToWString(errorString)); - } -} - -void SaveTextureAsPNG(ID3D11ShaderResourceView* srv, const wchar* filePath) -{ - ID3D11ResourcePtr texture; - srv->GetResource(&texture); - - SaveTextureAsPNG(texture, filePath); -} - -void SaveTextureAsPNG(ID3D11Resource* texture, const wchar* filePath) -{ - ID3D11DevicePtr device; - texture->GetDevice(&device); - - ID3D11DeviceContextPtr context; - device->GetImmediateContext(&context); - - ScratchImage scratchImage; - DXCall(CaptureTexture(device, context, texture, scratchImage)); - - DXCall(SaveToWICFile(scratchImage.GetImages(), scratchImage.GetImageCount(), WIC_FLAGS_NONE, - GetWICCodec(WIC_CODEC_PNG), filePath)); -} - -// Utility function to map a XY + Side coordinate to a direction vector -Float3 MapXYSToDirection(uint64 x, uint64 y, uint64 s, uint64 width, uint64 height) -{ - float u = ((x + 0.5f) / float(width)) * 2.0f - 1.0f; - float v = ((y + 0.5f) / float(height)) * 2.0f - 1.0f; - v *= -1.0f; - - Float3 dir = 0.0f; - - // +x, -x, +y, -y, +z, -z - switch(s) { - case 0: - dir = Float3::Normalize(Float3(1.0f, v, -u)); - break; - case 1: - dir = Float3::Normalize(Float3(-1.0f, v, u)); - break; - case 2: - dir = Float3::Normalize(Float3(u, 1.0f, -v)); - break; - case 3: - dir = Float3::Normalize(Float3(u, -1.0f, v)); - break; - case 4: - dir = Float3::Normalize(Float3(u, v, 1.0f)); - break; - case 5: - dir = Float3::Normalize(Float3(-u, v, -1.0f)); - break; - } - - return dir; -} - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include "PCH.h" + +#include "..\\Utility.h" +#include "..\\Exceptions.h" +#include "Textures.h" +#include "DDSTextureLoader.h" +#include "WICTextureLoader.h" +#include "..\\FileIO.h" +#include "ShaderCompilation.h" +#include "GraphicsTypes.h" +#include "TinyEXR.h" + +namespace SampleFramework11 +{ + +static const DXGI_FORMAT UnormFormats[] = +{ + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8_UNORM, + + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16_UNORM, + + DXGI_FORMAT_R10G10B10A2_UNORM, +}; + +static bool IsUnormFormat(DXGI_FORMAT format) +{ + for(uint64 i = 0; i < ArraySize_(UnormFormats); ++i) + if(format == UnormFormats[i]) + return true; + return false; +} + +// Loads a texture, using either the DDS loader or the WIC loader +ID3D11ShaderResourceViewPtr LoadTexture(ID3D11Device* device, const wchar* filePath, bool forceSRGB) +{ + ID3D11DeviceContextPtr context; + device->GetImmediateContext(&context); + + ID3D11ResourcePtr resource; + ID3D11ShaderResourceViewPtr srv; + + const std::wstring extension = GetFileExtension(filePath); + if(extension == L"DDS" || extension == L"dds") + { + DXCall(DirectX::CreateDDSTextureFromFileEx(device, filePath, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, forceSRGB, + &resource, &srv, nullptr)); + return srv; + } + else + { + DXCall(DirectX:: CreateWICTextureFromFileEx(device, context, filePath, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, forceSRGB, &resource, &srv)); + + return srv; + } +} + +template +static void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, + DXGI_FORMAT outFormat, TextureData& texData) +{ + static ComputeShaderPtr decodeTextureCS[2][2]; + static const uint32 TGSize = 16; + + if(decodeTextureCS[0][0].Valid() == false) + { + CompileOptions opts; + opts.Add("TGSize_", TGSize); + opts.Add("UnormOutput_", 0); + const std::wstring shaderPath = SampleFrameworkDir() + L"Shaders\\DecodeTextureCS.hlsl"; + + decodeTextureCS[0][0] = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureCS", "cs_5_0", opts); + decodeTextureCS[0][1] = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureArrayCS", "cs_5_0", opts); + + opts.Reset(); + opts.Add("TGSize_", TGSize); + opts.Add("UnormOutput_", 1); + decodeTextureCS[1][0] = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureCS", "cs_5_0", opts); + decodeTextureCS[1][1] = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureArrayCS", "cs_5_0", opts); + } + + ID3D11Texture2DPtr texture; + textureSRV->GetResource(reinterpret_cast(&texture)); + + D3D11_TEXTURE2D_DESC texDesc; + texture->GetDesc(&texDesc); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + textureSRV->GetDesc(&srvDesc); + + ID3D11ShaderResourceViewPtr sourceSRV = textureSRV; + uint32 arraySize = texDesc.ArraySize; + if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBE + || srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.ArraySize = arraySize; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.MostDetailedMip = 0; + srvDesc.Texture2DArray.MipLevels = -1; + DXCall(device->CreateShaderResourceView(texture, &srvDesc, &sourceSRV)); + } + + D3D11_TEXTURE2D_DESC decodeTextureDesc; + decodeTextureDesc.Width = texDesc.Width; + decodeTextureDesc.Height = texDesc.Height; + decodeTextureDesc.ArraySize = arraySize; + decodeTextureDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + decodeTextureDesc.Format = outFormat; + decodeTextureDesc.MipLevels = 1; + decodeTextureDesc.MiscFlags = 0; + decodeTextureDesc.SampleDesc.Count = 1; + decodeTextureDesc.SampleDesc.Quality = 0; + decodeTextureDesc.Usage = D3D11_USAGE_DEFAULT; + decodeTextureDesc.CPUAccessFlags = 0; + + ID3D11Texture2DPtr decodeTexture; + DXCall(device->CreateTexture2D(&decodeTextureDesc, nullptr, &decodeTexture)); + + ID3D11UnorderedAccessViewPtr decodeTextureUAV; + DXCall(device->CreateUnorderedAccessView(decodeTexture, nullptr, &decodeTextureUAV)); + + ID3D11DeviceContextPtr context; + device->GetImmediateContext(&context); + + SetCSInputs(context, sourceSRV); + SetCSOutputs(context, decodeTextureUAV); + + uint32 arrayOutput = arraySize > 1 ? 1 : 0; + uint32 unormOutput = IsUnormFormat(outFormat) ? 1 : 0; + SetCSShader(context, decodeTextureCS[unormOutput][arrayOutput]); + + context->Dispatch(DispatchSize(TGSize, texDesc.Width), DispatchSize(TGSize, texDesc.Height), arraySize); + + ClearCSInputs(context); + ClearCSOutputs(context); + + StagingTexture2D stagingTexture; + stagingTexture.Initialize(device, texDesc.Width, texDesc.Height, outFormat, 1, 1, 0, arraySize); + context->CopyResource(stagingTexture.Texture, decodeTexture); + + texData.Init(texDesc.Width, texDesc.Height, arraySize); + + for(uint32 slice = 0; slice < arraySize; ++slice) + { + uint32 pitch = 0; + const uint8* srcData = reinterpret_cast(stagingTexture.Map(context, slice, pitch)); + Assert_(pitch >= texDesc.Width * sizeof(T)); + + const uint32 sliceOffset = texDesc.Width * texDesc.Height * slice; + + for(uint32 y = 0; y < texDesc.Height; ++y) + { + const T* rowData = reinterpret_cast(srcData); + + for(uint32 x = 0; x < texDesc.Width; ++x) + texData.Texels[y * texDesc.Width + x + sliceOffset] = rowData[x]; + + srcData += pitch; + } + } +} + +// Decode a texture into 32-bit floats and copies it to the CPU +void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, + TextureData& textureData) +{ + GetTextureData(device, textureSRV, DXGI_FORMAT_R32G32B32A32_FLOAT, textureData); +} + +// Decode a texture into 16-bit floats and copies it to the CPU +void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, + TextureData& textureData) +{ + GetTextureData(device, textureSRV, DXGI_FORMAT_R16G16B16A16_FLOAT, textureData); +} + +// Decode a texture into 32-bit floats and copies it to the CPU +void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, + TextureData& textureData) +{ + GetTextureData(device, textureSRV, DXGI_FORMAT_R8G8B8A8_UNORM, textureData); +} + +template +static ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) +{ + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + if(typeid(T) == typeid(UByte4N)) + format = DXGI_FORMAT_R8G8B8A8_UNORM; + else if(typeid(T) == typeid(Half4)) + format = DXGI_FORMAT_R16G16B16A16_FLOAT; + else if(typeid(T) == typeid(Float4)) + format = DXGI_FORMAT_R32G32B32A32_FLOAT; + + Assert_(format != DXGI_FORMAT_UNKNOWN); + + const uint64 elemSize = sizeof(T); + Assert_(textureData.Texels.size() > 0); + Assert_(textureData.Width * textureData.Height * textureData.NumSlices == textureData.Texels.size()); + + std::vector subResources; + subResources.resize(textureData.NumSlices); + for(uint64 i = 0; i < textureData.NumSlices; ++i) + { + subResources[i].pSysMem = &textureData.Texels[textureData.Width * textureData.Height * i]; + subResources[i].SysMemPitch = elemSize * textureData.Width; + subResources[i].SysMemSlicePitch = 0; + } + + D3D11_TEXTURE2D_DESC texDesc; + texDesc.Width = textureData.Width; + texDesc.Height = textureData.Height; + texDesc.MipLevels = 1; + texDesc.ArraySize = textureData.NumSlices; + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + texDesc.SampleDesc.Count = 1; + texDesc.SampleDesc.Quality = 0; + texDesc.Usage = D3D11_USAGE_IMMUTABLE; + texDesc.CPUAccessFlags = 0; + texDesc.MiscFlags = 0; + texDesc.Format = format; + ID3D11Texture2DPtr texture; + DXCall(device->CreateTexture2D(&texDesc, subResources.data(), &texture)); + + ID3D11ShaderResourceViewPtr srv; + DXCall(device->CreateShaderResourceView(texture, nullptr, &srv)); + + return srv; +} + +ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) +{ + return CreateSRVFromTextureData(device, textureData); +} + +ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) +{ + return CreateSRVFromTextureData(device, textureData); +} + +ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) +{ + return CreateSRVFromTextureData(device, textureData); +} + +void SaveTextureAsDDS(ID3D11ShaderResourceView* srv, const wchar* filePath) +{ + ID3D11ResourcePtr texture; + srv->GetResource(&texture); + + SaveTextureAsDDS(texture, filePath); +} + +void SaveTextureAsDDS(ID3D11Resource* texture, const wchar* filePath) +{ + ID3D11DevicePtr device; + texture->GetDevice(&device); + + ID3D11DeviceContextPtr context; + device->GetImmediateContext(&context); + + ScratchImage scratchImage; + DXCall(CaptureTexture(device, context, texture, scratchImage)); + DXCall(SaveToDDSFile(scratchImage.GetImages(), scratchImage.GetImageCount(), + scratchImage.GetMetadata(), DDS_FLAGS_FORCE_DX10_EXT, filePath)); +} + +void SaveTextureAsEXR(ID3D11ShaderResourceView* srv, const wchar* filePath) +{ + ID3D11DevicePtr device; + srv->GetDevice(&device); + + TextureData textureData; + GetTextureData(device, srv, textureData); + + SaveTextureAsEXR(textureData, filePath); +} + +void SaveTextureAsEXR(const TextureData& texture, const wchar* filePath) +{ + Assert_(texture.Texels.size() > 0); + Assert_(texture.Width > 0 && texture.Height > 0); + Assert_(texture.NumSlices == 1); + + const uint64 numTexels = texture.Texels.size(); + std::vector channelDataR; + std::vector channelDataG; + std::vector channelDataB; + channelDataR.resize(numTexels); + channelDataG.resize(numTexels); + channelDataB.resize(numTexels); + for(uint64 i = 0; i < numTexels; ++i) + { + channelDataR[i] = texture.Texels[i].x; + channelDataG[i] = texture.Texels[i].y; + channelDataB[i] = texture.Texels[i].z; + } + + float* imageChannels[3] = { channelDataB.data(), channelDataG.data(), channelDataR.data() }; + const char* channelNames[3] = { "B", "G", "R" }; + + EXRImage exrImage; + exrImage.num_channels = 3; + exrImage.width = texture.Width; + exrImage.height = texture.Height; + exrImage.channel_names = channelNames; + exrImage.images = imageChannels; + + std::string filePathAnsi = WStringToAnsi(filePath); + + const char* errorString = nullptr; + int returnCode = SaveMultiChannelEXR(&exrImage, filePathAnsi.c_str(), &errorString); + if(returnCode != 0) + { + AssertFail_("%s", errorString); + throw Exception(AnsiToWString(errorString)); + } +} + +void SaveTextureAsPNG(ID3D11ShaderResourceView* srv, const wchar* filePath) +{ + ID3D11ResourcePtr texture; + srv->GetResource(&texture); + + SaveTextureAsPNG(texture, filePath); +} + +void SaveTextureAsPNG(ID3D11Resource* texture, const wchar* filePath) +{ + ID3D11DevicePtr device; + texture->GetDevice(&device); + + ID3D11DeviceContextPtr context; + device->GetImmediateContext(&context); + + ScratchImage scratchImage; + DXCall(CaptureTexture(device, context, texture, scratchImage)); + + DXCall(SaveToWICFile(scratchImage.GetImages(), scratchImage.GetImageCount(), WIC_FLAGS_NONE, + GetWICCodec(WIC_CODEC_PNG), filePath)); +} + +// Utility function to map a XY + Side coordinate to a direction vector +Float3 MapXYSToDirection(uint64 x, uint64 y, uint64 s, uint64 width, uint64 height) +{ + float u = ((x + 0.5f) / float(width)) * 2.0f - 1.0f; + float v = ((y + 0.5f) / float(height)) * 2.0f - 1.0f; + v *= -1.0f; + + Float3 dir = 0.0f; + + // +x, -x, +y, -y, +z, -z + switch(s) { + case 0: + dir = Float3::Normalize(Float3(1.0f, v, -u)); + break; + case 1: + dir = Float3::Normalize(Float3(-1.0f, v, u)); + break; + case 2: + dir = Float3::Normalize(Float3(u, 1.0f, -v)); + break; + case 3: + dir = Float3::Normalize(Float3(u, -1.0f, v)); + break; + case 4: + dir = Float3::Normalize(Float3(u, v, 1.0f)); + break; + case 5: + dir = Float3::Normalize(Float3(-u, v, -1.0f)); + break; + } + + return dir; +} + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Shaders/DecodeTextureCS.hlsl b/SampleFramework11/v1.02/Shaders/DecodeTextureCS.hlsl index 8f0f35c..325ec82 100644 --- a/SampleFramework11/v1.02/Shaders/DecodeTextureCS.hlsl +++ b/SampleFramework11/v1.02/Shaders/DecodeTextureCS.hlsl @@ -1,37 +1,42 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -//================================================================================================= -// Resources -//================================================================================================= - -// Inputs -Texture2D InputTexture : register(t0); -Texture2DArray InputTextureArray : register(t0); - -// Outputs -RWTexture2D OutputTexture : register(u0); -RWTexture2DArray OutputTextureArray : register(u0); - -//================================================================================================= -// Entry points -//================================================================================================= -[numthreads(TGSize_, TGSize_, 1)] -void DecodeTextureCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) -{ - const uint2 texelIdx = GroupID.xy * uint2(TGSize_, TGSize_) + GroupThreadID.xy; - OutputTexture[texelIdx] = InputTexture[texelIdx]; -} - -[numthreads(TGSize_, TGSize_, 1)] -void DecodeTextureArrayCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) -{ - const uint3 texelIdx = uint3(GroupID.xy * uint2(TGSize_, TGSize_) + GroupThreadID.xy, GroupID.z); - OutputTextureArray[texelIdx] = InputTextureArray[texelIdx]; +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Resources +//================================================================================================= + +// Inputs +Texture2D InputTexture : register(t0); +Texture2DArray InputTextureArray : register(t0); + +// Outputs +#if UnormOutput_ + RWTexture2D OutputTexture : register(u0); + RWTexture2DArray OutputTextureArray : register(u0); +#else + RWTexture2D OutputTexture : register(u0); + RWTexture2DArray OutputTextureArray : register(u0); +#endif + +//================================================================================================= +// Entry points +//================================================================================================= +[numthreads(TGSize_, TGSize_, 1)] +void DecodeTextureCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + const uint2 texelIdx = GroupID.xy * uint2(TGSize_, TGSize_) + GroupThreadID.xy; + OutputTexture[texelIdx] = InputTexture[texelIdx]; +} + +[numthreads(TGSize_, TGSize_, 1)] +void DecodeTextureArrayCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + const uint3 texelIdx = uint3(GroupID.xy * uint2(TGSize_, TGSize_) + GroupThreadID.xy, GroupID.z); + OutputTextureArray[texelIdx] = InputTextureArray[texelIdx]; } \ No newline at end of file From 6a6e5f218d5d9648157e4f3c70e233e239167394 Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 24 Sep 2017 21:18:50 -0700 Subject: [PATCH 02/43] Started refactoring the code to support probes --- BakingLab/AppSettings.cpp | 1882 ++++++++++++++++++------------------ BakingLab/AppSettings.cs | 1650 +++++++++++++++---------------- BakingLab/AppSettings.h | 1186 ++++++++++++----------- BakingLab/AppSettings.hlsl | 374 +++---- BakingLab/Mesh.hlsl | 1151 +++++++++++----------- 5 files changed, 3160 insertions(+), 3083 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 050597b..6009e7d 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -1,931 +1,953 @@ -#include -#include -#include "AppSettings.h" - -using namespace SampleFramework11; - -static const char* SunDirectionTypesLabels[2] = -{ - "Unit Vector", - "Horizontal Coordinate System", -}; - -static const char* SkyModesLabels[6] = -{ - "None", - "Procedural", - "Simple", - "Ennis", - "Grace Cathedral", - "Uffizi Cross", -}; - -static const char* LightUnitsLabels[4] = -{ - "Luminance", - "Illuminance", - "LuminousPower", - "EV100", -}; - -static const char* ExposureModesLabels[4] = -{ - "Manual (Simple)", - "Manual (SBS)", - "Manual (SOS)", - "Automatic", -}; - -static const char* FStopsLabels[23] = -{ - "f/1.8", - "f/2.0", - "f/2.2", - "f/2.5", - "f/2.8", - "f/3.2", - "f/3.5", - "f/4.0", - "f/4.5", - "f/5.0", - "f/5.6", - "f/6.3", - "f/7.1", - "f/8.0", - "f/9.0", - "f/10.0", - "f/11.0", - "f/13.0", - "f/14.0", - "f/16.0", - "f/18.0", - "f/20.0", - "f/22.0", -}; - -static const char* ISORatingsLabels[4] = -{ - "ISO100", - "ISO200", - "ISO400", - "ISO800", -}; - -static const char* ShutterSpeedsLabels[13] = -{ - "1s", - "1/2s", - "1/4s", - "1/8s", - "1/15s", - "1/30s", - "1/60s", - "1/125s", - "1/250s", - "1/500s", - "1/1000s", - "1/2000s", - "1/4000s", -}; - -static const char* ToneMappingModesLabels[5] = -{ - "Film Stock", - "Linear", - "ACES sRGB Monitor", - "Hejl 2015", - "Hable (Uncharted2)", -}; - -static const char* MSAAModesLabels[4] = -{ - "None", - "2x", - "4x", - "8x", -}; - -static const char* FilterTypesLabels[6] = -{ - "Box", - "Triangle", - "Gaussian", - "BlackmanHarris", - "Smoothstep", - "BSpline", -}; - -static const char* JitterModesLabels[5] = -{ - "None", - "Uniform2x", - "Hammersley4x", - "Hammersley8x", - "Hammersley16x", -}; - -static const char* SGDiffuseModesLabels[3] = -{ - "InnerProduct", - "Punctual", - "Fitted (Hill 16)", -}; - -static const char* SampleModesLabels[5] = -{ - "Random", - "Stratified", - "Hammersley", - "UniformGrid", - "CMJ", -}; - -static const char* BakeModesLabels[10] = -{ - "Diffuse", - "Half-Life 2", - "L1 SH", - "L2 SH", - "L1 H-basis", - "L2 H-basis", - "SG5", - "SG6", - "SG9", - "SG12", -}; - -static const char* SolveModesLabels[3] = -{ - "Ad-Hoc Projection", - "Least Squares", - "Non-Negative Least Squares", -}; - -static const char* ScenesLabels[3] = -{ - "Box", - "White Room", - "Sponza", -}; - -namespace AppSettings -{ - BoolSetting EnableSun; - BoolSetting SunAreaLightApproximation; - ColorSetting SunTintColor; - FloatSetting SunIntensityScale; - FloatSetting SunSize; - BoolSetting NormalizeSunIntensity; - SunDirectionTypesSetting SunDirType; - DirectionSetting SunDirection; - FloatSetting SunAzimuth; - FloatSetting SunElevation; - SkyModesSetting SkyMode; - ColorSetting SkyColor; - FloatSetting Turbidity; - ColorSetting GroundAlbedo; - BoolSetting EnableAreaLight; - ColorSetting AreaLightColor; - FloatSetting AreaLightIlluminance; - FloatSetting AreaLightLuminousPower; - FloatSetting AreaLightEV100; - LightUnitsSetting AreaLightUnits; - FloatSetting AreaLightIlluminanceDistance; - FloatSetting AreaLightSize; - FloatSetting AreaLightX; - FloatSetting AreaLightY; - FloatSetting AreaLightZ; - FloatSetting AreaLightShadowBias; - BoolSetting BakeDirectAreaLight; - BoolSetting EnableAreaLightShadows; - ExposureModesSetting ExposureMode; - FloatSetting ManualExposure; - FStopsSetting ApertureSize; - ISORatingsSetting ISORating; - ShutterSpeedsSetting ShutterSpeed; - FloatSetting FilmSize; - FloatSetting FocalLength; - FloatSetting FocusDistance; - IntSetting NumBlades; - BoolSetting EnableDOF; - FloatSetting KeyValue; - FloatSetting AdaptationRate; - FloatSetting ApertureFNumber; - FloatSetting ApertureWidth; - FloatSetting ShutterSpeedValue; - FloatSetting ISO; - FloatSetting BokehPolygonAmount; - ToneMappingModesSetting ToneMappingMode; - FloatSetting WhitePoint_Hejl; - FloatSetting ShoulderStrength; - FloatSetting LinearStrength; - FloatSetting LinearAngle; - FloatSetting ToeStrength; - FloatSetting WhitePoint_Hable; - MSAAModesSetting MSAAMode; - FilterTypesSetting FilterType; - FloatSetting FilterSize; - FloatSetting GaussianSigma; - BoolSetting EnableTemporalAA; - JitterModesSetting JitterMode; - FloatSetting JitterScale; - SGDiffuseModesSetting SGDiffuseMode; - BoolSetting UseASGWarp; - IntSetting LightMapResolution; - IntSetting NumBakeSamples; - SampleModesSetting BakeSampleMode; - IntSetting MaxBakePathLength; - IntSetting BakeRussianRouletteDepth; - FloatSetting BakeRussianRouletteProbability; - BakeModesSetting BakeMode; - SolveModesSetting SolveMode; - ScenesSetting CurrentScene; - BoolSetting EnableDiffuse; - BoolSetting EnableSpecular; - BoolSetting EnableDirectLighting; - BoolSetting EnableIndirectLighting; - BoolSetting EnableIndirectDiffuse; - BoolSetting EnableIndirectSpecular; - BoolSetting EnableAlbedoMaps; - BoolSetting EnableNormalMaps; - FloatSetting NormalMapIntensity; - FloatSetting DiffuseAlbedoScale; - FloatSetting RoughnessScale; - BoolSetting ShowGroundTruth; - IntSetting NumRenderSamples; - SampleModesSetting RenderSampleMode; - IntSetting MaxRenderPathLength; - IntSetting RenderRussianRouletteDepth; - FloatSetting RenderRussianRouletteProbability; - BoolSetting EnableRenderBounceSpecular; - FloatSetting BloomExposure; - FloatSetting BloomMagnitude; - FloatSetting BloomBlurSigma; - BoolSetting EnableLuminancePicker; - BoolSetting ShowBakeDataVisualizer; - BoolSetting ViewIndirectSpecular; - Button SaveLightSettings; - Button LoadLightSettings; - Button SaveEXRScreenshot; - BoolSetting ShowSunIntensity; - - ConstantBuffer CBuffer; - - void Initialize(ID3D11Device* device) - { - TwBar* tweakBar = Settings.TweakBar(); - - EnableSun.Initialize(tweakBar, "EnableSun", "Sun Light", "Enable Sun", "Enables the sun light", true); - Settings.AddSetting(&EnableSun); - - SunAreaLightApproximation.Initialize(tweakBar, "SunAreaLightApproximation", "Sun Light", "Sun Area Light Approximation", "Controls whether the sun is treated as a disc area light in the real-time shader", true); - Settings.AddSetting(&SunAreaLightApproximation); - - SunTintColor.Initialize(tweakBar, "SunTintColor", "Sun Light", "Sun Tint Color", "The color of the sun", Float3(1.0000f, 1.0000f, 1.0000f), false, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ColorUnit::None); - Settings.AddSetting(&SunTintColor); - - SunIntensityScale.Initialize(tweakBar, "SunIntensityScale", "Sun Light", "Sun Intensity Scale", "Scale the intensity of the sun", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&SunIntensityScale); - - SunSize.Initialize(tweakBar, "SunSize", "Sun Light", "Sun Size", "Angular radius of the sun in degrees", 0.2700f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0010f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&SunSize); - - NormalizeSunIntensity.Initialize(tweakBar, "NormalizeSunIntensity", "Sun Light", "Normalize Sun Intensity", "", false); - Settings.AddSetting(&NormalizeSunIntensity); - - SunDirType.Initialize(tweakBar, "SunDirType", "Sun Light", "Sun Dir Type", "Input direction type for the sun", SunDirectionTypes::HorizontalCoordSystem, 2, SunDirectionTypesLabels); - Settings.AddSetting(&SunDirType); - - SunDirection.Initialize(tweakBar, "SunDirection", "Sun Light", "Sun Direction", "Director of the sun", Float3(-0.7500f, 0.9770f, -0.4000f)); - Settings.AddSetting(&SunDirection); - - SunAzimuth.Initialize(tweakBar, "SunAzimuth", "Sun Light", "Sun Azimuth", "Angle around the horizon", 0.0000f, 0.0000f, 360.0000f, 0.1000f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&SunAzimuth); - - SunElevation.Initialize(tweakBar, "SunElevation", "Sun Light", "Sun Elevation", "Elevation of sun from ground. 0 degrees is aligned on the horizon while 90 degrees is directly overhead", 0.0000f, 0.0000f, 90.0000f, 0.1000f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&SunElevation); - - SkyMode.Initialize(tweakBar, "SkyMode", "Sky", "Sky Mode", "Controls the sky used for GI baking and background rendering", SkyModes::Procedural, 6, SkyModesLabels); - Settings.AddSetting(&SkyMode); - - SkyColor.Initialize(tweakBar, "SkyColor", "Sky", "Sky Color", "The color of the simple sky", Float3(1400.0000f, 3500.0000f, 7000.0000f), true, 0.0000f, 1000000.0000f, 0.1000f, ColorUnit::Luminance); - Settings.AddSetting(&SkyColor); - - Turbidity.Initialize(tweakBar, "Turbidity", "Sky", "Turbidity", "", 2.0000f, 1.0000f, 10.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&Turbidity); - - GroundAlbedo.Initialize(tweakBar, "GroundAlbedo", "Sky", "Ground Albedo", "", Float3(0.5000f, 0.5000f, 0.5000f), false, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ColorUnit::None); - Settings.AddSetting(&GroundAlbedo); - - EnableAreaLight.Initialize(tweakBar, "EnableAreaLight", "Area Light", "Enable Area Light", "Enables the area light during baking and ground truth rendering", false); - Settings.AddSetting(&EnableAreaLight); - - AreaLightColor.Initialize(tweakBar, "AreaLightColor", "Area Light", "Color", "The color of the area light", Float3(1000000.0000f, 1000000.0000f, 1000000.0000f), true, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.1000f, ColorUnit::Luminance); - Settings.AddSetting(&AreaLightColor); - - AreaLightIlluminance.Initialize(tweakBar, "AreaLightIlluminance", "Area Light", "Color Intensity (lux)", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightIlluminance); - AreaLightIlluminance.SetVisible(false); - - AreaLightLuminousPower.Initialize(tweakBar, "AreaLightLuminousPower", "Area Light", "Color Intensity (lm)", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightLuminousPower); - AreaLightLuminousPower.SetVisible(false); - - AreaLightEV100.Initialize(tweakBar, "AreaLightEV100", "Area Light", "Color Intensity (EV100)", "", 0.0000f, -64.0000f, 64.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightEV100); - AreaLightEV100.SetVisible(false); - - AreaLightUnits.Initialize(tweakBar, "AreaLightUnits", "Area Light", "Units", "", LightUnits::Luminance, 4, LightUnitsLabels); - Settings.AddSetting(&AreaLightUnits); - - AreaLightIlluminanceDistance.Initialize(tweakBar, "AreaLightIlluminanceDistance", "Area Light", "Illuminance Distance", "", 10.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightIlluminanceDistance); - AreaLightIlluminanceDistance.SetVisible(false); - - AreaLightSize.Initialize(tweakBar, "AreaLightSize", "Area Light", "Size", "The radius of the area light", 0.5000f, 0.0100f, 10.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightSize); - - AreaLightX.Initialize(tweakBar, "AreaLightX", "Area Light", "Position X", "The X coordinate of the area light", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightX); - - AreaLightY.Initialize(tweakBar, "AreaLightY", "Area Light", "Position Y", "The Y coordinate of the area light", 5.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightY); - - AreaLightZ.Initialize(tweakBar, "AreaLightZ", "Area Light", "Position Z", "The Z coordinate of the area light", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightZ); - - AreaLightShadowBias.Initialize(tweakBar, "AreaLightShadowBias", "Area Light", "Shadow Bias", "", 0.0010f, 0.0000f, 1.0000f, 0.0010f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightShadowBias); - - BakeDirectAreaLight.Initialize(tweakBar, "BakeDirectAreaLight", "Area Light", "Bake Direct Area Light", "Bakes the direct contribution from the area light into the light map", false); - Settings.AddSetting(&BakeDirectAreaLight); - - EnableAreaLightShadows.Initialize(tweakBar, "EnableAreaLightShadows", "Area Light", "Enable Area Light Shadows", "", true); - Settings.AddSetting(&EnableAreaLightShadows); - - ExposureMode.Initialize(tweakBar, "ExposureMode", "Camera Controls", "Exposure Mode", "Specifies how exposure should be controled", ExposureModes::Manual_SBS, 4, ExposureModesLabels); - Settings.AddSetting(&ExposureMode); - - ManualExposure.Initialize(tweakBar, "ManualExposure", "Camera Controls", "Manual Exposure", "Manual exposure value when auto-exposure is disabled", -16.0000f, -32.0000f, 32.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ManualExposure); - - ApertureSize.Initialize(tweakBar, "ApertureSize", "Camera Controls", "Aperture", "", FStops::FStop16Point0, 23, FStopsLabels); - Settings.AddSetting(&ApertureSize); - - ISORating.Initialize(tweakBar, "ISORating", "Camera Controls", "ISO Rating", "", ISORatings::ISO100, 4, ISORatingsLabels); - Settings.AddSetting(&ISORating); - - ShutterSpeed.Initialize(tweakBar, "ShutterSpeed", "Camera Controls", "Shutter Speed", "", ShutterSpeeds::ShutterSpeed1Over125, 13, ShutterSpeedsLabels); - Settings.AddSetting(&ShutterSpeed); - - FilmSize.Initialize(tweakBar, "FilmSize", "Camera Controls", "Film Size(mm)", "", 35.0000f, 1.0000f, 100.0000f, 0.1000f, ConversionMode::None, 0.0010f); - Settings.AddSetting(&FilmSize); - - FocalLength.Initialize(tweakBar, "FocalLength", "Camera Controls", "Focal Length(mm)", "", 35.0000f, 1.0000f, 200.0000f, 0.1000f, ConversionMode::None, 0.0010f); - Settings.AddSetting(&FocalLength); - - FocusDistance.Initialize(tweakBar, "FocusDistance", "Camera Controls", "Focus Distance", "", 10.0000f, 1.0000f, 100.0000f, 0.1000f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&FocusDistance); - - NumBlades.Initialize(tweakBar, "NumBlades", "Camera Controls", "Num Aperture Blades", "", 5, 5, 9); - Settings.AddSetting(&NumBlades); - - EnableDOF.Initialize(tweakBar, "EnableDOF", "Camera Controls", "Enable DOF", "", false); - Settings.AddSetting(&EnableDOF); - - KeyValue.Initialize(tweakBar, "KeyValue", "Camera Controls", "Auto-Exposure Key Value", "Parameter that biases the result of the auto-exposure pass", 0.1150f, 0.0000f, 0.5000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&KeyValue); - - AdaptationRate.Initialize(tweakBar, "AdaptationRate", "Camera Controls", "Adaptation Rate", "Controls how quickly auto-exposure adapts to changes in scene brightness", 0.5000f, 0.0000f, 4.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AdaptationRate); - - ApertureFNumber.Initialize(tweakBar, "ApertureFNumber", "Camera Controls", "Aperture FNumber", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ApertureFNumber); - ApertureFNumber.SetVisible(false); - ApertureFNumber.SetEditable(false); - - ApertureWidth.Initialize(tweakBar, "ApertureWidth", "Camera Controls", "Aperture Width", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ApertureWidth); - ApertureWidth.SetVisible(false); - ApertureWidth.SetEditable(false); - - ShutterSpeedValue.Initialize(tweakBar, "ShutterSpeedValue", "Camera Controls", "Shutter Speed Value", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ShutterSpeedValue); - ShutterSpeedValue.SetVisible(false); - ShutterSpeedValue.SetEditable(false); - - ISO.Initialize(tweakBar, "ISO", "Camera Controls", "ISO", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ISO); - ISO.SetVisible(false); - ISO.SetEditable(false); - - BokehPolygonAmount.Initialize(tweakBar, "BokehPolygonAmount", "Camera Controls", "Bokeh Polygon Amount", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BokehPolygonAmount); - BokehPolygonAmount.SetVisible(false); - BokehPolygonAmount.SetEditable(false); - - ToneMappingMode.Initialize(tweakBar, "ToneMappingMode", "Tone Mapping", "Tone Mapping Operator", "", ToneMappingModes::ACES, 5, ToneMappingModesLabels); - Settings.AddSetting(&ToneMappingMode); - - WhitePoint_Hejl.Initialize(tweakBar, "WhitePoint_Hejl", "Tone Mapping", "White Point (Hejl2015)", "", 1.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&WhitePoint_Hejl); - - ShoulderStrength.Initialize(tweakBar, "ShoulderStrength", "Tone Mapping", "Shoulder Strength", "", 4.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ShoulderStrength); - - LinearStrength.Initialize(tweakBar, "LinearStrength", "Tone Mapping", "Linear Strength", "", 5.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&LinearStrength); - - LinearAngle.Initialize(tweakBar, "LinearAngle", "Tone Mapping", "Linear Angle", "", 0.1200f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&LinearAngle); - - ToeStrength.Initialize(tweakBar, "ToeStrength", "Tone Mapping", "Toe Strength", "", 13.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ToeStrength); - - WhitePoint_Hable.Initialize(tweakBar, "WhitePoint_Hable", "Tone Mapping", "White Point (Hable)", "", 6.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&WhitePoint_Hable); - - MSAAMode.Initialize(tweakBar, "MSAAMode", "Anti Aliasing", "MSAAMode", "", MSAAModes::MSAA4x, 4, MSAAModesLabels); - Settings.AddSetting(&MSAAMode); - - FilterType.Initialize(tweakBar, "FilterType", "Anti Aliasing", "Filter Type", "", FilterTypes::Smoothstep, 6, FilterTypesLabels); - Settings.AddSetting(&FilterType); - - FilterSize.Initialize(tweakBar, "FilterSize", "Anti Aliasing", "Filter Size", "", 2.0000f, 0.0000f, 6.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&FilterSize); - - GaussianSigma.Initialize(tweakBar, "GaussianSigma", "Anti Aliasing", "Gaussian Sigma", "", 0.5000f, 0.0100f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&GaussianSigma); - - EnableTemporalAA.Initialize(tweakBar, "EnableTemporalAA", "Anti Aliasing", "Enable Temporal AA", "", true); - Settings.AddSetting(&EnableTemporalAA); - - JitterMode.Initialize(tweakBar, "JitterMode", "Anti Aliasing", "Jitter Mode", "", JitterModes::Hammersley4x, 5, JitterModesLabels); - Settings.AddSetting(&JitterMode); - - JitterScale.Initialize(tweakBar, "JitterScale", "Anti Aliasing", "Jitter Scale", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&JitterScale); - - SGDiffuseMode.Initialize(tweakBar, "SGDiffuseMode", "SG Settings", "SG Diffuse Mode", "", SGDiffuseModes::Fitted, 3, SGDiffuseModesLabels); - Settings.AddSetting(&SGDiffuseMode); - - UseASGWarp.Initialize(tweakBar, "UseASGWarp", "SG Settings", "Use ASG Warp", "", true); - Settings.AddSetting(&UseASGWarp); - - LightMapResolution.Initialize(tweakBar, "LightMapResolution", "Baking", "Light Map Resolution", "The texture resolution of the light map", 256, 64, 4096); - Settings.AddSetting(&LightMapResolution); - - NumBakeSamples.Initialize(tweakBar, "NumBakeSamples", "Baking", "Sqrt Num Samples", "The square root of the number of sample rays to use for baking GI", 25, 1, 100); - Settings.AddSetting(&NumBakeSamples); - - BakeSampleMode.Initialize(tweakBar, "BakeSampleMode", "Baking", "Sample Mode", "", SampleModes::CMJ, 5, SampleModesLabels); - Settings.AddSetting(&BakeSampleMode); - - MaxBakePathLength.Initialize(tweakBar, "MaxBakePathLength", "Baking", "Max Bake Path Length", "Maximum path length (bounces + 2) to use for baking GI (set to -1 for infinite)", -1, -1, 2147483647); - Settings.AddSetting(&MaxBakePathLength); - - BakeRussianRouletteDepth.Initialize(tweakBar, "BakeRussianRouletteDepth", "Baking", "Russian Roullette Depth", "Path length at which Russian roulette kicks in (-1 to disable)", 4, -1, 2147483647); - Settings.AddSetting(&BakeRussianRouletteDepth); - - BakeRussianRouletteProbability.Initialize(tweakBar, "BakeRussianRouletteProbability", "Baking", "Russian Roullette Probability", "Maximum probability for continuing when Russian roulette is used", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BakeRussianRouletteProbability); - - BakeMode.Initialize(tweakBar, "BakeMode", "Baking", "Bake Mode", "", BakeModes::SG9, 10, BakeModesLabels); - Settings.AddSetting(&BakeMode); - - SolveMode.Initialize(tweakBar, "SolveMode", "Baking", "Solve Mode", "", SolveModes::NNLS, 3, SolveModesLabels); - Settings.AddSetting(&SolveMode); - - CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); - Settings.AddSetting(&CurrentScene); - - EnableDiffuse.Initialize(tweakBar, "EnableDiffuse", "Scene", "Enable Diffuse", "Enables diffuse lighting", true); - Settings.AddSetting(&EnableDiffuse); - - EnableSpecular.Initialize(tweakBar, "EnableSpecular", "Scene", "Enable Specular", "Enables specular lighting", true); - Settings.AddSetting(&EnableSpecular); - - EnableDirectLighting.Initialize(tweakBar, "EnableDirectLighting", "Scene", "Enable Direct Lighting", "Enables direct lighting", true); - Settings.AddSetting(&EnableDirectLighting); - - EnableIndirectLighting.Initialize(tweakBar, "EnableIndirectLighting", "Scene", "Enable Indirect Lighting", "Enables indirect lighting", true); - Settings.AddSetting(&EnableIndirectLighting); - - EnableIndirectDiffuse.Initialize(tweakBar, "EnableIndirectDiffuse", "Scene", "Enable Indirect Diffuse", "Enables indirect diffuse lighting", true); - Settings.AddSetting(&EnableIndirectDiffuse); - - EnableIndirectSpecular.Initialize(tweakBar, "EnableIndirectSpecular", "Scene", "Enable Indirect Specular", "Enables indirect specular lighting", true); - Settings.AddSetting(&EnableIndirectSpecular); - - EnableAlbedoMaps.Initialize(tweakBar, "EnableAlbedoMaps", "Scene", "Enable Albedo Maps", "Enables albedo maps", true); - Settings.AddSetting(&EnableAlbedoMaps); - - EnableNormalMaps.Initialize(tweakBar, "EnableNormalMaps", "Scene", "Enable Normal Maps", "Enables normal maps", true); - Settings.AddSetting(&EnableNormalMaps); - - NormalMapIntensity.Initialize(tweakBar, "NormalMapIntensity", "Scene", "Normal Map Intensity", "Intensity of the normal map", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&NormalMapIntensity); - - DiffuseAlbedoScale.Initialize(tweakBar, "DiffuseAlbedoScale", "Scene", "Diffuse Albedo Scale", "Global scale applied to all material diffuse albedo values", 0.5000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&DiffuseAlbedoScale); - - RoughnessScale.Initialize(tweakBar, "RoughnessScale", "Scene", "Specular Roughness Scale", "Global scale applied to all material roughness values", 2.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&RoughnessScale); - - ShowGroundTruth.Initialize(tweakBar, "ShowGroundTruth", "Ground Truth", "Show Ground Truth", "If enabled, shows a ground truth image rendered on the CPU", false); - Settings.AddSetting(&ShowGroundTruth); - - NumRenderSamples.Initialize(tweakBar, "NumRenderSamples", "Ground Truth", "Sqrt Num Samples", "The square root of the number of per-pixel sample rays to use for ground truth rendering", 4, 1, 100); - Settings.AddSetting(&NumRenderSamples); - - RenderSampleMode.Initialize(tweakBar, "RenderSampleMode", "Ground Truth", "Sample Mode", "", SampleModes::CMJ, 5, SampleModesLabels); - Settings.AddSetting(&RenderSampleMode); - - MaxRenderPathLength.Initialize(tweakBar, "MaxRenderPathLength", "Ground Truth", "Max Path Length", "Maximum path length (bounces) to use for ground truth rendering (set to -1 for infinite)", -1, -1, 2147483647); - Settings.AddSetting(&MaxRenderPathLength); - - RenderRussianRouletteDepth.Initialize(tweakBar, "RenderRussianRouletteDepth", "Ground Truth", "Russian Roullette Depth", "Path length at which Russian roulette kicks in (-1 to disable)", 4, -1, 2147483647); - Settings.AddSetting(&RenderRussianRouletteDepth); - - RenderRussianRouletteProbability.Initialize(tweakBar, "RenderRussianRouletteProbability", "Ground Truth", "Russian Roullette Probability", "Maximum probability for continuing when Russian roulette is used", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&RenderRussianRouletteProbability); - - EnableRenderBounceSpecular.Initialize(tweakBar, "EnableRenderBounceSpecular", "Ground Truth", "Enable Bounce Specular", "Enables specular calculations after the first hit", false); - Settings.AddSetting(&EnableRenderBounceSpecular); - - BloomExposure.Initialize(tweakBar, "BloomExposure", "Post Processing", "Bloom Exposure Offset", "Exposure offset applied to generate the input of the bloom pass", -4.0000f, -10.0000f, 0.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BloomExposure); - - BloomMagnitude.Initialize(tweakBar, "BloomMagnitude", "Post Processing", "Bloom Magnitude", "Scale factor applied to the bloom results when combined with tone-mapped result", 1.0000f, 0.0000f, 2.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BloomMagnitude); - - BloomBlurSigma.Initialize(tweakBar, "BloomBlurSigma", "Post Processing", "Bloom Blur Sigma", "Sigma parameter of the Gaussian filter used in the bloom pass", 2.5000f, 0.5000f, 2.5000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BloomBlurSigma); - - EnableLuminancePicker.Initialize(tweakBar, "EnableLuminancePicker", "Debug", "Enable Luminance Picker", "", false); - Settings.AddSetting(&EnableLuminancePicker); - - ShowBakeDataVisualizer.Initialize(tweakBar, "ShowBakeDataVisualizer", "Debug", "Show Bake Data Visualizer", "", false); - Settings.AddSetting(&ShowBakeDataVisualizer); - - ViewIndirectSpecular.Initialize(tweakBar, "ViewIndirectSpecular", "Debug", "View Indirect Specular", "", false); - Settings.AddSetting(&ViewIndirectSpecular); - - SaveLightSettings.Initialize(tweakBar, "SaveLightSettings", "Debug", "Save Light Settings", "Saves the lighting settings to a file"); - Settings.AddSetting(&SaveLightSettings); - - LoadLightSettings.Initialize(tweakBar, "LoadLightSettings", "Debug", "Load Light Settings", "Loads the lighting settings from a file"); - Settings.AddSetting(&LoadLightSettings); - - SaveEXRScreenshot.Initialize(tweakBar, "SaveEXRScreenshot", "Debug", "Save EXR Screenshot", "Captures the current screen image in EXR format"); - Settings.AddSetting(&SaveEXRScreenshot); - - ShowSunIntensity.Initialize(tweakBar, "ShowSunIntensity", "Debug", "Show Sun Intensity", "", false); - Settings.AddSetting(&ShowSunIntensity); - - TwHelper::SetOpened(tweakBar, "Sun Light", true); - - TwHelper::SetOpened(tweakBar, "Sky", true); - - TwHelper::SetOpened(tweakBar, "Area Light", false); - - TwHelper::SetOpened(tweakBar, "Camera Controls", false); - - TwHelper::SetOpened(tweakBar, "Tone Mapping", false); - - TwHelper::SetOpened(tweakBar, "Anti Aliasing", false); - - TwHelper::SetOpened(tweakBar, "SG Settings", false); - - TwHelper::SetOpened(tweakBar, "Baking", false); - - TwHelper::SetOpened(tweakBar, "Scene", false); - - TwHelper::SetOpened(tweakBar, "Ground Truth", false); - - TwHelper::SetOpened(tweakBar, "Post Processing", false); - - TwHelper::SetOpened(tweakBar, "Debug", false); - - CBuffer.Initialize(device); - } - - void Update() - { - ApertureFNumber.SetValue(ApertureFNumber_()); - ApertureWidth.SetValue(ApertureWidth_()); - ShutterSpeedValue.SetValue(ShutterSpeedValue_()); - ISO.SetValue(ISO_()); - BokehPolygonAmount.SetValue(BokehPolygonAmount_()); - } - - void UpdateCBuffer(ID3D11DeviceContext* context) - { - CBuffer.Data.EnableSun = EnableSun; - CBuffer.Data.SunAreaLightApproximation = SunAreaLightApproximation; - CBuffer.Data.SunTintColor = SunTintColor; - CBuffer.Data.SunIntensityScale = SunIntensityScale; - CBuffer.Data.SunSize = SunSize; - CBuffer.Data.SunDirType = SunDirType; - CBuffer.Data.SunDirection = SunDirection; - CBuffer.Data.SunAzimuth = SunAzimuth; - CBuffer.Data.SunElevation = SunElevation; - CBuffer.Data.EnableAreaLight = EnableAreaLight; - CBuffer.Data.AreaLightColor = AreaLightColor; - CBuffer.Data.AreaLightSize = AreaLightSize; - CBuffer.Data.AreaLightX = AreaLightX; - CBuffer.Data.AreaLightY = AreaLightY; - CBuffer.Data.AreaLightZ = AreaLightZ; - CBuffer.Data.AreaLightShadowBias = AreaLightShadowBias; - CBuffer.Data.BakeDirectAreaLight = BakeDirectAreaLight; - CBuffer.Data.EnableAreaLightShadows = EnableAreaLightShadows; - CBuffer.Data.ExposureMode = ExposureMode; - CBuffer.Data.ManualExposure = ManualExposure; - CBuffer.Data.FilmSize = FilmSize; - CBuffer.Data.FocalLength = FocalLength; - CBuffer.Data.FocusDistance = FocusDistance; - CBuffer.Data.NumBlades = NumBlades; - CBuffer.Data.KeyValue = KeyValue; - CBuffer.Data.AdaptationRate = AdaptationRate; - CBuffer.Data.ApertureFNumber = ApertureFNumber; - CBuffer.Data.ApertureWidth = ApertureWidth; - CBuffer.Data.ShutterSpeedValue = ShutterSpeedValue; - CBuffer.Data.ISO = ISO; - CBuffer.Data.BokehPolygonAmount = BokehPolygonAmount; - CBuffer.Data.ToneMappingMode = ToneMappingMode; - CBuffer.Data.WhitePoint_Hejl = WhitePoint_Hejl; - CBuffer.Data.ShoulderStrength = ShoulderStrength; - CBuffer.Data.LinearStrength = LinearStrength; - CBuffer.Data.LinearAngle = LinearAngle; - CBuffer.Data.ToeStrength = ToeStrength; - CBuffer.Data.WhitePoint_Hable = WhitePoint_Hable; - CBuffer.Data.MSAAMode = MSAAMode; - CBuffer.Data.FilterType = FilterType; - CBuffer.Data.FilterSize = FilterSize; - CBuffer.Data.GaussianSigma = GaussianSigma; - CBuffer.Data.SGDiffuseMode = SGDiffuseMode; - CBuffer.Data.UseASGWarp = UseASGWarp; - CBuffer.Data.LightMapResolution = LightMapResolution; - CBuffer.Data.BakeMode = BakeMode; - CBuffer.Data.SolveMode = SolveMode; - CBuffer.Data.EnableDiffuse = EnableDiffuse; - CBuffer.Data.EnableSpecular = EnableSpecular; - CBuffer.Data.EnableDirectLighting = EnableDirectLighting; - CBuffer.Data.EnableIndirectLighting = EnableIndirectLighting; - CBuffer.Data.EnableIndirectDiffuse = EnableIndirectDiffuse; - CBuffer.Data.EnableIndirectSpecular = EnableIndirectSpecular; - CBuffer.Data.EnableAlbedoMaps = EnableAlbedoMaps; - CBuffer.Data.EnableNormalMaps = EnableNormalMaps; - CBuffer.Data.NormalMapIntensity = NormalMapIntensity; - CBuffer.Data.DiffuseAlbedoScale = DiffuseAlbedoScale; - CBuffer.Data.RoughnessScale = RoughnessScale; - CBuffer.Data.BloomExposure = BloomExposure; - CBuffer.Data.BloomMagnitude = BloomMagnitude; - CBuffer.Data.BloomBlurSigma = BloomBlurSigma; - CBuffer.Data.ViewIndirectSpecular = ViewIndirectSpecular; - - CBuffer.ApplyChanges(context); - CBuffer.SetVS(context, 7); - CBuffer.SetHS(context, 7); - CBuffer.SetDS(context, 7); - CBuffer.SetGS(context, 7); - CBuffer.SetPS(context, 7); - CBuffer.SetCS(context, 7); - } -} - -// ================================================================================================ - -#include -#include -#include - -namespace AppSettings -{ - // Returns the result of performing a irradiance/illuminance integral over the portion - // of the hemisphere covered by a region with angular radius = theta - static float IlluminanceIntegral(float theta) - { - float cosTheta = std::cos(theta); - return Pi * (1.0f - (cosTheta * cosTheta)); - } - - Float3 SunLuminance(bool& cached) - { - Float3 sunDirection = AppSettings::SunDirection; - sunDirection.y = Saturate(sunDirection.y); - sunDirection = Float3::Normalize(sunDirection); - const float turbidity = Clamp(AppSettings::Turbidity.Value(), 1.0f, 32.0f); - const float intensityScale = AppSettings::SunIntensityScale; - const Float3 tintColor = AppSettings::SunTintColor; - const bool32 normalizeIntensity = AppSettings::NormalizeSunIntensity; - const float sunSize = AppSettings::SunSize; - - static float turbidityCache = 2.0f; - static Float3 sunDirectionCache = Float3(-0.579149902f, 0.754439294f, -0.308879942f); - static Float3 luminanceCache = Float3(1.61212531e+009f, 1.36822630e+009f, 1.07235315e+009f) * FP16Scale; - static Float3 sunTintCache = Float3(1.0f, 1.0f, 1.0f); - static float sunIntensityCache = 1.0f; - static bool32 normalizeCache = false; - static float sunSizeCache = AppSettings::BaseSunSize; - - if(turbidityCache == turbidity && sunDirection == sunDirectionCache - && intensityScale == sunIntensityCache && tintColor == sunTintCache - && normalizeCache == normalizeIntensity && sunSize == sunSizeCache) - { - cached = true; - return luminanceCache; - } - - cached = false; - - float thetaS = std::acos(1.0f - sunDirection.y); - float elevation = Pi_2 - thetaS; - - // Get the sun's luminance, then apply tint and scale factors - Float3 sunLuminance; - - // For now, we'll compute an average luminance value from Hosek solar radiance model, even though - // we could compute illuminance directly while we're sampling the disk - SampledSpectrum groundAlbedoSpectrum = SampledSpectrum::FromRGB(GroundAlbedo); - SampledSpectrum solarRadiance; - - const uint64 NumDiscSamples = 8; - for(uint64 x = 0; x < NumDiscSamples; ++x) - { - for(uint64 y = 0; y < NumDiscSamples; ++y) - { - float u = (x + 0.5f) / NumDiscSamples; - float v = (y + 0.5f) / NumDiscSamples; - Float2 discSamplePos = SquareToConcentricDiskMapping(u, v); - - float theta = elevation + discSamplePos.y * DegToRad(AppSettings::BaseSunSize); - float gamma = discSamplePos.x * DegToRad(AppSettings::BaseSunSize); - - for(int32 i = 0; i < NumSpectralSamples; ++i) - { - ArHosekSkyModelState* skyState = arhosekskymodelstate_alloc_init(elevation, turbidity, groundAlbedoSpectrum[i]); - float wavelength = Lerp(float(SampledLambdaStart), float(SampledLambdaEnd), i / float(NumSpectralSamples)); - - solarRadiance[i] = float(arhosekskymodel_solar_radiance(skyState, theta, gamma, wavelength)); - - arhosekskymodelstate_free(skyState); - skyState = nullptr; - } - - Float3 sampleRadiance = solarRadiance.ToRGB() * FP16Scale; - sunLuminance += sampleRadiance; - } - } - - // Account for luminous efficiency, coordinate system scaling, and sample averaging - sunLuminance *= 683.0f * 100.0f * (1.0f / NumDiscSamples) * (1.0f / NumDiscSamples); - - sunLuminance = sunLuminance * tintColor; - sunLuminance = sunLuminance * intensityScale; - - if(normalizeIntensity) - { - // Normalize so that the intensity stays the same even when the sun is bigger or smaller - const float baseIntegral = IlluminanceIntegral(DegToRad(AppSettings::BaseSunSize)); - const float currIntegral = IlluminanceIntegral(DegToRad(AppSettings::SunSize)); - sunLuminance *= (baseIntegral / currIntegral); - } - - turbidityCache = turbidity; - sunDirectionCache = sunDirection; - luminanceCache = sunLuminance; - sunIntensityCache = intensityScale; - sunTintCache = tintColor; - normalizeCache = normalizeIntensity; - sunSizeCache = sunSize; - - return sunLuminance; - } - - Float3 SunLuminance() - { - bool cached = false; - return SunLuminance(cached); - } - - Float3 SunIlluminance() - { - Float3 sunLuminance = SunLuminance(); - - // Compute partial integral over the hemisphere in order to compute illuminance - float theta = DegToRad(AppSettings::SunSize); - float integralFactor = IlluminanceIntegral(theta); - - return sunLuminance * integralFactor; - } - - static void UpdateAreaLightUnits() - { - static LightUnits prevUnits = AreaLightUnits; - const LightUnits currUnits = AreaLightUnits; - - const float size = AreaLightSize; - const float distance = AreaLightIlluminanceDistance; - - // Compute the luminance from our currently active unit - float luminance = AreaLightColor.Intensity(); - if(prevUnits == LightUnits::Illuminance) - { - float illuminance = AreaLightIlluminance; - float angularRadius = std::atan2(size, distance); - float integralFactor = IlluminanceIntegral(angularRadius); - luminance = illuminance / integralFactor; - } - else if(prevUnits == LightUnits::LuminousPower) - { - float luminousPower = AreaLightLuminousPower; - luminance = luminousPower / (4 * size * size * Pi * Pi); - } - else if(prevUnits == LightUnits::EV100) - { - float ev100 = AreaLightEV100; - luminance = std::pow(2.0f, ev100 - 3.0f); - } - - // Set the new luminance onto the color - AreaLightColor.SetIntensity(luminance); - - // Update the other units - float angularRadius = std::atan2(size, distance); - float integralFactor = IlluminanceIntegral(angularRadius); - float illuminance = luminance * integralFactor; - AreaLightIlluminance.SetValue(illuminance); - - float luminousPower = luminance * (4 * size * size * Pi * Pi); - AreaLightLuminousPower.SetValue(luminousPower); - - float ev100 = std::log2(luminance) + 3.0f; - AreaLightEV100.SetValue(ev100); - - if(prevUnits != currUnits) - { - AreaLightColor.SetIntensityVisible(currUnits == LightUnits::Luminance); - AreaLightIlluminance.SetVisible(currUnits == LightUnits::Illuminance); - AreaLightLuminousPower.SetVisible(currUnits == LightUnits::LuminousPower); - AreaLightEV100.SetVisible(currUnits == LightUnits::EV100); - AreaLightIlluminanceDistance.SetVisible(currUnits == LightUnits::Illuminance); - - prevUnits = currUnits; - } - } - - void UpdateUI() - { - bool enableManualExposure = ExposureMode == ExposureModes::ManualSimple; - bool enableCameraExposure = ExposureMode == ExposureModes::Manual_SBS || - ExposureMode == ExposureModes::Manual_SOS; - bool enableAutoExposure = ExposureMode == ExposureModes::Automatic; - bool enableSimpleSkyParams = SkyMode == SkyModes::Simple; - bool enableProceduralSkyParams = SkyMode == SkyModes::Procedural; - bool useHejlTM = ToneMappingMode == ToneMappingModes::Hejl2015; - bool useHableTM = ToneMappingMode == ToneMappingModes::Hable; - bool useSGSettings = SGCount() > 0; - - ManualExposure.SetEditable(enableManualExposure); - ShutterSpeed.SetEditable(enableCameraExposure); - ISORating.SetEditable(enableCameraExposure); - KeyValue.SetEditable(enableAutoExposure); - AdaptationRate.SetEditable(enableAutoExposure); - SkyColor.SetEditable(enableSimpleSkyParams); - Turbidity.SetEditable(enableProceduralSkyParams); - GroundAlbedo.SetEditable(enableProceduralSkyParams); - - WhitePoint_Hejl.SetVisible(useHejlTM); - - WhitePoint_Hable.SetVisible(useHableTM); - ShoulderStrength.SetVisible(useHableTM); - LinearStrength.SetVisible(useHableTM); - LinearAngle.SetVisible(useHableTM); - ToeStrength.SetVisible(useHableTM); - - bool enableSunDirection = SunDirType == SunDirectionTypes::UnitVector; - bool enableHorizCoord = SunDirType == SunDirectionTypes::HorizontalCoordSystem; - - SunDirection.SetVisible(enableSunDirection); - SunAzimuth.SetVisible(enableHorizCoord); - SunElevation.SetVisible(enableHorizCoord); - - SGDiffuseMode.SetEditable(useSGSettings); - SolveMode.SetEditable(useSGSettings); - - if(AppSettings::HasSunDirChanged()) - { - if(SunDirType == SunDirectionTypes::UnitVector) - { - UpdateHorizontalCoords(); - } - else if(SunDirType == SunDirectionTypes::HorizontalCoordSystem) - { - UpdateUnitVector(); - } - } - - UpdateAreaLightUnits(); - } +#include +#include +#include "AppSettings.h" + +using namespace SampleFramework11; + +static const char* SunDirectionTypesLabels[2] = +{ + "Unit Vector", + "Horizontal Coordinate System", +}; + +static const char* SkyModesLabels[6] = +{ + "None", + "Procedural", + "Simple", + "Ennis", + "Grace Cathedral", + "Uffizi Cross", +}; + +static const char* LightUnitsLabels[4] = +{ + "Luminance", + "Illuminance", + "LuminousPower", + "EV100", +}; + +static const char* ExposureModesLabels[4] = +{ + "Manual (Simple)", + "Manual (SBS)", + "Manual (SOS)", + "Automatic", +}; + +static const char* FStopsLabels[23] = +{ + "f/1.8", + "f/2.0", + "f/2.2", + "f/2.5", + "f/2.8", + "f/3.2", + "f/3.5", + "f/4.0", + "f/4.5", + "f/5.0", + "f/5.6", + "f/6.3", + "f/7.1", + "f/8.0", + "f/9.0", + "f/10.0", + "f/11.0", + "f/13.0", + "f/14.0", + "f/16.0", + "f/18.0", + "f/20.0", + "f/22.0", +}; + +static const char* ISORatingsLabels[4] = +{ + "ISO100", + "ISO200", + "ISO400", + "ISO800", +}; + +static const char* ShutterSpeedsLabels[13] = +{ + "1s", + "1/2s", + "1/4s", + "1/8s", + "1/15s", + "1/30s", + "1/60s", + "1/125s", + "1/250s", + "1/500s", + "1/1000s", + "1/2000s", + "1/4000s", +}; + +static const char* ToneMappingModesLabels[5] = +{ + "Film Stock", + "Linear", + "ACES sRGB Monitor", + "Hejl 2015", + "Hable (Uncharted2)", +}; + +static const char* MSAAModesLabels[4] = +{ + "None", + "2x", + "4x", + "8x", +}; + +static const char* FilterTypesLabels[6] = +{ + "Box", + "Triangle", + "Gaussian", + "BlackmanHarris", + "Smoothstep", + "BSpline", +}; + +static const char* JitterModesLabels[5] = +{ + "None", + "Uniform2x", + "Hammersley4x", + "Hammersley8x", + "Hammersley16x", +}; + +static const char* SGDiffuseModesLabels[3] = +{ + "InnerProduct", + "Punctual", + "Fitted (Hill 16)", +}; + +static const char* SampleModesLabels[5] = +{ + "Random", + "Stratified", + "Hammersley", + "UniformGrid", + "CMJ", +}; + +static const char* BakeModesLabels[10] = +{ + "Diffuse", + "Half-Life 2", + "L1 SH", + "L2 SH", + "L1 H-basis", + "L2 H-basis", + "SG5", + "SG6", + "SG9", + "SG12", +}; + +static const char* SolveModesLabels[3] = +{ + "Ad-Hoc Projection", + "Least Squares", + "Non-Negative Least Squares", +}; + +static const char* ScenesLabels[3] = +{ + "Box", + "White Room", + "Sponza", +}; + +namespace AppSettings +{ + BoolSetting EnableSun; + BoolSetting SunAreaLightApproximation; + ColorSetting SunTintColor; + FloatSetting SunIntensityScale; + FloatSetting SunSize; + BoolSetting NormalizeSunIntensity; + SunDirectionTypesSetting SunDirType; + DirectionSetting SunDirection; + FloatSetting SunAzimuth; + FloatSetting SunElevation; + SkyModesSetting SkyMode; + ColorSetting SkyColor; + FloatSetting Turbidity; + ColorSetting GroundAlbedo; + BoolSetting EnableAreaLight; + ColorSetting AreaLightColor; + FloatSetting AreaLightIlluminance; + FloatSetting AreaLightLuminousPower; + FloatSetting AreaLightEV100; + LightUnitsSetting AreaLightUnits; + FloatSetting AreaLightIlluminanceDistance; + FloatSetting AreaLightSize; + FloatSetting AreaLightX; + FloatSetting AreaLightY; + FloatSetting AreaLightZ; + FloatSetting AreaLightShadowBias; + BoolSetting BakeDirectAreaLight; + BoolSetting EnableAreaLightShadows; + ExposureModesSetting ExposureMode; + FloatSetting ManualExposure; + FStopsSetting ApertureSize; + ISORatingsSetting ISORating; + ShutterSpeedsSetting ShutterSpeed; + FloatSetting FilmSize; + FloatSetting FocalLength; + FloatSetting FocusDistance; + IntSetting NumBlades; + BoolSetting EnableDOF; + FloatSetting KeyValue; + FloatSetting AdaptationRate; + FloatSetting ApertureFNumber; + FloatSetting ApertureWidth; + FloatSetting ShutterSpeedValue; + FloatSetting ISO; + FloatSetting BokehPolygonAmount; + ToneMappingModesSetting ToneMappingMode; + FloatSetting WhitePoint_Hejl; + FloatSetting ShoulderStrength; + FloatSetting LinearStrength; + FloatSetting LinearAngle; + FloatSetting ToeStrength; + FloatSetting WhitePoint_Hable; + MSAAModesSetting MSAAMode; + FilterTypesSetting FilterType; + FloatSetting FilterSize; + FloatSetting GaussianSigma; + BoolSetting EnableTemporalAA; + JitterModesSetting JitterMode; + FloatSetting JitterScale; + SGDiffuseModesSetting SGDiffuseMode; + BoolSetting UseASGWarp; + IntSetting LightMapResolution; + IntSetting NumBakeSamples; + SampleModesSetting BakeSampleMode; + IntSetting MaxBakePathLength; + IntSetting BakeRussianRouletteDepth; + FloatSetting BakeRussianRouletteProbability; + BakeModesSetting BakeMode; + SolveModesSetting SolveMode; + BoolSetting UseProbes; + IntSetting ProbeResX; + IntSetting ProbeResY; + IntSetting ProbeResZ; + ScenesSetting CurrentScene; + BoolSetting EnableDiffuse; + BoolSetting EnableSpecular; + BoolSetting EnableDirectLighting; + BoolSetting EnableIndirectLighting; + BoolSetting EnableIndirectDiffuse; + BoolSetting EnableIndirectSpecular; + BoolSetting EnableAlbedoMaps; + BoolSetting EnableNormalMaps; + FloatSetting NormalMapIntensity; + FloatSetting DiffuseAlbedoScale; + FloatSetting RoughnessScale; + BoolSetting ShowGroundTruth; + IntSetting NumRenderSamples; + SampleModesSetting RenderSampleMode; + IntSetting MaxRenderPathLength; + IntSetting RenderRussianRouletteDepth; + FloatSetting RenderRussianRouletteProbability; + BoolSetting EnableRenderBounceSpecular; + FloatSetting BloomExposure; + FloatSetting BloomMagnitude; + FloatSetting BloomBlurSigma; + BoolSetting EnableLuminancePicker; + BoolSetting ShowBakeDataVisualizer; + BoolSetting ViewIndirectSpecular; + Button SaveLightSettings; + Button LoadLightSettings; + Button SaveEXRScreenshot; + BoolSetting ShowSunIntensity; + + ConstantBuffer CBuffer; + + void Initialize(ID3D11Device* device) + { + TwBar* tweakBar = Settings.TweakBar(); + + EnableSun.Initialize(tweakBar, "EnableSun", "Sun Light", "Enable Sun", "Enables the sun light", true); + Settings.AddSetting(&EnableSun); + + SunAreaLightApproximation.Initialize(tweakBar, "SunAreaLightApproximation", "Sun Light", "Sun Area Light Approximation", "Controls whether the sun is treated as a disc area light in the real-time shader", true); + Settings.AddSetting(&SunAreaLightApproximation); + + SunTintColor.Initialize(tweakBar, "SunTintColor", "Sun Light", "Sun Tint Color", "The color of the sun", Float3(1.0000f, 1.0000f, 1.0000f), false, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ColorUnit::None); + Settings.AddSetting(&SunTintColor); + + SunIntensityScale.Initialize(tweakBar, "SunIntensityScale", "Sun Light", "Sun Intensity Scale", "Scale the intensity of the sun", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SunIntensityScale); + + SunSize.Initialize(tweakBar, "SunSize", "Sun Light", "Sun Size", "Angular radius of the sun in degrees", 0.2700f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0010f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SunSize); + + NormalizeSunIntensity.Initialize(tweakBar, "NormalizeSunIntensity", "Sun Light", "Normalize Sun Intensity", "", false); + Settings.AddSetting(&NormalizeSunIntensity); + + SunDirType.Initialize(tweakBar, "SunDirType", "Sun Light", "Sun Dir Type", "Input direction type for the sun", SunDirectionTypes::HorizontalCoordSystem, 2, SunDirectionTypesLabels); + Settings.AddSetting(&SunDirType); + + SunDirection.Initialize(tweakBar, "SunDirection", "Sun Light", "Sun Direction", "Director of the sun", Float3(-0.7500f, 0.9770f, -0.4000f)); + Settings.AddSetting(&SunDirection); + + SunAzimuth.Initialize(tweakBar, "SunAzimuth", "Sun Light", "Sun Azimuth", "Angle around the horizon", 0.0000f, 0.0000f, 360.0000f, 0.1000f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SunAzimuth); + + SunElevation.Initialize(tweakBar, "SunElevation", "Sun Light", "Sun Elevation", "Elevation of sun from ground. 0 degrees is aligned on the horizon while 90 degrees is directly overhead", 0.0000f, 0.0000f, 90.0000f, 0.1000f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SunElevation); + + SkyMode.Initialize(tweakBar, "SkyMode", "Sky", "Sky Mode", "Controls the sky used for GI baking and background rendering", SkyModes::Procedural, 6, SkyModesLabels); + Settings.AddSetting(&SkyMode); + + SkyColor.Initialize(tweakBar, "SkyColor", "Sky", "Sky Color", "The color of the simple sky", Float3(1400.0000f, 3500.0000f, 7000.0000f), true, 0.0000f, 1000000.0000f, 0.1000f, ColorUnit::Luminance); + Settings.AddSetting(&SkyColor); + + Turbidity.Initialize(tweakBar, "Turbidity", "Sky", "Turbidity", "", 2.0000f, 1.0000f, 10.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&Turbidity); + + GroundAlbedo.Initialize(tweakBar, "GroundAlbedo", "Sky", "Ground Albedo", "", Float3(0.5000f, 0.5000f, 0.5000f), false, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ColorUnit::None); + Settings.AddSetting(&GroundAlbedo); + + EnableAreaLight.Initialize(tweakBar, "EnableAreaLight", "Area Light", "Enable Area Light", "Enables the area light during baking and ground truth rendering", false); + Settings.AddSetting(&EnableAreaLight); + + AreaLightColor.Initialize(tweakBar, "AreaLightColor", "Area Light", "Color", "The color of the area light", Float3(1000000.0000f, 1000000.0000f, 1000000.0000f), true, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.1000f, ColorUnit::Luminance); + Settings.AddSetting(&AreaLightColor); + + AreaLightIlluminance.Initialize(tweakBar, "AreaLightIlluminance", "Area Light", "Color Intensity (lux)", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightIlluminance); + AreaLightIlluminance.SetVisible(false); + + AreaLightLuminousPower.Initialize(tweakBar, "AreaLightLuminousPower", "Area Light", "Color Intensity (lm)", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightLuminousPower); + AreaLightLuminousPower.SetVisible(false); + + AreaLightEV100.Initialize(tweakBar, "AreaLightEV100", "Area Light", "Color Intensity (EV100)", "", 0.0000f, -64.0000f, 64.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightEV100); + AreaLightEV100.SetVisible(false); + + AreaLightUnits.Initialize(tweakBar, "AreaLightUnits", "Area Light", "Units", "", LightUnits::Luminance, 4, LightUnitsLabels); + Settings.AddSetting(&AreaLightUnits); + + AreaLightIlluminanceDistance.Initialize(tweakBar, "AreaLightIlluminanceDistance", "Area Light", "Illuminance Distance", "", 10.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightIlluminanceDistance); + AreaLightIlluminanceDistance.SetVisible(false); + + AreaLightSize.Initialize(tweakBar, "AreaLightSize", "Area Light", "Size", "The radius of the area light", 0.5000f, 0.0100f, 10.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightSize); + + AreaLightX.Initialize(tweakBar, "AreaLightX", "Area Light", "Position X", "The X coordinate of the area light", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightX); + + AreaLightY.Initialize(tweakBar, "AreaLightY", "Area Light", "Position Y", "The Y coordinate of the area light", 5.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightY); + + AreaLightZ.Initialize(tweakBar, "AreaLightZ", "Area Light", "Position Z", "The Z coordinate of the area light", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightZ); + + AreaLightShadowBias.Initialize(tweakBar, "AreaLightShadowBias", "Area Light", "Shadow Bias", "", 0.0010f, 0.0000f, 1.0000f, 0.0010f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightShadowBias); + + BakeDirectAreaLight.Initialize(tweakBar, "BakeDirectAreaLight", "Area Light", "Bake Direct Area Light", "Bakes the direct contribution from the area light into the light map", false); + Settings.AddSetting(&BakeDirectAreaLight); + + EnableAreaLightShadows.Initialize(tweakBar, "EnableAreaLightShadows", "Area Light", "Enable Area Light Shadows", "", true); + Settings.AddSetting(&EnableAreaLightShadows); + + ExposureMode.Initialize(tweakBar, "ExposureMode", "Camera Controls", "Exposure Mode", "Specifies how exposure should be controled", ExposureModes::Manual_SBS, 4, ExposureModesLabels); + Settings.AddSetting(&ExposureMode); + + ManualExposure.Initialize(tweakBar, "ManualExposure", "Camera Controls", "Manual Exposure", "Manual exposure value when auto-exposure is disabled", -16.0000f, -32.0000f, 32.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ManualExposure); + + ApertureSize.Initialize(tweakBar, "ApertureSize", "Camera Controls", "Aperture", "", FStops::FStop16Point0, 23, FStopsLabels); + Settings.AddSetting(&ApertureSize); + + ISORating.Initialize(tweakBar, "ISORating", "Camera Controls", "ISO Rating", "", ISORatings::ISO100, 4, ISORatingsLabels); + Settings.AddSetting(&ISORating); + + ShutterSpeed.Initialize(tweakBar, "ShutterSpeed", "Camera Controls", "Shutter Speed", "", ShutterSpeeds::ShutterSpeed1Over125, 13, ShutterSpeedsLabels); + Settings.AddSetting(&ShutterSpeed); + + FilmSize.Initialize(tweakBar, "FilmSize", "Camera Controls", "Film Size(mm)", "", 35.0000f, 1.0000f, 100.0000f, 0.1000f, ConversionMode::None, 0.0010f); + Settings.AddSetting(&FilmSize); + + FocalLength.Initialize(tweakBar, "FocalLength", "Camera Controls", "Focal Length(mm)", "", 35.0000f, 1.0000f, 200.0000f, 0.1000f, ConversionMode::None, 0.0010f); + Settings.AddSetting(&FocalLength); + + FocusDistance.Initialize(tweakBar, "FocusDistance", "Camera Controls", "Focus Distance", "", 10.0000f, 1.0000f, 100.0000f, 0.1000f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&FocusDistance); + + NumBlades.Initialize(tweakBar, "NumBlades", "Camera Controls", "Num Aperture Blades", "", 5, 5, 9); + Settings.AddSetting(&NumBlades); + + EnableDOF.Initialize(tweakBar, "EnableDOF", "Camera Controls", "Enable DOF", "", false); + Settings.AddSetting(&EnableDOF); + + KeyValue.Initialize(tweakBar, "KeyValue", "Camera Controls", "Auto-Exposure Key Value", "Parameter that biases the result of the auto-exposure pass", 0.1150f, 0.0000f, 0.5000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&KeyValue); + + AdaptationRate.Initialize(tweakBar, "AdaptationRate", "Camera Controls", "Adaptation Rate", "Controls how quickly auto-exposure adapts to changes in scene brightness", 0.5000f, 0.0000f, 4.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AdaptationRate); + + ApertureFNumber.Initialize(tweakBar, "ApertureFNumber", "Camera Controls", "Aperture FNumber", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ApertureFNumber); + ApertureFNumber.SetVisible(false); + ApertureFNumber.SetEditable(false); + + ApertureWidth.Initialize(tweakBar, "ApertureWidth", "Camera Controls", "Aperture Width", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ApertureWidth); + ApertureWidth.SetVisible(false); + ApertureWidth.SetEditable(false); + + ShutterSpeedValue.Initialize(tweakBar, "ShutterSpeedValue", "Camera Controls", "Shutter Speed Value", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ShutterSpeedValue); + ShutterSpeedValue.SetVisible(false); + ShutterSpeedValue.SetEditable(false); + + ISO.Initialize(tweakBar, "ISO", "Camera Controls", "ISO", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ISO); + ISO.SetVisible(false); + ISO.SetEditable(false); + + BokehPolygonAmount.Initialize(tweakBar, "BokehPolygonAmount", "Camera Controls", "Bokeh Polygon Amount", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BokehPolygonAmount); + BokehPolygonAmount.SetVisible(false); + BokehPolygonAmount.SetEditable(false); + + ToneMappingMode.Initialize(tweakBar, "ToneMappingMode", "Tone Mapping", "Tone Mapping Operator", "", ToneMappingModes::ACES, 5, ToneMappingModesLabels); + Settings.AddSetting(&ToneMappingMode); + + WhitePoint_Hejl.Initialize(tweakBar, "WhitePoint_Hejl", "Tone Mapping", "White Point (Hejl2015)", "", 1.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&WhitePoint_Hejl); + + ShoulderStrength.Initialize(tweakBar, "ShoulderStrength", "Tone Mapping", "Shoulder Strength", "", 4.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ShoulderStrength); + + LinearStrength.Initialize(tweakBar, "LinearStrength", "Tone Mapping", "Linear Strength", "", 5.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&LinearStrength); + + LinearAngle.Initialize(tweakBar, "LinearAngle", "Tone Mapping", "Linear Angle", "", 0.1200f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&LinearAngle); + + ToeStrength.Initialize(tweakBar, "ToeStrength", "Tone Mapping", "Toe Strength", "", 13.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ToeStrength); + + WhitePoint_Hable.Initialize(tweakBar, "WhitePoint_Hable", "Tone Mapping", "White Point (Hable)", "", 6.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&WhitePoint_Hable); + + MSAAMode.Initialize(tweakBar, "MSAAMode", "Anti Aliasing", "MSAAMode", "", MSAAModes::MSAA4x, 4, MSAAModesLabels); + Settings.AddSetting(&MSAAMode); + + FilterType.Initialize(tweakBar, "FilterType", "Anti Aliasing", "Filter Type", "", FilterTypes::Smoothstep, 6, FilterTypesLabels); + Settings.AddSetting(&FilterType); + + FilterSize.Initialize(tweakBar, "FilterSize", "Anti Aliasing", "Filter Size", "", 2.0000f, 0.0000f, 6.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&FilterSize); + + GaussianSigma.Initialize(tweakBar, "GaussianSigma", "Anti Aliasing", "Gaussian Sigma", "", 0.5000f, 0.0100f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&GaussianSigma); + + EnableTemporalAA.Initialize(tweakBar, "EnableTemporalAA", "Anti Aliasing", "Enable Temporal AA", "", true); + Settings.AddSetting(&EnableTemporalAA); + + JitterMode.Initialize(tweakBar, "JitterMode", "Anti Aliasing", "Jitter Mode", "", JitterModes::Hammersley4x, 5, JitterModesLabels); + Settings.AddSetting(&JitterMode); + + JitterScale.Initialize(tweakBar, "JitterScale", "Anti Aliasing", "Jitter Scale", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&JitterScale); + + SGDiffuseMode.Initialize(tweakBar, "SGDiffuseMode", "SG Settings", "SG Diffuse Mode", "", SGDiffuseModes::Fitted, 3, SGDiffuseModesLabels); + Settings.AddSetting(&SGDiffuseMode); + + UseASGWarp.Initialize(tweakBar, "UseASGWarp", "SG Settings", "Use ASG Warp", "", true); + Settings.AddSetting(&UseASGWarp); + + LightMapResolution.Initialize(tweakBar, "LightMapResolution", "Baking", "Light Map Resolution", "The texture resolution of the light map", 256, 64, 4096); + Settings.AddSetting(&LightMapResolution); + + NumBakeSamples.Initialize(tweakBar, "NumBakeSamples", "Baking", "Sqrt Num Samples", "The square root of the number of sample rays to use for baking GI", 25, 1, 100); + Settings.AddSetting(&NumBakeSamples); + + BakeSampleMode.Initialize(tweakBar, "BakeSampleMode", "Baking", "Sample Mode", "", SampleModes::CMJ, 5, SampleModesLabels); + Settings.AddSetting(&BakeSampleMode); + + MaxBakePathLength.Initialize(tweakBar, "MaxBakePathLength", "Baking", "Max Bake Path Length", "Maximum path length (bounces + 2) to use for baking GI (set to -1 for infinite)", -1, -1, 2147483647); + Settings.AddSetting(&MaxBakePathLength); + + BakeRussianRouletteDepth.Initialize(tweakBar, "BakeRussianRouletteDepth", "Baking", "Russian Roullette Depth", "Path length at which Russian roulette kicks in (-1 to disable)", 4, -1, 2147483647); + Settings.AddSetting(&BakeRussianRouletteDepth); + + BakeRussianRouletteProbability.Initialize(tweakBar, "BakeRussianRouletteProbability", "Baking", "Russian Roullette Probability", "Maximum probability for continuing when Russian roulette is used", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BakeRussianRouletteProbability); + + BakeMode.Initialize(tweakBar, "BakeMode", "Baking", "Bake Mode", "", BakeModes::SG9, 10, BakeModesLabels); + Settings.AddSetting(&BakeMode); + + SolveMode.Initialize(tweakBar, "SolveMode", "Baking", "Solve Mode", "", SolveModes::NNLS, 3, SolveModesLabels); + Settings.AddSetting(&SolveMode); + + UseProbes.Initialize(tweakBar, "UseProbes", "Probes", "Use Probes", "", true); + Settings.AddSetting(&UseProbes); + + ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 2, 2, 64); + Settings.AddSetting(&ProbeResX); + + ProbeResY.Initialize(tweakBar, "ProbeResY", "Probes", "Probe Res Y", "", 2, 2, 64); + Settings.AddSetting(&ProbeResY); + + ProbeResZ.Initialize(tweakBar, "ProbeResZ", "Probes", "Probe Res Z", "", 2, 2, 64); + Settings.AddSetting(&ProbeResZ); + + CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); + Settings.AddSetting(&CurrentScene); + + EnableDiffuse.Initialize(tweakBar, "EnableDiffuse", "Scene", "Enable Diffuse", "Enables diffuse lighting", true); + Settings.AddSetting(&EnableDiffuse); + + EnableSpecular.Initialize(tweakBar, "EnableSpecular", "Scene", "Enable Specular", "Enables specular lighting", true); + Settings.AddSetting(&EnableSpecular); + + EnableDirectLighting.Initialize(tweakBar, "EnableDirectLighting", "Scene", "Enable Direct Lighting", "Enables direct lighting", true); + Settings.AddSetting(&EnableDirectLighting); + + EnableIndirectLighting.Initialize(tweakBar, "EnableIndirectLighting", "Scene", "Enable Indirect Lighting", "Enables indirect lighting", true); + Settings.AddSetting(&EnableIndirectLighting); + + EnableIndirectDiffuse.Initialize(tweakBar, "EnableIndirectDiffuse", "Scene", "Enable Indirect Diffuse", "Enables indirect diffuse lighting", true); + Settings.AddSetting(&EnableIndirectDiffuse); + + EnableIndirectSpecular.Initialize(tweakBar, "EnableIndirectSpecular", "Scene", "Enable Indirect Specular", "Enables indirect specular lighting", true); + Settings.AddSetting(&EnableIndirectSpecular); + + EnableAlbedoMaps.Initialize(tweakBar, "EnableAlbedoMaps", "Scene", "Enable Albedo Maps", "Enables albedo maps", true); + Settings.AddSetting(&EnableAlbedoMaps); + + EnableNormalMaps.Initialize(tweakBar, "EnableNormalMaps", "Scene", "Enable Normal Maps", "Enables normal maps", true); + Settings.AddSetting(&EnableNormalMaps); + + NormalMapIntensity.Initialize(tweakBar, "NormalMapIntensity", "Scene", "Normal Map Intensity", "Intensity of the normal map", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&NormalMapIntensity); + + DiffuseAlbedoScale.Initialize(tweakBar, "DiffuseAlbedoScale", "Scene", "Diffuse Albedo Scale", "Global scale applied to all material diffuse albedo values", 0.5000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&DiffuseAlbedoScale); + + RoughnessScale.Initialize(tweakBar, "RoughnessScale", "Scene", "Specular Roughness Scale", "Global scale applied to all material roughness values", 2.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&RoughnessScale); + + ShowGroundTruth.Initialize(tweakBar, "ShowGroundTruth", "Ground Truth", "Show Ground Truth", "If enabled, shows a ground truth image rendered on the CPU", false); + Settings.AddSetting(&ShowGroundTruth); + + NumRenderSamples.Initialize(tweakBar, "NumRenderSamples", "Ground Truth", "Sqrt Num Samples", "The square root of the number of per-pixel sample rays to use for ground truth rendering", 4, 1, 100); + Settings.AddSetting(&NumRenderSamples); + + RenderSampleMode.Initialize(tweakBar, "RenderSampleMode", "Ground Truth", "Sample Mode", "", SampleModes::CMJ, 5, SampleModesLabels); + Settings.AddSetting(&RenderSampleMode); + + MaxRenderPathLength.Initialize(tweakBar, "MaxRenderPathLength", "Ground Truth", "Max Path Length", "Maximum path length (bounces) to use for ground truth rendering (set to -1 for infinite)", -1, -1, 2147483647); + Settings.AddSetting(&MaxRenderPathLength); + + RenderRussianRouletteDepth.Initialize(tweakBar, "RenderRussianRouletteDepth", "Ground Truth", "Russian Roullette Depth", "Path length at which Russian roulette kicks in (-1 to disable)", 4, -1, 2147483647); + Settings.AddSetting(&RenderRussianRouletteDepth); + + RenderRussianRouletteProbability.Initialize(tweakBar, "RenderRussianRouletteProbability", "Ground Truth", "Russian Roullette Probability", "Maximum probability for continuing when Russian roulette is used", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&RenderRussianRouletteProbability); + + EnableRenderBounceSpecular.Initialize(tweakBar, "EnableRenderBounceSpecular", "Ground Truth", "Enable Bounce Specular", "Enables specular calculations after the first hit", false); + Settings.AddSetting(&EnableRenderBounceSpecular); + + BloomExposure.Initialize(tweakBar, "BloomExposure", "Post Processing", "Bloom Exposure Offset", "Exposure offset applied to generate the input of the bloom pass", -4.0000f, -10.0000f, 0.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BloomExposure); + + BloomMagnitude.Initialize(tweakBar, "BloomMagnitude", "Post Processing", "Bloom Magnitude", "Scale factor applied to the bloom results when combined with tone-mapped result", 1.0000f, 0.0000f, 2.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BloomMagnitude); + + BloomBlurSigma.Initialize(tweakBar, "BloomBlurSigma", "Post Processing", "Bloom Blur Sigma", "Sigma parameter of the Gaussian filter used in the bloom pass", 2.5000f, 0.5000f, 2.5000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BloomBlurSigma); + + EnableLuminancePicker.Initialize(tweakBar, "EnableLuminancePicker", "Debug", "Enable Luminance Picker", "", false); + Settings.AddSetting(&EnableLuminancePicker); + + ShowBakeDataVisualizer.Initialize(tweakBar, "ShowBakeDataVisualizer", "Debug", "Show Bake Data Visualizer", "", false); + Settings.AddSetting(&ShowBakeDataVisualizer); + + ViewIndirectSpecular.Initialize(tweakBar, "ViewIndirectSpecular", "Debug", "View Indirect Specular", "", false); + Settings.AddSetting(&ViewIndirectSpecular); + + SaveLightSettings.Initialize(tweakBar, "SaveLightSettings", "Debug", "Save Light Settings", "Saves the lighting settings to a file"); + Settings.AddSetting(&SaveLightSettings); + + LoadLightSettings.Initialize(tweakBar, "LoadLightSettings", "Debug", "Load Light Settings", "Loads the lighting settings from a file"); + Settings.AddSetting(&LoadLightSettings); + + SaveEXRScreenshot.Initialize(tweakBar, "SaveEXRScreenshot", "Debug", "Save EXR Screenshot", "Captures the current screen image in EXR format"); + Settings.AddSetting(&SaveEXRScreenshot); + + ShowSunIntensity.Initialize(tweakBar, "ShowSunIntensity", "Debug", "Show Sun Intensity", "", false); + Settings.AddSetting(&ShowSunIntensity); + + TwHelper::SetOpened(tweakBar, "Sun Light", true); + + TwHelper::SetOpened(tweakBar, "Sky", true); + + TwHelper::SetOpened(tweakBar, "Area Light", false); + + TwHelper::SetOpened(tweakBar, "Camera Controls", false); + + TwHelper::SetOpened(tweakBar, "Tone Mapping", false); + + TwHelper::SetOpened(tweakBar, "Anti Aliasing", false); + + TwHelper::SetOpened(tweakBar, "SG Settings", false); + + TwHelper::SetOpened(tweakBar, "Baking", false); + + TwHelper::SetOpened(tweakBar, "Probes", true); + + TwHelper::SetOpened(tweakBar, "Scene", false); + + TwHelper::SetOpened(tweakBar, "Ground Truth", false); + + TwHelper::SetOpened(tweakBar, "Post Processing", false); + + TwHelper::SetOpened(tweakBar, "Debug", false); + + CBuffer.Initialize(device); + } + + void Update() + { + ApertureFNumber.SetValue(ApertureFNumber_()); + ApertureWidth.SetValue(ApertureWidth_()); + ShutterSpeedValue.SetValue(ShutterSpeedValue_()); + ISO.SetValue(ISO_()); + BokehPolygonAmount.SetValue(BokehPolygonAmount_()); + } + + void UpdateCBuffer(ID3D11DeviceContext* context) + { + CBuffer.Data.EnableSun = EnableSun; + CBuffer.Data.SunAreaLightApproximation = SunAreaLightApproximation; + CBuffer.Data.SunTintColor = SunTintColor; + CBuffer.Data.SunIntensityScale = SunIntensityScale; + CBuffer.Data.SunSize = SunSize; + CBuffer.Data.SunDirType = SunDirType; + CBuffer.Data.SunDirection = SunDirection; + CBuffer.Data.SunAzimuth = SunAzimuth; + CBuffer.Data.SunElevation = SunElevation; + CBuffer.Data.EnableAreaLight = EnableAreaLight; + CBuffer.Data.AreaLightColor = AreaLightColor; + CBuffer.Data.AreaLightSize = AreaLightSize; + CBuffer.Data.AreaLightX = AreaLightX; + CBuffer.Data.AreaLightY = AreaLightY; + CBuffer.Data.AreaLightZ = AreaLightZ; + CBuffer.Data.AreaLightShadowBias = AreaLightShadowBias; + CBuffer.Data.BakeDirectAreaLight = BakeDirectAreaLight; + CBuffer.Data.EnableAreaLightShadows = EnableAreaLightShadows; + CBuffer.Data.ExposureMode = ExposureMode; + CBuffer.Data.ManualExposure = ManualExposure; + CBuffer.Data.FilmSize = FilmSize; + CBuffer.Data.FocalLength = FocalLength; + CBuffer.Data.FocusDistance = FocusDistance; + CBuffer.Data.NumBlades = NumBlades; + CBuffer.Data.KeyValue = KeyValue; + CBuffer.Data.AdaptationRate = AdaptationRate; + CBuffer.Data.ApertureFNumber = ApertureFNumber; + CBuffer.Data.ApertureWidth = ApertureWidth; + CBuffer.Data.ShutterSpeedValue = ShutterSpeedValue; + CBuffer.Data.ISO = ISO; + CBuffer.Data.BokehPolygonAmount = BokehPolygonAmount; + CBuffer.Data.ToneMappingMode = ToneMappingMode; + CBuffer.Data.WhitePoint_Hejl = WhitePoint_Hejl; + CBuffer.Data.ShoulderStrength = ShoulderStrength; + CBuffer.Data.LinearStrength = LinearStrength; + CBuffer.Data.LinearAngle = LinearAngle; + CBuffer.Data.ToeStrength = ToeStrength; + CBuffer.Data.WhitePoint_Hable = WhitePoint_Hable; + CBuffer.Data.MSAAMode = MSAAMode; + CBuffer.Data.FilterType = FilterType; + CBuffer.Data.FilterSize = FilterSize; + CBuffer.Data.GaussianSigma = GaussianSigma; + CBuffer.Data.SGDiffuseMode = SGDiffuseMode; + CBuffer.Data.UseASGWarp = UseASGWarp; + CBuffer.Data.LightMapResolution = LightMapResolution; + CBuffer.Data.BakeMode = BakeMode; + CBuffer.Data.SolveMode = SolveMode; + CBuffer.Data.UseProbes = UseProbes; + CBuffer.Data.ProbeResX = ProbeResX; + CBuffer.Data.ProbeResY = ProbeResY; + CBuffer.Data.ProbeResZ = ProbeResZ; + CBuffer.Data.EnableDiffuse = EnableDiffuse; + CBuffer.Data.EnableSpecular = EnableSpecular; + CBuffer.Data.EnableDirectLighting = EnableDirectLighting; + CBuffer.Data.EnableIndirectLighting = EnableIndirectLighting; + CBuffer.Data.EnableIndirectDiffuse = EnableIndirectDiffuse; + CBuffer.Data.EnableIndirectSpecular = EnableIndirectSpecular; + CBuffer.Data.EnableAlbedoMaps = EnableAlbedoMaps; + CBuffer.Data.EnableNormalMaps = EnableNormalMaps; + CBuffer.Data.NormalMapIntensity = NormalMapIntensity; + CBuffer.Data.DiffuseAlbedoScale = DiffuseAlbedoScale; + CBuffer.Data.RoughnessScale = RoughnessScale; + CBuffer.Data.BloomExposure = BloomExposure; + CBuffer.Data.BloomMagnitude = BloomMagnitude; + CBuffer.Data.BloomBlurSigma = BloomBlurSigma; + CBuffer.Data.ViewIndirectSpecular = ViewIndirectSpecular; + + CBuffer.ApplyChanges(context); + CBuffer.SetVS(context, 7); + CBuffer.SetHS(context, 7); + CBuffer.SetDS(context, 7); + CBuffer.SetGS(context, 7); + CBuffer.SetPS(context, 7); + CBuffer.SetCS(context, 7); + } +} + +// ================================================================================================ + +#include +#include +#include + +namespace AppSettings +{ + // Returns the result of performing a irradiance/illuminance integral over the portion + // of the hemisphere covered by a region with angular radius = theta + static float IlluminanceIntegral(float theta) + { + float cosTheta = std::cos(theta); + return Pi * (1.0f - (cosTheta * cosTheta)); + } + + Float3 SunLuminance(bool& cached) + { + Float3 sunDirection = AppSettings::SunDirection; + sunDirection.y = Saturate(sunDirection.y); + sunDirection = Float3::Normalize(sunDirection); + const float turbidity = Clamp(AppSettings::Turbidity.Value(), 1.0f, 32.0f); + const float intensityScale = AppSettings::SunIntensityScale; + const Float3 tintColor = AppSettings::SunTintColor; + const bool32 normalizeIntensity = AppSettings::NormalizeSunIntensity; + const float sunSize = AppSettings::SunSize; + + static float turbidityCache = 2.0f; + static Float3 sunDirectionCache = Float3(-0.579149902f, 0.754439294f, -0.308879942f); + static Float3 luminanceCache = Float3(1.61212531e+009f, 1.36822630e+009f, 1.07235315e+009f) * FP16Scale; + static Float3 sunTintCache = Float3(1.0f, 1.0f, 1.0f); + static float sunIntensityCache = 1.0f; + static bool32 normalizeCache = false; + static float sunSizeCache = AppSettings::BaseSunSize; + + if(turbidityCache == turbidity && sunDirection == sunDirectionCache + && intensityScale == sunIntensityCache && tintColor == sunTintCache + && normalizeCache == normalizeIntensity && sunSize == sunSizeCache) + { + cached = true; + return luminanceCache; + } + + cached = false; + + float thetaS = std::acos(1.0f - sunDirection.y); + float elevation = Pi_2 - thetaS; + + // Get the sun's luminance, then apply tint and scale factors + Float3 sunLuminance; + + // For now, we'll compute an average luminance value from Hosek solar radiance model, even though + // we could compute illuminance directly while we're sampling the disk + SampledSpectrum groundAlbedoSpectrum = SampledSpectrum::FromRGB(GroundAlbedo); + SampledSpectrum solarRadiance; + + const uint64 NumDiscSamples = 8; + for(uint64 x = 0; x < NumDiscSamples; ++x) + { + for(uint64 y = 0; y < NumDiscSamples; ++y) + { + float u = (x + 0.5f) / NumDiscSamples; + float v = (y + 0.5f) / NumDiscSamples; + Float2 discSamplePos = SquareToConcentricDiskMapping(u, v); + + float theta = elevation + discSamplePos.y * DegToRad(AppSettings::BaseSunSize); + float gamma = discSamplePos.x * DegToRad(AppSettings::BaseSunSize); + + for(int32 i = 0; i < NumSpectralSamples; ++i) + { + ArHosekSkyModelState* skyState = arhosekskymodelstate_alloc_init(elevation, turbidity, groundAlbedoSpectrum[i]); + float wavelength = Lerp(float(SampledLambdaStart), float(SampledLambdaEnd), i / float(NumSpectralSamples)); + + solarRadiance[i] = float(arhosekskymodel_solar_radiance(skyState, theta, gamma, wavelength)); + + arhosekskymodelstate_free(skyState); + skyState = nullptr; + } + + Float3 sampleRadiance = solarRadiance.ToRGB() * FP16Scale; + sunLuminance += sampleRadiance; + } + } + + // Account for luminous efficiency, coordinate system scaling, and sample averaging + sunLuminance *= 683.0f * 100.0f * (1.0f / NumDiscSamples) * (1.0f / NumDiscSamples); + + sunLuminance = sunLuminance * tintColor; + sunLuminance = sunLuminance * intensityScale; + + if(normalizeIntensity) + { + // Normalize so that the intensity stays the same even when the sun is bigger or smaller + const float baseIntegral = IlluminanceIntegral(DegToRad(AppSettings::BaseSunSize)); + const float currIntegral = IlluminanceIntegral(DegToRad(AppSettings::SunSize)); + sunLuminance *= (baseIntegral / currIntegral); + } + + turbidityCache = turbidity; + sunDirectionCache = sunDirection; + luminanceCache = sunLuminance; + sunIntensityCache = intensityScale; + sunTintCache = tintColor; + normalizeCache = normalizeIntensity; + sunSizeCache = sunSize; + + return sunLuminance; + } + + Float3 SunLuminance() + { + bool cached = false; + return SunLuminance(cached); + } + + Float3 SunIlluminance() + { + Float3 sunLuminance = SunLuminance(); + + // Compute partial integral over the hemisphere in order to compute illuminance + float theta = DegToRad(AppSettings::SunSize); + float integralFactor = IlluminanceIntegral(theta); + + return sunLuminance * integralFactor; + } + + static void UpdateAreaLightUnits() + { + static LightUnits prevUnits = AreaLightUnits; + const LightUnits currUnits = AreaLightUnits; + + const float size = AreaLightSize; + const float distance = AreaLightIlluminanceDistance; + + // Compute the luminance from our currently active unit + float luminance = AreaLightColor.Intensity(); + if(prevUnits == LightUnits::Illuminance) + { + float illuminance = AreaLightIlluminance; + float angularRadius = std::atan2(size, distance); + float integralFactor = IlluminanceIntegral(angularRadius); + luminance = illuminance / integralFactor; + } + else if(prevUnits == LightUnits::LuminousPower) + { + float luminousPower = AreaLightLuminousPower; + luminance = luminousPower / (4 * size * size * Pi * Pi); + } + else if(prevUnits == LightUnits::EV100) + { + float ev100 = AreaLightEV100; + luminance = std::pow(2.0f, ev100 - 3.0f); + } + + // Set the new luminance onto the color + AreaLightColor.SetIntensity(luminance); + + // Update the other units + float angularRadius = std::atan2(size, distance); + float integralFactor = IlluminanceIntegral(angularRadius); + float illuminance = luminance * integralFactor; + AreaLightIlluminance.SetValue(illuminance); + + float luminousPower = luminance * (4 * size * size * Pi * Pi); + AreaLightLuminousPower.SetValue(luminousPower); + + float ev100 = std::log2(luminance) + 3.0f; + AreaLightEV100.SetValue(ev100); + + if(prevUnits != currUnits) + { + AreaLightColor.SetIntensityVisible(currUnits == LightUnits::Luminance); + AreaLightIlluminance.SetVisible(currUnits == LightUnits::Illuminance); + AreaLightLuminousPower.SetVisible(currUnits == LightUnits::LuminousPower); + AreaLightEV100.SetVisible(currUnits == LightUnits::EV100); + AreaLightIlluminanceDistance.SetVisible(currUnits == LightUnits::Illuminance); + + prevUnits = currUnits; + } + } + + void UpdateUI() + { + bool enableManualExposure = ExposureMode == ExposureModes::ManualSimple; + bool enableCameraExposure = ExposureMode == ExposureModes::Manual_SBS || + ExposureMode == ExposureModes::Manual_SOS; + bool enableAutoExposure = ExposureMode == ExposureModes::Automatic; + bool enableSimpleSkyParams = SkyMode == SkyModes::Simple; + bool enableProceduralSkyParams = SkyMode == SkyModes::Procedural; + bool useHejlTM = ToneMappingMode == ToneMappingModes::Hejl2015; + bool useHableTM = ToneMappingMode == ToneMappingModes::Hable; + bool useSGSettings = SGCount() > 0; + + ManualExposure.SetEditable(enableManualExposure); + ShutterSpeed.SetEditable(enableCameraExposure); + ISORating.SetEditable(enableCameraExposure); + KeyValue.SetEditable(enableAutoExposure); + AdaptationRate.SetEditable(enableAutoExposure); + SkyColor.SetEditable(enableSimpleSkyParams); + Turbidity.SetEditable(enableProceduralSkyParams); + GroundAlbedo.SetEditable(enableProceduralSkyParams); + + WhitePoint_Hejl.SetVisible(useHejlTM); + + WhitePoint_Hable.SetVisible(useHableTM); + ShoulderStrength.SetVisible(useHableTM); + LinearStrength.SetVisible(useHableTM); + LinearAngle.SetVisible(useHableTM); + ToeStrength.SetVisible(useHableTM); + + bool enableSunDirection = SunDirType == SunDirectionTypes::UnitVector; + bool enableHorizCoord = SunDirType == SunDirectionTypes::HorizontalCoordSystem; + + SunDirection.SetVisible(enableSunDirection); + SunAzimuth.SetVisible(enableHorizCoord); + SunElevation.SetVisible(enableHorizCoord); + + SGDiffuseMode.SetEditable(useSGSettings); + SolveMode.SetEditable(useSGSettings); + + if(AppSettings::HasSunDirChanged()) + { + if(SunDirType == SunDirectionTypes::UnitVector) + { + UpdateHorizontalCoords(); + } + else if(SunDirType == SunDirectionTypes::HorizontalCoordSystem) + { + UpdateUnitVector(); + } + } + + UpdateAreaLightUnits(); + } } \ No newline at end of file diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 56a96a6..a864cb6 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -1,817 +1,835 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -enum SunDirectionTypes -{ - [EnumLabel("Unit Vector")] - UnitVector, - - [EnumLabel("Horizontal Coordinate System")] - HorizontalCoordSystem, -} - -enum SkyModes -{ - [EnumLabel("None")] - None = 0, - - [EnumLabel("Procedural")] - Procedural, - - [EnumLabel("Simple")] - Simple, - - [EnumLabel("Ennis")] - CubeMapEnnis, - - [EnumLabel("Grace Cathedral")] - CubeMapGraceCathedral, - - [EnumLabel("Uffizi Cross")] - CubeMapUffizi -} - -enum ToneMappingModes -{ - [EnumLabel("Film Stock")] - FilmStock, - - [EnumLabel("Linear")] - Linear, - - [EnumLabel("ACES sRGB Monitor")] - ACES, - - [EnumLabel("Hejl 2015")] - Hejl2015, - - [EnumLabel("Hable (Uncharted2)")] - Hable, -} - -enum ExposureModes -{ - [EnumLabel("Manual (Simple)")] - ManualSimple = 0, - - [EnumLabel("Manual (SBS)")] - Manual_SBS = 1, - - [EnumLabel("Manual (SOS)")] - Manual_SOS = 2, - - [EnumLabel("Automatic")] - Automatic = 3 -} - -enum FStops -{ - [EnumLabel("f/1.8")] - FStop1Point8 = 0, - - [EnumLabel("f/2.0")] - FStop2Point0, - - [EnumLabel("f/2.2")] - FStop2Point2, - - [EnumLabel("f/2.5")] - FStop2Point5, - - [EnumLabel("f/2.8")] - FStop2Point8, - - [EnumLabel("f/3.2")] - FStop3Point2, - - [EnumLabel("f/3.5")] - FStop3Point5, - - [EnumLabel("f/4.0")] - FStop4Point0, - - [EnumLabel("f/4.5")] - FStop4Point5, - - [EnumLabel("f/5.0")] - FStop5Point0, - - [EnumLabel("f/5.6")] - FStop5Point6, - - [EnumLabel("f/6.3")] - FStop6Point3, - - [EnumLabel("f/7.1")] - FStop7Point1, - - [EnumLabel("f/8.0")] - FStop8Point0, - - [EnumLabel("f/9.0")] - FStop9Point0, - - [EnumLabel("f/10.0")] - FStop10Point0, - - [EnumLabel("f/11.0")] - FStop11Point0, - - [EnumLabel("f/13.0")] - FStop13Point0, - - [EnumLabel("f/14.0")] - FStop14Point0, - - [EnumLabel("f/16.0")] - FStop16Point0, - - [EnumLabel("f/18.0")] - FStop18Point0, - - [EnumLabel("f/20.0")] - FStop20Point0, - - [EnumLabel("f/22.0")] - FStop22Point0, -} - -enum ISORatings -{ - ISO100 = 0, - ISO200, - ISO400, - ISO800, -} - -enum ShutterSpeeds -{ - [EnumLabel("1s")] - ShutterSpeed1Over1 = 0, - - [EnumLabel("1/2s")] - ShutterSpeed1Over2, - - [EnumLabel("1/4s")] - ShutterSpeed1Over4, - - [EnumLabel("1/8s")] - ShutterSpeed1Over8, - - [EnumLabel("1/15s")] - ShutterSpeed1Over15, - - [EnumLabel("1/30s")] - ShutterSpeed1Over30, - - [EnumLabel("1/60s")] - ShutterSpeed1Over60, - - [EnumLabel("1/125s")] - ShutterSpeed1Over125, - - [EnumLabel("1/250s")] - ShutterSpeed1Over250, - - [EnumLabel("1/500s")] - ShutterSpeed1Over500, - - [EnumLabel("1/1000s")] - ShutterSpeed1Over1000, - - [EnumLabel("1/2000s")] - ShutterSpeed1Over2000, - - [EnumLabel("1/4000s")] - ShutterSpeed1Over4000, -} - -enum SampleModes -{ - Random = 0, - Stratified = 1, - Hammersley = 2, - UniformGrid = 3, - CMJ = 4, -} - -enum LightUnits -{ - Luminance = 0, - Illuminance = 1, - LuminousPower = 2, - EV100 = 3 -} - -enum Scenes -{ - Box = 0, - - [EnumLabel("White Room")] - WhiteRoom = 1, - - Sponza = 2, -} - -enum MSAAModes -{ - [EnumLabel("None")] - MSAANone = 0, - - [EnumLabel("2x")] - MSAA2x, - - [EnumLabel("4x")] - MSAA4x, - - [EnumLabel("8x")] - MSAA8x, -} - -enum FilterTypes -{ - Box = 0, - Triangle, - Gaussian, - BlackmanHarris, - Smoothstep, - BSpline, -} - -enum JitterModes -{ - None, - Uniform2x, - Hammersley4x, - Hammersley8x, - Hammersley16x, -} - -enum BakeModes -{ - Diffuse = 0, - - [EnumLabel("Half-Life 2")] - HL2, - - [EnumLabel("L1 SH")] - SH4, - - [EnumLabel("L2 SH")] - SH9, - - [EnumLabel("L1 H-basis")] - H4, - - [EnumLabel("L2 H-basis")] - H6, - - SG5, - SG6, - SG9, - SG12, -} - -enum SolveModes -{ - [EnumLabel("Ad-Hoc Projection")] - Projection = 0, - - [EnumLabel("Least Squares")] - SVD, - - [EnumLabel("Non-Negative Least Squares")] - NNLS, -} - -enum SGDiffuseModes -{ - InnerProduct = 0, - Punctual, - - [EnumLabel("Fitted (Hill 16)")] - Fitted, -} - -public class Settings -{ - const float BaseSunSize = 0.27f; - - public class SunLight - { - [HelpText("Enables the sun light")] - bool EnableSun = true; - - [HelpText("Controls whether the sun is treated as a disc area light in the real-time shader")] - bool SunAreaLightApproximation = true; - - [HelpText("The color of the sun")] - Color SunTintColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); - - [HelpText("Scale the intensity of the sun")] - [MinValue(0.0f)] - float SunIntensityScale = 1.0f; - - [HelpText("Angular radius of the sun in degrees")] - [MinValue(0.01f)] - [StepSize(0.001f)] - float SunSize = BaseSunSize; - - [UseAsShaderConstant(false)] - bool NormalizeSunIntensity = false; - - [HelpText("Input direction type for the sun")] - SunDirectionTypes SunDirType = SunDirectionTypes.HorizontalCoordSystem; - - [HelpText("Director of the sun")] - Direction SunDirection = new Direction(-0.75f, 0.977f, -0.4f); - - [HelpText("Angle around the horizon")] - [MinValue(0.0f)] - [MaxValue(360.0f)] - [StepSize(0.1f)] - float SunAzimuth; - - [HelpText("Elevation of sun from ground. 0 degrees is aligned on the horizon while 90 degrees is directly overhead")] - [MinValue(0.0f)] - [MaxValue(90.0f)] - [StepSize(0.1f)] - float SunElevation; - } - - public class Sky - { - [HelpText("Controls the sky used for GI baking and background rendering")] - [UseAsShaderConstant(false)] - SkyModes SkyMode = SkyModes.Procedural; - - [HelpText("The color of the simple sky")] - [MinValue(0.0f)] - [MaxValue(1000000.0f)] - [StepSize(0.1f)] - [HDR(true)] - [ColorUnit(ColorUnit.Luminance)] - [UseAsShaderConstant(false)] - Color SkyColor = new Color(0.2f, 0.5f, 1.0f, 7000.0f); - - [MinValue(1.0f)] - [MaxValue(10.0f)] - [UseAsShaderConstant(false)] - float Turbidity = 2.0f; - - [HDR(false)] - [UseAsShaderConstant(false)] - Color GroundAlbedo = new Color(0.5f, 0.5f, 0.5f); - } - - [ExpandGroup(false)] - public class AreaLight - { - [HelpText("Enables the area light during baking and ground truth rendering")] - bool EnableAreaLight = false; - - [DisplayName("Color")] - [MinValue(0.0f)] - [StepSize(0.1f)] - [HDR(true)] - [ColorUnit(ColorUnit.Luminance)] - [HelpText("The color of the area light")] - Color AreaLightColor = new Color(1.0f, 1.0f, 1.0f, 1000000.0f); - - [DisplayName("Color Intensity (lux)")] - [MinValue(0.0f)] - [Visible(false)] - [UseAsShaderConstant(false)] - float AreaLightIlluminance = 1.0f; - - [DisplayName("Color Intensity (lm)")] - [MinValue(0.0f)] - [Visible(false)] - [UseAsShaderConstant(false)] - float AreaLightLuminousPower = 1.0f; - - [DisplayName("Color Intensity (EV100)")] - [MinValue(-64.0f)] - [MaxValue(64.0f)] - [Visible(false)] - [UseAsShaderConstant(false)] - float AreaLightEV100 = 0.0f; - - [UseAsShaderConstant(false)] - [DisplayName("Units")] - LightUnits AreaLightUnits = LightUnits.Luminance; - - [DisplayName("Illuminance Distance")] - [UseAsShaderConstant(false)] - [Visible(false)] - float AreaLightIlluminanceDistance = 10.0f; - - [DisplayName("Size")] - [MinValue(0.01f)] - [MaxValue(10.0f)] - [StepSize(0.01f)] - [HelpText("The radius of the area light")] - float AreaLightSize = 0.5f; - - [DisplayName("Position X")] - [MinValue(-100.0f)] - [MaxValue(100.0f)] - [StepSize(0.01f)] - [HelpText("The X coordinate of the area light")] - float AreaLightX = 0.0f; - - [DisplayName("Position Y")] - [MinValue(-100.0f)] - [MaxValue(100.0f)] - [StepSize(0.01f)] - [HelpText("The Y coordinate of the area light")] - float AreaLightY = 5.0f; - - [DisplayName("Position Z")] - [MinValue(-100.0f)] - [MaxValue(100.0f)] - [StepSize(0.01f)] - [HelpText("The Z coordinate of the area light")] - float AreaLightZ = 0.0f; - - [DisplayName("Shadow Bias")] - [MinValue(0.0f)] - [MaxValue(1.0f)] - [StepSize(0.001f)] - float AreaLightShadowBias = 0.001f; - - [HelpText("Bakes the direct contribution from the area light into the light map")] - bool BakeDirectAreaLight = false; - - bool EnableAreaLightShadows = true; - } - - [ExpandGroup(false)] - public class CameraControls - { - [HelpText("Specifies how exposure should be controled")] - ExposureModes ExposureMode = ExposureModes.Manual_SBS; - - [MinValue(-32.0f)] - [MaxValue(32.0f)] - [StepSize(0.01f)] - [HelpText("Manual exposure value when auto-exposure is disabled")] - float ManualExposure = -16.0f; - - [DisplayName("Aperture")] - [UseAsShaderConstant(false)] - FStops ApertureSize = FStops.FStop16Point0; - - [DisplayName("ISO Rating")] - [UseAsShaderConstant(false)] - ISORatings ISORating = ISORatings.ISO100; - - [DisplayName("Shutter Speed")] - [UseAsShaderConstant(false)] - ShutterSpeeds ShutterSpeed = ShutterSpeeds.ShutterSpeed1Over125; - - [DisplayName("Film Size(mm)")] - [MinValue(1.0f)] - [MaxValue(100.0f)] - [StepSize(0.1f)] - [ConversionScale(0.001f)] - float FilmSize = 35.0f; - - [DisplayName("Focal Length(mm)")] - [MinValue(1.0f)] - [MaxValue(200.0f)] - [StepSize(0.1f)] - [ConversionScale(0.001f)] - float FocalLength = 35.0f; - - [MinValue(1.0f)] - [MaxValue(100.0f)] - [StepSize(0.1f)] - float FocusDistance = 10.0f; - - [DisplayName("Num Aperture Blades")] - [MinValue(5)] - [MaxValue(9)] - int NumBlades = 5; - - [DisplayName("Enable DOF")] - [UseAsShaderConstant(false)] - bool EnableDOF = false; - - [DisplayName("Auto-Exposure Key Value")] - [MinValue(0.0f)] - [MaxValue(0.5f)] - [StepSize(0.01f)] - [HelpText("Parameter that biases the result of the auto-exposure pass")] - float KeyValue = 0.115f; - - [DisplayName("Adaptation Rate")] - [MinValue(0.0f)] - [MaxValue(4.0f)] - [StepSize(0.01f)] - [HelpText("Controls how quickly auto-exposure adapts to changes in scene brightness")] - float AdaptationRate = 0.5f; - - // Virtuals - [VirtualSetting("ApertureFNumber_()")] - [Visible(false)] - float ApertureFNumber; - - [VirtualSetting("ApertureWidth_()")] - [Visible(false)] - float ApertureWidth; - - [VirtualSetting("ShutterSpeedValue_()")] - [Visible(false)] - float ShutterSpeedValue; - - [VirtualSetting("ISO_()")] - [Visible(false)] - float ISO; - - [VirtualSetting("BokehPolygonAmount_()")] - [Visible(false)] - float BokehPolygonAmount; - } - - [ExpandGroup(false)] - public class ToneMapping - { - [DisplayName("Tone Mapping Operator")] - ToneMappingModes ToneMappingMode = ToneMappingModes.ACES; - - [MinValue(0.01f)] - [StepSize(0.01f)] - [DisplayName("White Point (Hejl2015)")] - float WhitePoint_Hejl = 1.0f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - float ShoulderStrength = 4.0f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - float LinearStrength = 5.0f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - float LinearAngle = 0.12f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - float ToeStrength = 13.0f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - [DisplayName("White Point (Hable)")] - float WhitePoint_Hable = 6.0f; - } - - [ExpandGroup(false)] - public class AntiAliasing - { - MSAAModes MSAAMode = MSAAModes.MSAA4x; - - FilterTypes FilterType = FilterTypes.Smoothstep; - - [MinValue(0.0f)] - [MaxValue(6.0f)] - [StepSize(0.01f)] - float FilterSize = 2.0f; - - [MinValue(0.01f)] - [MaxValue(1.0f)] - [StepSize(0.01f)] - float GaussianSigma = 0.5f; - - [UseAsShaderConstant(false)] - bool EnableTemporalAA = true; - - [UseAsShaderConstant(false)] - JitterModes JitterMode = JitterModes.Hammersley4x; - - [MinValue(0.0f)] - [UseAsShaderConstant(false)] - float JitterScale = 1.0f; - } - - const int MaxSGCount = 12; - const int MaxBasisCount = MaxSGCount; - - [ExpandGroup(false)] - [DisplayName("SG Settings")] - public class SGSettings - { - [DisplayName("SG Diffuse Mode")] - SGDiffuseModes SGDiffuseMode = SGDiffuseModes.Fitted; - - [DisplayName("Use ASG Warp")] - bool UseASGWarp = true; - } - - [ExpandGroup(false)] - public class Baking - { - [DisplayName("Light Map Resolution")] - [HelpText("The texture resolution of the light map")] - [MinValue(64)] - [MaxValue(4096)] - int LightMapResolution = 256; - - [HelpText("The square root of the number of sample rays to use for baking GI")] - [MinValue(1)] - [MaxValue(100)] - [UseAsShaderConstant(false)] - [DisplayName("Sqrt Num Samples")] - int NumBakeSamples = 25; - - [UseAsShaderConstant(false)] - [DisplayName("Sample Mode")] - SampleModes BakeSampleMode = SampleModes.CMJ; - - [HelpText("Maximum path length (bounces + 2) to use for baking GI (set to -1 for infinite)")] - [UseAsShaderConstant(false)] - [MinValue(-1)] - int MaxBakePathLength = -1; - - [HelpText("Path length at which Russian roulette kicks in (-1 to disable)")] - [UseAsShaderConstant(false)] - [MinValue(-1)] - [DisplayName("Russian Roullette Depth")] - int BakeRussianRouletteDepth = 4; - - [HelpText("Maximum probability for continuing when Russian roulette is used")] - [UseAsShaderConstant(false)] - [MinValue(0.0f)] - [MaxValue(1.0f)] - [StepSize(0.01f)] - [DisplayName("Russian Roullette Probability")] - float BakeRussianRouletteProbability = 0.5f; - - BakeModes BakeMode = BakeModes.SG9; - - SolveModes SolveMode = SolveModes.NNLS; - } - - [ExpandGroup(false)] - public class Scene - { - [UseAsShaderConstant(false)] - Scenes CurrentScene = Scenes.Box; - - [DisplayName("Enable Diffuse")] - [HelpText("Enables diffuse lighting")] - bool EnableDiffuse = true; - - [DisplayName("Enable Specular")] - [HelpText("Enables specular lighting")] - bool EnableSpecular = true; - - [DisplayName("Enable Direct Lighting")] - [HelpText("Enables direct lighting")] - bool EnableDirectLighting = true; - - [DisplayName("Enable Indirect Lighting")] - [HelpText("Enables indirect lighting")] - bool EnableIndirectLighting = true; - - [DisplayName("Enable Indirect Diffuse")] - [HelpText("Enables indirect diffuse lighting")] - bool EnableIndirectDiffuse = true; - - [DisplayName("Enable Indirect Specular")] - [HelpText("Enables indirect specular lighting")] - bool EnableIndirectSpecular = true; - - [DisplayName("Enable Albedo Maps")] - [HelpText("Enables albedo maps")] - bool EnableAlbedoMaps = true; - - [DisplayName("Enable Normal Maps")] - [HelpText("Enables normal maps")] - bool EnableNormalMaps = true; - - [DisplayName("Normal Map Intensity")] - [MinValue(0.0f)] - [MaxValue(1.0f)] - [StepSize(0.01f)] - [HelpText("Intensity of the normal map")] - float NormalMapIntensity = 0.5f; - - [DisplayName("Diffuse Albedo Scale")] - [MinValue(0.0f)] - [StepSize(0.01f)] - [HelpText("Global scale applied to all material diffuse albedo values")] - float DiffuseAlbedoScale = 0.5f; - - [DisplayName("Specular Roughness Scale")] - [MinValue(0.01f)] - [StepSize(0.01f)] - [HelpText("Global scale applied to all material roughness values")] - float RoughnessScale = 2.0f; - } - - [ExpandGroup(false)] - public class GroundTruth - { - [DisplayName("Show Ground Truth")] - [HelpText("If enabled, shows a ground truth image rendered on the CPU")] - [UseAsShaderConstant(false)] - bool ShowGroundTruth = false; - - [HelpText("The square root of the number of per-pixel sample rays to use for ground truth rendering")] - [UseAsShaderConstant(false)] - [MinValue(1)] - [MaxValue(100)] - [DisplayName("Sqrt Num Samples")] - int NumRenderSamples = 4; - - [UseAsShaderConstant(false)] - [DisplayName("Sample Mode")] - SampleModes RenderSampleMode = SampleModes.CMJ; - - [HelpText("Maximum path length (bounces) to use for ground truth rendering (set to -1 for infinite)")] - [UseAsShaderConstant(false)] - [MinValue(-1)] - [DisplayName("Max Path Length")] - int MaxRenderPathLength = -1; - - [HelpText("Path length at which Russian roulette kicks in (-1 to disable)")] - [UseAsShaderConstant(false)] - [MinValue(-1)] - [DisplayName("Russian Roullette Depth")] - int RenderRussianRouletteDepth = 4; - - [HelpText("Maximum probability for continuing when Russian roulette is used")] - [UseAsShaderConstant(false)] - [MinValue(0.0f)] - [MaxValue(1.0f)] - [StepSize(0.01f)] - [DisplayName("Russian Roullette Probability")] - float RenderRussianRouletteProbability = 0.5f; - - [DisplayName("Enable Bounce Specular")] - [HelpText("Enables specular calculations after the first hit")] - [UseAsShaderConstant(false)] - bool EnableRenderBounceSpecular = false; - } - - [ExpandGroup(false)] - public class PostProcessing - { - [DisplayName("Bloom Exposure Offset")] - [MinValue(-10.0f)] - [MaxValue(0.0f)] - [StepSize(0.01f)] - [HelpText("Exposure offset applied to generate the input of the bloom pass")] - float BloomExposure = -4.0f; - - [DisplayName("Bloom Magnitude")] - [MinValue(0.0f)] - [MaxValue(2.0f)] - [StepSize(0.01f)] - [HelpText("Scale factor applied to the bloom results when combined with tone-mapped result")] - float BloomMagnitude = 1.0f; - - [DisplayName("Bloom Blur Sigma")] - [MinValue(0.5f)] - [MaxValue(2.5f)] - [StepSize(0.01f)] - [HelpText("Sigma parameter of the Gaussian filter used in the bloom pass")] - float BloomBlurSigma = 2.5f; - } - - [ExpandGroup(false)] - public class Debug - { - [UseAsShaderConstant(false)] - bool EnableLuminancePicker = false; - - [UseAsShaderConstant(false)] - bool ShowBakeDataVisualizer = false; - - bool ViewIndirectSpecular = false; - - [DisplayName("Save Light Settings")] - [HelpText("Saves the lighting settings to a file")] - Button SaveLightSettings; - - [DisplayName("Load Light Settings")] - [HelpText("Loads the lighting settings from a file")] - Button LoadLightSettings; - - [DisplayName("Save EXR Screenshot")] - [HelpText("Captures the current screen image in EXR format")] - Button SaveEXRScreenshot; - - [UseAsShaderConstant(false)] - bool ShowSunIntensity = false; - } +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +enum SunDirectionTypes +{ + [EnumLabel("Unit Vector")] + UnitVector, + + [EnumLabel("Horizontal Coordinate System")] + HorizontalCoordSystem, +} + +enum SkyModes +{ + [EnumLabel("None")] + None = 0, + + [EnumLabel("Procedural")] + Procedural, + + [EnumLabel("Simple")] + Simple, + + [EnumLabel("Ennis")] + CubeMapEnnis, + + [EnumLabel("Grace Cathedral")] + CubeMapGraceCathedral, + + [EnumLabel("Uffizi Cross")] + CubeMapUffizi +} + +enum ToneMappingModes +{ + [EnumLabel("Film Stock")] + FilmStock, + + [EnumLabel("Linear")] + Linear, + + [EnumLabel("ACES sRGB Monitor")] + ACES, + + [EnumLabel("Hejl 2015")] + Hejl2015, + + [EnumLabel("Hable (Uncharted2)")] + Hable, +} + +enum ExposureModes +{ + [EnumLabel("Manual (Simple)")] + ManualSimple = 0, + + [EnumLabel("Manual (SBS)")] + Manual_SBS = 1, + + [EnumLabel("Manual (SOS)")] + Manual_SOS = 2, + + [EnumLabel("Automatic")] + Automatic = 3 +} + +enum FStops +{ + [EnumLabel("f/1.8")] + FStop1Point8 = 0, + + [EnumLabel("f/2.0")] + FStop2Point0, + + [EnumLabel("f/2.2")] + FStop2Point2, + + [EnumLabel("f/2.5")] + FStop2Point5, + + [EnumLabel("f/2.8")] + FStop2Point8, + + [EnumLabel("f/3.2")] + FStop3Point2, + + [EnumLabel("f/3.5")] + FStop3Point5, + + [EnumLabel("f/4.0")] + FStop4Point0, + + [EnumLabel("f/4.5")] + FStop4Point5, + + [EnumLabel("f/5.0")] + FStop5Point0, + + [EnumLabel("f/5.6")] + FStop5Point6, + + [EnumLabel("f/6.3")] + FStop6Point3, + + [EnumLabel("f/7.1")] + FStop7Point1, + + [EnumLabel("f/8.0")] + FStop8Point0, + + [EnumLabel("f/9.0")] + FStop9Point0, + + [EnumLabel("f/10.0")] + FStop10Point0, + + [EnumLabel("f/11.0")] + FStop11Point0, + + [EnumLabel("f/13.0")] + FStop13Point0, + + [EnumLabel("f/14.0")] + FStop14Point0, + + [EnumLabel("f/16.0")] + FStop16Point0, + + [EnumLabel("f/18.0")] + FStop18Point0, + + [EnumLabel("f/20.0")] + FStop20Point0, + + [EnumLabel("f/22.0")] + FStop22Point0, +} + +enum ISORatings +{ + ISO100 = 0, + ISO200, + ISO400, + ISO800, +} + +enum ShutterSpeeds +{ + [EnumLabel("1s")] + ShutterSpeed1Over1 = 0, + + [EnumLabel("1/2s")] + ShutterSpeed1Over2, + + [EnumLabel("1/4s")] + ShutterSpeed1Over4, + + [EnumLabel("1/8s")] + ShutterSpeed1Over8, + + [EnumLabel("1/15s")] + ShutterSpeed1Over15, + + [EnumLabel("1/30s")] + ShutterSpeed1Over30, + + [EnumLabel("1/60s")] + ShutterSpeed1Over60, + + [EnumLabel("1/125s")] + ShutterSpeed1Over125, + + [EnumLabel("1/250s")] + ShutterSpeed1Over250, + + [EnumLabel("1/500s")] + ShutterSpeed1Over500, + + [EnumLabel("1/1000s")] + ShutterSpeed1Over1000, + + [EnumLabel("1/2000s")] + ShutterSpeed1Over2000, + + [EnumLabel("1/4000s")] + ShutterSpeed1Over4000, +} + +enum SampleModes +{ + Random = 0, + Stratified = 1, + Hammersley = 2, + UniformGrid = 3, + CMJ = 4, +} + +enum LightUnits +{ + Luminance = 0, + Illuminance = 1, + LuminousPower = 2, + EV100 = 3 +} + +enum Scenes +{ + Box = 0, + + [EnumLabel("White Room")] + WhiteRoom = 1, + + Sponza = 2, +} + +enum MSAAModes +{ + [EnumLabel("None")] + MSAANone = 0, + + [EnumLabel("2x")] + MSAA2x, + + [EnumLabel("4x")] + MSAA4x, + + [EnumLabel("8x")] + MSAA8x, +} + +enum FilterTypes +{ + Box = 0, + Triangle, + Gaussian, + BlackmanHarris, + Smoothstep, + BSpline, +} + +enum JitterModes +{ + None, + Uniform2x, + Hammersley4x, + Hammersley8x, + Hammersley16x, +} + +enum BakeModes +{ + Diffuse = 0, + + [EnumLabel("Half-Life 2")] + HL2, + + [EnumLabel("L1 SH")] + SH4, + + [EnumLabel("L2 SH")] + SH9, + + [EnumLabel("L1 H-basis")] + H4, + + [EnumLabel("L2 H-basis")] + H6, + + SG5, + SG6, + SG9, + SG12, +} + +enum SolveModes +{ + [EnumLabel("Ad-Hoc Projection")] + Projection = 0, + + [EnumLabel("Least Squares")] + SVD, + + [EnumLabel("Non-Negative Least Squares")] + NNLS, +} + +enum SGDiffuseModes +{ + InnerProduct = 0, + Punctual, + + [EnumLabel("Fitted (Hill 16)")] + Fitted, +} + +public class Settings +{ + const float BaseSunSize = 0.27f; + + public class SunLight + { + [HelpText("Enables the sun light")] + bool EnableSun = true; + + [HelpText("Controls whether the sun is treated as a disc area light in the real-time shader")] + bool SunAreaLightApproximation = true; + + [HelpText("The color of the sun")] + Color SunTintColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + + [HelpText("Scale the intensity of the sun")] + [MinValue(0.0f)] + float SunIntensityScale = 1.0f; + + [HelpText("Angular radius of the sun in degrees")] + [MinValue(0.01f)] + [StepSize(0.001f)] + float SunSize = BaseSunSize; + + [UseAsShaderConstant(false)] + bool NormalizeSunIntensity = false; + + [HelpText("Input direction type for the sun")] + SunDirectionTypes SunDirType = SunDirectionTypes.HorizontalCoordSystem; + + [HelpText("Director of the sun")] + Direction SunDirection = new Direction(-0.75f, 0.977f, -0.4f); + + [HelpText("Angle around the horizon")] + [MinValue(0.0f)] + [MaxValue(360.0f)] + [StepSize(0.1f)] + float SunAzimuth; + + [HelpText("Elevation of sun from ground. 0 degrees is aligned on the horizon while 90 degrees is directly overhead")] + [MinValue(0.0f)] + [MaxValue(90.0f)] + [StepSize(0.1f)] + float SunElevation; + } + + public class Sky + { + [HelpText("Controls the sky used for GI baking and background rendering")] + [UseAsShaderConstant(false)] + SkyModes SkyMode = SkyModes.Procedural; + + [HelpText("The color of the simple sky")] + [MinValue(0.0f)] + [MaxValue(1000000.0f)] + [StepSize(0.1f)] + [HDR(true)] + [ColorUnit(ColorUnit.Luminance)] + [UseAsShaderConstant(false)] + Color SkyColor = new Color(0.2f, 0.5f, 1.0f, 7000.0f); + + [MinValue(1.0f)] + [MaxValue(10.0f)] + [UseAsShaderConstant(false)] + float Turbidity = 2.0f; + + [HDR(false)] + [UseAsShaderConstant(false)] + Color GroundAlbedo = new Color(0.5f, 0.5f, 0.5f); + } + + [ExpandGroup(false)] + public class AreaLight + { + [HelpText("Enables the area light during baking and ground truth rendering")] + bool EnableAreaLight = false; + + [DisplayName("Color")] + [MinValue(0.0f)] + [StepSize(0.1f)] + [HDR(true)] + [ColorUnit(ColorUnit.Luminance)] + [HelpText("The color of the area light")] + Color AreaLightColor = new Color(1.0f, 1.0f, 1.0f, 1000000.0f); + + [DisplayName("Color Intensity (lux)")] + [MinValue(0.0f)] + [Visible(false)] + [UseAsShaderConstant(false)] + float AreaLightIlluminance = 1.0f; + + [DisplayName("Color Intensity (lm)")] + [MinValue(0.0f)] + [Visible(false)] + [UseAsShaderConstant(false)] + float AreaLightLuminousPower = 1.0f; + + [DisplayName("Color Intensity (EV100)")] + [MinValue(-64.0f)] + [MaxValue(64.0f)] + [Visible(false)] + [UseAsShaderConstant(false)] + float AreaLightEV100 = 0.0f; + + [UseAsShaderConstant(false)] + [DisplayName("Units")] + LightUnits AreaLightUnits = LightUnits.Luminance; + + [DisplayName("Illuminance Distance")] + [UseAsShaderConstant(false)] + [Visible(false)] + float AreaLightIlluminanceDistance = 10.0f; + + [DisplayName("Size")] + [MinValue(0.01f)] + [MaxValue(10.0f)] + [StepSize(0.01f)] + [HelpText("The radius of the area light")] + float AreaLightSize = 0.5f; + + [DisplayName("Position X")] + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [StepSize(0.01f)] + [HelpText("The X coordinate of the area light")] + float AreaLightX = 0.0f; + + [DisplayName("Position Y")] + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [StepSize(0.01f)] + [HelpText("The Y coordinate of the area light")] + float AreaLightY = 5.0f; + + [DisplayName("Position Z")] + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [StepSize(0.01f)] + [HelpText("The Z coordinate of the area light")] + float AreaLightZ = 0.0f; + + [DisplayName("Shadow Bias")] + [MinValue(0.0f)] + [MaxValue(1.0f)] + [StepSize(0.001f)] + float AreaLightShadowBias = 0.001f; + + [HelpText("Bakes the direct contribution from the area light into the light map")] + bool BakeDirectAreaLight = false; + + bool EnableAreaLightShadows = true; + } + + [ExpandGroup(false)] + public class CameraControls + { + [HelpText("Specifies how exposure should be controled")] + ExposureModes ExposureMode = ExposureModes.Manual_SBS; + + [MinValue(-32.0f)] + [MaxValue(32.0f)] + [StepSize(0.01f)] + [HelpText("Manual exposure value when auto-exposure is disabled")] + float ManualExposure = -16.0f; + + [DisplayName("Aperture")] + [UseAsShaderConstant(false)] + FStops ApertureSize = FStops.FStop16Point0; + + [DisplayName("ISO Rating")] + [UseAsShaderConstant(false)] + ISORatings ISORating = ISORatings.ISO100; + + [DisplayName("Shutter Speed")] + [UseAsShaderConstant(false)] + ShutterSpeeds ShutterSpeed = ShutterSpeeds.ShutterSpeed1Over125; + + [DisplayName("Film Size(mm)")] + [MinValue(1.0f)] + [MaxValue(100.0f)] + [StepSize(0.1f)] + [ConversionScale(0.001f)] + float FilmSize = 35.0f; + + [DisplayName("Focal Length(mm)")] + [MinValue(1.0f)] + [MaxValue(200.0f)] + [StepSize(0.1f)] + [ConversionScale(0.001f)] + float FocalLength = 35.0f; + + [MinValue(1.0f)] + [MaxValue(100.0f)] + [StepSize(0.1f)] + float FocusDistance = 10.0f; + + [DisplayName("Num Aperture Blades")] + [MinValue(5)] + [MaxValue(9)] + int NumBlades = 5; + + [DisplayName("Enable DOF")] + [UseAsShaderConstant(false)] + bool EnableDOF = false; + + [DisplayName("Auto-Exposure Key Value")] + [MinValue(0.0f)] + [MaxValue(0.5f)] + [StepSize(0.01f)] + [HelpText("Parameter that biases the result of the auto-exposure pass")] + float KeyValue = 0.115f; + + [DisplayName("Adaptation Rate")] + [MinValue(0.0f)] + [MaxValue(4.0f)] + [StepSize(0.01f)] + [HelpText("Controls how quickly auto-exposure adapts to changes in scene brightness")] + float AdaptationRate = 0.5f; + + // Virtuals + [VirtualSetting("ApertureFNumber_()")] + [Visible(false)] + float ApertureFNumber; + + [VirtualSetting("ApertureWidth_()")] + [Visible(false)] + float ApertureWidth; + + [VirtualSetting("ShutterSpeedValue_()")] + [Visible(false)] + float ShutterSpeedValue; + + [VirtualSetting("ISO_()")] + [Visible(false)] + float ISO; + + [VirtualSetting("BokehPolygonAmount_()")] + [Visible(false)] + float BokehPolygonAmount; + } + + [ExpandGroup(false)] + public class ToneMapping + { + [DisplayName("Tone Mapping Operator")] + ToneMappingModes ToneMappingMode = ToneMappingModes.ACES; + + [MinValue(0.01f)] + [StepSize(0.01f)] + [DisplayName("White Point (Hejl2015)")] + float WhitePoint_Hejl = 1.0f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + float ShoulderStrength = 4.0f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + float LinearStrength = 5.0f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + float LinearAngle = 0.12f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + float ToeStrength = 13.0f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + [DisplayName("White Point (Hable)")] + float WhitePoint_Hable = 6.0f; + } + + [ExpandGroup(false)] + public class AntiAliasing + { + MSAAModes MSAAMode = MSAAModes.MSAA4x; + + FilterTypes FilterType = FilterTypes.Smoothstep; + + [MinValue(0.0f)] + [MaxValue(6.0f)] + [StepSize(0.01f)] + float FilterSize = 2.0f; + + [MinValue(0.01f)] + [MaxValue(1.0f)] + [StepSize(0.01f)] + float GaussianSigma = 0.5f; + + [UseAsShaderConstant(false)] + bool EnableTemporalAA = true; + + [UseAsShaderConstant(false)] + JitterModes JitterMode = JitterModes.Hammersley4x; + + [MinValue(0.0f)] + [UseAsShaderConstant(false)] + float JitterScale = 1.0f; + } + + const int MaxSGCount = 12; + const int MaxBasisCount = MaxSGCount; + + [ExpandGroup(false)] + [DisplayName("SG Settings")] + public class SGSettings + { + [DisplayName("SG Diffuse Mode")] + SGDiffuseModes SGDiffuseMode = SGDiffuseModes.Fitted; + + [DisplayName("Use ASG Warp")] + bool UseASGWarp = true; + } + + [ExpandGroup(false)] + public class Baking + { + [DisplayName("Light Map Resolution")] + [HelpText("The texture resolution of the light map")] + [MinValue(64)] + [MaxValue(4096)] + int LightMapResolution = 256; + + [HelpText("The square root of the number of sample rays to use for baking GI")] + [MinValue(1)] + [MaxValue(100)] + [UseAsShaderConstant(false)] + [DisplayName("Sqrt Num Samples")] + int NumBakeSamples = 25; + + [UseAsShaderConstant(false)] + [DisplayName("Sample Mode")] + SampleModes BakeSampleMode = SampleModes.CMJ; + + [HelpText("Maximum path length (bounces + 2) to use for baking GI (set to -1 for infinite)")] + [UseAsShaderConstant(false)] + [MinValue(-1)] + int MaxBakePathLength = -1; + + [HelpText("Path length at which Russian roulette kicks in (-1 to disable)")] + [UseAsShaderConstant(false)] + [MinValue(-1)] + [DisplayName("Russian Roullette Depth")] + int BakeRussianRouletteDepth = 4; + + [HelpText("Maximum probability for continuing when Russian roulette is used")] + [UseAsShaderConstant(false)] + [MinValue(0.0f)] + [MaxValue(1.0f)] + [StepSize(0.01f)] + [DisplayName("Russian Roullette Probability")] + float BakeRussianRouletteProbability = 0.5f; + + BakeModes BakeMode = BakeModes.SG9; + + SolveModes SolveMode = SolveModes.NNLS; + } + + [ExpandGroup(true)] + public class Probes + { + bool UseProbes = true; + + [MinValue(2)] + [MaxValue(64)] + int ProbeResX = 2; + + [MinValue(2)] + [MaxValue(64)] + int ProbeResY = 2; + + [MinValue(2)] + [MaxValue(64)] + int ProbeResZ = 2; + } + + [ExpandGroup(false)] + public class Scene + { + [UseAsShaderConstant(false)] + Scenes CurrentScene = Scenes.Box; + + [DisplayName("Enable Diffuse")] + [HelpText("Enables diffuse lighting")] + bool EnableDiffuse = true; + + [DisplayName("Enable Specular")] + [HelpText("Enables specular lighting")] + bool EnableSpecular = true; + + [DisplayName("Enable Direct Lighting")] + [HelpText("Enables direct lighting")] + bool EnableDirectLighting = true; + + [DisplayName("Enable Indirect Lighting")] + [HelpText("Enables indirect lighting")] + bool EnableIndirectLighting = true; + + [DisplayName("Enable Indirect Diffuse")] + [HelpText("Enables indirect diffuse lighting")] + bool EnableIndirectDiffuse = true; + + [DisplayName("Enable Indirect Specular")] + [HelpText("Enables indirect specular lighting")] + bool EnableIndirectSpecular = true; + + [DisplayName("Enable Albedo Maps")] + [HelpText("Enables albedo maps")] + bool EnableAlbedoMaps = true; + + [DisplayName("Enable Normal Maps")] + [HelpText("Enables normal maps")] + bool EnableNormalMaps = true; + + [DisplayName("Normal Map Intensity")] + [MinValue(0.0f)] + [MaxValue(1.0f)] + [StepSize(0.01f)] + [HelpText("Intensity of the normal map")] + float NormalMapIntensity = 0.5f; + + [DisplayName("Diffuse Albedo Scale")] + [MinValue(0.0f)] + [StepSize(0.01f)] + [HelpText("Global scale applied to all material diffuse albedo values")] + float DiffuseAlbedoScale = 0.5f; + + [DisplayName("Specular Roughness Scale")] + [MinValue(0.01f)] + [StepSize(0.01f)] + [HelpText("Global scale applied to all material roughness values")] + float RoughnessScale = 2.0f; + } + + [ExpandGroup(false)] + public class GroundTruth + { + [DisplayName("Show Ground Truth")] + [HelpText("If enabled, shows a ground truth image rendered on the CPU")] + [UseAsShaderConstant(false)] + bool ShowGroundTruth = false; + + [HelpText("The square root of the number of per-pixel sample rays to use for ground truth rendering")] + [UseAsShaderConstant(false)] + [MinValue(1)] + [MaxValue(100)] + [DisplayName("Sqrt Num Samples")] + int NumRenderSamples = 4; + + [UseAsShaderConstant(false)] + [DisplayName("Sample Mode")] + SampleModes RenderSampleMode = SampleModes.CMJ; + + [HelpText("Maximum path length (bounces) to use for ground truth rendering (set to -1 for infinite)")] + [UseAsShaderConstant(false)] + [MinValue(-1)] + [DisplayName("Max Path Length")] + int MaxRenderPathLength = -1; + + [HelpText("Path length at which Russian roulette kicks in (-1 to disable)")] + [UseAsShaderConstant(false)] + [MinValue(-1)] + [DisplayName("Russian Roullette Depth")] + int RenderRussianRouletteDepth = 4; + + [HelpText("Maximum probability for continuing when Russian roulette is used")] + [UseAsShaderConstant(false)] + [MinValue(0.0f)] + [MaxValue(1.0f)] + [StepSize(0.01f)] + [DisplayName("Russian Roullette Probability")] + float RenderRussianRouletteProbability = 0.5f; + + [DisplayName("Enable Bounce Specular")] + [HelpText("Enables specular calculations after the first hit")] + [UseAsShaderConstant(false)] + bool EnableRenderBounceSpecular = false; + } + + [ExpandGroup(false)] + public class PostProcessing + { + [DisplayName("Bloom Exposure Offset")] + [MinValue(-10.0f)] + [MaxValue(0.0f)] + [StepSize(0.01f)] + [HelpText("Exposure offset applied to generate the input of the bloom pass")] + float BloomExposure = -4.0f; + + [DisplayName("Bloom Magnitude")] + [MinValue(0.0f)] + [MaxValue(2.0f)] + [StepSize(0.01f)] + [HelpText("Scale factor applied to the bloom results when combined with tone-mapped result")] + float BloomMagnitude = 1.0f; + + [DisplayName("Bloom Blur Sigma")] + [MinValue(0.5f)] + [MaxValue(2.5f)] + [StepSize(0.01f)] + [HelpText("Sigma parameter of the Gaussian filter used in the bloom pass")] + float BloomBlurSigma = 2.5f; + } + + [ExpandGroup(false)] + public class Debug + { + [UseAsShaderConstant(false)] + bool EnableLuminancePicker = false; + + [UseAsShaderConstant(false)] + bool ShowBakeDataVisualizer = false; + + bool ViewIndirectSpecular = false; + + [DisplayName("Save Light Settings")] + [HelpText("Saves the lighting settings to a file")] + Button SaveLightSettings; + + [DisplayName("Load Light Settings")] + [HelpText("Loads the lighting settings from a file")] + Button LoadLightSettings; + + [DisplayName("Save EXR Screenshot")] + [HelpText("Captures the current screen image in EXR format")] + Button SaveEXRScreenshot; + + [UseAsShaderConstant(false)] + bool ShowSunIntensity = false; + } } \ No newline at end of file diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index a1d941d..3d946dc 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -1,590 +1,598 @@ -#pragma once - -#include -#include -#include - -using namespace SampleFramework11; - -enum class SunDirectionTypes -{ - UnitVector = 0, - HorizontalCoordSystem = 1, - - NumValues -}; - -typedef EnumSettingT SunDirectionTypesSetting; - -enum class SkyModes -{ - None = 0, - Procedural = 1, - Simple = 2, - CubeMapEnnis = 3, - CubeMapGraceCathedral = 4, - CubeMapUffizi = 5, - - NumValues -}; - -typedef EnumSettingT SkyModesSetting; - -enum class LightUnits -{ - Luminance = 0, - Illuminance = 1, - LuminousPower = 2, - EV100 = 3, - - NumValues -}; - -typedef EnumSettingT LightUnitsSetting; - -enum class ExposureModes -{ - ManualSimple = 0, - Manual_SBS = 1, - Manual_SOS = 2, - Automatic = 3, - - NumValues -}; - -typedef EnumSettingT ExposureModesSetting; - -enum class FStops -{ - FStop1Point8 = 0, - FStop2Point0 = 1, - FStop2Point2 = 2, - FStop2Point5 = 3, - FStop2Point8 = 4, - FStop3Point2 = 5, - FStop3Point5 = 6, - FStop4Point0 = 7, - FStop4Point5 = 8, - FStop5Point0 = 9, - FStop5Point6 = 10, - FStop6Point3 = 11, - FStop7Point1 = 12, - FStop8Point0 = 13, - FStop9Point0 = 14, - FStop10Point0 = 15, - FStop11Point0 = 16, - FStop13Point0 = 17, - FStop14Point0 = 18, - FStop16Point0 = 19, - FStop18Point0 = 20, - FStop20Point0 = 21, - FStop22Point0 = 22, - - NumValues -}; - -typedef EnumSettingT FStopsSetting; - -enum class ISORatings -{ - ISO100 = 0, - ISO200 = 1, - ISO400 = 2, - ISO800 = 3, - - NumValues -}; - -typedef EnumSettingT ISORatingsSetting; - -enum class ShutterSpeeds -{ - ShutterSpeed1Over1 = 0, - ShutterSpeed1Over2 = 1, - ShutterSpeed1Over4 = 2, - ShutterSpeed1Over8 = 3, - ShutterSpeed1Over15 = 4, - ShutterSpeed1Over30 = 5, - ShutterSpeed1Over60 = 6, - ShutterSpeed1Over125 = 7, - ShutterSpeed1Over250 = 8, - ShutterSpeed1Over500 = 9, - ShutterSpeed1Over1000 = 10, - ShutterSpeed1Over2000 = 11, - ShutterSpeed1Over4000 = 12, - - NumValues -}; - -typedef EnumSettingT ShutterSpeedsSetting; - -enum class ToneMappingModes -{ - FilmStock = 0, - Linear = 1, - ACES = 2, - Hejl2015 = 3, - Hable = 4, - - NumValues -}; - -typedef EnumSettingT ToneMappingModesSetting; - -enum class MSAAModes -{ - MSAANone = 0, - MSAA2x = 1, - MSAA4x = 2, - MSAA8x = 3, - - NumValues -}; - -typedef EnumSettingT MSAAModesSetting; - -enum class FilterTypes -{ - Box = 0, - Triangle = 1, - Gaussian = 2, - BlackmanHarris = 3, - Smoothstep = 4, - BSpline = 5, - - NumValues -}; - -typedef EnumSettingT FilterTypesSetting; - -enum class JitterModes -{ - None = 0, - Uniform2x = 1, - Hammersley4x = 2, - Hammersley8x = 3, - Hammersley16x = 4, - - NumValues -}; - -typedef EnumSettingT JitterModesSetting; - -enum class SGDiffuseModes -{ - InnerProduct = 0, - Punctual = 1, - Fitted = 2, - - NumValues -}; - -typedef EnumSettingT SGDiffuseModesSetting; - -enum class SampleModes -{ - Random = 0, - Stratified = 1, - Hammersley = 2, - UniformGrid = 3, - CMJ = 4, - - NumValues -}; - -typedef EnumSettingT SampleModesSetting; - -enum class BakeModes -{ - Diffuse = 0, - HL2 = 1, - SH4 = 2, - SH9 = 3, - H4 = 4, - H6 = 5, - SG5 = 6, - SG6 = 7, - SG9 = 8, - SG12 = 9, - - NumValues -}; - -typedef EnumSettingT BakeModesSetting; - -enum class SolveModes -{ - Projection = 0, - SVD = 1, - NNLS = 2, - - NumValues -}; - -typedef EnumSettingT SolveModesSetting; - -enum class Scenes -{ - Box = 0, - WhiteRoom = 1, - Sponza = 2, - - NumValues -}; - -typedef EnumSettingT ScenesSetting; - -namespace AppSettings -{ - static const float BaseSunSize = 0.2700f; - static const int64 MaxSGCount = 12; - static const int64 MaxBasisCount = 12; - - extern BoolSetting EnableSun; - extern BoolSetting SunAreaLightApproximation; - extern ColorSetting SunTintColor; - extern FloatSetting SunIntensityScale; - extern FloatSetting SunSize; - extern BoolSetting NormalizeSunIntensity; - extern SunDirectionTypesSetting SunDirType; - extern DirectionSetting SunDirection; - extern FloatSetting SunAzimuth; - extern FloatSetting SunElevation; - extern SkyModesSetting SkyMode; - extern ColorSetting SkyColor; - extern FloatSetting Turbidity; - extern ColorSetting GroundAlbedo; - extern BoolSetting EnableAreaLight; - extern ColorSetting AreaLightColor; - extern FloatSetting AreaLightIlluminance; - extern FloatSetting AreaLightLuminousPower; - extern FloatSetting AreaLightEV100; - extern LightUnitsSetting AreaLightUnits; - extern FloatSetting AreaLightIlluminanceDistance; - extern FloatSetting AreaLightSize; - extern FloatSetting AreaLightX; - extern FloatSetting AreaLightY; - extern FloatSetting AreaLightZ; - extern FloatSetting AreaLightShadowBias; - extern BoolSetting BakeDirectAreaLight; - extern BoolSetting EnableAreaLightShadows; - extern ExposureModesSetting ExposureMode; - extern FloatSetting ManualExposure; - extern FStopsSetting ApertureSize; - extern ISORatingsSetting ISORating; - extern ShutterSpeedsSetting ShutterSpeed; - extern FloatSetting FilmSize; - extern FloatSetting FocalLength; - extern FloatSetting FocusDistance; - extern IntSetting NumBlades; - extern BoolSetting EnableDOF; - extern FloatSetting KeyValue; - extern FloatSetting AdaptationRate; - extern FloatSetting ApertureFNumber; - extern FloatSetting ApertureWidth; - extern FloatSetting ShutterSpeedValue; - extern FloatSetting ISO; - extern FloatSetting BokehPolygonAmount; - extern ToneMappingModesSetting ToneMappingMode; - extern FloatSetting WhitePoint_Hejl; - extern FloatSetting ShoulderStrength; - extern FloatSetting LinearStrength; - extern FloatSetting LinearAngle; - extern FloatSetting ToeStrength; - extern FloatSetting WhitePoint_Hable; - extern MSAAModesSetting MSAAMode; - extern FilterTypesSetting FilterType; - extern FloatSetting FilterSize; - extern FloatSetting GaussianSigma; - extern BoolSetting EnableTemporalAA; - extern JitterModesSetting JitterMode; - extern FloatSetting JitterScale; - extern SGDiffuseModesSetting SGDiffuseMode; - extern BoolSetting UseASGWarp; - extern IntSetting LightMapResolution; - extern IntSetting NumBakeSamples; - extern SampleModesSetting BakeSampleMode; - extern IntSetting MaxBakePathLength; - extern IntSetting BakeRussianRouletteDepth; - extern FloatSetting BakeRussianRouletteProbability; - extern BakeModesSetting BakeMode; - extern SolveModesSetting SolveMode; - extern ScenesSetting CurrentScene; - extern BoolSetting EnableDiffuse; - extern BoolSetting EnableSpecular; - extern BoolSetting EnableDirectLighting; - extern BoolSetting EnableIndirectLighting; - extern BoolSetting EnableIndirectDiffuse; - extern BoolSetting EnableIndirectSpecular; - extern BoolSetting EnableAlbedoMaps; - extern BoolSetting EnableNormalMaps; - extern FloatSetting NormalMapIntensity; - extern FloatSetting DiffuseAlbedoScale; - extern FloatSetting RoughnessScale; - extern BoolSetting ShowGroundTruth; - extern IntSetting NumRenderSamples; - extern SampleModesSetting RenderSampleMode; - extern IntSetting MaxRenderPathLength; - extern IntSetting RenderRussianRouletteDepth; - extern FloatSetting RenderRussianRouletteProbability; - extern BoolSetting EnableRenderBounceSpecular; - extern FloatSetting BloomExposure; - extern FloatSetting BloomMagnitude; - extern FloatSetting BloomBlurSigma; - extern BoolSetting EnableLuminancePicker; - extern BoolSetting ShowBakeDataVisualizer; - extern BoolSetting ViewIndirectSpecular; - extern Button SaveLightSettings; - extern Button LoadLightSettings; - extern Button SaveEXRScreenshot; - extern BoolSetting ShowSunIntensity; - - struct AppSettingsCBuffer - { - bool32 EnableSun; - bool32 SunAreaLightApproximation; - Float4Align Float3 SunTintColor; - float SunIntensityScale; - float SunSize; - int32 SunDirType; - Float4Align Float3 SunDirection; - float SunAzimuth; - float SunElevation; - bool32 EnableAreaLight; - Float4Align Float3 AreaLightColor; - float AreaLightSize; - float AreaLightX; - float AreaLightY; - float AreaLightZ; - float AreaLightShadowBias; - bool32 BakeDirectAreaLight; - bool32 EnableAreaLightShadows; - int32 ExposureMode; - float ManualExposure; - float FilmSize; - float FocalLength; - float FocusDistance; - int32 NumBlades; - float KeyValue; - float AdaptationRate; - float ApertureFNumber; - float ApertureWidth; - float ShutterSpeedValue; - float ISO; - float BokehPolygonAmount; - int32 ToneMappingMode; - float WhitePoint_Hejl; - float ShoulderStrength; - float LinearStrength; - float LinearAngle; - float ToeStrength; - float WhitePoint_Hable; - int32 MSAAMode; - int32 FilterType; - float FilterSize; - float GaussianSigma; - int32 SGDiffuseMode; - bool32 UseASGWarp; - int32 LightMapResolution; - int32 BakeMode; - int32 SolveMode; - bool32 EnableDiffuse; - bool32 EnableSpecular; - bool32 EnableDirectLighting; - bool32 EnableIndirectLighting; - bool32 EnableIndirectDiffuse; - bool32 EnableIndirectSpecular; - bool32 EnableAlbedoMaps; - bool32 EnableNormalMaps; - float NormalMapIntensity; - float DiffuseAlbedoScale; - float RoughnessScale; - float BloomExposure; - float BloomMagnitude; - float BloomBlurSigma; - bool32 ViewIndirectSpecular; - }; - - extern ConstantBuffer CBuffer; - - void Initialize(ID3D11Device* device); - void Update(); - void UpdateCBuffer(ID3D11DeviceContext* context); -}; - -// ================================================================================================ - -enum class BRDF -{ - GGX = 0, - Beckmann = 1, - Velvet = 2, - - NumValues -}; - -namespace AppSettings -{ - const uint64 CubeMapStart = uint64(SkyModes::CubeMapEnnis); - const uint64 NumCubeMaps = uint64(SkyModes::NumValues) - CubeMapStart; - - inline const wchar* CubeMapPaths(uint64 idx) - { - Assert_(idx < NumCubeMaps); - - const wchar* Paths[] = - { - L"..\\Content\\EnvMaps\\Ennis.dds", - L"..\\Content\\EnvMaps\\GraceCathedral.dds", - L"..\\Content\\EnvMaps\\Uffizi.dds", - }; - StaticAssert_(ArraySize_(Paths) == NumCubeMaps); - - return Paths[idx]; - } - - Float3 SunLuminance(); - Float3 SunIlluminance(); - - inline float ISO_() - { - static const float ISOValues[] = - { - 100.0f, 200.0f, 400.0f, 800.0f - }; - StaticAssert_(ArraySize_(ISOValues) == uint64(ISORatings::NumValues)); - - return ISOValues[uint64(AppSettings::ISORating)]; - } - - inline float ApertureFNumber_() - { - static const float FNumbers[] = - { - 1.8f, 2.0f, 2.2f, 2.5f, 2.8f, 3.2f, 3.5f, 4.0f, 4.5f, 5.0f, 5.6f, 6.3f, 7.1f, 8.0f, - 9.0f, 10.0f, 11.0f, 13.0f, 14.0f, 16.0f, 18.0f, 20.0f, 22.0f - }; - StaticAssert_(ArraySize_(FNumbers) == uint64(FStops::NumValues)); - - return FNumbers[uint64(AppSettings::ApertureSize)]; - } - - inline float ApertureWidth_() - { - return (FocalLength / ApertureFNumber_()) * 0.5f; - } - - inline float ShutterSpeedValue_() - { - static const float ShutterSpeedValues[] = - { - 1.0f / 1.0f, 1.0f / 2.0f, 1.0f / 4.0f, 1.0f / 8.0f, 1.0f / 15.0f, 1.0f / 30.0f, - 1.0f / 60.0f, 1.0f / 125.0f, 1.0f / 250.0f, 1.0f / 500.0f, 1.0f / 1000.0f, 1.0f / 2000.0f, 1.0f / 4000.0f, - }; - StaticAssert_(ArraySize_(ShutterSpeedValues) == uint64(ShutterSpeeds::NumValues)); - - return ShutterSpeedValues[uint64(AppSettings::ShutterSpeed)]; - } - - inline float VerticalFOV(float aspectRatio) - { - float verticalSize = FilmSize / aspectRatio; - return 2.0f * std::atan2(verticalSize, 2.0f * FocalLength); - } - - inline void SetFocalLengthFromVFOV(float FOV, float aspectRatio) - { - float fs = FilmSize.RawValue(); - float verticalSize = fs / aspectRatio; - FocalLength.SetValue(2.0f * (verticalSize * 0.5f) / tanf(FOV * 0.5f)); - } - - inline float BokehPolygonAmount_() - { - return std::sqrt(Saturate((ApertureFNumber_() - 1.8f) / (5.0f - 1.8f))); - } - - inline bool HasSunDirChanged() - { - return AppSettings::SunDirType.Changed() || - AppSettings::SunDirection.Changed() || - AppSettings::SunAzimuth.Changed() || - AppSettings::SunElevation.Changed(); - } - - inline void UpdateHorizontalCoords() - { - Float3 sunDir = SunDirection.Value(); - SunElevation.SetValue(RadToDeg(asin(sunDir.y))); - - float rad = atan2(sunDir.z, sunDir.x); - if(rad < 0.0f) - rad = 2.0f * Pi + rad; - - float deg = RadToDeg(rad); - SunAzimuth.SetValue(deg); - } - - inline void UpdateUnitVector() - { - Float3 newDir; - newDir.x = cos(DegToRad(SunAzimuth)) * cos(DegToRad(SunElevation)); - newDir.y = sin(DegToRad(SunElevation)); - newDir.z = sin(DegToRad(SunAzimuth)) * cos(DegToRad(SunElevation)); - SunDirection.SetValue(newDir); - } - - inline uint32 NumMSAASamples(MSAAModes mode) - { - static const uint32 NumSamples[uint32(MSAAModes::NumValues)] = { 1, 2, 4, 8 }; - return NumSamples[uint32(mode)]; - } - - inline uint32 NumMSAASamples() - { - return NumMSAASamples(MSAAMode); - } - - inline uint64 BasisCount(uint64 bakeMode) - { - Assert_(bakeMode < uint64(BakeModes::NumValues)); - static const uint64 BasisCounts[] = { 1, 3, 4, 9, 4, 6, 5, 6, 9, 12 }; - StaticAssert_(ArraySize_(BasisCounts) == uint64(BakeModes::NumValues)); - Assert_(BasisCounts[bakeMode] <= MaxBasisCount); - return BasisCounts[bakeMode]; - } - - inline uint64 BasisCount(BakeModes bakeMode) - { - return BasisCount(uint64(bakeMode)); - } - - inline uint64 BasisCount() - { - return BasisCount(uint64(BakeMode)); - } - - inline uint64 SGCount(BakeModes bakeMode) - { - Assert_(uint64(bakeMode) < uint64(BakeModes::NumValues)); - if(uint64(bakeMode) >= uint64(BakeModes::SG5)) - return BasisCount(bakeMode); - else - return 0; - } - - inline uint64 SGCount() - { - return SGCount(BakeMode); - } - - inline bool SupportsProgressiveIntegration(BakeModes bakeMode, SolveModes solveMode) - { - if(SGCount(bakeMode) > 0 && (solveMode == SolveModes::SVD || solveMode == SolveModes::NNLS)) - return false; - else - return true; - } - - void UpdateUI(); +#pragma once + +#include +#include +#include + +using namespace SampleFramework11; + +enum class SunDirectionTypes +{ + UnitVector = 0, + HorizontalCoordSystem = 1, + + NumValues +}; + +typedef EnumSettingT SunDirectionTypesSetting; + +enum class SkyModes +{ + None = 0, + Procedural = 1, + Simple = 2, + CubeMapEnnis = 3, + CubeMapGraceCathedral = 4, + CubeMapUffizi = 5, + + NumValues +}; + +typedef EnumSettingT SkyModesSetting; + +enum class LightUnits +{ + Luminance = 0, + Illuminance = 1, + LuminousPower = 2, + EV100 = 3, + + NumValues +}; + +typedef EnumSettingT LightUnitsSetting; + +enum class ExposureModes +{ + ManualSimple = 0, + Manual_SBS = 1, + Manual_SOS = 2, + Automatic = 3, + + NumValues +}; + +typedef EnumSettingT ExposureModesSetting; + +enum class FStops +{ + FStop1Point8 = 0, + FStop2Point0 = 1, + FStop2Point2 = 2, + FStop2Point5 = 3, + FStop2Point8 = 4, + FStop3Point2 = 5, + FStop3Point5 = 6, + FStop4Point0 = 7, + FStop4Point5 = 8, + FStop5Point0 = 9, + FStop5Point6 = 10, + FStop6Point3 = 11, + FStop7Point1 = 12, + FStop8Point0 = 13, + FStop9Point0 = 14, + FStop10Point0 = 15, + FStop11Point0 = 16, + FStop13Point0 = 17, + FStop14Point0 = 18, + FStop16Point0 = 19, + FStop18Point0 = 20, + FStop20Point0 = 21, + FStop22Point0 = 22, + + NumValues +}; + +typedef EnumSettingT FStopsSetting; + +enum class ISORatings +{ + ISO100 = 0, + ISO200 = 1, + ISO400 = 2, + ISO800 = 3, + + NumValues +}; + +typedef EnumSettingT ISORatingsSetting; + +enum class ShutterSpeeds +{ + ShutterSpeed1Over1 = 0, + ShutterSpeed1Over2 = 1, + ShutterSpeed1Over4 = 2, + ShutterSpeed1Over8 = 3, + ShutterSpeed1Over15 = 4, + ShutterSpeed1Over30 = 5, + ShutterSpeed1Over60 = 6, + ShutterSpeed1Over125 = 7, + ShutterSpeed1Over250 = 8, + ShutterSpeed1Over500 = 9, + ShutterSpeed1Over1000 = 10, + ShutterSpeed1Over2000 = 11, + ShutterSpeed1Over4000 = 12, + + NumValues +}; + +typedef EnumSettingT ShutterSpeedsSetting; + +enum class ToneMappingModes +{ + FilmStock = 0, + Linear = 1, + ACES = 2, + Hejl2015 = 3, + Hable = 4, + + NumValues +}; + +typedef EnumSettingT ToneMappingModesSetting; + +enum class MSAAModes +{ + MSAANone = 0, + MSAA2x = 1, + MSAA4x = 2, + MSAA8x = 3, + + NumValues +}; + +typedef EnumSettingT MSAAModesSetting; + +enum class FilterTypes +{ + Box = 0, + Triangle = 1, + Gaussian = 2, + BlackmanHarris = 3, + Smoothstep = 4, + BSpline = 5, + + NumValues +}; + +typedef EnumSettingT FilterTypesSetting; + +enum class JitterModes +{ + None = 0, + Uniform2x = 1, + Hammersley4x = 2, + Hammersley8x = 3, + Hammersley16x = 4, + + NumValues +}; + +typedef EnumSettingT JitterModesSetting; + +enum class SGDiffuseModes +{ + InnerProduct = 0, + Punctual = 1, + Fitted = 2, + + NumValues +}; + +typedef EnumSettingT SGDiffuseModesSetting; + +enum class SampleModes +{ + Random = 0, + Stratified = 1, + Hammersley = 2, + UniformGrid = 3, + CMJ = 4, + + NumValues +}; + +typedef EnumSettingT SampleModesSetting; + +enum class BakeModes +{ + Diffuse = 0, + HL2 = 1, + SH4 = 2, + SH9 = 3, + H4 = 4, + H6 = 5, + SG5 = 6, + SG6 = 7, + SG9 = 8, + SG12 = 9, + + NumValues +}; + +typedef EnumSettingT BakeModesSetting; + +enum class SolveModes +{ + Projection = 0, + SVD = 1, + NNLS = 2, + + NumValues +}; + +typedef EnumSettingT SolveModesSetting; + +enum class Scenes +{ + Box = 0, + WhiteRoom = 1, + Sponza = 2, + + NumValues +}; + +typedef EnumSettingT ScenesSetting; + +namespace AppSettings +{ + static const float BaseSunSize = 0.2700f; + static const int64 MaxSGCount = 12; + static const int64 MaxBasisCount = 12; + + extern BoolSetting EnableSun; + extern BoolSetting SunAreaLightApproximation; + extern ColorSetting SunTintColor; + extern FloatSetting SunIntensityScale; + extern FloatSetting SunSize; + extern BoolSetting NormalizeSunIntensity; + extern SunDirectionTypesSetting SunDirType; + extern DirectionSetting SunDirection; + extern FloatSetting SunAzimuth; + extern FloatSetting SunElevation; + extern SkyModesSetting SkyMode; + extern ColorSetting SkyColor; + extern FloatSetting Turbidity; + extern ColorSetting GroundAlbedo; + extern BoolSetting EnableAreaLight; + extern ColorSetting AreaLightColor; + extern FloatSetting AreaLightIlluminance; + extern FloatSetting AreaLightLuminousPower; + extern FloatSetting AreaLightEV100; + extern LightUnitsSetting AreaLightUnits; + extern FloatSetting AreaLightIlluminanceDistance; + extern FloatSetting AreaLightSize; + extern FloatSetting AreaLightX; + extern FloatSetting AreaLightY; + extern FloatSetting AreaLightZ; + extern FloatSetting AreaLightShadowBias; + extern BoolSetting BakeDirectAreaLight; + extern BoolSetting EnableAreaLightShadows; + extern ExposureModesSetting ExposureMode; + extern FloatSetting ManualExposure; + extern FStopsSetting ApertureSize; + extern ISORatingsSetting ISORating; + extern ShutterSpeedsSetting ShutterSpeed; + extern FloatSetting FilmSize; + extern FloatSetting FocalLength; + extern FloatSetting FocusDistance; + extern IntSetting NumBlades; + extern BoolSetting EnableDOF; + extern FloatSetting KeyValue; + extern FloatSetting AdaptationRate; + extern FloatSetting ApertureFNumber; + extern FloatSetting ApertureWidth; + extern FloatSetting ShutterSpeedValue; + extern FloatSetting ISO; + extern FloatSetting BokehPolygonAmount; + extern ToneMappingModesSetting ToneMappingMode; + extern FloatSetting WhitePoint_Hejl; + extern FloatSetting ShoulderStrength; + extern FloatSetting LinearStrength; + extern FloatSetting LinearAngle; + extern FloatSetting ToeStrength; + extern FloatSetting WhitePoint_Hable; + extern MSAAModesSetting MSAAMode; + extern FilterTypesSetting FilterType; + extern FloatSetting FilterSize; + extern FloatSetting GaussianSigma; + extern BoolSetting EnableTemporalAA; + extern JitterModesSetting JitterMode; + extern FloatSetting JitterScale; + extern SGDiffuseModesSetting SGDiffuseMode; + extern BoolSetting UseASGWarp; + extern IntSetting LightMapResolution; + extern IntSetting NumBakeSamples; + extern SampleModesSetting BakeSampleMode; + extern IntSetting MaxBakePathLength; + extern IntSetting BakeRussianRouletteDepth; + extern FloatSetting BakeRussianRouletteProbability; + extern BakeModesSetting BakeMode; + extern SolveModesSetting SolveMode; + extern BoolSetting UseProbes; + extern IntSetting ProbeResX; + extern IntSetting ProbeResY; + extern IntSetting ProbeResZ; + extern ScenesSetting CurrentScene; + extern BoolSetting EnableDiffuse; + extern BoolSetting EnableSpecular; + extern BoolSetting EnableDirectLighting; + extern BoolSetting EnableIndirectLighting; + extern BoolSetting EnableIndirectDiffuse; + extern BoolSetting EnableIndirectSpecular; + extern BoolSetting EnableAlbedoMaps; + extern BoolSetting EnableNormalMaps; + extern FloatSetting NormalMapIntensity; + extern FloatSetting DiffuseAlbedoScale; + extern FloatSetting RoughnessScale; + extern BoolSetting ShowGroundTruth; + extern IntSetting NumRenderSamples; + extern SampleModesSetting RenderSampleMode; + extern IntSetting MaxRenderPathLength; + extern IntSetting RenderRussianRouletteDepth; + extern FloatSetting RenderRussianRouletteProbability; + extern BoolSetting EnableRenderBounceSpecular; + extern FloatSetting BloomExposure; + extern FloatSetting BloomMagnitude; + extern FloatSetting BloomBlurSigma; + extern BoolSetting EnableLuminancePicker; + extern BoolSetting ShowBakeDataVisualizer; + extern BoolSetting ViewIndirectSpecular; + extern Button SaveLightSettings; + extern Button LoadLightSettings; + extern Button SaveEXRScreenshot; + extern BoolSetting ShowSunIntensity; + + struct AppSettingsCBuffer + { + bool32 EnableSun; + bool32 SunAreaLightApproximation; + Float4Align Float3 SunTintColor; + float SunIntensityScale; + float SunSize; + int32 SunDirType; + Float4Align Float3 SunDirection; + float SunAzimuth; + float SunElevation; + bool32 EnableAreaLight; + Float4Align Float3 AreaLightColor; + float AreaLightSize; + float AreaLightX; + float AreaLightY; + float AreaLightZ; + float AreaLightShadowBias; + bool32 BakeDirectAreaLight; + bool32 EnableAreaLightShadows; + int32 ExposureMode; + float ManualExposure; + float FilmSize; + float FocalLength; + float FocusDistance; + int32 NumBlades; + float KeyValue; + float AdaptationRate; + float ApertureFNumber; + float ApertureWidth; + float ShutterSpeedValue; + float ISO; + float BokehPolygonAmount; + int32 ToneMappingMode; + float WhitePoint_Hejl; + float ShoulderStrength; + float LinearStrength; + float LinearAngle; + float ToeStrength; + float WhitePoint_Hable; + int32 MSAAMode; + int32 FilterType; + float FilterSize; + float GaussianSigma; + int32 SGDiffuseMode; + bool32 UseASGWarp; + int32 LightMapResolution; + int32 BakeMode; + int32 SolveMode; + bool32 UseProbes; + int32 ProbeResX; + int32 ProbeResY; + int32 ProbeResZ; + bool32 EnableDiffuse; + bool32 EnableSpecular; + bool32 EnableDirectLighting; + bool32 EnableIndirectLighting; + bool32 EnableIndirectDiffuse; + bool32 EnableIndirectSpecular; + bool32 EnableAlbedoMaps; + bool32 EnableNormalMaps; + float NormalMapIntensity; + float DiffuseAlbedoScale; + float RoughnessScale; + float BloomExposure; + float BloomMagnitude; + float BloomBlurSigma; + bool32 ViewIndirectSpecular; + }; + + extern ConstantBuffer CBuffer; + + void Initialize(ID3D11Device* device); + void Update(); + void UpdateCBuffer(ID3D11DeviceContext* context); +}; + +// ================================================================================================ + +enum class BRDF +{ + GGX = 0, + Beckmann = 1, + Velvet = 2, + + NumValues +}; + +namespace AppSettings +{ + const uint64 CubeMapStart = uint64(SkyModes::CubeMapEnnis); + const uint64 NumCubeMaps = uint64(SkyModes::NumValues) - CubeMapStart; + + inline const wchar* CubeMapPaths(uint64 idx) + { + Assert_(idx < NumCubeMaps); + + const wchar* Paths[] = + { + L"..\\Content\\EnvMaps\\Ennis.dds", + L"..\\Content\\EnvMaps\\GraceCathedral.dds", + L"..\\Content\\EnvMaps\\Uffizi.dds", + }; + StaticAssert_(ArraySize_(Paths) == NumCubeMaps); + + return Paths[idx]; + } + + Float3 SunLuminance(); + Float3 SunIlluminance(); + + inline float ISO_() + { + static const float ISOValues[] = + { + 100.0f, 200.0f, 400.0f, 800.0f + }; + StaticAssert_(ArraySize_(ISOValues) == uint64(ISORatings::NumValues)); + + return ISOValues[uint64(AppSettings::ISORating)]; + } + + inline float ApertureFNumber_() + { + static const float FNumbers[] = + { + 1.8f, 2.0f, 2.2f, 2.5f, 2.8f, 3.2f, 3.5f, 4.0f, 4.5f, 5.0f, 5.6f, 6.3f, 7.1f, 8.0f, + 9.0f, 10.0f, 11.0f, 13.0f, 14.0f, 16.0f, 18.0f, 20.0f, 22.0f + }; + StaticAssert_(ArraySize_(FNumbers) == uint64(FStops::NumValues)); + + return FNumbers[uint64(AppSettings::ApertureSize)]; + } + + inline float ApertureWidth_() + { + return (FocalLength / ApertureFNumber_()) * 0.5f; + } + + inline float ShutterSpeedValue_() + { + static const float ShutterSpeedValues[] = + { + 1.0f / 1.0f, 1.0f / 2.0f, 1.0f / 4.0f, 1.0f / 8.0f, 1.0f / 15.0f, 1.0f / 30.0f, + 1.0f / 60.0f, 1.0f / 125.0f, 1.0f / 250.0f, 1.0f / 500.0f, 1.0f / 1000.0f, 1.0f / 2000.0f, 1.0f / 4000.0f, + }; + StaticAssert_(ArraySize_(ShutterSpeedValues) == uint64(ShutterSpeeds::NumValues)); + + return ShutterSpeedValues[uint64(AppSettings::ShutterSpeed)]; + } + + inline float VerticalFOV(float aspectRatio) + { + float verticalSize = FilmSize / aspectRatio; + return 2.0f * std::atan2(verticalSize, 2.0f * FocalLength); + } + + inline void SetFocalLengthFromVFOV(float FOV, float aspectRatio) + { + float fs = FilmSize.RawValue(); + float verticalSize = fs / aspectRatio; + FocalLength.SetValue(2.0f * (verticalSize * 0.5f) / tanf(FOV * 0.5f)); + } + + inline float BokehPolygonAmount_() + { + return std::sqrt(Saturate((ApertureFNumber_() - 1.8f) / (5.0f - 1.8f))); + } + + inline bool HasSunDirChanged() + { + return AppSettings::SunDirType.Changed() || + AppSettings::SunDirection.Changed() || + AppSettings::SunAzimuth.Changed() || + AppSettings::SunElevation.Changed(); + } + + inline void UpdateHorizontalCoords() + { + Float3 sunDir = SunDirection.Value(); + SunElevation.SetValue(RadToDeg(asin(sunDir.y))); + + float rad = atan2(sunDir.z, sunDir.x); + if(rad < 0.0f) + rad = 2.0f * Pi + rad; + + float deg = RadToDeg(rad); + SunAzimuth.SetValue(deg); + } + + inline void UpdateUnitVector() + { + Float3 newDir; + newDir.x = cos(DegToRad(SunAzimuth)) * cos(DegToRad(SunElevation)); + newDir.y = sin(DegToRad(SunElevation)); + newDir.z = sin(DegToRad(SunAzimuth)) * cos(DegToRad(SunElevation)); + SunDirection.SetValue(newDir); + } + + inline uint32 NumMSAASamples(MSAAModes mode) + { + static const uint32 NumSamples[uint32(MSAAModes::NumValues)] = { 1, 2, 4, 8 }; + return NumSamples[uint32(mode)]; + } + + inline uint32 NumMSAASamples() + { + return NumMSAASamples(MSAAMode); + } + + inline uint64 BasisCount(uint64 bakeMode) + { + Assert_(bakeMode < uint64(BakeModes::NumValues)); + static const uint64 BasisCounts[] = { 1, 3, 4, 9, 4, 6, 5, 6, 9, 12 }; + StaticAssert_(ArraySize_(BasisCounts) == uint64(BakeModes::NumValues)); + Assert_(BasisCounts[bakeMode] <= MaxBasisCount); + return BasisCounts[bakeMode]; + } + + inline uint64 BasisCount(BakeModes bakeMode) + { + return BasisCount(uint64(bakeMode)); + } + + inline uint64 BasisCount() + { + return BasisCount(uint64(BakeMode)); + } + + inline uint64 SGCount(BakeModes bakeMode) + { + Assert_(uint64(bakeMode) < uint64(BakeModes::NumValues)); + if(uint64(bakeMode) >= uint64(BakeModes::SG5)) + return BasisCount(bakeMode); + else + return 0; + } + + inline uint64 SGCount() + { + return SGCount(BakeMode); + } + + inline bool SupportsProgressiveIntegration(BakeModes bakeMode, SolveModes solveMode) + { + if(SGCount(bakeMode) > 0 && (solveMode == SolveModes::SVD || solveMode == SolveModes::NNLS)) + return false; + else + return true; + } + + void UpdateUI(); } \ No newline at end of file diff --git a/BakingLab/AppSettings.hlsl b/BakingLab/AppSettings.hlsl index bc8a603..c6a8bb7 100644 --- a/BakingLab/AppSettings.hlsl +++ b/BakingLab/AppSettings.hlsl @@ -1,185 +1,189 @@ -cbuffer AppSettings : register(b7) -{ - bool EnableSun; - bool SunAreaLightApproximation; - float3 SunTintColor; - float SunIntensityScale; - float SunSize; - int SunDirType; - float3 SunDirection; - float SunAzimuth; - float SunElevation; - bool EnableAreaLight; - float3 AreaLightColor; - float AreaLightSize; - float AreaLightX; - float AreaLightY; - float AreaLightZ; - float AreaLightShadowBias; - bool BakeDirectAreaLight; - bool EnableAreaLightShadows; - int ExposureMode; - float ManualExposure; - float FilmSize; - float FocalLength; - float FocusDistance; - int NumBlades; - float KeyValue; - float AdaptationRate; - float ApertureFNumber; - float ApertureWidth; - float ShutterSpeedValue; - float ISO; - float BokehPolygonAmount; - int ToneMappingMode; - float WhitePoint_Hejl; - float ShoulderStrength; - float LinearStrength; - float LinearAngle; - float ToeStrength; - float WhitePoint_Hable; - int MSAAMode; - int FilterType; - float FilterSize; - float GaussianSigma; - int SGDiffuseMode; - bool UseASGWarp; - int LightMapResolution; - int BakeMode; - int SolveMode; - bool EnableDiffuse; - bool EnableSpecular; - bool EnableDirectLighting; - bool EnableIndirectLighting; - bool EnableIndirectDiffuse; - bool EnableIndirectSpecular; - bool EnableAlbedoMaps; - bool EnableNormalMaps; - float NormalMapIntensity; - float DiffuseAlbedoScale; - float RoughnessScale; - float BloomExposure; - float BloomMagnitude; - float BloomBlurSigma; - bool ViewIndirectSpecular; -} - -static const int SunDirectionTypes_UnitVector = 0; -static const int SunDirectionTypes_HorizontalCoordSystem = 1; - -static const int SkyModes_None = 0; -static const int SkyModes_Procedural = 1; -static const int SkyModes_Simple = 2; -static const int SkyModes_CubeMapEnnis = 3; -static const int SkyModes_CubeMapGraceCathedral = 4; -static const int SkyModes_CubeMapUffizi = 5; - -static const int LightUnits_Luminance = 0; -static const int LightUnits_Illuminance = 1; -static const int LightUnits_LuminousPower = 2; -static const int LightUnits_EV100 = 3; - -static const int ExposureModes_ManualSimple = 0; -static const int ExposureModes_Manual_SBS = 1; -static const int ExposureModes_Manual_SOS = 2; -static const int ExposureModes_Automatic = 3; - -static const int FStops_FStop1Point8 = 0; -static const int FStops_FStop2Point0 = 1; -static const int FStops_FStop2Point2 = 2; -static const int FStops_FStop2Point5 = 3; -static const int FStops_FStop2Point8 = 4; -static const int FStops_FStop3Point2 = 5; -static const int FStops_FStop3Point5 = 6; -static const int FStops_FStop4Point0 = 7; -static const int FStops_FStop4Point5 = 8; -static const int FStops_FStop5Point0 = 9; -static const int FStops_FStop5Point6 = 10; -static const int FStops_FStop6Point3 = 11; -static const int FStops_FStop7Point1 = 12; -static const int FStops_FStop8Point0 = 13; -static const int FStops_FStop9Point0 = 14; -static const int FStops_FStop10Point0 = 15; -static const int FStops_FStop11Point0 = 16; -static const int FStops_FStop13Point0 = 17; -static const int FStops_FStop14Point0 = 18; -static const int FStops_FStop16Point0 = 19; -static const int FStops_FStop18Point0 = 20; -static const int FStops_FStop20Point0 = 21; -static const int FStops_FStop22Point0 = 22; - -static const int ISORatings_ISO100 = 0; -static const int ISORatings_ISO200 = 1; -static const int ISORatings_ISO400 = 2; -static const int ISORatings_ISO800 = 3; - -static const int ShutterSpeeds_ShutterSpeed1Over1 = 0; -static const int ShutterSpeeds_ShutterSpeed1Over2 = 1; -static const int ShutterSpeeds_ShutterSpeed1Over4 = 2; -static const int ShutterSpeeds_ShutterSpeed1Over8 = 3; -static const int ShutterSpeeds_ShutterSpeed1Over15 = 4; -static const int ShutterSpeeds_ShutterSpeed1Over30 = 5; -static const int ShutterSpeeds_ShutterSpeed1Over60 = 6; -static const int ShutterSpeeds_ShutterSpeed1Over125 = 7; -static const int ShutterSpeeds_ShutterSpeed1Over250 = 8; -static const int ShutterSpeeds_ShutterSpeed1Over500 = 9; -static const int ShutterSpeeds_ShutterSpeed1Over1000 = 10; -static const int ShutterSpeeds_ShutterSpeed1Over2000 = 11; -static const int ShutterSpeeds_ShutterSpeed1Over4000 = 12; - -static const int ToneMappingModes_FilmStock = 0; -static const int ToneMappingModes_Linear = 1; -static const int ToneMappingModes_ACES = 2; -static const int ToneMappingModes_Hejl2015 = 3; -static const int ToneMappingModes_Hable = 4; - -static const int MSAAModes_MSAANone = 0; -static const int MSAAModes_MSAA2x = 1; -static const int MSAAModes_MSAA4x = 2; -static const int MSAAModes_MSAA8x = 3; - -static const int FilterTypes_Box = 0; -static const int FilterTypes_Triangle = 1; -static const int FilterTypes_Gaussian = 2; -static const int FilterTypes_BlackmanHarris = 3; -static const int FilterTypes_Smoothstep = 4; -static const int FilterTypes_BSpline = 5; - -static const int JitterModes_None = 0; -static const int JitterModes_Uniform2x = 1; -static const int JitterModes_Hammersley4x = 2; -static const int JitterModes_Hammersley8x = 3; -static const int JitterModes_Hammersley16x = 4; - -static const int SGDiffuseModes_InnerProduct = 0; -static const int SGDiffuseModes_Punctual = 1; -static const int SGDiffuseModes_Fitted = 2; - -static const int SampleModes_Random = 0; -static const int SampleModes_Stratified = 1; -static const int SampleModes_Hammersley = 2; -static const int SampleModes_UniformGrid = 3; -static const int SampleModes_CMJ = 4; - -static const int BakeModes_Diffuse = 0; -static const int BakeModes_HL2 = 1; -static const int BakeModes_SH4 = 2; -static const int BakeModes_SH9 = 3; -static const int BakeModes_H4 = 4; -static const int BakeModes_H6 = 5; -static const int BakeModes_SG5 = 6; -static const int BakeModes_SG6 = 7; -static const int BakeModes_SG9 = 8; -static const int BakeModes_SG12 = 9; - -static const int SolveModes_Projection = 0; -static const int SolveModes_SVD = 1; -static const int SolveModes_NNLS = 2; - -static const int Scenes_Box = 0; -static const int Scenes_WhiteRoom = 1; -static const int Scenes_Sponza = 2; - -static const float BaseSunSize = 0.2700f; -static const int MaxSGCount = 12; -static const int MaxBasisCount = 12; +cbuffer AppSettings : register(b7) +{ + bool EnableSun; + bool SunAreaLightApproximation; + float3 SunTintColor; + float SunIntensityScale; + float SunSize; + int SunDirType; + float3 SunDirection; + float SunAzimuth; + float SunElevation; + bool EnableAreaLight; + float3 AreaLightColor; + float AreaLightSize; + float AreaLightX; + float AreaLightY; + float AreaLightZ; + float AreaLightShadowBias; + bool BakeDirectAreaLight; + bool EnableAreaLightShadows; + int ExposureMode; + float ManualExposure; + float FilmSize; + float FocalLength; + float FocusDistance; + int NumBlades; + float KeyValue; + float AdaptationRate; + float ApertureFNumber; + float ApertureWidth; + float ShutterSpeedValue; + float ISO; + float BokehPolygonAmount; + int ToneMappingMode; + float WhitePoint_Hejl; + float ShoulderStrength; + float LinearStrength; + float LinearAngle; + float ToeStrength; + float WhitePoint_Hable; + int MSAAMode; + int FilterType; + float FilterSize; + float GaussianSigma; + int SGDiffuseMode; + bool UseASGWarp; + int LightMapResolution; + int BakeMode; + int SolveMode; + bool UseProbes; + int ProbeResX; + int ProbeResY; + int ProbeResZ; + bool EnableDiffuse; + bool EnableSpecular; + bool EnableDirectLighting; + bool EnableIndirectLighting; + bool EnableIndirectDiffuse; + bool EnableIndirectSpecular; + bool EnableAlbedoMaps; + bool EnableNormalMaps; + float NormalMapIntensity; + float DiffuseAlbedoScale; + float RoughnessScale; + float BloomExposure; + float BloomMagnitude; + float BloomBlurSigma; + bool ViewIndirectSpecular; +} + +static const int SunDirectionTypes_UnitVector = 0; +static const int SunDirectionTypes_HorizontalCoordSystem = 1; + +static const int SkyModes_None = 0; +static const int SkyModes_Procedural = 1; +static const int SkyModes_Simple = 2; +static const int SkyModes_CubeMapEnnis = 3; +static const int SkyModes_CubeMapGraceCathedral = 4; +static const int SkyModes_CubeMapUffizi = 5; + +static const int LightUnits_Luminance = 0; +static const int LightUnits_Illuminance = 1; +static const int LightUnits_LuminousPower = 2; +static const int LightUnits_EV100 = 3; + +static const int ExposureModes_ManualSimple = 0; +static const int ExposureModes_Manual_SBS = 1; +static const int ExposureModes_Manual_SOS = 2; +static const int ExposureModes_Automatic = 3; + +static const int FStops_FStop1Point8 = 0; +static const int FStops_FStop2Point0 = 1; +static const int FStops_FStop2Point2 = 2; +static const int FStops_FStop2Point5 = 3; +static const int FStops_FStop2Point8 = 4; +static const int FStops_FStop3Point2 = 5; +static const int FStops_FStop3Point5 = 6; +static const int FStops_FStop4Point0 = 7; +static const int FStops_FStop4Point5 = 8; +static const int FStops_FStop5Point0 = 9; +static const int FStops_FStop5Point6 = 10; +static const int FStops_FStop6Point3 = 11; +static const int FStops_FStop7Point1 = 12; +static const int FStops_FStop8Point0 = 13; +static const int FStops_FStop9Point0 = 14; +static const int FStops_FStop10Point0 = 15; +static const int FStops_FStop11Point0 = 16; +static const int FStops_FStop13Point0 = 17; +static const int FStops_FStop14Point0 = 18; +static const int FStops_FStop16Point0 = 19; +static const int FStops_FStop18Point0 = 20; +static const int FStops_FStop20Point0 = 21; +static const int FStops_FStop22Point0 = 22; + +static const int ISORatings_ISO100 = 0; +static const int ISORatings_ISO200 = 1; +static const int ISORatings_ISO400 = 2; +static const int ISORatings_ISO800 = 3; + +static const int ShutterSpeeds_ShutterSpeed1Over1 = 0; +static const int ShutterSpeeds_ShutterSpeed1Over2 = 1; +static const int ShutterSpeeds_ShutterSpeed1Over4 = 2; +static const int ShutterSpeeds_ShutterSpeed1Over8 = 3; +static const int ShutterSpeeds_ShutterSpeed1Over15 = 4; +static const int ShutterSpeeds_ShutterSpeed1Over30 = 5; +static const int ShutterSpeeds_ShutterSpeed1Over60 = 6; +static const int ShutterSpeeds_ShutterSpeed1Over125 = 7; +static const int ShutterSpeeds_ShutterSpeed1Over250 = 8; +static const int ShutterSpeeds_ShutterSpeed1Over500 = 9; +static const int ShutterSpeeds_ShutterSpeed1Over1000 = 10; +static const int ShutterSpeeds_ShutterSpeed1Over2000 = 11; +static const int ShutterSpeeds_ShutterSpeed1Over4000 = 12; + +static const int ToneMappingModes_FilmStock = 0; +static const int ToneMappingModes_Linear = 1; +static const int ToneMappingModes_ACES = 2; +static const int ToneMappingModes_Hejl2015 = 3; +static const int ToneMappingModes_Hable = 4; + +static const int MSAAModes_MSAANone = 0; +static const int MSAAModes_MSAA2x = 1; +static const int MSAAModes_MSAA4x = 2; +static const int MSAAModes_MSAA8x = 3; + +static const int FilterTypes_Box = 0; +static const int FilterTypes_Triangle = 1; +static const int FilterTypes_Gaussian = 2; +static const int FilterTypes_BlackmanHarris = 3; +static const int FilterTypes_Smoothstep = 4; +static const int FilterTypes_BSpline = 5; + +static const int JitterModes_None = 0; +static const int JitterModes_Uniform2x = 1; +static const int JitterModes_Hammersley4x = 2; +static const int JitterModes_Hammersley8x = 3; +static const int JitterModes_Hammersley16x = 4; + +static const int SGDiffuseModes_InnerProduct = 0; +static const int SGDiffuseModes_Punctual = 1; +static const int SGDiffuseModes_Fitted = 2; + +static const int SampleModes_Random = 0; +static const int SampleModes_Stratified = 1; +static const int SampleModes_Hammersley = 2; +static const int SampleModes_UniformGrid = 3; +static const int SampleModes_CMJ = 4; + +static const int BakeModes_Diffuse = 0; +static const int BakeModes_HL2 = 1; +static const int BakeModes_SH4 = 2; +static const int BakeModes_SH9 = 3; +static const int BakeModes_H4 = 4; +static const int BakeModes_H6 = 5; +static const int BakeModes_SG5 = 6; +static const int BakeModes_SG6 = 7; +static const int BakeModes_SG9 = 8; +static const int BakeModes_SG12 = 9; + +static const int SolveModes_Projection = 0; +static const int SolveModes_SVD = 1; +static const int SolveModes_NNLS = 2; + +static const int Scenes_Box = 0; +static const int Scenes_WhiteRoom = 1; +static const int Scenes_Sponza = 2; + +static const float BaseSunSize = 0.2700f; +static const int MaxSGCount = 12; +static const int MaxBasisCount = 12; diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 34c0719..b7e5283 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -1,563 +1,588 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -//================================================================================================= -// Includes -//================================================================================================= -#include -#include "EVSM.hlsl" -#include -#include "AppSettings.hlsl" -#include "SG.hlsl" - -//================================================================================================= -// Constants -//================================================================================================= -static const uint NumCascades = 4; - -//================================================================================================= -// Constant buffers -//================================================================================================= -cbuffer VSConstants : register(b0) -{ - float4x4 World; - float4x4 View; - float4x4 WorldViewProjection; - float4x4 PrevWorldViewProjection; -} - -cbuffer PSConstants : register(b0) -{ - float3 SunDirectionWS; - float CosSunAngularRadius; - float3 SunIlluminance; - float SinSunAngularRadius; - float3 CameraPosWS; - float4x4 ShadowMatrix; - float4 CascadeSplits; - float4 CascadeOffsets[NumCascades]; - float4 CascadeScales[NumCascades]; - float OffsetScale; - float PositiveExponent; - float NegativeExponent; - float LightBleedingReduction; - float2 RTSize; - float2 JitterOffset; - float4 SGDirections[MaxSGCount]; - float SGSharpness; -} - -//================================================================================================= -// Resources -//================================================================================================= -Texture2D AlbedoMap : register(t0); -Texture2D NormalMap : register(t1); -Texture2D RoughnessMap : register(t2); -Texture2D MetallicMap : register(t3); -Texture2DArray SunShadowMap : register(t4); -Texture2DArray BakedLightingMap : register(t5); -TextureCube AreaLightShadowMap : register(t6); -Texture3D SHSpecularLookupA : register(t7); -Texture3D SHSpecularLookupB : register(t8); - -SamplerState AnisoSampler : register(s0); -SamplerState EVSMSampler : register(s1); -SamplerState LinearSampler : register(s2); -SamplerComparisonState PCFSampler : register(s3); - -//================================================================================================= -// Input/Output structs -//================================================================================================= -struct VSInput -{ - float3 PositionOS : POSITION; - float3 NormalOS : NORMAL; - float2 TexCoord : TEXCOORD0; - float2 LightMapUV : TEXCOORD1; - float3 TangentOS : TANGENT; - float3 BitangentOS : BITANGENT; -}; - -struct VSOutput -{ - float4 PositionCS : SV_Position; - - float3 NormalWS : NORMALWS; - float3 PositionWS : POSITIONWS; - float DepthVS : DEPTHVS; - float3 TangentWS : TANGENTWS; - float3 BitangentWS : BITANGENTWS; - float2 TexCoord : TEXCOORD; - float2 LightMapUV : LIGHTMAPUV; - float3 PrevPosition : PREVPOSITION; -}; - -struct PSInput -{ - float4 PositionSS : SV_Position; - - float3 NormalWS : NORMALWS; - float3 PositionWS : POSITIONWS; - float DepthVS : DEPTHVS; - float3 TangentWS : TANGENTWS; - float3 BitangentWS : BITANGENTWS; - float2 TexCoord : TEXCOORD; - float2 LightMapUV : LIGHTMAPUV; - float3 PrevPosition : PREVPOSITION; -}; - -struct PSOutput -{ - float4 Lighting : SV_Target0; - float2 Velocity : SV_Target1; -}; - -//================================================================================================= -// Vertex Shader -//================================================================================================= -VSOutput VS(in VSInput input, in uint VertexID : SV_VertexID) -{ - VSOutput output; - - float3 positionOS = input.PositionOS; - - // Calc the world-space position - output.PositionWS = mul(float4(positionOS, 1.0f), World).xyz; - - // Calc the clip-space position - output.PositionCS = mul(float4(positionOS, 1.0f), WorldViewProjection); - output.DepthVS = output.PositionCS.w; - - - // Rotate the normal into world space - output.NormalWS = normalize(mul(input.NormalOS, (float3x3)World)); - - // Rotate the rest of the tangent frame into world space - output.TangentWS = normalize(mul(input.TangentOS, (float3x3)World)); - output.BitangentWS = normalize(mul(input.BitangentOS, (float3x3)World)); - - // Pass along the texture coordinates - output.TexCoord = input.TexCoord; - output.LightMapUV = input.LightMapUV; - - output.PrevPosition = mul(float4(input.PositionOS, 1.0f), PrevWorldViewProjection).xyw; - - return output; -} - -//------------------------------------------------------------------------------------------------- -// Samples the EVSM shadow map -//------------------------------------------------------------------------------------------------- -float SampleShadowMapEVSM(in float3 shadowPos, in float3 shadowPosDX, - in float3 shadowPosDY, uint cascadeIdx) -{ - float2 exponents = GetEVSMExponents(PositiveExponent, NegativeExponent, - CascadeScales[cascadeIdx].xyz); - float2 warpedDepth = WarpDepth(shadowPos.z, exponents); - - float4 occluder = SunShadowMap.SampleGrad(EVSMSampler, float3(shadowPos.xy, cascadeIdx), - shadowPosDX.xy, shadowPosDY.xy); - - // Derivative of warping at depth - float2 depthScale = 0.0001f * exponents * warpedDepth; - float2 minVariance = depthScale * depthScale; - - float posContrib = ChebyshevUpperBound(occluder.xz, warpedDepth.x, minVariance.x, LightBleedingReduction); - float negContrib = ChebyshevUpperBound(occluder.yw, warpedDepth.y, minVariance.y, LightBleedingReduction); - float shadowContrib = posContrib; - shadowContrib = min(shadowContrib, negContrib); - - return shadowContrib; -} - -//------------------------------------------------------------------------------------------------- -// Samples the appropriate shadow map cascade -//------------------------------------------------------------------------------------------------- -float3 SampleShadowCascade(in float3 shadowPosition, in float3 shadowPosDX, - in float3 shadowPosDY, in uint cascadeIdx) -{ - shadowPosition += CascadeOffsets[cascadeIdx].xyz; - shadowPosition *= CascadeScales[cascadeIdx].xyz; - - shadowPosDX *= CascadeScales[cascadeIdx].xyz; - shadowPosDY *= CascadeScales[cascadeIdx].xyz; - - float3 cascadeColor = 1.0f; - - float shadow = SampleShadowMapEVSM(shadowPosition, shadowPosDX, shadowPosDY, cascadeIdx); - - return shadow * cascadeColor; -} - -//-------------------------------------------------------------------------------------- -// Computes the sun visibility term by performing the shadow test -//-------------------------------------------------------------------------------------- -float3 SunShadowVisibility(in float3 positionWS, in float depthVS) -{ - float3 shadowVisibility = 1.0f; - uint cascadeIdx = 0; - - // Project into shadow space - float3 samplePos = positionWS; - float3 shadowPosition = mul(float4(samplePos, 1.0f), ShadowMatrix).xyz; - float3 shadowPosDX = ddx(shadowPosition); - float3 shadowPosDY = ddy(shadowPosition); - - // Figure out which cascade to sample from - [unroll] - for(uint i = 0; i < NumCascades - 1; ++i) - { - [flatten] - if(depthVS > CascadeSplits[i]) - cascadeIdx = i + 1; - } - - shadowVisibility = SampleShadowCascade(shadowPosition, shadowPosDX, shadowPosDY, - cascadeIdx); - - return shadowVisibility; -} - -//------------------------------------------------------------------------------------------------- -// Computes the area light shadow visibility term -//------------------------------------------------------------------------------------------------- -float AreaLightShadowVisibility(in float3 positionWS) -{ - float3 shadowPos = positionWS - float3(AreaLightX, AreaLightY, AreaLightZ); - float3 shadowDistance = length(shadowPos); - float3 shadowDir = normalize(shadowPos); - - // Doing the max of the components tells us 2 things: which cubemap face we're going to use, - // and also what the projected distance is onto the major axis for that face. - float projectedDistance = max(max(abs(shadowPos.x), abs(shadowPos.y)), abs(shadowPos.z)); - - // Compute the project depth value that matches what would be stored in the depth buffer - // for the current cube map face. Note that we use a reversed infinite projection. - float nearClip = AreaLightSize; - float a = 0.0f; - float b = nearClip; - float z = projectedDistance * a + b; - float dbDistance = z / projectedDistance; - - return AreaLightShadowMap.SampleCmpLevelZero(PCFSampler, shadowDir, dbDistance + AreaLightShadowBias); -} - -//------------------------------------------------------------------------------------------------- -// Calculates the lighting result for an analytical light source -//------------------------------------------------------------------------------------------------- -float3 CalcLighting(in float3 normal, in float3 lightDir, in float3 lightColor, - in float3 diffuseAlbedo, in float3 specularAlbedo, in float roughness, - in float3 positionWS, inout float3 irradiance) -{ - float3 lighting = diffuseAlbedo * (1.0f / 3.14159f); - - float3 view = normalize(CameraPosWS - positionWS); - const float nDotL = saturate(dot(normal, lightDir)); - if(nDotL > 0.0f) - { - const float nDotV = saturate(dot(normal, view)); - float3 h = normalize(view + lightDir); - - float3 fresnel = Fresnel(specularAlbedo, h, lightDir); - - float specular = GGX_Specular(roughness, normal, h, view, lightDir); - lighting += specular * fresnel; - } - - irradiance += nDotL * lightColor; - return lighting * nDotL * lightColor; -} - -// ------------------------------------------------------------------------------------------------ -// Computes the irradiance for an SG light source using the selected approximation -// ------------------------------------------------------------------------------------------------ -float3 SGIrradiance(in SG lightingLobe, in float3 normal, in int diffuseMode) -{ - if(diffuseMode == SGDiffuseModes_Punctual) - return SGIrradiancePunctual(lightingLobe, normal); - else if(diffuseMode == SGDiffuseModes_Fitted) - return SGIrradianceFitted(lightingLobe, normal); - else - return SGIrradianceInnerProduct(lightingLobe, normal); -} - -// ------------------------------------------------------------------------------------------------ -// Computes the specular contribution from an SG light source -// ------------------------------------------------------------------------------------------------ -float3 SpecularTermSG(in SG light, in float3 normal, in float roughness, - in float3 view, in float3 specAlbedo) -{ - if(UseASGWarp) - return SpecularTermASGWarp(light, normal, roughness, view, specAlbedo); - else - return SpecularTermSGWarp(light, normal, roughness, view, specAlbedo); -} - -// ------------------------------------------------------------------------------------------------ -// Determine the exit radiance towards the eye from the SG's stored in the lightmap -// ------------------------------------------------------------------------------------------------ -void ComputeSGContribution(in Texture2DArray bakedLightingMap, in float2 lightMapUV, in float3 normalTS, - in float3 specularAlbedo, in float roughness, in float3 viewTS, in uint numSGs, - out float3 irradiance, out float3 specular) -{ - irradiance = 0.0f; - specular = 0.0f; - - for(uint i = 0; i < numSGs; ++i) - { - SG sg; - sg.Amplitude = bakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; - sg.Axis = SGDirections[i].xyz; - sg.Sharpness = SGSharpness; - - irradiance += SGIrradiance(sg, normalTS, SGDiffuseMode); - specular += SpecularTermSG(sg, normalTS, roughness, viewTS, specularAlbedo); - } -} - -SH9Color GetSHSpecularBRDF(in float3 viewTS, in float3x3 tangentToWorld, in float3 normalTS, - in float3 specularAlbedo, in float sqrtRoughness) -{ - // Make a local coordinate frame in tangent space, with the x-axis - // aligned with the view direction and the z-axis aligned with the normal - float3 zBasis = normalTS; - float3 yBasis = normalize(cross(zBasis, viewTS)); - float3 xBasis = normalize(cross(yBasis, zBasis)); - float3x3 localFrame = float3x3(xBasis, yBasis, zBasis); - float viewAngle = saturate(dot(normalTS, viewTS)); - - // Look up coefficients from the SH lookup texture to make the SH BRDF - SH9Color shBrdf = (SH9Color)0.0f; - - [unroll] - for(uint i = 0; i < 3; ++i) - { - float4 t0 = SHSpecularLookupA.SampleLevel(LinearSampler, float3(viewAngle, sqrtRoughness, specularAlbedo[i]), 0.0f); - float2 t1 = SHSpecularLookupB.SampleLevel(LinearSampler, float3(viewAngle, sqrtRoughness, specularAlbedo[i]), 0.0f); - shBrdf.c[0][i] = t0.x; - shBrdf.c[2][i] = t0.y; - shBrdf.c[3][i] = t0.z; - shBrdf.c[6][i] = t0.w; - shBrdf.c[7][i] = t1.x; - shBrdf.c[8][i] = t1.y; - } - - // Transform the SH BRDF to tangent space - return RotateSH9(shBrdf, localFrame); -} - -//================================================================================================= -// Pixel Shader -//================================================================================================= -PSOutput PS(in PSInput input) -{ - float3 vtxNormal = normalize(input.NormalWS); - float3 positionWS = input.PositionWS; - - float3 viewWS = normalize(CameraPosWS - positionWS); - - float3 normalWS = vtxNormal; - - float2 uv = input.TexCoord; - - float3 normalTS = float3(0, 0, 1); - float3 tangentWS = normalize(input.TangentWS); - float3 bitangentWS = normalize(input.BitangentWS); - float3x3 tangentToWorld = float3x3(tangentWS, bitangentWS, normalWS); - - if(EnableNormalMaps) - { - // Sample the normal map, and convert the normal to world space - normalTS.xy = NormalMap.Sample(AnisoSampler, uv).xy * 2.0f - 1.0f; - normalTS.z = sqrt(1.0f - saturate(normalTS.x * normalTS.x + normalTS.y * normalTS.y)); - normalTS = lerp(float3(0, 0, 1), normalTS, NormalMapIntensity); - normalWS = normalize(mul(normalTS, tangentToWorld)); - } - - float3 viewTS = mul(viewWS, transpose(tangentToWorld)); - - // Gather material parameters - float3 albedoMap = 1.0f; - - if(EnableAlbedoMaps) - albedoMap = AlbedoMap.Sample(AnisoSampler, uv).xyz; - - float metallic = saturate(MetallicMap.Sample(AnisoSampler, uv)); - float3 diffuseAlbedo = lerp(albedoMap.xyz, 0.0f, metallic) * DiffuseAlbedoScale * EnableDiffuse; - float3 specularAlbedo = lerp(0.03f, albedoMap.xyz, metallic) * EnableSpecular; - - float sqrtRoughness = RoughnessMap.Sample(AnisoSampler, uv); - sqrtRoughness *= RoughnessScale; - float roughness = sqrtRoughness * sqrtRoughness; - - float depthVS = input.DepthVS; - - // Add in the primary directional light - float3 lighting = 0.0f; - float3 irradiance = 0.0f; - - if(EnableDirectLighting && EnableSun) - { - float3 sunIrradiance = 0.0f; - float3 sunShadowVisibility = SunShadowVisibility(positionWS, depthVS); - float3 sunDirection = SunDirectionWS; - if(SunAreaLightApproximation) - { - float3 D = SunDirectionWS; - float3 R = reflect(-viewWS, normalWS); - float r = SinSunAngularRadius; - float d = CosSunAngularRadius; - float3 DDotR = dot(D, R); - float3 S = R - DDotR * D; - sunDirection = DDotR < d ? normalize(d * D + normalize(S) * r) : R; - } - lighting += CalcLighting(normalWS, sunDirection, SunIlluminance, diffuseAlbedo, specularAlbedo, - roughness, positionWS, sunIrradiance) * sunShadowVisibility; - irradiance += sunIrradiance * sunShadowVisibility; - } - - if(EnableDirectLighting && EnableAreaLight && BakeDirectAreaLight == false) - { - float3 areaLightPos = float3(AreaLightX, AreaLightY, AreaLightZ); - float3 areaLightDir = normalize(areaLightPos - positionWS); - float areaLightDist = length(areaLightPos - positionWS); - SG lightLobe = MakeSphereSG(areaLightDir, AreaLightSize, AreaLightColor * FP16Scale, areaLightDist); - float3 sgIrradiance = SGIrradiance(lightLobe, normalWS, SGDiffuseMode); - - float areaLightVisibility = 1.0f; - if(EnableAreaLightShadows) - areaLightVisibility = AreaLightShadowVisibility(positionWS); - - lighting += sgIrradiance * (diffuseAlbedo / Pi) * areaLightVisibility; - lighting += SpecularTermSG(lightLobe, normalWS, roughness, viewWS, specularAlbedo) * areaLightVisibility; - irradiance += sgIrradiance * areaLightVisibility; - } - - // Add in the indirect - if(EnableIndirectLighting || ViewIndirectSpecular) - { - float3 indirectIrradiance = 0.0f; - float3 indirectSpecular = 0.0f; - - if(BakeMode == BakeModes_Diffuse) - { - indirectIrradiance = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, 0.0f), 0.0f).xyz * Pi; - } - else if(BakeMode == BakeModes_HL2) - { - const float3 BasisDirs[3] = - { - float3(-1.0f / sqrt(6.0f), -1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), - float3(-1.0f / sqrt(6.0f), 1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), - float3(sqrt(2.0f / 3.0f), 0.0f, 1.0f / sqrt(3.0f)), - }; - - float weightSum = 0.0f; - - [unroll] - for(uint i = 0; i < 3; ++i) - { - float3 lightMap = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - indirectIrradiance += saturate(dot(normalTS, BasisDirs[i])) * lightMap; - } - } - else if(BakeMode == BakeModes_SH4) - { - SH4Color shRadiance; - - [unroll] - for(uint i = 0; i < 4; ++i) - shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - - indirectIrradiance = EvalSH4Irradiance(normalTS, shRadiance); - - SH4Color shSpecularBRDF = ConvertToSH4(GetSHSpecularBRDF(viewTS, tangentToWorld, normalTS, specularAlbedo, sqrtRoughness)); - indirectSpecular = SHDotProduct(shSpecularBRDF, shRadiance); - } - else if(BakeMode == BakeModes_SH9) - { - SH9Color shRadiance; - - [unroll] - for(uint i = 0; i < 9; ++i) - shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - - indirectIrradiance = EvalSH9Irradiance(normalTS, shRadiance); - - SH9Color shSpecularBRDF = GetSHSpecularBRDF(viewTS, tangentToWorld, normalTS, specularAlbedo, sqrtRoughness); - indirectSpecular = SHDotProduct(shSpecularBRDF, shRadiance); - } - else if(BakeMode == BakeModes_H4) - { - H4Color hbIrradiance; - - [unroll] - for(uint i = 0; i < 4; ++i) - hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - - indirectIrradiance = EvalH4(normalTS, hbIrradiance); - } - else if(BakeMode == BakeModes_H6) - { - H6Color hbIrradiance; - - [unroll] - for(uint i = 0; i < 6; ++i) - hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - - indirectIrradiance = EvalH6(normalTS, hbIrradiance); - } - else if(BakeMode == BakeModes_SG5) - { - ComputeSGContribution(BakedLightingMap, input.LightMapUV, normalTS, specularAlbedo, roughness, - viewTS, 5, indirectIrradiance, indirectSpecular); - } - else if(BakeMode == BakeModes_SG6) - { - ComputeSGContribution(BakedLightingMap, input.LightMapUV, normalTS, specularAlbedo, roughness, - viewTS, 6, indirectIrradiance, indirectSpecular); - } - else if(BakeMode == BakeModes_SG9) - { - ComputeSGContribution(BakedLightingMap, input.LightMapUV, normalTS, specularAlbedo, roughness, - viewTS, 9, indirectIrradiance, indirectSpecular); - } - else if(BakeMode == BakeModes_SG12) - { - ComputeSGContribution(BakedLightingMap, input.LightMapUV, normalTS, specularAlbedo, roughness, - viewTS, 12, indirectIrradiance, indirectSpecular); - } - - if(EnableIndirectDiffuse) - { - irradiance += indirectIrradiance; - lighting += indirectIrradiance * (diffuseAlbedo / Pi); - } - - if(EnableIndirectSpecular) - lighting += indirectSpecular; - - if(ViewIndirectSpecular) - lighting = indirectSpecular; - } - - float illuminance = dot(irradiance, float3(0.2126f, 0.7152f, 0.0722f)); - - PSOutput output; - output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); - - float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; - prevPositionSS *= RTSize; - output.Velocity = input.PositionSS.xy - prevPositionSS; - output.Velocity -= JitterOffset; - output.Velocity /= RTSize; - - return output; -} +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include +#include "EVSM.hlsl" +#include +#include "AppSettings.hlsl" +#include "SG.hlsl" + +//================================================================================================= +// Constants +//================================================================================================= +static const uint NumCascades = 4; + +//================================================================================================= +// Constant buffers +//================================================================================================= +cbuffer VSConstants : register(b0) +{ + float4x4 World; + float4x4 View; + float4x4 WorldViewProjection; + float4x4 PrevWorldViewProjection; +} + +cbuffer PSConstants : register(b0) +{ + float3 SunDirectionWS; + float CosSunAngularRadius; + float3 SunIlluminance; + float SinSunAngularRadius; + float3 CameraPosWS; + float4x4 ShadowMatrix; + float4 CascadeSplits; + float4 CascadeOffsets[NumCascades]; + float4 CascadeScales[NumCascades]; + float OffsetScale; + float PositiveExponent; + float NegativeExponent; + float LightBleedingReduction; + float2 RTSize; + float2 JitterOffset; + float4 SGDirections[MaxSGCount]; + float SGSharpness; +} + +//================================================================================================= +// Resources +//================================================================================================= +Texture2D AlbedoMap : register(t0); +Texture2D NormalMap : register(t1); +Texture2D RoughnessMap : register(t2); +Texture2D MetallicMap : register(t3); +Texture2DArray SunShadowMap : register(t4); +Texture2DArray BakedLightingMap : register(t5); +TextureCube AreaLightShadowMap : register(t6); +Texture3D SHSpecularLookupA : register(t7); +Texture3D SHSpecularLookupB : register(t8); + +SamplerState AnisoSampler : register(s0); +SamplerState EVSMSampler : register(s1); +SamplerState LinearSampler : register(s2); +SamplerComparisonState PCFSampler : register(s3); + +//================================================================================================= +// Input/Output structs +//================================================================================================= +struct VSInput +{ + float3 PositionOS : POSITION; + float3 NormalOS : NORMAL; + float2 TexCoord : TEXCOORD0; + float2 LightMapUV : TEXCOORD1; + float3 TangentOS : TANGENT; + float3 BitangentOS : BITANGENT; +}; + +struct VSOutput +{ + float4 PositionCS : SV_Position; + + float3 NormalWS : NORMALWS; + float3 PositionWS : POSITIONWS; + float DepthVS : DEPTHVS; + float3 TangentWS : TANGENTWS; + float3 BitangentWS : BITANGENTWS; + float2 TexCoord : TEXCOORD; + float2 LightMapUV : LIGHTMAPUV; + float3 PrevPosition : PREVPOSITION; +}; + +struct PSInput +{ + float4 PositionSS : SV_Position; + + float3 NormalWS : NORMALWS; + float3 PositionWS : POSITIONWS; + float DepthVS : DEPTHVS; + float3 TangentWS : TANGENTWS; + float3 BitangentWS : BITANGENTWS; + float2 TexCoord : TEXCOORD; + float2 LightMapUV : LIGHTMAPUV; + float3 PrevPosition : PREVPOSITION; +}; + +struct PSOutput +{ + float4 Lighting : SV_Target0; + float2 Velocity : SV_Target1; +}; + +//================================================================================================= +// Vertex Shader +//================================================================================================= +VSOutput VS(in VSInput input, in uint VertexID : SV_VertexID) +{ + VSOutput output; + + float3 positionOS = input.PositionOS; + + // Calc the world-space position + output.PositionWS = mul(float4(positionOS, 1.0f), World).xyz; + + // Calc the clip-space position + output.PositionCS = mul(float4(positionOS, 1.0f), WorldViewProjection); + output.DepthVS = output.PositionCS.w; + + + // Rotate the normal into world space + output.NormalWS = normalize(mul(input.NormalOS, (float3x3)World)); + + // Rotate the rest of the tangent frame into world space + output.TangentWS = normalize(mul(input.TangentOS, (float3x3)World)); + output.BitangentWS = normalize(mul(input.BitangentOS, (float3x3)World)); + + // Pass along the texture coordinates + output.TexCoord = input.TexCoord; + output.LightMapUV = input.LightMapUV; + + output.PrevPosition = mul(float4(input.PositionOS, 1.0f), PrevWorldViewProjection).xyw; + + return output; +} + +//------------------------------------------------------------------------------------------------- +// Samples the EVSM shadow map +//------------------------------------------------------------------------------------------------- +float SampleShadowMapEVSM(in float3 shadowPos, in float3 shadowPosDX, + in float3 shadowPosDY, uint cascadeIdx) +{ + float2 exponents = GetEVSMExponents(PositiveExponent, NegativeExponent, + CascadeScales[cascadeIdx].xyz); + float2 warpedDepth = WarpDepth(shadowPos.z, exponents); + + float4 occluder = SunShadowMap.SampleGrad(EVSMSampler, float3(shadowPos.xy, cascadeIdx), + shadowPosDX.xy, shadowPosDY.xy); + + // Derivative of warping at depth + float2 depthScale = 0.0001f * exponents * warpedDepth; + float2 minVariance = depthScale * depthScale; + + float posContrib = ChebyshevUpperBound(occluder.xz, warpedDepth.x, minVariance.x, LightBleedingReduction); + float negContrib = ChebyshevUpperBound(occluder.yw, warpedDepth.y, minVariance.y, LightBleedingReduction); + float shadowContrib = posContrib; + shadowContrib = min(shadowContrib, negContrib); + + return shadowContrib; +} + +//------------------------------------------------------------------------------------------------- +// Samples the appropriate shadow map cascade +//------------------------------------------------------------------------------------------------- +float3 SampleShadowCascade(in float3 shadowPosition, in float3 shadowPosDX, + in float3 shadowPosDY, in uint cascadeIdx) +{ + shadowPosition += CascadeOffsets[cascadeIdx].xyz; + shadowPosition *= CascadeScales[cascadeIdx].xyz; + + shadowPosDX *= CascadeScales[cascadeIdx].xyz; + shadowPosDY *= CascadeScales[cascadeIdx].xyz; + + float3 cascadeColor = 1.0f; + + float shadow = SampleShadowMapEVSM(shadowPosition, shadowPosDX, shadowPosDY, cascadeIdx); + + return shadow * cascadeColor; +} + +//-------------------------------------------------------------------------------------- +// Computes the sun visibility term by performing the shadow test +//-------------------------------------------------------------------------------------- +float3 SunShadowVisibility(in float3 positionWS, in float depthVS) +{ + float3 shadowVisibility = 1.0f; + uint cascadeIdx = 0; + + // Project into shadow space + float3 samplePos = positionWS; + float3 shadowPosition = mul(float4(samplePos, 1.0f), ShadowMatrix).xyz; + float3 shadowPosDX = ddx(shadowPosition); + float3 shadowPosDY = ddy(shadowPosition); + + // Figure out which cascade to sample from + [unroll] + for(uint i = 0; i < NumCascades - 1; ++i) + { + [flatten] + if(depthVS > CascadeSplits[i]) + cascadeIdx = i + 1; + } + + shadowVisibility = SampleShadowCascade(shadowPosition, shadowPosDX, shadowPosDY, + cascadeIdx); + + return shadowVisibility; +} + +//------------------------------------------------------------------------------------------------- +// Computes the area light shadow visibility term +//------------------------------------------------------------------------------------------------- +float AreaLightShadowVisibility(in float3 positionWS) +{ + float3 shadowPos = positionWS - float3(AreaLightX, AreaLightY, AreaLightZ); + float3 shadowDistance = length(shadowPos); + float3 shadowDir = normalize(shadowPos); + + // Doing the max of the components tells us 2 things: which cubemap face we're going to use, + // and also what the projected distance is onto the major axis for that face. + float projectedDistance = max(max(abs(shadowPos.x), abs(shadowPos.y)), abs(shadowPos.z)); + + // Compute the project depth value that matches what would be stored in the depth buffer + // for the current cube map face. Note that we use a reversed infinite projection. + float nearClip = AreaLightSize; + float a = 0.0f; + float b = nearClip; + float z = projectedDistance * a + b; + float dbDistance = z / projectedDistance; + + return AreaLightShadowMap.SampleCmpLevelZero(PCFSampler, shadowDir, dbDistance + AreaLightShadowBias); +} + +//------------------------------------------------------------------------------------------------- +// Calculates the lighting result for an analytical light source +//------------------------------------------------------------------------------------------------- +float3 CalcLighting(in float3 normal, in float3 lightDir, in float3 lightColor, + in float3 diffuseAlbedo, in float3 specularAlbedo, in float roughness, + in float3 positionWS, inout float3 irradiance) +{ + float3 lighting = diffuseAlbedo * (1.0f / 3.14159f); + + float3 view = normalize(CameraPosWS - positionWS); + const float nDotL = saturate(dot(normal, lightDir)); + if(nDotL > 0.0f) + { + const float nDotV = saturate(dot(normal, view)); + float3 h = normalize(view + lightDir); + + float3 fresnel = Fresnel(specularAlbedo, h, lightDir); + + float specular = GGX_Specular(roughness, normal, h, view, lightDir); + lighting += specular * fresnel; + } + + irradiance += nDotL * lightColor; + return lighting * nDotL * lightColor; +} + +// ------------------------------------------------------------------------------------------------ +// Computes the irradiance for an SG light source using the selected approximation +// ------------------------------------------------------------------------------------------------ +float3 SGIrradiance(in SG lightingLobe, in float3 normal, in int diffuseMode) +{ + if(diffuseMode == SGDiffuseModes_Punctual) + return SGIrradiancePunctual(lightingLobe, normal); + else if(diffuseMode == SGDiffuseModes_Fitted) + return SGIrradianceFitted(lightingLobe, normal); + else + return SGIrradianceInnerProduct(lightingLobe, normal); +} + +// ------------------------------------------------------------------------------------------------ +// Computes the specular contribution from an SG light source +// ------------------------------------------------------------------------------------------------ +float3 SpecularTermSG(in SG light, in float3 normal, in float roughness, + in float3 view, in float3 specAlbedo) +{ + if(UseASGWarp) + return SpecularTermASGWarp(light, normal, roughness, view, specAlbedo); + else + return SpecularTermSGWarp(light, normal, roughness, view, specAlbedo); +} + +// ------------------------------------------------------------------------------------------------ +// Determine the exit radiance towards the eye from the SG's stored in the lightmap +// ------------------------------------------------------------------------------------------------ +void ComputeSGContribution(in Texture2DArray bakedLightingMap, in float2 lightMapUV, in float3 normalTS, + in float3 specularAlbedo, in float roughness, in float3 viewTS, in uint numSGs, + out float3 irradiance, out float3 specular) +{ + irradiance = 0.0f; + specular = 0.0f; + + for(uint i = 0; i < numSGs; ++i) + { + SG sg; + sg.Amplitude = bakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + sg.Axis = SGDirections[i].xyz; + sg.Sharpness = SGSharpness; + + irradiance += SGIrradiance(sg, normalTS, SGDiffuseMode); + specular += SpecularTermSG(sg, normalTS, roughness, viewTS, specularAlbedo); + } +} + +SH9Color GetSHSpecularBRDF(in float3 viewTS, in float3x3 tangentToWorld, in float3 normalTS, + in float3 specularAlbedo, in float sqrtRoughness) +{ + // Make a local coordinate frame in tangent space, with the x-axis + // aligned with the view direction and the z-axis aligned with the normal + float3 zBasis = normalTS; + float3 yBasis = normalize(cross(zBasis, viewTS)); + float3 xBasis = normalize(cross(yBasis, zBasis)); + float3x3 localFrame = float3x3(xBasis, yBasis, zBasis); + float viewAngle = saturate(dot(normalTS, viewTS)); + + // Look up coefficients from the SH lookup texture to make the SH BRDF + SH9Color shBrdf = (SH9Color)0.0f; + + [unroll] + for(uint i = 0; i < 3; ++i) + { + float4 t0 = SHSpecularLookupA.SampleLevel(LinearSampler, float3(viewAngle, sqrtRoughness, specularAlbedo[i]), 0.0f); + float2 t1 = SHSpecularLookupB.SampleLevel(LinearSampler, float3(viewAngle, sqrtRoughness, specularAlbedo[i]), 0.0f); + shBrdf.c[0][i] = t0.x; + shBrdf.c[2][i] = t0.y; + shBrdf.c[3][i] = t0.z; + shBrdf.c[6][i] = t0.w; + shBrdf.c[7][i] = t1.x; + shBrdf.c[8][i] = t1.y; + } + + // Transform the SH BRDF to tangent space + return RotateSH9(shBrdf, localFrame); +} + +struct SurfaceContext +{ + float3 ViewWS; + float3x3 TangentToWorld; + float3 NormalTS; + float3 NormalWS; + float3 VtxNormalWS; + float3 PositionWS; + float3 DiffuseAlbedo; + float3 SpecularAlbedo; + float SqrtRoughness; + float Roughness; +}; + +void ComputeIndirectFromLightmap(in SurfaceContext surface, in float2 lightMapUV, + out float3 indirectIrradiance, out float3 indirectSpecular) +{ + indirectIrradiance = 0.0f; + indirectSpecular = 0.0f; + + float3 viewTS = mul(surface.ViewWS, transpose(surface.TangentToWorld)); + + if(BakeMode == BakeModes_Diffuse) + { + indirectIrradiance = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, 0.0f), 0.0f).xyz * Pi; + } + else if(BakeMode == BakeModes_HL2) + { + const float3 BasisDirs[3] = + { + float3(-1.0f / sqrt(6.0f), -1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), + float3(-1.0f / sqrt(6.0f), 1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), + float3(sqrt(2.0f / 3.0f), 0.0f, 1.0f / sqrt(3.0f)), + }; + + float weightSum = 0.0f; + + [unroll] + for(uint i = 0; i < 3; ++i) + { + float3 lightMap = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + indirectIrradiance += saturate(dot(surface.NormalTS, BasisDirs[i])) * lightMap; + } + } + else if(BakeMode == BakeModes_SH4) + { + SH4Color shRadiance; + + [unroll] + for(uint i = 0; i < 4; ++i) + shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + + indirectIrradiance = EvalSH4Irradiance(surface.NormalTS, shRadiance); + + SH4Color shSpecularBRDF = ConvertToSH4(GetSHSpecularBRDF(viewTS, surface.TangentToWorld, surface.NormalTS, surface.SpecularAlbedo, surface.SqrtRoughness)); + indirectSpecular = SHDotProduct(shSpecularBRDF, shRadiance); + } + else if(BakeMode == BakeModes_SH9) + { + SH9Color shRadiance; + + [unroll] + for(uint i = 0; i < 9; ++i) + shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + + indirectIrradiance = EvalSH9Irradiance(surface.NormalTS, shRadiance); + + SH9Color shSpecularBRDF = GetSHSpecularBRDF(viewTS, surface.TangentToWorld, surface.NormalTS, surface.SpecularAlbedo, surface.SqrtRoughness); + indirectSpecular = SHDotProduct(shSpecularBRDF, shRadiance); + } + else if(BakeMode == BakeModes_H4) + { + H4Color hbIrradiance; + + [unroll] + for(uint i = 0; i < 4; ++i) + hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + + indirectIrradiance = EvalH4(surface.NormalTS, hbIrradiance); + } + else if(BakeMode == BakeModes_H6) + { + H6Color hbIrradiance; + + [unroll] + for(uint i = 0; i < 6; ++i) + hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + + indirectIrradiance = EvalH6(surface.NormalTS, hbIrradiance); + } + else if(BakeMode == BakeModes_SG5) + { + ComputeSGContribution(BakedLightingMap, lightMapUV, surface.NormalTS, surface.SpecularAlbedo, surface.Roughness, + viewTS, 5, indirectIrradiance, indirectSpecular); + } + else if(BakeMode == BakeModes_SG6) + { + ComputeSGContribution(BakedLightingMap, lightMapUV, surface.NormalTS, surface.SpecularAlbedo, surface.Roughness, + viewTS, 6, indirectIrradiance, indirectSpecular); + } + else if(BakeMode == BakeModes_SG9) + { + ComputeSGContribution(BakedLightingMap, lightMapUV, surface.NormalTS, surface.SpecularAlbedo, surface.Roughness, + viewTS, 9, indirectIrradiance, indirectSpecular); + } + else if(BakeMode == BakeModes_SG12) + { + ComputeSGContribution(BakedLightingMap, lightMapUV, surface.NormalTS, surface.SpecularAlbedo, surface.Roughness, + viewTS, 12, indirectIrradiance, indirectSpecular); + } +} + +//================================================================================================= +// Pixel Shader +//================================================================================================= +PSOutput PS(in PSInput input) +{ + SurfaceContext surface; + surface.VtxNormalWS = normalize(input.NormalWS); + surface.NormalWS = surface.VtxNormalWS; + surface.PositionWS = input.PositionWS; + surface.ViewWS = normalize(CameraPosWS - surface.PositionWS); + + float2 uv = input.TexCoord; + + float3 normalTS = float3(0, 0, 1); + float3 tangentWS = normalize(input.TangentWS); + float3 bitangentWS = normalize(input.BitangentWS); + float3x3 tangentToWorld = float3x3(tangentWS, bitangentWS, surface.VtxNormalWS); + + if(EnableNormalMaps) + { + // Sample the normal map, and convert the normal to world space + normalTS.xy = NormalMap.Sample(AnisoSampler, uv).xy * 2.0f - 1.0f; + normalTS.z = sqrt(1.0f - saturate(normalTS.x * normalTS.x + normalTS.y * normalTS.y)); + normalTS = lerp(float3(0, 0, 1), normalTS, NormalMapIntensity); + surface.NormalWS = normalize(mul(normalTS, tangentToWorld)); + } + + surface.NormalTS = normalTS; + surface.TangentToWorld = tangentToWorld; + + // Gather material parameters + float3 albedoMap = 1.0f; + + if(EnableAlbedoMaps) + albedoMap = AlbedoMap.Sample(AnisoSampler, uv).xyz; + + float metallic = saturate(MetallicMap.Sample(AnisoSampler, uv)); + surface.DiffuseAlbedo = lerp(albedoMap.xyz, 0.0f, metallic) * DiffuseAlbedoScale * EnableDiffuse; + surface.SpecularAlbedo = lerp(0.03f, albedoMap.xyz, metallic) * EnableSpecular; + + surface.SqrtRoughness = RoughnessMap.Sample(AnisoSampler, uv); + surface.SqrtRoughness *= RoughnessScale; + surface.Roughness = surface.SqrtRoughness * surface.SqrtRoughness; + + float depthVS = input.DepthVS; + + // Add in the primary directional light + float3 lighting = 0.0f; + float3 irradiance = 0.0f; + + if(EnableDirectLighting && EnableSun) + { + float3 sunIrradiance = 0.0f; + float3 sunShadowVisibility = SunShadowVisibility(surface.PositionWS, depthVS); + float3 sunDirection = SunDirectionWS; + if(SunAreaLightApproximation) + { + float3 D = SunDirectionWS; + float3 R = reflect(-surface.ViewWS, surface.NormalWS); + float r = SinSunAngularRadius; + float d = CosSunAngularRadius; + float3 DDotR = dot(D, R); + float3 S = R - DDotR * D; + sunDirection = DDotR < d ? normalize(d * D + normalize(S) * r) : R; + } + lighting += CalcLighting(surface.NormalWS, sunDirection, SunIlluminance, surface.DiffuseAlbedo, surface.SpecularAlbedo, + surface.Roughness, surface.PositionWS, sunIrradiance) * sunShadowVisibility; + irradiance += sunIrradiance * sunShadowVisibility; + } + + if(EnableDirectLighting && EnableAreaLight && BakeDirectAreaLight == false) + { + float3 areaLightPos = float3(AreaLightX, AreaLightY, AreaLightZ); + float3 areaLightDir = normalize(areaLightPos - surface.PositionWS); + float areaLightDist = length(areaLightPos - surface.PositionWS); + SG lightLobe = MakeSphereSG(areaLightDir, AreaLightSize, AreaLightColor * FP16Scale, areaLightDist); + float3 sgIrradiance = SGIrradiance(lightLobe, surface.NormalWS, SGDiffuseMode); + + float areaLightVisibility = 1.0f; + if(EnableAreaLightShadows) + areaLightVisibility = AreaLightShadowVisibility(surface.PositionWS); + + lighting += sgIrradiance * (surface.DiffuseAlbedo / Pi) * areaLightVisibility; + lighting += SpecularTermSG(lightLobe, surface.NormalWS, surface.Roughness, surface.ViewWS, surface.SpecularAlbedo) * areaLightVisibility; + irradiance += sgIrradiance * areaLightVisibility; + } + + // Add in the indirect + if(EnableIndirectLighting || ViewIndirectSpecular) + { + float3 indirectIrradiance = 0.0f; + float3 indirectSpecular = 0.0f; + + ComputeIndirectFromLightmap(surface, input.LightMapUV, indirectIrradiance, indirectSpecular); + + if(EnableIndirectDiffuse) + { + irradiance += indirectIrradiance; + lighting += indirectIrradiance * (surface.DiffuseAlbedo / Pi); + } + + if(EnableIndirectSpecular) + lighting += indirectSpecular; + + if(ViewIndirectSpecular) + lighting = indirectSpecular; + } + + float illuminance = dot(irradiance, float3(0.2126f, 0.7152f, 0.0722f)); + + PSOutput output; + output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); + + float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; + prevPositionSS *= RTSize; + output.Velocity = input.PositionSS.xy - prevPositionSS; + output.Velocity -= JitterOffset; + output.Velocity /= RTSize; + + return output; +} From 7f76edd0c80e484230dd03a0c6e6286a3c69018c Mon Sep 17 00:00:00 2001 From: MJP Date: Thu, 28 Sep 2017 00:42:42 -0700 Subject: [PATCH 03/43] Implemented very basic irradiance probe capture + integration --- BakingLab/BakingLab.cpp | 179 +- BakingLab/BakingLab.h | 236 +- BakingLab/Mesh.hlsl | 9 +- BakingLab/MeshBaker.h | 333 +-- BakingLab/MeshRenderer.cpp | 2119 +++++++++-------- BakingLab/MeshRenderer.h | 400 ++-- BakingLab/ProbeIntegrate.hlsl | 177 ++ .../v1.02/Graphics/GraphicsTypes.cpp | 1262 +++++----- 8 files changed, 2520 insertions(+), 2195 deletions(-) create mode 100644 BakingLab/ProbeIntegrate.hlsl diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index eaf6f80..4f8c46e 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -419,6 +419,29 @@ void BakingLab::Initialize() sceneModels[i].CreateFromMeshData(device, ScenePaths[i], true); else sceneModels[i].CreateWithAssimp(device, ScenePaths[i], true); + + // Compute the scene AABB + sceneMins[i] = FLT_MAX; + sceneMaxes[i] = -FLT_MAX; + + const uint64 numMeshes = sceneModels[i].Meshes().size(); + for(uint64 meshIdx = 0; meshIdx < numMeshes; ++meshIdx) + { + const Mesh& mesh = sceneModels[i].Meshes()[meshIdx]; + const uint8* vertices = mesh.Vertices(); + const uint64 numVertices = mesh.NumVertices(); + const uint64 stride = mesh.VertexStride(); + for(uint64 vtxIdx = 0; vtxIdx < numVertices; ++vtxIdx) + { + const Float3& vtx = *(const Float3*)(vertices + vtxIdx * stride); + sceneMins[i].x = Min(sceneMins[i].x, vtx.x); + sceneMins[i].y = Min(sceneMins[i].y, vtx.y); + sceneMins[i].z = Min(sceneMins[i].z, vtx.z); + sceneMaxes[i].x = Max(sceneMaxes[i].x, vtx.x); + sceneMaxes[i].y = Max(sceneMaxes[i].y, vtx.y); + sceneMaxes[i].z = Max(sceneMaxes[i].z, vtx.z); + } + } } Model& currentModel = sceneModels[AppSettings::CurrentScene.Value()]; @@ -444,8 +467,11 @@ void BakingLab::Initialize() backgroundVelocityVS = CompileVSFromFile(device, L"BackgroundVelocity.hlsl", "BackgroundVelocityVS"); backgroundVelocityPS = CompilePSFromFile(device, L"BackgroundVelocity.hlsl", "BackgroundVelocityPS"); + probeIntegrateIrradiance = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateIrradiance"); + resolveConstants.Initialize(device); backgroundVelocityConstants.Initialize(device); + integrateConstants.Initialize(device); // Init the post processor postProcessor.Initialize(device); @@ -585,6 +611,99 @@ void BakingLab::Update(const Timer& timer) meshRenderer.Update(camera, jitterOffset); } +void BakingLab::RenderProbes() +{ + PIXEvent pixEvent(L"Render Probes"); + + ID3D11DeviceContextPtr context = deviceManager.ImmediateContext(); + ID3D11DevicePtr device = deviceManager.Device(); + + const uint64 currSceneIdx = AppSettings::CurrentScene; + const uint32 numProbes = AppSettings::ProbeResX * AppSettings::ProbeResY * AppSettings::ProbeResZ; + + if(probeCaptureMap.Width == 0) + { + currProbeIdx = 0; + probeCaptureMap.Initialize(device, 256, 256, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, false, 6, true); + probeVelocityTarget.Initialize(device, 256, 256, DXGI_FORMAT_R16G16_FLOAT); + probeDepthBuffer.Initialize(device, 256, 256, DXGI_FORMAT_D24_UNORM_S8_UINT, true); + } + + if(AppSettings::ProbeResX.Changed() || AppSettings::ProbeResY.Changed() || + AppSettings::ProbeResZ.Changed() || probeIrradianceMap.ArraySize == 0) + { + currProbeIdx = 0; + probeIrradianceMap.Initialize(device, 16, 16, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); + } + + if(currProbeIdx >= numProbes) + return; + + bool32 prevUseProbes = AppSettings::UseProbes; + AppSettings::UseProbes.SetValue(false); + + uint64 probeX = currProbeIdx % AppSettings::ProbeResX; + uint64 probeY = (currProbeIdx / AppSettings::ProbeResX) % AppSettings::ProbeResY; + uint64 probeZ = currProbeIdx / (AppSettings::ProbeResX * AppSettings::ProbeResY); + + Float3 probePos; + probePos.x = Lerp(sceneMins[currSceneIdx].x, sceneMaxes[currSceneIdx].x, (probeX + 0.5f) / AppSettings::ProbeResX); + probePos.y = Lerp(sceneMins[currSceneIdx].y, sceneMaxes[currSceneIdx].y, (probeY + 0.5f) / AppSettings::ProbeResY); + probePos.z = Lerp(sceneMins[currSceneIdx].z, sceneMaxes[currSceneIdx].z, (probeZ + 0.5f) / AppSettings::ProbeResZ); + + PerspectiveCamera probeCam(1.0f, Pi_2, NearClip, FarClip); + probeCam.SetPosition(probePos); + + MeshBakerStatus status; + + for(uint64 i = 0; i < 6; ++i) + { + Quaternion orientation; + if(i == 0) + orientation = Quaternion::FromAxisAngle(Float3(0.0f, 1.0f, 0.0f), Pi_2); + else if(i == 1) + orientation = Quaternion::FromAxisAngle(Float3(0.0f, 1.0f, 0.0f), -Pi_2); + else if(i == 2) + orientation = Quaternion::FromAxisAngle(Float3(1.0f, 0.0f, 0.0f), -Pi_2); + else if(i == 3) + orientation = Quaternion::FromAxisAngle(Float3(1.0f, 0.0f, 0.0f), Pi_2); + else if(i == 4) + orientation = Quaternion(); + else + orientation = Quaternion::FromAxisAngle(Float3(0.0f, 1.0f, 0.0f), Pi); + + probeCam.SetOrientation(orientation); + RenderScene(status, probeCaptureMap.RTVArraySlices[i], probeVelocityTarget.RTView, probeDepthBuffer, probeCam, + false, AppSettings::BakeDirectAreaLight); + } + + AppSettings::UseProbes.SetValue(prevUseProbes); + + ID3D11RenderTargetView* rtvs[2] = { }; + context->OMSetRenderTargets(2, rtvs, nullptr); + + SetCSInputs(context, probeCaptureMap.SRView); + SetCSOutputs(context, probeIrradianceMap.UAView); + SetCSSamplers(context, samplerStates.LinearClamp()); + SetCSShader(context, probeIntegrateIrradiance); + + integrateConstants.Data.OutputTextureSize.x = float(probeIrradianceMap.Width); + integrateConstants.Data.OutputTextureSize.y = float(probeIrradianceMap.Height); + integrateConstants.Data.OutputSliceOffset = uint32(currProbeIdx * 6); + integrateConstants.ApplyChanges(context); + integrateConstants.SetCS(context, 0); + + context->Dispatch(DispatchSize(8, probeIrradianceMap.Width), DispatchSize(8, probeIrradianceMap.Height), 6); + + ClearCSInputs(context); + ClearCSOutputs(context); + + ++currProbeIdx; + + /*if(currProbeIdx == numProbes) + currProbeIdx = 0;*/ +} + void BakingLab::Render(const Timer& timer) { if(AppSettings::MSAAMode.Changed()) @@ -595,6 +714,8 @@ void BakingLab::Render(const Timer& timer) MeshBakerStatus status = meshBaker.Update(unJitteredCamera, colorTargetMSAA.Width, colorTargetMSAA.Height, context, &sceneModels[AppSettings::CurrentScene]); + RenderProbes(); + if(AppSettings::ShowGroundTruth) { ID3D11RenderTargetView* rtvs[1] = { colorTargetMSAA.RTView }; @@ -614,7 +735,9 @@ void BakingLab::Render(const Timer& timer) } else { - RenderMainPass(status); + status.ProbeIrradiance = probeIrradianceMap.SRView; + RenderScene(status, colorTargetMSAA.RTView, velocityTargetMSAA.RTView, depthBuffer, camera, + AppSettings::ShowBakeDataVisualizer, AppSettings::EnableAreaLight); RenderBackgroundVelocity(); } @@ -640,65 +763,67 @@ void BakingLab::Render(const Timer& timer) ++frameCount; } -void BakingLab::RenderMainPass(const MeshBakerStatus& status) +void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, + const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 renderAreaLight) { - PIXEvent event(L"Main Pass"); + PIXEvent event(L"Render Scene"); ID3D11DeviceContextPtr context = deviceManager.ImmediateContext(); ID3D11RenderTargetView* renderTargets[2] = { nullptr, nullptr }; - ID3D11DepthStencilView* ds = depthBuffer.DSView; - context->OMSetRenderTargets(1, renderTargets, ds); + ID3D11DepthStencilView* dsv = depth.DSView; + context->OMSetRenderTargets(1, renderTargets, dsv); - SetViewport(context, colorTargetMSAA.Width, colorTargetMSAA.Height); + SetViewport(context, depth.Width, depth.Height); - float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - context->ClearRenderTargetView(colorTargetMSAA.RTView, clearColor); - context->ClearRenderTargetView(velocityTargetMSAA.RTView, clearColor); - context->ClearDepthStencilView(ds, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); + context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); - meshRenderer.RenderDepth(context, camera, false, false); + meshRenderer.RenderDepth(context, cam, false, false); - meshRenderer.ReduceDepth(context, depthBuffer, camera); + meshRenderer.ReduceDepth(context, depth, cam); if(AppSettings::EnableSun) - meshRenderer.RenderSunShadowMap(context, camera); + meshRenderer.RenderSunShadowMap(context, cam); if(AppSettings::EnableAreaLight) - meshRenderer.RenderAreaLightShadowMap(context, camera); + meshRenderer.RenderAreaLightShadowMap(context, cam); - renderTargets[0] = colorTargetMSAA.RTView; - renderTargets[1] = velocityTargetMSAA.RTView; - context->OMSetRenderTargets(2, renderTargets, ds); - SetViewport(context, colorTargetMSAA.Width, colorTargetMSAA.Height); + renderTargets[0] = colorTarget; + renderTargets[1] = velocityTarget; + context->OMSetRenderTargets(2, renderTargets, dsv); + SetViewport(context, depth.Width, depth.Height); - meshRenderer.RenderMainPass(context, camera, status); + float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + context->ClearRenderTargetView(colorTarget, clearColor); + context->ClearRenderTargetView(velocityTarget, clearColor); - if(AppSettings::ShowBakeDataVisualizer) - meshRenderer.RenderBakeDataVisualizer(context, camera, status); + meshRenderer.RenderMainPass(context, cam, status); - if(AppSettings::EnableAreaLight) - meshRenderer.RenderAreaLight(context, camera); + if(showBakeDataVisualizer) + meshRenderer.RenderBakeDataVisualizer(context, cam, status); + + if(renderAreaLight) + meshRenderer.RenderAreaLight(context, cam); if(AppSettings::SkyMode == SkyModes::Procedural) { float sunSize = AppSettings::EnableSun ? AppSettings::SunSize : 0.0f; skybox.RenderSky(context, AppSettings::SunDirection, AppSettings::GroundAlbedo, AppSettings::SunLuminance(), sunSize, - AppSettings::Turbidity, camera.ViewMatrix(), - camera.ProjectionMatrix(), 1.0f); + AppSettings::Turbidity, cam.ViewMatrix(), + cam.ProjectionMatrix(), 1.0f); } else if(AppSettings::SkyMode == SkyModes::Simple) { float sunSize = AppSettings::EnableSun ? AppSettings::SunSize : 0.0f; skybox.RenderSimpleSky(context, AppSettings::SkyColor, AppSettings::SunDirection, AppSettings::SunLuminance(), sunSize, - camera.ViewMatrix(), camera.ProjectionMatrix(), FP16Scale); + cam.ViewMatrix(), cam.ProjectionMatrix(), FP16Scale); } else if(AppSettings::SkyMode >= AppSettings::CubeMapStart) { skybox.RenderEnvironmentMap(context, envMaps[AppSettings::SkyMode - AppSettings::CubeMapStart], - camera.ViewMatrix(), camera.ProjectionMatrix(), 1.0f); + cam.ViewMatrix(), cam.ProjectionMatrix(), 1.0f); } } diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index 5ed1084..93d3be8 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -1,108 +1,128 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "PostProcessor.h" -#include "MeshRenderer.h" -#include "MeshBaker.h" - -using namespace SampleFramework11; - -class BakingLab : public App -{ - -protected: - - FirstPersonCamera camera; - - SpriteFont font; - SampleFramework11::SpriteRenderer spriteRenderer; - Skybox skybox; - ID3D11ShaderResourceViewPtr envMaps[AppSettings::NumCubeMaps]; - - PostProcessor postProcessor; - DepthStencilBuffer depthBuffer; - RenderTarget2D colorTargetMSAA; - RenderTarget2D colorResolveTarget; - RenderTarget2D prevFrameTarget; - RenderTarget2D velocityTargetMSAA; - StagingTexture2D readbackTexture; - - // Model - Model sceneModels[uint64(Scenes::NumValues)]; - MeshRenderer meshRenderer; - MeshBaker meshBaker; - - MouseState mouseState; - - float GTSampleRateBuffer[64]; - uint64 GTSampleRateBufferIdx = 0; - - VertexShaderPtr resolveVS; - PixelShaderPtr resolvePS[uint64(MSAAModes::NumValues)]; - - VertexShaderPtr backgroundVelocityVS; - PixelShaderPtr backgroundVelocityPS; - Float4x4 prevViewProjection; - - Float2 jitterOffset; - Float2 prevJitter; - uint64 frameCount = 0; - FirstPersonCamera unJitteredCamera; - - struct ResolveConstants - { - uint32 SampleRadius; - bool32 EnableTemporalAA; - Float2 TextureSize; - }; - - struct BackgroundVelocityConstants - { - Float4x4 InvViewProjection; - Float4x4 PrevViewProjection; - Float2 RTSize; - Float2 JitterOffset; - }; - - ConstantBuffer resolveConstants; - ConstantBuffer backgroundVelocityConstants; - - virtual void Initialize() override; - virtual void Render(const Timer& timer) override; - virtual void Update(const Timer& timer) override; - virtual void BeforeReset() override; - virtual void AfterReset() override; - - void CreateRenderTargets(); - - void RenderMainPass(const MeshBakerStatus& status); - void RenderAA(); - void RenderBackgroundVelocity(); - void RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, - uint64 groundTruthSampleCount); - -public: - - BakingLab(); -}; +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PostProcessor.h" +#include "MeshRenderer.h" +#include "MeshBaker.h" + +using namespace SampleFramework11; + +class BakingLab : public App +{ + +protected: + + FirstPersonCamera camera; + + SpriteFont font; + SampleFramework11::SpriteRenderer spriteRenderer; + Skybox skybox; + ID3D11ShaderResourceViewPtr envMaps[AppSettings::NumCubeMaps]; + + PostProcessor postProcessor; + DepthStencilBuffer depthBuffer; + RenderTarget2D colorTargetMSAA; + RenderTarget2D colorResolveTarget; + RenderTarget2D prevFrameTarget; + RenderTarget2D velocityTargetMSAA; + StagingTexture2D readbackTexture; + + // Model + Model sceneModels[uint64(Scenes::NumValues)]; + Float3 sceneMins[uint64(Scenes::NumValues)]; + Float3 sceneMaxes[uint64(Scenes::NumValues)]; + MeshRenderer meshRenderer; + MeshBaker meshBaker; + + MouseState mouseState; + + float GTSampleRateBuffer[64]; + uint64 GTSampleRateBufferIdx = 0; + + VertexShaderPtr resolveVS; + PixelShaderPtr resolvePS[uint64(MSAAModes::NumValues)]; + + VertexShaderPtr backgroundVelocityVS; + PixelShaderPtr backgroundVelocityPS; + Float4x4 prevViewProjection; + + Float2 jitterOffset; + Float2 prevJitter; + uint64 frameCount = 0; + FirstPersonCamera unJitteredCamera; + + RenderTarget2D probeCaptureMap; + RenderTarget2D probeVelocityTarget; + RenderTarget2D probeIrradianceMap; + DepthStencilBuffer probeDepthBuffer; + + uint64 currProbeIdx = 0; + + ComputeShaderPtr probeIntegrateIrradiance; + + struct ResolveConstants + { + uint32 SampleRadius; + bool32 EnableTemporalAA; + Float2 TextureSize; + }; + + struct BackgroundVelocityConstants + { + Float4x4 InvViewProjection; + Float4x4 PrevViewProjection; + Float2 RTSize; + Float2 JitterOffset; + }; + + struct IntegrateConstants + { + Float2 OutputTextureSize; + uint32 OutputSliceOffset; + }; + + ConstantBuffer resolveConstants; + ConstantBuffer backgroundVelocityConstants; + ConstantBuffer integrateConstants; + + virtual void Initialize() override; + virtual void Render(const Timer& timer) override; + virtual void Update(const Timer& timer) override; + virtual void BeforeReset() override; + virtual void AfterReset() override; + + void CreateRenderTargets(); + + void RenderProbes(); + void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, + const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 renderAreaLight); + void RenderAA(); + void RenderBackgroundVelocity(); + void RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, + uint64 groundTruthSampleCount); + +public: + + BakingLab(); +}; diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index b7e5283..9decd63 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -66,6 +66,7 @@ Texture2DArray BakedLightingMap : register(t5); TextureCube AreaLightShadowMap : register(t6); Texture3D SHSpecularLookupA : register(t7); Texture3D SHSpecularLookupB : register(t8); +TextureCubeArray ProbeIrradiance : register(t9); SamplerState AnisoSampler : register(s0); SamplerState EVSMSampler : register(s1); @@ -558,7 +559,13 @@ PSOutput PS(in PSInput input) float3 indirectIrradiance = 0.0f; float3 indirectSpecular = 0.0f; - ComputeIndirectFromLightmap(surface, input.LightMapUV, indirectIrradiance, indirectSpecular); + if(UseProbes) + { + float probeIdx = 0.0f; + indirectIrradiance = ProbeIrradiance.Sample(LinearSampler, float4(surface.NormalWS, probeIdx)).xyz; + } + else + ComputeIndirectFromLightmap(surface, input.LightMapUV, indirectIrradiance, indirectSpecular); if(EnableIndirectDiffuse) { diff --git a/BakingLab/MeshBaker.h b/BakingLab/MeshBaker.h index fade745..c18a325 100644 --- a/BakingLab/MeshBaker.h +++ b/BakingLab/MeshBaker.h @@ -1,167 +1,168 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "PathTracer.h" -#include "SharedConstants.h" -#include "AppSettings.h" - -namespace SampleFramework11 -{ - class Model; - class Camera; - struct StructuredBuffer; -} - -using namespace SampleFramework11; - -struct RenderThreadContext; -struct RenderThreadData; -struct IntegrationSamples; -struct BakeThreadData; -struct GutterTexel; -struct Vertex; - -// Input to the baker -struct BakeInputData -{ - const Model* SceneModel = nullptr; - ID3D11Device* Device = nullptr; - ID3D11ShaderResourceView* EnvMaps[AppSettings::NumCubeMaps]; - TextureData EnvMapData[AppSettings::NumCubeMaps]; - - BakeInputData() - { - for(uint64 i = 0; i < ArraySize_(EnvMaps); ++i) - EnvMaps[i] = nullptr; - } -}; - -struct MeshBakerStatus -{ - ID3D11ShaderResourceView* GroundTruth = nullptr; - ID3D11ShaderResourceView* LightMap = nullptr; - ID3D11ShaderResourceView* BakePoints = nullptr; - uint64 NumBakePoints = 0; - float GroundTruthProgress = 0.0f; - float BakeProgress = 0.0f; - uint64 GroundTruthSampleCount = 0; - Float3 SGDirections[AppSettings::MaxSGCount]; - float SGSharpness = 0.0f; -}; - -class MeshBaker -{ - -public: - - MeshBaker(); - ~MeshBaker(); - - void Initialize(const BakeInputData& inputData); - void Shutdown(); - - MeshBakerStatus Update(const Camera& camera, uint32 screenWidth, uint32 screenHeight, - ID3D11DeviceContext* deviceContext, const Model* currentModel); - - // Read/Write Data shared with render threads - FixedArray renderBuffer; - FixedArray renderWeightBuffer; - volatile int64 currTile = 0; - - // Read-only data shared with render threads - volatile int64 renderTag = 0; - uint32 currWidth = 0; - uint32 currHeight = 0; - Float3 currCameraPos; - Quaternion currCameraOrientation; - Float4x4 currProj; - Float4x4 currViewProjInv; - bool killRenderThreads = false; - uint64 currNumTiles = 0; - - // Read/Write data shared with bake threads - FixedArray bakeResults[AppSettings::MaxBasisCount]; - volatile int64 currBakeBatch = 0; - - // Read-only data shared with bake threads - volatile int64 bakeTag = 0; - bool killBakeThreads = false; - uint64 currNumBakeBatches = 0; - uint64 currLightMapSize = 0; - BakeModes currBakeMode = BakeModes::Diffuse; - SolveModes currSolveMode = SolveModes::NNLS; - std::vector bakePoints; - std::vector gutterTexels; - - // Read-only data shared with both bake and render threads - BVHData sceneBVH; - TextureData envMap; - BakeInputData input; - -private: - - void KillBakeThreads(); - void StartBakeThreads(); - - void KillRenderThreads(); - void StartRenderThreads(); - - bool initialized = false; - - RTCDevice rtcDevice = nullptr; - - Random rng; - - static const uint64 NumStagingTextures = 2; - - ID3D11Texture2DPtr renderTexture; - ID3D11ShaderResourceViewPtr renderTextureSRV; - ID3D11Texture2DPtr renderStagingTextures[NumStagingTextures]; - uint64 renderStagingTextureIdx = 0; - - std::vector renderThreads; - std::vector renderThreadData; - std::vector renderSamples; - SampleModes renderSampleMode = SampleModes::Random; - uint64 numRenderSamples = 0; - - bool renderThreadsSuspended = false; - - ID3D11Texture2DPtr bakeTexture; - ID3D11ShaderResourceViewPtr bakeTextureSRV; - uint64 bakeStagingTextureIdx = 0; - ID3D11Texture2DPtr bakeStagingTextures[NumStagingTextures]; - uint64 bakeTextureUpdateIdx = 0; - - uint64 numThreads = 0; - std::vector bakeThreads; - std::vector bakeThreadData; - std::vector bakeSamples; - SampleModes bakeSampleMode = SampleModes::Random; - uint64 numBakeSamples = 0; - StructuredBuffer bakePointBuffer; - bool bakeThreadsSuspended = false; - - Float3 sgDirections[AppSettings::MaxSGCount]; - float sgSharpness = 0.0f; - - int64 lastTileNum = INT64_MAX; +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PathTracer.h" +#include "SharedConstants.h" +#include "AppSettings.h" + +namespace SampleFramework11 +{ + class Model; + class Camera; + struct StructuredBuffer; +} + +using namespace SampleFramework11; + +struct RenderThreadContext; +struct RenderThreadData; +struct IntegrationSamples; +struct BakeThreadData; +struct GutterTexel; +struct Vertex; + +// Input to the baker +struct BakeInputData +{ + const Model* SceneModel = nullptr; + ID3D11Device* Device = nullptr; + ID3D11ShaderResourceView* EnvMaps[AppSettings::NumCubeMaps]; + TextureData EnvMapData[AppSettings::NumCubeMaps]; + + BakeInputData() + { + for(uint64 i = 0; i < ArraySize_(EnvMaps); ++i) + EnvMaps[i] = nullptr; + } +}; + +struct MeshBakerStatus +{ + ID3D11ShaderResourceView* GroundTruth = nullptr; + ID3D11ShaderResourceView* LightMap = nullptr; + ID3D11ShaderResourceView* BakePoints = nullptr; + ID3D11ShaderResourceView* ProbeIrradiance = nullptr; + uint64 NumBakePoints = 0; + float GroundTruthProgress = 0.0f; + float BakeProgress = 0.0f; + uint64 GroundTruthSampleCount = 0; + Float3 SGDirections[AppSettings::MaxSGCount]; + float SGSharpness = 0.0f; +}; + +class MeshBaker +{ + +public: + + MeshBaker(); + ~MeshBaker(); + + void Initialize(const BakeInputData& inputData); + void Shutdown(); + + MeshBakerStatus Update(const Camera& camera, uint32 screenWidth, uint32 screenHeight, + ID3D11DeviceContext* deviceContext, const Model* currentModel); + + // Read/Write Data shared with render threads + FixedArray renderBuffer; + FixedArray renderWeightBuffer; + volatile int64 currTile = 0; + + // Read-only data shared with render threads + volatile int64 renderTag = 0; + uint32 currWidth = 0; + uint32 currHeight = 0; + Float3 currCameraPos; + Quaternion currCameraOrientation; + Float4x4 currProj; + Float4x4 currViewProjInv; + bool killRenderThreads = false; + uint64 currNumTiles = 0; + + // Read/Write data shared with bake threads + FixedArray bakeResults[AppSettings::MaxBasisCount]; + volatile int64 currBakeBatch = 0; + + // Read-only data shared with bake threads + volatile int64 bakeTag = 0; + bool killBakeThreads = false; + uint64 currNumBakeBatches = 0; + uint64 currLightMapSize = 0; + BakeModes currBakeMode = BakeModes::Diffuse; + SolveModes currSolveMode = SolveModes::NNLS; + std::vector bakePoints; + std::vector gutterTexels; + + // Read-only data shared with both bake and render threads + BVHData sceneBVH; + TextureData envMap; + BakeInputData input; + +private: + + void KillBakeThreads(); + void StartBakeThreads(); + + void KillRenderThreads(); + void StartRenderThreads(); + + bool initialized = false; + + RTCDevice rtcDevice = nullptr; + + Random rng; + + static const uint64 NumStagingTextures = 2; + + ID3D11Texture2DPtr renderTexture; + ID3D11ShaderResourceViewPtr renderTextureSRV; + ID3D11Texture2DPtr renderStagingTextures[NumStagingTextures]; + uint64 renderStagingTextureIdx = 0; + + std::vector renderThreads; + std::vector renderThreadData; + std::vector renderSamples; + SampleModes renderSampleMode = SampleModes::Random; + uint64 numRenderSamples = 0; + + bool renderThreadsSuspended = false; + + ID3D11Texture2DPtr bakeTexture; + ID3D11ShaderResourceViewPtr bakeTextureSRV; + uint64 bakeStagingTextureIdx = 0; + ID3D11Texture2DPtr bakeStagingTextures[NumStagingTextures]; + uint64 bakeTextureUpdateIdx = 0; + + uint64 numThreads = 0; + std::vector bakeThreads; + std::vector bakeThreadData; + std::vector bakeSamples; + SampleModes bakeSampleMode = SampleModes::Random; + uint64 numBakeSamples = 0; + StructuredBuffer bakePointBuffer; + bool bakeThreadsSuspended = false; + + Float3 sgDirections[AppSettings::MaxSGCount]; + float sgSharpness = 0.0f; + + int64 lastTileNum = INT64_MAX; }; \ No newline at end of file diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index e6ded79..fb5e297 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -1,1060 +1,1061 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include - -#include "MeshRenderer.h" - -#include -#include -#include -#include - -#include "AppSettings.h" -#include "SharedConstants.h" -#include "MeshBaker.h" - -// Constants -static const float ShadowNearClip = 1.0f; -static const float FilterSize = 7.0f; -static const uint32 SampleRadius = 3; -static const float OffsetScale = 0.0f; -static const float LightBleedingReduction = 0.10f; -static const float PositiveExponent = 40.0f; -static const float NegativeExponent = 8.0f; -static const uint32 ShadowMapSize = 1024; -static const uint32 ShadowMSAASamples = 4; -static const uint32 ShadowAnisotropy = 16; -static const bool EnableShadowMips = true; - -static void GenerateHemisphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* device, - ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer, uint64& numIndices) -{ - Assert_(NumUSlices >= 3); - Assert_(NumVSlices >= 2); - - std::vector hemisphereVerts; - - // Add the vert at the top - hemisphereVerts.push_back(Float3(0.0f, 0.0f, 1.0f)); - - // Add the rings - for(uint64 v = 0; v < NumVSlices; ++v) - { - for(uint64 u = 0; u < NumUSlices; ++u) - { - const float theta = ((v + 1.0f) / NumVSlices) * Pi_2; - const float phi = (float(u) / NumUSlices) * Pi2; - - Float3 pos; - pos.x = std::sin(theta) * std::cos(phi); - pos.y = std::sin(theta) * std::sin(phi); - pos.z = std::cos(theta); - - hemisphereVerts.push_back(pos); - } - } - - Assert_(hemisphereVerts.size() <= UINT32_MAX); - - // Add the top ring of triangles - std::vector hemisphereIndices; - for(uint32 u = 0; u < NumUSlices; ++u) - { - hemisphereIndices.push_back(0); - hemisphereIndices.push_back(u + 1); - - if(u < NumUSlices - 1) - hemisphereIndices.push_back(u + 2); - else - hemisphereIndices.push_back(1); - } - - // Add the rest of the rings - uint32 prevRowStart = 1; - uint32 currRowStart = uint32(NumUSlices + 1); - for(uint32 v = 1; v < NumVSlices; ++v) - { - for(uint32 u = 0; u < NumUSlices; ++u) - { - uint32 nextBottom = currRowStart + u + 1; - uint32 nextTop = prevRowStart + u + 1; - if(u == NumUSlices - 1) - { - nextBottom = currRowStart; - nextTop = prevRowStart; - } - - hemisphereIndices.push_back(prevRowStart + u); - hemisphereIndices.push_back(currRowStart + u); - hemisphereIndices.push_back(nextBottom); - hemisphereIndices.push_back(nextBottom); - hemisphereIndices.push_back(nextTop); - hemisphereIndices.push_back(prevRowStart + u); - } - - prevRowStart = currRowStart; - currRowStart += uint32(NumUSlices); - } - - numIndices = hemisphereIndices.size(); - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = sizeof(Float3) * uint32(hemisphereVerts.size()); - bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc.CPUAccessFlags = 0; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; - - D3D11_SUBRESOURCE_DATA initData; - initData.pSysMem = hemisphereVerts.data(); - initData.SysMemPitch = 0; - initData.SysMemSlicePitch = 0; - DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); - - bufferDesc.ByteWidth = sizeof(uint32) * uint32(hemisphereIndices.size()); - bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; - initData.pSysMem = hemisphereIndices.data(); - DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); -} - -static void GenerateSphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* device, - ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer, uint64& numIndices) -{ - Assert_(NumUSlices >= 3); - Assert_(NumVSlices >= 3); - - std::vector sphereVerts; - - // Add the vert at the top - sphereVerts.push_back(Float3(0.0f, 0.0f, 1.0f)); - - // Add the rings - for(uint64 v = 0; v < NumVSlices - 1; ++v) - { - for(uint64 u = 0; u < NumUSlices; ++u) - { - const float theta = ((v + 1.0f) / NumVSlices) * Pi; - const float phi = (float(u) / NumUSlices) * Pi2; - - Float3 pos; - pos.x = std::sin(theta) * std::cos(phi); - pos.y = std::sin(theta) * std::sin(phi); - pos.z = std::cos(theta); - - sphereVerts.push_back(pos); - } - } - - // Add the vert at the bottom - const uint32 lastVertIdx = uint32(sphereVerts.size()); - sphereVerts.push_back(Float3(0.0f, 0.0f, -1.0f)); - - Assert_(sphereVerts.size() <= UINT32_MAX); - - // Add the top ring of triangles - std::vector sphereIndices; - for(uint32 u = 0; u < NumUSlices; ++u) - { - sphereIndices.push_back(0); - sphereIndices.push_back(u + 1); - - if(u < NumUSlices - 1) - sphereIndices.push_back(u + 2); - else - sphereIndices.push_back(1); - } - - // Add the rest of the rings - uint32 prevRowStart = 1; - uint32 currRowStart = uint32(NumUSlices + 1); - for(uint32 v = 1; v < NumVSlices - 1; ++v) - { - for(uint32 u = 0; u < NumUSlices; ++u) - { - uint32 nextBottom = currRowStart + u + 1; - uint32 nextTop = prevRowStart + u + 1; - if(u == NumUSlices - 1) - { - nextBottom = currRowStart; - nextTop = prevRowStart; - } - - sphereIndices.push_back(prevRowStart + u); - sphereIndices.push_back(currRowStart + u); - sphereIndices.push_back(nextBottom); - sphereIndices.push_back(nextBottom); - sphereIndices.push_back(nextTop); - sphereIndices.push_back(prevRowStart + u); - } - - prevRowStart = currRowStart; - currRowStart += uint32(NumUSlices); - } - - // Add the last ring at the bottom - const uint32 lastRingStart = uint32(lastVertIdx - NumUSlices); - for(uint32 u = 0; u < NumUSlices; ++u) - { - sphereIndices.push_back(lastVertIdx); - sphereIndices.push_back(lastRingStart + u); - - if(u < NumUSlices - 1) - sphereIndices.push_back(lastRingStart + u + 1); - else - sphereIndices.push_back(lastRingStart); - } - - numIndices = sphereIndices.size(); - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = sizeof(Float3) * uint32(sphereVerts.size()); - bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc.CPUAccessFlags = 0; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; - - D3D11_SUBRESOURCE_DATA initData; - initData.pSysMem = sphereVerts.data(); - initData.SysMemPitch = 0; - initData.SysMemSlicePitch = 0; - DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); - - bufferDesc.ByteWidth = sizeof(uint32) * uint32(sphereIndices.size()); - bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; - initData.pSysMem = sphereIndices.data(); - DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); -} - -MeshRenderer::MeshRenderer() : currFrame(0), sceneModel(nullptr), - numHemisphereIndices(0), numAreaLightIndices(0) -{ -} - -void MeshRenderer::LoadShaders() -{ - // Load the mesh shaders - meshDepthVS = CompileVSFromFile(device, L"DepthOnly.hlsl", "VS", "vs_5_0"); - meshVS = CompileVSFromFile(device, L"Mesh.hlsl", "VS", "vs_5_0"); - meshPS = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0"); - - areaLightVS = CompileVSFromFile(device, L"AreaLight.hlsl", "VS", "vs_5_0"); - areaLightPS = CompilePSFromFile(device, L"AreaLight.hlsl", "PS", "ps_5_0"); - - visualizerVS = CompileVSFromFile(device, L"BakeDataVisualizer.hlsl", "VS", "vs_5_0"); - visualizerPS = CompilePSFromFile(device, L"BakeDataVisualizer.hlsl", "PS", "ps_5_0"); - - fullScreenVS = CompileVSFromFile(device, L"EVSMConvert.hlsl", "FullScreenVS"); - - CompileOptions opts; - opts.Add("MSAASamples_", ShadowMSAASamples); - evsmConvertPS = CompilePSFromFile(device, L"EVSMConvert.hlsl", "ConvertToEVSM", "ps_5_0", opts); - - opts.Reset(); - opts.Add("Horizontal_", 1); - opts.Add("Vertical_", 0); - opts.Add("SampleRadius_", SampleRadius); - evsmBlurH = CompilePSFromFile(device, L"EVSMConvert.hlsl", "BlurEVSM", "ps_5_0", opts); - - opts.Reset(); - opts.Add("Horizontal_", 0); - opts.Add("Vertical_", 1); - opts.Add("SampleRadius_", SampleRadius); - evsmBlurV = CompilePSFromFile(device, L"EVSMConvert.hlsl", "BlurEVSM", "ps_5_0", opts); - - opts.Reset(); - opts.Add("MSAA_", 0); - depthReductionInitialCS[0] = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionInitialCS", "cs_5_0", opts); - - opts.Reset(); - opts.Add("MSAA_", 1); - depthReductionInitialCS[1] = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionInitialCS", "cs_5_0", opts); - - depthReductionCS = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionCS"); -} - -void MeshRenderer::CreateShadowMaps() -{ - // Create the shadow map as a texture atlas - sunShadowDepthMap.Initialize(device, ShadowMapSize, ShadowMapSize, DXGI_FORMAT_D24_UNORM_S8_UINT, true, - ShadowMSAASamples, 0, 1); - - DXGI_FORMAT smFmt = DXGI_FORMAT_R32G32B32A32_FLOAT; - uint32 numMips = EnableShadowMips ? 0 : 1; - sunVSM.Initialize(device, ShadowMapSize, ShadowMapSize, smFmt, numMips, 1, 0, - EnableShadowMips, false, NumCascades, false); - - tempVSM.Initialize(device, ShadowMapSize, ShadowMapSize, smFmt, 1, 1, 0, false, false, 1, false); - - areaLightShadowMap.Initialize(device, ShadowMapSize, ShadowMapSize, DXGI_FORMAT_D32_FLOAT, true, 1, 0, 6, true); -} - -// Loads resources -void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* model) -{ - this->device = device; - - blendStates.Initialize(device); - rasterizerStates.Initialize(device); - depthStencilStates.Initialize(device); - samplerStates.Initialize(device); - - meshVSConstants.Initialize(device); - meshPSConstants.Initialize(device); - areaLightConstants.Initialize(device); - visualizerConstants.Initialize(device); - evsmConstants.Initialize(device); - reductionConstants.Initialize(device); - - shSpecularLookupA = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularA.dds"); - shSpecularLookupB = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularB.dds"); - - LoadShaders(); - - D3D11_RASTERIZER_DESC rsDesc = RasterizerStates::NoCullDesc(); - rsDesc.DepthClipEnable = false; - DXCall(device->CreateRasterizerState(&rsDesc, &noZClipRSState)); - - D3D11_SAMPLER_DESC sampDesc = SamplerStates::AnisotropicDesc(); - sampDesc.MaxAnisotropy = ShadowAnisotropy; - DXCall(device->CreateSamplerState(&sampDesc, &evsmSampler)); - - // Create the staging textures for reading back the reduced depth buffer - for(uint32 i = 0; i < ReadbackLatency; ++i) - reductionStagingTextures[i].Initialize(device, 1, 1, DXGI_FORMAT_R16G16_UNORM); - - CreateShadowMaps(); - - GenerateHemisphere(16, 4, device, hemisphereVB, hemisphereIB, numHemisphereIndices); - - GenerateSphere(256, 192, device, areaLightVB, areaLightIB, numAreaLightIndices); - - D3D11_INPUT_ELEMENT_DESC elements[1]; - elements[0].AlignedByteOffset = 0; - elements[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; - elements[0].InputSlot = 0; - elements[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - elements[0].InstanceDataStepRate = 0; - elements[0].SemanticName = "POSITION"; - elements[0].SemanticIndex = 0; - - DXCall(device->CreateInputLayout(elements, 1, visualizerVS->ByteCode->GetBufferPointer(), - visualizerVS->ByteCode->GetBufferSize(), &visualizerInputLayout)); - - DXCall(device->CreateInputLayout(elements, 1, areaLightVS->ByteCode->GetBufferPointer(), - areaLightVS->ByteCode->GetBufferSize(), &areaLightInputLayout)); - - SetModel(model); -} - -void MeshRenderer::SetModel(const Model* model) -{ - Assert_(model != nullptr); - sceneModel = model; - - meshInputLayouts.clear(); - meshDepthInputLayouts.clear(); - - for(uint64 i = 0; i < sceneModel->Meshes().size(); ++i) - { - // Generate input layouts for the scene meshes - const Mesh& mesh = sceneModel->Meshes()[i]; - ID3D11InputLayoutPtr inputLayout; - DXCall(device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), - meshVS->ByteCode->GetBufferPointer(), meshVS->ByteCode->GetBufferSize(), &inputLayout)); - meshInputLayouts.push_back(inputLayout); - - DXCall(device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), - meshDepthVS->ByteCode->GetBufferPointer(), meshDepthVS->ByteCode->GetBufferSize(), &inputLayout)); - meshDepthInputLayouts.push_back(inputLayout); - } -} - -void MeshRenderer::Update(const Camera& camera, Float2 jitterOffset) -{ - prevVP = currVP; - currVP = camera.ViewProjectionMatrix(); - if(firstFrame) - { - prevVP = currVP; - firstFrame = false; - } - - meshPSConstants.Data.JitterOffset = jitterOffset; - areaLightConstants.Data.JitterOffset = jitterOffset; -} - -void MeshRenderer::OnResize(uint32 width, uint32 height) -{ - depthReductionTargets.clear(); - - uint32 w = width; - uint32 h = height; - - while(w > 1 || h > 1) - { - w = DispatchSize(ReductionTGSize, w); - h = DispatchSize(ReductionTGSize, h); - - RenderTarget2D rt; - rt.Initialize(device, w, h, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true); - depthReductionTargets.push_back(rt); - } - - meshPSConstants.Data.RTSize.x = float(width); - meshPSConstants.Data.RTSize.y = float(height); - - areaLightConstants.Data.RTSize = meshPSConstants.Data.RTSize; -} - -void MeshRenderer::ReduceDepth(ID3D11DeviceContext* context, DepthStencilBuffer& depthTarget, - const Camera& camera) -{ - PIXEvent event(L"Depth Reduction"); - - reductionConstants.Data.Projection = Float4x4::Transpose(camera.ProjectionMatrix()); - reductionConstants.Data.NearClip = camera.NearClip(); - reductionConstants.Data.FarClip = camera.FarClip(); - reductionConstants.Data.TextureSize = Uint2(depthTarget.Width, depthTarget.Height); - reductionConstants.Data.NumSamples = depthTarget.MultiSamples; - reductionConstants.ApplyChanges(context); - reductionConstants.SetCS(context, 0); - - ID3D11RenderTargetView* rtvs[1] = { NULL }; - context->OMSetRenderTargets(1, rtvs, NULL); - - ID3D11UnorderedAccessView* uavs[1] = { depthReductionTargets[0].UAView }; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); - - ID3D11ShaderResourceView* srvs[1] = { depthTarget.SRView }; - context->CSSetShaderResources(0, 1, srvs); - - const bool msaa = depthTarget.MultiSamples > 1; - - ID3D11ComputeShader* shader = depthReductionInitialCS[msaa ? 1 : 0]; - context->CSSetShader(shader, NULL, 0); - - uint32 dispatchX = depthReductionTargets[0].Width; - uint32 dispatchY = depthReductionTargets[0].Height; - context->Dispatch(dispatchX, dispatchY, 1); - - uavs[0] = NULL; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); - - srvs[0] = NULL; - context->CSSetShaderResources(0, 1, srvs); - - context->CSSetShader(depthReductionCS, NULL, 0); - - for(uint32 i = 1; i < depthReductionTargets.size(); ++i) - { - RenderTarget2D& srcTexture = depthReductionTargets[i - 1]; - reductionConstants.Data.TextureSize.x = srcTexture.Width; - reductionConstants.Data.TextureSize.y = srcTexture.Height; - reductionConstants.Data.NumSamples = srcTexture.MultiSamples; - reductionConstants.ApplyChanges(context); - - uavs[0] = depthReductionTargets[i].UAView; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); - - srvs[0] = srcTexture.SRView; - context->CSSetShaderResources(0, 1, srvs); - - dispatchX = depthReductionTargets[i].Width; - dispatchY = depthReductionTargets[i].Height; - context->Dispatch(dispatchX, dispatchY, 1); - - uavs[0] = NULL; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); - - srvs[0] = NULL; - context->CSSetShaderResources(0, 1, srvs); - } - - // Copy to a staging texture - ID3D11Texture2D* lastTarget = depthReductionTargets[depthReductionTargets.size() - 1].Texture; - context->CopyResource(reductionStagingTextures[currFrame % ReadbackLatency].Texture, lastTarget); - - ++currFrame; - - if(currFrame >= ReadbackLatency) - { - StagingTexture2D& stagingTexture = reductionStagingTextures[currFrame % ReadbackLatency]; - - uint32 pitch; - const uint16* texData = reinterpret_cast(stagingTexture.Map(context, 0, pitch)); - reductionDepth.x = texData[0] / static_cast(0xffff); - reductionDepth.y = texData[1] / static_cast(0xffff); - - stagingTexture.Unmap(context, 0); - } - else - { - reductionDepth = Float2(0.0f, 1.0f); - } -} - -// Convert to an EVSM map -void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx, Float3 cascadeScale) -{ - PIXEvent event(L"EVSM Conversion"); - - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); - context->RSSetState(rasterizerStates.NoCull()); - context->OMSetDepthStencilState(depthStencilStates.DepthDisabled(), 0); - ID3D11Buffer* vbs[1] = { NULL }; - uint32 strides[1] = { 0 }; - uint32 offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vbs, strides, offsets); - context->IASetIndexBuffer(NULL, DXGI_FORMAT_R32_UINT, 0); - context->IASetInputLayout(NULL); - - SetViewport(context, sunVSM.Width, sunVSM.Height); - - evsmConstants.Data.PositiveExponent = PositiveExponent; - evsmConstants.Data.NegativeExponent = NegativeExponent; - evsmConstants.Data.CascadeScale = meshPSConstants.Data.CascadeScales[cascadeIdx].To3D(); - evsmConstants.Data.FilterSize = 1.0f; - evsmConstants.Data.ShadowMapSize.x = float(sunVSM.Width); - evsmConstants.Data.ShadowMapSize.y = float(sunVSM.Height); - evsmConstants.ApplyChanges(context); - evsmConstants.SetPS(context, 0); - - context->VSSetShader(fullScreenVS, NULL, 0); - context->PSSetShader(evsmConvertPS, NULL, 0); - - ID3D11RenderTargetView* rtvs[1] = { sunVSM.RTVArraySlices[cascadeIdx] }; - context->OMSetRenderTargets(1, rtvs, NULL); - - ID3D11ShaderResourceView* srvs[1] = { sunShadowDepthMap.SRView }; - context->PSSetShaderResources(0, 1, srvs); - - context->Draw(3, 0); - - srvs[0] = NULL; - context->PSSetShaderResources(0, 1, srvs); - - const float FilterSizeU = std::max(FilterSize * cascadeScale.x, 1.0f); - const float FilterSizeV = std::max(FilterSize * cascadeScale.y, 1.0f); - - if(FilterSizeU > 1.0f || FilterSizeV > 1.0f) - { - // Horizontal pass - evsmConstants.Data.FilterSize = FilterSizeU; - evsmConstants.ApplyChanges(context); - - uint32 sampleRadiusU = static_cast((FilterSizeU / 2) + 0.499f); - - rtvs[0] = tempVSM.RTView; - context->OMSetRenderTargets(1, rtvs, NULL); - - srvs[0] = sunVSM.SRVArraySlices[cascadeIdx]; - context->PSSetShaderResources(0, 1, srvs); - - context->PSSetShader(evsmBlurH, NULL, 0); - - context->Draw(3, 0); - - srvs[0] = NULL; - context->PSSetShaderResources(0, 1, srvs); - - // Vertical pass - evsmConstants.Data.FilterSize = FilterSizeV; - evsmConstants.ApplyChanges(context); - - uint32 sampleRadiusV = static_cast((FilterSizeV / 2) + 0.499f); - - rtvs[0] = sunVSM.RTVArraySlices[cascadeIdx]; - context->OMSetRenderTargets(1, rtvs, NULL); - - srvs[0] = tempVSM.SRView; - context->PSSetShaderResources(0, 1, srvs); - - context->PSSetShader(evsmBlurV, NULL, 0); - - context->Draw(3, 0); - - srvs[0] = NULL; - context->PSSetShaderResources(0, 1, srvs); - } - - if(EnableShadowMips && cascadeIdx == NumCascades - 1) - context->GenerateMips(sunVSM.SRView); -} - -// Renders all meshes in the model, with shadows -void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) -{ - PIXEvent event(L"Mesh Rendering"); - - // Set states - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); - context->OMSetDepthStencilState(depthStencilStates.DepthEnabled(), 0); - context->RSSetState(rasterizerStates.BackFaceCull()); - - ID3D11SamplerState* sampStates[] = { - samplerStates.Anisotropic(), - evsmSampler, - samplerStates.LinearClamp(), - samplerStates.ReversedShadowMapPCF(), - }; - - context->PSSetSamplers(0, ArraySize_(sampStates), sampStates); - - // Set constant buffers - meshVSConstants.Data.World = Float4x4(); - meshVSConstants.Data.View = Float4x4::Transpose(camera.ViewMatrix()); - meshVSConstants.Data.WorldViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); - meshVSConstants.Data.PrevWorldViewProjection = Float4x4::Transpose(prevVP); - meshVSConstants.ApplyChanges(context); - meshVSConstants.SetVS(context, 0); - - meshPSConstants.Data.SunDirectionWS = AppSettings::SunDirection; - meshPSConstants.Data.SunIlluminance = AppSettings::SunIlluminance(); - meshPSConstants.Data.CosSunAngularRadius = std::cos(DegToRad(AppSettings::SunSize) / 2.0f); - meshPSConstants.Data.SinSunAngularRadius = std::sin(DegToRad(AppSettings::SunSize) / 2.0f); - meshPSConstants.Data.CameraPosWS = camera.Position(); - meshPSConstants.Data.OffsetScale = OffsetScale; - meshPSConstants.Data.PositiveExponent = PositiveExponent; - meshPSConstants.Data.NegativeExponent = NegativeExponent; - meshPSConstants.Data.LightBleedingReduction = LightBleedingReduction; - for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) - meshPSConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); - meshPSConstants.Data.SGSharpness = status.SGSharpness; - meshPSConstants.ApplyChanges(context); - meshPSConstants.SetPS(context, 0); - - // Set shaders - context->DSSetShader(nullptr, nullptr, 0); - context->HSSetShader(nullptr, nullptr, 0); - context->GSSetShader(nullptr, nullptr, 0); - context->VSSetShader(meshVS, nullptr, 0); - context->PSSetShader(meshPS, nullptr, 0); - - // Draw all meshes - for(uint64 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) - { - const Mesh& mesh = sceneModel->Meshes()[meshIdx]; - - // Set the vertices and indices - ID3D11Buffer* vertexBuffers[1] = { mesh.VertexBuffer() }; - UINT vertexStrides[1] = { mesh.VertexStride() }; - UINT offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); - context->IASetIndexBuffer(mesh.IndexBuffer(), mesh.IndexBufferFormat(), 0); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - // Set the input layout - context->IASetInputLayout(meshInputLayouts[meshIdx]); - - // Draw all parts - for(uint64 partIdx = 0; partIdx < mesh.MeshParts().size(); ++partIdx) - { - const MeshPart& part = mesh.MeshParts()[partIdx]; - const MeshMaterial& material = sceneModel->Materials()[part.MaterialIdx]; - - // Set the textures - ID3D11ShaderResourceView* psTextures[] = - { - material.DiffuseMap, - material.NormalMap, - material.RoughnessMap, - material.MetallicMap, - sunVSM.SRView, - status.LightMap, - areaLightShadowMap.SRView, - shSpecularLookupA, - shSpecularLookupB, - }; - - context->PSSetShaderResources(0, ArraySize_(psTextures), psTextures); - context->DrawIndexed(part.IndexCount, part.IndexStart, 0); - } - } - - ID3D11ShaderResourceView* nullSRVs[10] = { NULL }; - context->PSSetShaderResources(0, ArraySize_(nullSRVs), nullSRVs); -} - -// Renders all meshes using depth-only rendering -void MeshRenderer::RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange) -{ - PIXEvent event(L"Mesh Depth Rendering"); - - // Set states - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.ColorWriteDisabled(), blendFactor, 0xFFFFFFFF); - context->OMSetDepthStencilState(flippedZRange ? depthStencilStates.ReverseDepthWriteEnabled() - : depthStencilStates.DepthWriteEnabled(), 0); - - if(noZClip) - context->RSSetState(noZClipRSState); - else - context->RSSetState(rasterizerStates.BackFaceCull()); - - // Set constant buffers - meshVSConstants.Data.World = Float4x4(); - meshVSConstants.Data.View = Float4x4::Transpose(camera.ViewMatrix()); - meshVSConstants.Data.WorldViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); - meshVSConstants.ApplyChanges(context); - meshVSConstants.SetVS(context, 0); - - // Set shaders - context->VSSetShader(meshDepthVS , nullptr, 0); - context->PSSetShader(nullptr, nullptr, 0); - context->GSSetShader(nullptr, nullptr, 0); - context->DSSetShader(nullptr, nullptr, 0); - context->HSSetShader(nullptr, nullptr, 0); - - for(uint32 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) - { - const Mesh& mesh = sceneModel->Meshes()[meshIdx]; - - // Set the vertices and indices - ID3D11Buffer* vertexBuffers[1] = { mesh.VertexBuffer() }; - UINT vertexStrides[1] = { mesh.VertexStride() }; - UINT offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); - context->IASetIndexBuffer(mesh.IndexBuffer(), mesh.IndexBufferFormat(), 0); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - // Set the input layout - context->IASetInputLayout(meshDepthInputLayouts[meshIdx]); - - // Draw all parts - for(uint64 partIdx = 0; partIdx < mesh.MeshParts().size(); ++partIdx) - { - const MeshPart& part = mesh.MeshParts()[partIdx]; - context->DrawIndexed(part.IndexCount, part.IndexStart, 0); - } - } -} - -// Renders meshes using cascaded shadow mapping -void MeshRenderer::RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera) -{ - PIXEvent event(L"Sun Shadow Map Rendering"); - - const float MinDistance = reductionDepth.x; - const float MaxDistance = reductionDepth.y; - - // Compute the split distances based on the partitioning mode - float CascadeSplits[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - - { - float lambda = 1.0f; - - float nearClip = camera.NearClip(); - float farClip = camera.FarClip(); - float clipRange = farClip - nearClip; - - float minZ = nearClip + MinDistance * clipRange; - float maxZ = nearClip + MaxDistance * clipRange; - - float range = maxZ - minZ; - float ratio = maxZ / minZ; - - for(uint32 i = 0; i < NumCascades; ++i) - { - float p = (i + 1) / static_cast(NumCascades); - float log = minZ * std::pow(ratio, p); - float uniform = minZ + range * p; - float d = lambda * (log - uniform) + uniform; - CascadeSplits[i] = (d - nearClip) / clipRange; - } - } - - Float3 c0Extents; - Float4x4 c0Matrix; - - const Float3 lightDir = AppSettings::SunDirection; - - // Render the meshes to each cascade - for(uint32 cascadeIdx = 0; cascadeIdx < NumCascades; ++cascadeIdx) - { - PIXEvent cascadeEvent((L"Rendering Shadow Map Cascade " + ToString(cascadeIdx)).c_str()); - - // Set the viewport - SetViewport(context, ShadowMapSize, ShadowMapSize); - - // Set the shadow map as the depth target - ID3D11DepthStencilView* dsv = sunShadowDepthMap.DSView; - ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { NULL }; - context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); - context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); - - // Get the 8 points of the view frustum in world space - XMVECTOR frustumCornersWS[8] = - { - XMVectorSet(-1.0f, 1.0f, 0.0f, 1.0f), - XMVectorSet( 1.0f, 1.0f, 0.0f, 1.0f), - XMVectorSet( 1.0f, -1.0f, 0.0f, 1.0f), - XMVectorSet(-1.0f, -1.0f, 0.0f, 1.0f), - XMVectorSet(-1.0f, 1.0f, 1.0f, 1.0f), - XMVectorSet( 1.0f, 1.0f, 1.0f, 1.0f), - XMVectorSet( 1.0f, -1.0f, 1.0f, 1.0f), - XMVectorSet(-1.0f, -1.0f, 1.0f, 1.0f), - }; - - float prevSplitDist = cascadeIdx == 0 ? MinDistance : CascadeSplits[cascadeIdx - 1]; - float splitDist = CascadeSplits[cascadeIdx]; - - XMVECTOR det; - XMMATRIX invViewProj = XMMatrixInverse(&det, camera.ViewProjectionMatrix().ToSIMD()); - for(uint32 i = 0; i < 8; ++i) - frustumCornersWS[i] = XMVector3TransformCoord(frustumCornersWS[i], invViewProj); - - // Get the corners of the current cascade slice of the view frustum - for(uint32 i = 0; i < 4; ++i) - { - XMVECTOR cornerRay = XMVectorSubtract(frustumCornersWS[i + 4], frustumCornersWS[i]); - XMVECTOR nearCornerRay = XMVectorScale(cornerRay, prevSplitDist); - XMVECTOR farCornerRay = XMVectorScale(cornerRay, splitDist); - frustumCornersWS[i + 4] = XMVectorAdd(frustumCornersWS[i], farCornerRay); - frustumCornersWS[i] = XMVectorAdd(frustumCornersWS[i], nearCornerRay); - } - - // Calculate the centroid of the view frustum slice - XMVECTOR frustumCenterVec = XMVectorZero(); - for(uint32 i = 0; i < 8; ++i) - frustumCenterVec = XMVectorAdd(frustumCenterVec, frustumCornersWS[i]); - frustumCenterVec = XMVectorScale(frustumCenterVec, 1.0f / 8.0f); - Float3 frustumCenter = frustumCenterVec; - - // Pick the up vector to use for the light camera - Float3 upDir = camera.Right(); - - Float3 minExtents; - Float3 maxExtents; - - { - // Create a temporary view matrix for the light - Float3 lightCameraPos = frustumCenter; - Float3 lookAt = frustumCenter - lightDir; - XMMATRIX lightView = XMMatrixLookAtLH(lightCameraPos.ToSIMD(), lookAt.ToSIMD(), upDir.ToSIMD()); - - // Calculate an AABB around the frustum corners - XMVECTOR mins = XMVectorSet(REAL_MAX, REAL_MAX, REAL_MAX, REAL_MAX); - XMVECTOR maxes = XMVectorSet(-REAL_MAX, -REAL_MAX, -REAL_MAX, -REAL_MAX); - for(uint32 i = 0; i < 8; ++i) - { - XMVECTOR corner = XMVector3TransformCoord(frustumCornersWS[i], lightView); - mins = XMVectorMin(mins, corner); - maxes = XMVectorMax(maxes, corner); - } - - minExtents = mins; - maxExtents = maxes; - } - - // Adjust the min/max to accommodate the filtering size - float scale = (ShadowMapSize + FilterSize) / static_cast(ShadowMapSize); - minExtents.x *= scale; - minExtents.y *= scale; - maxExtents.x *= scale; - maxExtents.y *= scale; - - Float3 cascadeExtents = maxExtents - minExtents; - - // Get position of the shadow camera - Float3 shadowCameraPos = frustumCenter + lightDir * -minExtents.z; - - // Come up with a new orthographic camera for the shadow caster - OrthographicCamera shadowCamera(minExtents.x, minExtents.y, maxExtents.x, - maxExtents.y, 0.0f, cascadeExtents.z); - shadowCamera.SetLookAt(shadowCameraPos, frustumCenter, upDir); - - // Draw the mesh with depth only, using the new shadow camera - RenderDepth(context, shadowCamera, true, false); - - // Apply the scale/offset matrix, which transforms from [-1,1] - // post-projection space to [0,1] UV space - XMMATRIX texScaleBias; - texScaleBias.r[0] = XMVectorSet(0.5f, 0.0f, 0.0f, 0.0f); - texScaleBias.r[1] = XMVectorSet(0.0f, -0.5f, 0.0f, 0.0f); - texScaleBias.r[2] = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); - texScaleBias.r[3] = XMVectorSet(0.5f, 0.5f, 0.0f, 1.0f); - XMMATRIX shadowMatrix = shadowCamera.ViewProjectionMatrix().ToSIMD(); - shadowMatrix = XMMatrixMultiply(shadowMatrix, texScaleBias); - - // Store the split distance in terms of view space depth - const float clipDist = camera.FarClip() - camera.NearClip(); - meshPSConstants.Data.CascadeSplits[cascadeIdx] = camera.NearClip() + splitDist * clipDist; - - if(cascadeIdx == 0) - { - c0Extents = cascadeExtents; - c0Matrix = shadowMatrix; - meshPSConstants.Data.ShadowMatrix = XMMatrixTranspose(shadowMatrix); - meshPSConstants.Data.CascadeOffsets[0] = Float4(0.0f, 0.0f, 0.0f, 0.0f); - meshPSConstants.Data.CascadeScales[0] = Float4(1.0f, 1.0f, 1.0f, 1.0f); - } - else - { - // Calculate the position of the lower corner of the cascade partition, in the UV space - // of the first cascade partition - Float4x4 invCascadeMat = Float4x4::Invert(shadowMatrix); - Float3 cascadeCorner = Float3::Transform(Float3(0.0f, 0.0f, 0.0f), invCascadeMat); - cascadeCorner = Float3::Transform(cascadeCorner, c0Matrix); - - // Do the same for the upper corner - Float3 otherCorner = Float3::Transform(Float3(1.0f, 1.0f, 1.0f), invCascadeMat); - otherCorner = Float3::Transform(otherCorner, c0Matrix); - - // Calculate the scale and offset - Float3 cascadeScale = Float3(1.0f, 1.0f, 1.f) / (otherCorner - cascadeCorner); - meshPSConstants.Data.CascadeOffsets[cascadeIdx] = Float4(-cascadeCorner, 0.0f); - meshPSConstants.Data.CascadeScales[cascadeIdx] = Float4(cascadeScale, 1.0f); - } - - ConvertToEVSM(context, cascadeIdx, meshPSConstants.Data.CascadeScales[cascadeIdx].To3D()); - } -} - -// Renders an omni-directional shadow map for the spherical area light -void MeshRenderer::RenderAreaLightShadowMap(ID3D11DeviceContext* context, const Camera& camera) -{ - PIXEvent event(L"Area Light Shadow Map Rendering"); - - const uint32 sMapSize = areaLightShadowMap.Width; - const Float3 areaLightPos = Float3(AppSettings::AreaLightX, AppSettings::AreaLightY, AppSettings::AreaLightZ); - const float nearClip = AppSettings::AreaLightSize; - - for(uint64 face = 0; face < 6; ++face) - { - PIXEvent faceEvent(L"Area Light Shadow Map Face " + ToString(face)); - - // Set the viewport - SetViewport(context, sMapSize, sMapSize); - - // Set the shadow map as the depth target - ID3D11DepthStencilView* dsv = areaLightShadowMap.ArraySlices[face]; - ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { NULL }; - context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); - context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 0.0f, 0); - - PerspectiveCamera shadowCamera(1.0f, Pi_2, nearClip, nearClip + 1.0f); - - // Set up a infinite reverse projection - Float4x4 projection; - projection._33 = 0.0f; - projection._43 = nearClip; - projection._34 = 1.0f; - projection._44 = 0.0f; - shadowCamera.SetProjection(projection); - - static const Float3 LookAtDirs[6] = - { - Float3(1.0f, 0.0f, 0.0f), Float3(-1.0f, 0.0f, 0.0f), - Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, -1.0f, 0.0f), - Float3(0.0f, 0.0f, 1.0f), Float3(0.0f, 0.0f, -1.0f) - }; - - static const Float3 UpDirs[6] = { - Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, 1.0f, 0.0f), - Float3(0.0f, 0.0f, -1.0f), Float3(0.0f, 0.0f, 1.0f), - Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, 1.0f, 0.0f), - }; - - shadowCamera.SetLookAt(areaLightPos, areaLightPos + LookAtDirs[face], UpDirs[face]); - - RenderDepth(context, shadowCamera, false, true); - } -} - -// Renders the area light -void MeshRenderer::RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera) -{ - PIXEvent event(L"Area Light Rendering"); - - // Set states - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); - context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); - context->RSSetState(rasterizerStates.NoCull()); - - // Set constant buffers - areaLightConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); - areaLightConstants.Data.PrevViewProjection = Float4x4::Transpose(prevVP); - areaLightConstants.ApplyChanges(context); - areaLightConstants.SetVS(context, 0); - areaLightConstants.SetPS(context, 0); - - // Set shaders - context->DSSetShader(nullptr, nullptr, 0); - context->HSSetShader(nullptr, nullptr, 0); - context->GSSetShader(nullptr, nullptr, 0); - context->VSSetShader(areaLightVS , nullptr, 0); - context->PSSetShader(areaLightPS, nullptr, 0); - - // Draw the visualizer sphere - ID3D11Buffer* vertexBuffers[1] = { areaLightVB }; - uint32 vertexStrides[1] = { sizeof(Float3) }; - uint32 offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); - context->IASetIndexBuffer(areaLightIB, DXGI_FORMAT_R32_UINT, 0); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - context->IASetInputLayout(areaLightInputLayout); - context->DrawIndexedInstanced(uint32(numAreaLightIndices), 1, 0, 0, 0); -} - -// Renders the bake data visualizer -void MeshRenderer::RenderBakeDataVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) -{ - PIXEvent event(L"Bake Data Visualizer"); - - // Set states - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); - context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); - context->RSSetState(rasterizerStates.NoCull()); - - // Set constant buffers - visualizerConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); - for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) - visualizerConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); - visualizerConstants.Data.SGSharpness = status.SGSharpness; - visualizerConstants.ApplyChanges(context); - visualizerConstants.SetVS(context, 0); - visualizerConstants.SetPS(context, 0); - - // Set shaders - context->DSSetShader(nullptr, nullptr, 0); - context->HSSetShader(nullptr, nullptr, 0); - context->GSSetShader(nullptr, nullptr, 0); - context->VSSetShader(visualizerVS , nullptr, 0); - context->PSSetShader(visualizerPS, nullptr, 0); - - ID3D11ShaderResourceView* vsSrvs[] = { status.BakePoints }; - context->VSSetShaderResources(0, ArraySize_(vsSrvs), vsSrvs); - - ID3D11ShaderResourceView* psSrvs[1] = { status.LightMap }; - context->PSSetShaderResources(0, 1, psSrvs); - - // Draw the visualizer hemispheres for all sample points - ID3D11Buffer* vertexBuffers[1] = { hemisphereVB }; - uint32 vertexStrides[1] = { sizeof(Float3) }; - uint32 offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); - context->IASetIndexBuffer(hemisphereIB, DXGI_FORMAT_R32_UINT, 0); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - context->IASetInputLayout(visualizerInputLayout); - - // Draw - context->DrawIndexedInstanced(uint32(numHemisphereIndices), uint32(status.NumBakePoints), 0, 0, 0); - - ID3D11ShaderResourceView* nullSRVs[] = { nullptr }; - context->VSSetShaderResources(0, 1, nullSRVs); - context->PSSetShaderResources(0, 1, nullSRVs); +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include + +#include "MeshRenderer.h" + +#include +#include +#include +#include + +#include "AppSettings.h" +#include "SharedConstants.h" +#include "MeshBaker.h" + +// Constants +static const float ShadowNearClip = 1.0f; +static const float FilterSize = 7.0f; +static const uint32 SampleRadius = 3; +static const float OffsetScale = 0.0f; +static const float LightBleedingReduction = 0.10f; +static const float PositiveExponent = 40.0f; +static const float NegativeExponent = 8.0f; +static const uint32 ShadowMapSize = 1024; +static const uint32 ShadowMSAASamples = 4; +static const uint32 ShadowAnisotropy = 16; +static const bool EnableShadowMips = true; + +static void GenerateHemisphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* device, + ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer, uint64& numIndices) +{ + Assert_(NumUSlices >= 3); + Assert_(NumVSlices >= 2); + + std::vector hemisphereVerts; + + // Add the vert at the top + hemisphereVerts.push_back(Float3(0.0f, 0.0f, 1.0f)); + + // Add the rings + for(uint64 v = 0; v < NumVSlices; ++v) + { + for(uint64 u = 0; u < NumUSlices; ++u) + { + const float theta = ((v + 1.0f) / NumVSlices) * Pi_2; + const float phi = (float(u) / NumUSlices) * Pi2; + + Float3 pos; + pos.x = std::sin(theta) * std::cos(phi); + pos.y = std::sin(theta) * std::sin(phi); + pos.z = std::cos(theta); + + hemisphereVerts.push_back(pos); + } + } + + Assert_(hemisphereVerts.size() <= UINT32_MAX); + + // Add the top ring of triangles + std::vector hemisphereIndices; + for(uint32 u = 0; u < NumUSlices; ++u) + { + hemisphereIndices.push_back(0); + hemisphereIndices.push_back(u + 1); + + if(u < NumUSlices - 1) + hemisphereIndices.push_back(u + 2); + else + hemisphereIndices.push_back(1); + } + + // Add the rest of the rings + uint32 prevRowStart = 1; + uint32 currRowStart = uint32(NumUSlices + 1); + for(uint32 v = 1; v < NumVSlices; ++v) + { + for(uint32 u = 0; u < NumUSlices; ++u) + { + uint32 nextBottom = currRowStart + u + 1; + uint32 nextTop = prevRowStart + u + 1; + if(u == NumUSlices - 1) + { + nextBottom = currRowStart; + nextTop = prevRowStart; + } + + hemisphereIndices.push_back(prevRowStart + u); + hemisphereIndices.push_back(currRowStart + u); + hemisphereIndices.push_back(nextBottom); + hemisphereIndices.push_back(nextBottom); + hemisphereIndices.push_back(nextTop); + hemisphereIndices.push_back(prevRowStart + u); + } + + prevRowStart = currRowStart; + currRowStart += uint32(NumUSlices); + } + + numIndices = hemisphereIndices.size(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = sizeof(Float3) * uint32(hemisphereVerts.size()); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = hemisphereVerts.data(); + initData.SysMemPitch = 0; + initData.SysMemSlicePitch = 0; + DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); + + bufferDesc.ByteWidth = sizeof(uint32) * uint32(hemisphereIndices.size()); + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + initData.pSysMem = hemisphereIndices.data(); + DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); +} + +static void GenerateSphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* device, + ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer, uint64& numIndices) +{ + Assert_(NumUSlices >= 3); + Assert_(NumVSlices >= 3); + + std::vector sphereVerts; + + // Add the vert at the top + sphereVerts.push_back(Float3(0.0f, 0.0f, 1.0f)); + + // Add the rings + for(uint64 v = 0; v < NumVSlices - 1; ++v) + { + for(uint64 u = 0; u < NumUSlices; ++u) + { + const float theta = ((v + 1.0f) / NumVSlices) * Pi; + const float phi = (float(u) / NumUSlices) * Pi2; + + Float3 pos; + pos.x = std::sin(theta) * std::cos(phi); + pos.y = std::sin(theta) * std::sin(phi); + pos.z = std::cos(theta); + + sphereVerts.push_back(pos); + } + } + + // Add the vert at the bottom + const uint32 lastVertIdx = uint32(sphereVerts.size()); + sphereVerts.push_back(Float3(0.0f, 0.0f, -1.0f)); + + Assert_(sphereVerts.size() <= UINT32_MAX); + + // Add the top ring of triangles + std::vector sphereIndices; + for(uint32 u = 0; u < NumUSlices; ++u) + { + sphereIndices.push_back(0); + sphereIndices.push_back(u + 1); + + if(u < NumUSlices - 1) + sphereIndices.push_back(u + 2); + else + sphereIndices.push_back(1); + } + + // Add the rest of the rings + uint32 prevRowStart = 1; + uint32 currRowStart = uint32(NumUSlices + 1); + for(uint32 v = 1; v < NumVSlices - 1; ++v) + { + for(uint32 u = 0; u < NumUSlices; ++u) + { + uint32 nextBottom = currRowStart + u + 1; + uint32 nextTop = prevRowStart + u + 1; + if(u == NumUSlices - 1) + { + nextBottom = currRowStart; + nextTop = prevRowStart; + } + + sphereIndices.push_back(prevRowStart + u); + sphereIndices.push_back(currRowStart + u); + sphereIndices.push_back(nextBottom); + sphereIndices.push_back(nextBottom); + sphereIndices.push_back(nextTop); + sphereIndices.push_back(prevRowStart + u); + } + + prevRowStart = currRowStart; + currRowStart += uint32(NumUSlices); + } + + // Add the last ring at the bottom + const uint32 lastRingStart = uint32(lastVertIdx - NumUSlices); + for(uint32 u = 0; u < NumUSlices; ++u) + { + sphereIndices.push_back(lastVertIdx); + sphereIndices.push_back(lastRingStart + u); + + if(u < NumUSlices - 1) + sphereIndices.push_back(lastRingStart + u + 1); + else + sphereIndices.push_back(lastRingStart); + } + + numIndices = sphereIndices.size(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = sizeof(Float3) * uint32(sphereVerts.size()); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = sphereVerts.data(); + initData.SysMemPitch = 0; + initData.SysMemSlicePitch = 0; + DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); + + bufferDesc.ByteWidth = sizeof(uint32) * uint32(sphereIndices.size()); + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + initData.pSysMem = sphereIndices.data(); + DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); +} + +MeshRenderer::MeshRenderer() : currFrame(0), sceneModel(nullptr), + numHemisphereIndices(0), numAreaLightIndices(0) +{ +} + +void MeshRenderer::LoadShaders() +{ + // Load the mesh shaders + meshDepthVS = CompileVSFromFile(device, L"DepthOnly.hlsl", "VS", "vs_5_0"); + meshVS = CompileVSFromFile(device, L"Mesh.hlsl", "VS", "vs_5_0"); + meshPS = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0"); + + areaLightVS = CompileVSFromFile(device, L"AreaLight.hlsl", "VS", "vs_5_0"); + areaLightPS = CompilePSFromFile(device, L"AreaLight.hlsl", "PS", "ps_5_0"); + + visualizerVS = CompileVSFromFile(device, L"BakeDataVisualizer.hlsl", "VS", "vs_5_0"); + visualizerPS = CompilePSFromFile(device, L"BakeDataVisualizer.hlsl", "PS", "ps_5_0"); + + fullScreenVS = CompileVSFromFile(device, L"EVSMConvert.hlsl", "FullScreenVS"); + + CompileOptions opts; + opts.Add("MSAASamples_", ShadowMSAASamples); + evsmConvertPS = CompilePSFromFile(device, L"EVSMConvert.hlsl", "ConvertToEVSM", "ps_5_0", opts); + + opts.Reset(); + opts.Add("Horizontal_", 1); + opts.Add("Vertical_", 0); + opts.Add("SampleRadius_", SampleRadius); + evsmBlurH = CompilePSFromFile(device, L"EVSMConvert.hlsl", "BlurEVSM", "ps_5_0", opts); + + opts.Reset(); + opts.Add("Horizontal_", 0); + opts.Add("Vertical_", 1); + opts.Add("SampleRadius_", SampleRadius); + evsmBlurV = CompilePSFromFile(device, L"EVSMConvert.hlsl", "BlurEVSM", "ps_5_0", opts); + + opts.Reset(); + opts.Add("MSAA_", 0); + depthReductionInitialCS[0] = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionInitialCS", "cs_5_0", opts); + + opts.Reset(); + opts.Add("MSAA_", 1); + depthReductionInitialCS[1] = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionInitialCS", "cs_5_0", opts); + + depthReductionCS = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionCS"); +} + +void MeshRenderer::CreateShadowMaps() +{ + // Create the shadow map as a texture atlas + sunShadowDepthMap.Initialize(device, ShadowMapSize, ShadowMapSize, DXGI_FORMAT_D24_UNORM_S8_UINT, true, + ShadowMSAASamples, 0, 1); + + DXGI_FORMAT smFmt = DXGI_FORMAT_R32G32B32A32_FLOAT; + uint32 numMips = EnableShadowMips ? 0 : 1; + sunVSM.Initialize(device, ShadowMapSize, ShadowMapSize, smFmt, numMips, 1, 0, + EnableShadowMips, false, NumCascades, false); + + tempVSM.Initialize(device, ShadowMapSize, ShadowMapSize, smFmt, 1, 1, 0, false, false, 1, false); + + areaLightShadowMap.Initialize(device, ShadowMapSize, ShadowMapSize, DXGI_FORMAT_D32_FLOAT, true, 1, 0, 6, true); +} + +// Loads resources +void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* model) +{ + this->device = device; + + blendStates.Initialize(device); + rasterizerStates.Initialize(device); + depthStencilStates.Initialize(device); + samplerStates.Initialize(device); + + meshVSConstants.Initialize(device); + meshPSConstants.Initialize(device); + areaLightConstants.Initialize(device); + visualizerConstants.Initialize(device); + evsmConstants.Initialize(device); + reductionConstants.Initialize(device); + + shSpecularLookupA = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularA.dds"); + shSpecularLookupB = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularB.dds"); + + LoadShaders(); + + D3D11_RASTERIZER_DESC rsDesc = RasterizerStates::NoCullDesc(); + rsDesc.DepthClipEnable = false; + DXCall(device->CreateRasterizerState(&rsDesc, &noZClipRSState)); + + D3D11_SAMPLER_DESC sampDesc = SamplerStates::AnisotropicDesc(); + sampDesc.MaxAnisotropy = ShadowAnisotropy; + DXCall(device->CreateSamplerState(&sampDesc, &evsmSampler)); + + // Create the staging textures for reading back the reduced depth buffer + for(uint32 i = 0; i < ReadbackLatency; ++i) + reductionStagingTextures[i].Initialize(device, 1, 1, DXGI_FORMAT_R16G16_UNORM); + + CreateShadowMaps(); + + GenerateHemisphere(16, 4, device, hemisphereVB, hemisphereIB, numHemisphereIndices); + + GenerateSphere(256, 192, device, areaLightVB, areaLightIB, numAreaLightIndices); + + D3D11_INPUT_ELEMENT_DESC elements[1]; + elements[0].AlignedByteOffset = 0; + elements[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; + elements[0].InputSlot = 0; + elements[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + elements[0].InstanceDataStepRate = 0; + elements[0].SemanticName = "POSITION"; + elements[0].SemanticIndex = 0; + + DXCall(device->CreateInputLayout(elements, 1, visualizerVS->ByteCode->GetBufferPointer(), + visualizerVS->ByteCode->GetBufferSize(), &visualizerInputLayout)); + + DXCall(device->CreateInputLayout(elements, 1, areaLightVS->ByteCode->GetBufferPointer(), + areaLightVS->ByteCode->GetBufferSize(), &areaLightInputLayout)); + + SetModel(model); +} + +void MeshRenderer::SetModel(const Model* model) +{ + Assert_(model != nullptr); + sceneModel = model; + + meshInputLayouts.clear(); + meshDepthInputLayouts.clear(); + + for(uint64 i = 0; i < sceneModel->Meshes().size(); ++i) + { + // Generate input layouts for the scene meshes + const Mesh& mesh = sceneModel->Meshes()[i]; + ID3D11InputLayoutPtr inputLayout; + DXCall(device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), + meshVS->ByteCode->GetBufferPointer(), meshVS->ByteCode->GetBufferSize(), &inputLayout)); + meshInputLayouts.push_back(inputLayout); + + DXCall(device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), + meshDepthVS->ByteCode->GetBufferPointer(), meshDepthVS->ByteCode->GetBufferSize(), &inputLayout)); + meshDepthInputLayouts.push_back(inputLayout); + } +} + +void MeshRenderer::Update(const Camera& camera, Float2 jitterOffset) +{ + prevVP = currVP; + currVP = camera.ViewProjectionMatrix(); + if(firstFrame) + { + prevVP = currVP; + firstFrame = false; + } + + meshPSConstants.Data.JitterOffset = jitterOffset; + areaLightConstants.Data.JitterOffset = jitterOffset; +} + +void MeshRenderer::OnResize(uint32 width, uint32 height) +{ + depthReductionTargets.clear(); + + uint32 w = width; + uint32 h = height; + + while(w > 1 || h > 1) + { + w = DispatchSize(ReductionTGSize, w); + h = DispatchSize(ReductionTGSize, h); + + RenderTarget2D rt; + rt.Initialize(device, w, h, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true); + depthReductionTargets.push_back(rt); + } + + meshPSConstants.Data.RTSize.x = float(width); + meshPSConstants.Data.RTSize.y = float(height); + + areaLightConstants.Data.RTSize = meshPSConstants.Data.RTSize; +} + +void MeshRenderer::ReduceDepth(ID3D11DeviceContext* context, const DepthStencilBuffer& depthTarget, + const Camera& camera) +{ + PIXEvent event(L"Depth Reduction"); + + reductionConstants.Data.Projection = Float4x4::Transpose(camera.ProjectionMatrix()); + reductionConstants.Data.NearClip = camera.NearClip(); + reductionConstants.Data.FarClip = camera.FarClip(); + reductionConstants.Data.TextureSize = Uint2(depthTarget.Width, depthTarget.Height); + reductionConstants.Data.NumSamples = depthTarget.MultiSamples; + reductionConstants.ApplyChanges(context); + reductionConstants.SetCS(context, 0); + + ID3D11RenderTargetView* rtvs[1] = { NULL }; + context->OMSetRenderTargets(1, rtvs, NULL); + + ID3D11UnorderedAccessView* uavs[1] = { depthReductionTargets[0].UAView }; + context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); + + ID3D11ShaderResourceView* srvs[1] = { depthTarget.SRView }; + context->CSSetShaderResources(0, 1, srvs); + + const bool msaa = depthTarget.MultiSamples > 1; + + ID3D11ComputeShader* shader = depthReductionInitialCS[msaa ? 1 : 0]; + context->CSSetShader(shader, NULL, 0); + + uint32 dispatchX = depthReductionTargets[0].Width; + uint32 dispatchY = depthReductionTargets[0].Height; + context->Dispatch(dispatchX, dispatchY, 1); + + uavs[0] = NULL; + context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); + + srvs[0] = NULL; + context->CSSetShaderResources(0, 1, srvs); + + context->CSSetShader(depthReductionCS, NULL, 0); + + for(uint32 i = 1; i < depthReductionTargets.size(); ++i) + { + RenderTarget2D& srcTexture = depthReductionTargets[i - 1]; + reductionConstants.Data.TextureSize.x = srcTexture.Width; + reductionConstants.Data.TextureSize.y = srcTexture.Height; + reductionConstants.Data.NumSamples = srcTexture.MultiSamples; + reductionConstants.ApplyChanges(context); + + uavs[0] = depthReductionTargets[i].UAView; + context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); + + srvs[0] = srcTexture.SRView; + context->CSSetShaderResources(0, 1, srvs); + + dispatchX = depthReductionTargets[i].Width; + dispatchY = depthReductionTargets[i].Height; + context->Dispatch(dispatchX, dispatchY, 1); + + uavs[0] = NULL; + context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); + + srvs[0] = NULL; + context->CSSetShaderResources(0, 1, srvs); + } + + // Copy to a staging texture + ID3D11Texture2D* lastTarget = depthReductionTargets[depthReductionTargets.size() - 1].Texture; + context->CopyResource(reductionStagingTextures[currFrame % ReadbackLatency].Texture, lastTarget); + + ++currFrame; + + if(currFrame >= ReadbackLatency) + { + StagingTexture2D& stagingTexture = reductionStagingTextures[currFrame % ReadbackLatency]; + + uint32 pitch; + const uint16* texData = reinterpret_cast(stagingTexture.Map(context, 0, pitch)); + reductionDepth.x = texData[0] / static_cast(0xffff); + reductionDepth.y = texData[1] / static_cast(0xffff); + + stagingTexture.Unmap(context, 0); + } + else + { + reductionDepth = Float2(0.0f, 1.0f); + } +} + +// Convert to an EVSM map +void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx, Float3 cascadeScale) +{ + PIXEvent event(L"EVSM Conversion"); + + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->RSSetState(rasterizerStates.NoCull()); + context->OMSetDepthStencilState(depthStencilStates.DepthDisabled(), 0); + ID3D11Buffer* vbs[1] = { NULL }; + uint32 strides[1] = { 0 }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vbs, strides, offsets); + context->IASetIndexBuffer(NULL, DXGI_FORMAT_R32_UINT, 0); + context->IASetInputLayout(NULL); + + SetViewport(context, sunVSM.Width, sunVSM.Height); + + evsmConstants.Data.PositiveExponent = PositiveExponent; + evsmConstants.Data.NegativeExponent = NegativeExponent; + evsmConstants.Data.CascadeScale = meshPSConstants.Data.CascadeScales[cascadeIdx].To3D(); + evsmConstants.Data.FilterSize = 1.0f; + evsmConstants.Data.ShadowMapSize.x = float(sunVSM.Width); + evsmConstants.Data.ShadowMapSize.y = float(sunVSM.Height); + evsmConstants.ApplyChanges(context); + evsmConstants.SetPS(context, 0); + + context->VSSetShader(fullScreenVS, NULL, 0); + context->PSSetShader(evsmConvertPS, NULL, 0); + + ID3D11RenderTargetView* rtvs[1] = { sunVSM.RTVArraySlices[cascadeIdx] }; + context->OMSetRenderTargets(1, rtvs, NULL); + + ID3D11ShaderResourceView* srvs[1] = { sunShadowDepthMap.SRView }; + context->PSSetShaderResources(0, 1, srvs); + + context->Draw(3, 0); + + srvs[0] = NULL; + context->PSSetShaderResources(0, 1, srvs); + + const float FilterSizeU = std::max(FilterSize * cascadeScale.x, 1.0f); + const float FilterSizeV = std::max(FilterSize * cascadeScale.y, 1.0f); + + if(FilterSizeU > 1.0f || FilterSizeV > 1.0f) + { + // Horizontal pass + evsmConstants.Data.FilterSize = FilterSizeU; + evsmConstants.ApplyChanges(context); + + uint32 sampleRadiusU = static_cast((FilterSizeU / 2) + 0.499f); + + rtvs[0] = tempVSM.RTView; + context->OMSetRenderTargets(1, rtvs, NULL); + + srvs[0] = sunVSM.SRVArraySlices[cascadeIdx]; + context->PSSetShaderResources(0, 1, srvs); + + context->PSSetShader(evsmBlurH, NULL, 0); + + context->Draw(3, 0); + + srvs[0] = NULL; + context->PSSetShaderResources(0, 1, srvs); + + // Vertical pass + evsmConstants.Data.FilterSize = FilterSizeV; + evsmConstants.ApplyChanges(context); + + uint32 sampleRadiusV = static_cast((FilterSizeV / 2) + 0.499f); + + rtvs[0] = sunVSM.RTVArraySlices[cascadeIdx]; + context->OMSetRenderTargets(1, rtvs, NULL); + + srvs[0] = tempVSM.SRView; + context->PSSetShaderResources(0, 1, srvs); + + context->PSSetShader(evsmBlurV, NULL, 0); + + context->Draw(3, 0); + + srvs[0] = NULL; + context->PSSetShaderResources(0, 1, srvs); + } + + if(EnableShadowMips && cascadeIdx == NumCascades - 1) + context->GenerateMips(sunVSM.SRView); +} + +// Renders all meshes in the model, with shadows +void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) +{ + PIXEvent event(L"Mesh Rendering"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthEnabled(), 0); + context->RSSetState(rasterizerStates.BackFaceCull()); + + ID3D11SamplerState* sampStates[] = { + samplerStates.Anisotropic(), + evsmSampler, + samplerStates.LinearClamp(), + samplerStates.ReversedShadowMapPCF(), + }; + + context->PSSetSamplers(0, ArraySize_(sampStates), sampStates); + + // Set constant buffers + meshVSConstants.Data.World = Float4x4(); + meshVSConstants.Data.View = Float4x4::Transpose(camera.ViewMatrix()); + meshVSConstants.Data.WorldViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + meshVSConstants.Data.PrevWorldViewProjection = Float4x4::Transpose(prevVP); + meshVSConstants.ApplyChanges(context); + meshVSConstants.SetVS(context, 0); + + meshPSConstants.Data.SunDirectionWS = AppSettings::SunDirection; + meshPSConstants.Data.SunIlluminance = AppSettings::SunIlluminance(); + meshPSConstants.Data.CosSunAngularRadius = std::cos(DegToRad(AppSettings::SunSize) / 2.0f); + meshPSConstants.Data.SinSunAngularRadius = std::sin(DegToRad(AppSettings::SunSize) / 2.0f); + meshPSConstants.Data.CameraPosWS = camera.Position(); + meshPSConstants.Data.OffsetScale = OffsetScale; + meshPSConstants.Data.PositiveExponent = PositiveExponent; + meshPSConstants.Data.NegativeExponent = NegativeExponent; + meshPSConstants.Data.LightBleedingReduction = LightBleedingReduction; + for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) + meshPSConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); + meshPSConstants.Data.SGSharpness = status.SGSharpness; + meshPSConstants.ApplyChanges(context); + meshPSConstants.SetPS(context, 0); + + // Set shaders + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->VSSetShader(meshVS, nullptr, 0); + context->PSSetShader(meshPS, nullptr, 0); + + // Draw all meshes + for(uint64 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) + { + const Mesh& mesh = sceneModel->Meshes()[meshIdx]; + + // Set the vertices and indices + ID3D11Buffer* vertexBuffers[1] = { mesh.VertexBuffer() }; + UINT vertexStrides[1] = { mesh.VertexStride() }; + UINT offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(mesh.IndexBuffer(), mesh.IndexBufferFormat(), 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + // Set the input layout + context->IASetInputLayout(meshInputLayouts[meshIdx]); + + // Draw all parts + for(uint64 partIdx = 0; partIdx < mesh.MeshParts().size(); ++partIdx) + { + const MeshPart& part = mesh.MeshParts()[partIdx]; + const MeshMaterial& material = sceneModel->Materials()[part.MaterialIdx]; + + // Set the textures + ID3D11ShaderResourceView* psTextures[] = + { + material.DiffuseMap, + material.NormalMap, + material.RoughnessMap, + material.MetallicMap, + sunVSM.SRView, + status.LightMap, + areaLightShadowMap.SRView, + shSpecularLookupA, + shSpecularLookupB, + status.ProbeIrradiance, + }; + + context->PSSetShaderResources(0, ArraySize_(psTextures), psTextures); + context->DrawIndexed(part.IndexCount, part.IndexStart, 0); + } + } + + ID3D11ShaderResourceView* nullSRVs[10] = { NULL }; + context->PSSetShaderResources(0, ArraySize_(nullSRVs), nullSRVs); +} + +// Renders all meshes using depth-only rendering +void MeshRenderer::RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange) +{ + PIXEvent event(L"Mesh Depth Rendering"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.ColorWriteDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(flippedZRange ? depthStencilStates.ReverseDepthWriteEnabled() + : depthStencilStates.DepthWriteEnabled(), 0); + + if(noZClip) + context->RSSetState(noZClipRSState); + else + context->RSSetState(rasterizerStates.BackFaceCull()); + + // Set constant buffers + meshVSConstants.Data.World = Float4x4(); + meshVSConstants.Data.View = Float4x4::Transpose(camera.ViewMatrix()); + meshVSConstants.Data.WorldViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + meshVSConstants.ApplyChanges(context); + meshVSConstants.SetVS(context, 0); + + // Set shaders + context->VSSetShader(meshDepthVS , nullptr, 0); + context->PSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + + for(uint32 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) + { + const Mesh& mesh = sceneModel->Meshes()[meshIdx]; + + // Set the vertices and indices + ID3D11Buffer* vertexBuffers[1] = { mesh.VertexBuffer() }; + UINT vertexStrides[1] = { mesh.VertexStride() }; + UINT offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(mesh.IndexBuffer(), mesh.IndexBufferFormat(), 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + // Set the input layout + context->IASetInputLayout(meshDepthInputLayouts[meshIdx]); + + // Draw all parts + for(uint64 partIdx = 0; partIdx < mesh.MeshParts().size(); ++partIdx) + { + const MeshPart& part = mesh.MeshParts()[partIdx]; + context->DrawIndexed(part.IndexCount, part.IndexStart, 0); + } + } +} + +// Renders meshes using cascaded shadow mapping +void MeshRenderer::RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera) +{ + PIXEvent event(L"Sun Shadow Map Rendering"); + + const float MinDistance = reductionDepth.x; + const float MaxDistance = reductionDepth.y; + + // Compute the split distances based on the partitioning mode + float CascadeSplits[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + { + float lambda = 1.0f; + + float nearClip = camera.NearClip(); + float farClip = camera.FarClip(); + float clipRange = farClip - nearClip; + + float minZ = nearClip + MinDistance * clipRange; + float maxZ = nearClip + MaxDistance * clipRange; + + float range = maxZ - minZ; + float ratio = maxZ / minZ; + + for(uint32 i = 0; i < NumCascades; ++i) + { + float p = (i + 1) / static_cast(NumCascades); + float log = minZ * std::pow(ratio, p); + float uniform = minZ + range * p; + float d = lambda * (log - uniform) + uniform; + CascadeSplits[i] = (d - nearClip) / clipRange; + } + } + + Float3 c0Extents; + Float4x4 c0Matrix; + + const Float3 lightDir = AppSettings::SunDirection; + + // Render the meshes to each cascade + for(uint32 cascadeIdx = 0; cascadeIdx < NumCascades; ++cascadeIdx) + { + PIXEvent cascadeEvent((L"Rendering Shadow Map Cascade " + ToString(cascadeIdx)).c_str()); + + // Set the viewport + SetViewport(context, ShadowMapSize, ShadowMapSize); + + // Set the shadow map as the depth target + ID3D11DepthStencilView* dsv = sunShadowDepthMap.DSView; + ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { NULL }; + context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); + context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); + + // Get the 8 points of the view frustum in world space + XMVECTOR frustumCornersWS[8] = + { + XMVectorSet(-1.0f, 1.0f, 0.0f, 1.0f), + XMVectorSet( 1.0f, 1.0f, 0.0f, 1.0f), + XMVectorSet( 1.0f, -1.0f, 0.0f, 1.0f), + XMVectorSet(-1.0f, -1.0f, 0.0f, 1.0f), + XMVectorSet(-1.0f, 1.0f, 1.0f, 1.0f), + XMVectorSet( 1.0f, 1.0f, 1.0f, 1.0f), + XMVectorSet( 1.0f, -1.0f, 1.0f, 1.0f), + XMVectorSet(-1.0f, -1.0f, 1.0f, 1.0f), + }; + + float prevSplitDist = cascadeIdx == 0 ? MinDistance : CascadeSplits[cascadeIdx - 1]; + float splitDist = CascadeSplits[cascadeIdx]; + + XMVECTOR det; + XMMATRIX invViewProj = XMMatrixInverse(&det, camera.ViewProjectionMatrix().ToSIMD()); + for(uint32 i = 0; i < 8; ++i) + frustumCornersWS[i] = XMVector3TransformCoord(frustumCornersWS[i], invViewProj); + + // Get the corners of the current cascade slice of the view frustum + for(uint32 i = 0; i < 4; ++i) + { + XMVECTOR cornerRay = XMVectorSubtract(frustumCornersWS[i + 4], frustumCornersWS[i]); + XMVECTOR nearCornerRay = XMVectorScale(cornerRay, prevSplitDist); + XMVECTOR farCornerRay = XMVectorScale(cornerRay, splitDist); + frustumCornersWS[i + 4] = XMVectorAdd(frustumCornersWS[i], farCornerRay); + frustumCornersWS[i] = XMVectorAdd(frustumCornersWS[i], nearCornerRay); + } + + // Calculate the centroid of the view frustum slice + XMVECTOR frustumCenterVec = XMVectorZero(); + for(uint32 i = 0; i < 8; ++i) + frustumCenterVec = XMVectorAdd(frustumCenterVec, frustumCornersWS[i]); + frustumCenterVec = XMVectorScale(frustumCenterVec, 1.0f / 8.0f); + Float3 frustumCenter = frustumCenterVec; + + // Pick the up vector to use for the light camera + Float3 upDir = camera.Right(); + + Float3 minExtents; + Float3 maxExtents; + + { + // Create a temporary view matrix for the light + Float3 lightCameraPos = frustumCenter; + Float3 lookAt = frustumCenter - lightDir; + XMMATRIX lightView = XMMatrixLookAtLH(lightCameraPos.ToSIMD(), lookAt.ToSIMD(), upDir.ToSIMD()); + + // Calculate an AABB around the frustum corners + XMVECTOR mins = XMVectorSet(REAL_MAX, REAL_MAX, REAL_MAX, REAL_MAX); + XMVECTOR maxes = XMVectorSet(-REAL_MAX, -REAL_MAX, -REAL_MAX, -REAL_MAX); + for(uint32 i = 0; i < 8; ++i) + { + XMVECTOR corner = XMVector3TransformCoord(frustumCornersWS[i], lightView); + mins = XMVectorMin(mins, corner); + maxes = XMVectorMax(maxes, corner); + } + + minExtents = mins; + maxExtents = maxes; + } + + // Adjust the min/max to accommodate the filtering size + float scale = (ShadowMapSize + FilterSize) / static_cast(ShadowMapSize); + minExtents.x *= scale; + minExtents.y *= scale; + maxExtents.x *= scale; + maxExtents.y *= scale; + + Float3 cascadeExtents = maxExtents - minExtents; + + // Get position of the shadow camera + Float3 shadowCameraPos = frustumCenter + lightDir * -minExtents.z; + + // Come up with a new orthographic camera for the shadow caster + OrthographicCamera shadowCamera(minExtents.x, minExtents.y, maxExtents.x, + maxExtents.y, 0.0f, cascadeExtents.z); + shadowCamera.SetLookAt(shadowCameraPos, frustumCenter, upDir); + + // Draw the mesh with depth only, using the new shadow camera + RenderDepth(context, shadowCamera, true, false); + + // Apply the scale/offset matrix, which transforms from [-1,1] + // post-projection space to [0,1] UV space + XMMATRIX texScaleBias; + texScaleBias.r[0] = XMVectorSet(0.5f, 0.0f, 0.0f, 0.0f); + texScaleBias.r[1] = XMVectorSet(0.0f, -0.5f, 0.0f, 0.0f); + texScaleBias.r[2] = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); + texScaleBias.r[3] = XMVectorSet(0.5f, 0.5f, 0.0f, 1.0f); + XMMATRIX shadowMatrix = shadowCamera.ViewProjectionMatrix().ToSIMD(); + shadowMatrix = XMMatrixMultiply(shadowMatrix, texScaleBias); + + // Store the split distance in terms of view space depth + const float clipDist = camera.FarClip() - camera.NearClip(); + meshPSConstants.Data.CascadeSplits[cascadeIdx] = camera.NearClip() + splitDist * clipDist; + + if(cascadeIdx == 0) + { + c0Extents = cascadeExtents; + c0Matrix = shadowMatrix; + meshPSConstants.Data.ShadowMatrix = XMMatrixTranspose(shadowMatrix); + meshPSConstants.Data.CascadeOffsets[0] = Float4(0.0f, 0.0f, 0.0f, 0.0f); + meshPSConstants.Data.CascadeScales[0] = Float4(1.0f, 1.0f, 1.0f, 1.0f); + } + else + { + // Calculate the position of the lower corner of the cascade partition, in the UV space + // of the first cascade partition + Float4x4 invCascadeMat = Float4x4::Invert(shadowMatrix); + Float3 cascadeCorner = Float3::Transform(Float3(0.0f, 0.0f, 0.0f), invCascadeMat); + cascadeCorner = Float3::Transform(cascadeCorner, c0Matrix); + + // Do the same for the upper corner + Float3 otherCorner = Float3::Transform(Float3(1.0f, 1.0f, 1.0f), invCascadeMat); + otherCorner = Float3::Transform(otherCorner, c0Matrix); + + // Calculate the scale and offset + Float3 cascadeScale = Float3(1.0f, 1.0f, 1.f) / (otherCorner - cascadeCorner); + meshPSConstants.Data.CascadeOffsets[cascadeIdx] = Float4(-cascadeCorner, 0.0f); + meshPSConstants.Data.CascadeScales[cascadeIdx] = Float4(cascadeScale, 1.0f); + } + + ConvertToEVSM(context, cascadeIdx, meshPSConstants.Data.CascadeScales[cascadeIdx].To3D()); + } +} + +// Renders an omni-directional shadow map for the spherical area light +void MeshRenderer::RenderAreaLightShadowMap(ID3D11DeviceContext* context, const Camera& camera) +{ + PIXEvent event(L"Area Light Shadow Map Rendering"); + + const uint32 sMapSize = areaLightShadowMap.Width; + const Float3 areaLightPos = Float3(AppSettings::AreaLightX, AppSettings::AreaLightY, AppSettings::AreaLightZ); + const float nearClip = AppSettings::AreaLightSize; + + for(uint64 face = 0; face < 6; ++face) + { + PIXEvent faceEvent(L"Area Light Shadow Map Face " + ToString(face)); + + // Set the viewport + SetViewport(context, sMapSize, sMapSize); + + // Set the shadow map as the depth target + ID3D11DepthStencilView* dsv = areaLightShadowMap.ArraySlices[face]; + ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { NULL }; + context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); + context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 0.0f, 0); + + PerspectiveCamera shadowCamera(1.0f, Pi_2, nearClip, nearClip + 1.0f); + + // Set up a infinite reverse projection + Float4x4 projection; + projection._33 = 0.0f; + projection._43 = nearClip; + projection._34 = 1.0f; + projection._44 = 0.0f; + shadowCamera.SetProjection(projection); + + static const Float3 LookAtDirs[6] = + { + Float3(1.0f, 0.0f, 0.0f), Float3(-1.0f, 0.0f, 0.0f), + Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, -1.0f, 0.0f), + Float3(0.0f, 0.0f, 1.0f), Float3(0.0f, 0.0f, -1.0f) + }; + + static const Float3 UpDirs[6] = { + Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, 1.0f, 0.0f), + Float3(0.0f, 0.0f, -1.0f), Float3(0.0f, 0.0f, 1.0f), + Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, 1.0f, 0.0f), + }; + + shadowCamera.SetLookAt(areaLightPos, areaLightPos + LookAtDirs[face], UpDirs[face]); + + RenderDepth(context, shadowCamera, false, true); + } +} + +// Renders the area light +void MeshRenderer::RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera) +{ + PIXEvent event(L"Area Light Rendering"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); + context->RSSetState(rasterizerStates.NoCull()); + + // Set constant buffers + areaLightConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + areaLightConstants.Data.PrevViewProjection = Float4x4::Transpose(prevVP); + areaLightConstants.ApplyChanges(context); + areaLightConstants.SetVS(context, 0); + areaLightConstants.SetPS(context, 0); + + // Set shaders + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->VSSetShader(areaLightVS , nullptr, 0); + context->PSSetShader(areaLightPS, nullptr, 0); + + // Draw the visualizer sphere + ID3D11Buffer* vertexBuffers[1] = { areaLightVB }; + uint32 vertexStrides[1] = { sizeof(Float3) }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(areaLightIB, DXGI_FORMAT_R32_UINT, 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(areaLightInputLayout); + context->DrawIndexedInstanced(uint32(numAreaLightIndices), 1, 0, 0, 0); +} + +// Renders the bake data visualizer +void MeshRenderer::RenderBakeDataVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) +{ + PIXEvent event(L"Bake Data Visualizer"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); + context->RSSetState(rasterizerStates.NoCull()); + + // Set constant buffers + visualizerConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) + visualizerConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); + visualizerConstants.Data.SGSharpness = status.SGSharpness; + visualizerConstants.ApplyChanges(context); + visualizerConstants.SetVS(context, 0); + visualizerConstants.SetPS(context, 0); + + // Set shaders + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->VSSetShader(visualizerVS , nullptr, 0); + context->PSSetShader(visualizerPS, nullptr, 0); + + ID3D11ShaderResourceView* vsSrvs[] = { status.BakePoints }; + context->VSSetShaderResources(0, ArraySize_(vsSrvs), vsSrvs); + + ID3D11ShaderResourceView* psSrvs[1] = { status.LightMap }; + context->PSSetShaderResources(0, 1, psSrvs); + + // Draw the visualizer hemispheres for all sample points + ID3D11Buffer* vertexBuffers[1] = { hemisphereVB }; + uint32 vertexStrides[1] = { sizeof(Float3) }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(hemisphereIB, DXGI_FORMAT_R32_UINT, 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(visualizerInputLayout); + + // Draw + context->DrawIndexedInstanced(uint32(numHemisphereIndices), uint32(status.NumBakePoints), 0, 0, 0); + + ID3D11ShaderResourceView* nullSRVs[] = { nullptr }; + context->VSSetShaderResources(0, 1, nullSRVs); + context->PSSetShaderResources(0, 1, nullSRVs); } \ No newline at end of file diff --git a/BakingLab/MeshRenderer.h b/BakingLab/MeshRenderer.h index f3295d6..a4d31ee 100644 --- a/BakingLab/MeshRenderer.h +++ b/BakingLab/MeshRenderer.h @@ -1,201 +1,201 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -#include "AppSettings.h" - -using namespace SampleFramework11; - -struct MeshBakerStatus; - -class MeshRenderer -{ - -protected: - - // Constants - static const uint32 NumCascades = 4; - static const uint32 ReadbackLatency = 1; - -public: -MeshRenderer(); - - void Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* sceneModel); - void SetModel(const Model* model); - - void RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange); - void RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status); - - void Update(const Camera& camera, Float2 jitterOffset); - - void OnResize(uint32 width, uint32 height); - - void ReduceDepth(ID3D11DeviceContext* context, DepthStencilBuffer& depthTarget, - const Camera& camera); - - void RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera); - void RenderAreaLightShadowMap(ID3D11DeviceContext* context, const Camera& camera); - - void RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera); - void RenderBakeDataVisualizer(ID3D11DeviceContext* context, const Camera& camera, - const MeshBakerStatus& status); - -protected: - - void LoadShaders(); - void CreateShadowMaps(); - void ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx, Float3 cascadeScale); - - ID3D11DevicePtr device; - - BlendStates blendStates; - RasterizerStates rasterizerStates; - DepthStencilStates depthStencilStates; - SamplerStates samplerStates; - - const Model* sceneModel; - - DepthStencilBuffer sunShadowDepthMap; - RenderTarget2D sunVSM; - RenderTarget2D tempVSM; - - DepthStencilBuffer areaLightShadowMap; - - ID3D11RasterizerStatePtr noZClipRSState; - ID3D11SamplerStatePtr evsmSampler; - - std::vector meshInputLayouts; - VertexShaderPtr meshVS; - PixelShaderPtr meshPS; - - std::vector meshDepthInputLayouts; - VertexShaderPtr meshDepthVS; - - ID3D11BufferPtr hemisphereVB; - ID3D11BufferPtr hemisphereIB; - uint64 numHemisphereIndices; - - ID3D11InputLayoutPtr visualizerInputLayout; - VertexShaderPtr visualizerVS; - PixelShaderPtr visualizerPS; - - ID3D11BufferPtr areaLightVB; - ID3D11BufferPtr areaLightIB; - uint64 numAreaLightIndices; - - VertexShaderPtr areaLightVS; - PixelShaderPtr areaLightPS; - ID3D11InputLayoutPtr areaLightInputLayout; - - VertexShaderPtr fullScreenVS; - PixelShaderPtr evsmConvertPS; - PixelShaderPtr evsmBlurH; - PixelShaderPtr evsmBlurV; - - ComputeShaderPtr depthReductionInitialCS[2]; - ComputeShaderPtr depthReductionCS; - std::vector depthReductionTargets; - StagingTexture2D reductionStagingTextures[ReadbackLatency]; - uint32 currFrame; - - Float2 reductionDepth; - - Float4x4 prevVP; - Float4x4 currVP; - bool firstFrame = true; - - ID3D11ShaderResourceViewPtr shSpecularLookupA; - ID3D11ShaderResourceViewPtr shSpecularLookupB; - - // Constant buffers - struct MeshVSConstants - { - Float4Align Float4x4 World; - Float4Align Float4x4 View; - Float4Align Float4x4 WorldViewProjection; - Float4Align Float4x4 PrevWorldViewProjection; - }; - - struct MeshPSConstants - { - Float4Align Float3 SunDirectionWS; - float CosSunAngularRadius; - Float4Align Float3 SunIlluminance; - float SinSunAngularRadius; - Float4Align Float3 CameraPosWS; - - Float4Align Float4x4 ShadowMatrix; - Float4Align float CascadeSplits[NumCascades]; - - Float4Align Float4 CascadeOffsets[NumCascades]; - Float4Align Float4 CascadeScales[NumCascades]; - - float OffsetScale; - float PositiveExponent; - float NegativeExponent; - float LightBleedingReduction; - - Float2 RTSize; - Float2 JitterOffset; - - Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; - float SGSharpness; - }; - - struct AreaLightConstants - { - Float4x4 ViewProjection; - Float4x4 PrevViewProjection; - Float2 RTSize; - Float2 JitterOffset; - }; - - struct EVSMConstants - { - Float3 CascadeScale; - float PositiveExponent; - float NegativeExponent; - float FilterSize; - Float2 ShadowMapSize; - }; - - struct ReductionConstants - { - Float4x4 Projection; - float NearClip; - float FarClip; - Uint2 TextureSize; - uint32 NumSamples; - }; - - struct VisualizerConstants - { - Float4x4 ViewProjection; - Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; - float SGSharpness; - }; - - ConstantBuffer meshVSConstants; - ConstantBuffer meshPSConstants; - ConstantBuffer areaLightConstants; - ConstantBuffer visualizerConstants; - ConstantBuffer evsmConstants; - ConstantBuffer reductionConstants; +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +#include "AppSettings.h" + +using namespace SampleFramework11; + +struct MeshBakerStatus; + +class MeshRenderer +{ + +protected: + + // Constants + static const uint32 NumCascades = 4; + static const uint32 ReadbackLatency = 1; + +public: +MeshRenderer(); + + void Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* sceneModel); + void SetModel(const Model* model); + + void RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange); + void RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status); + + void Update(const Camera& camera, Float2 jitterOffset); + + void OnResize(uint32 width, uint32 height); + + void ReduceDepth(ID3D11DeviceContext* context, const DepthStencilBuffer& depthTarget, + const Camera& camera); + + void RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera); + void RenderAreaLightShadowMap(ID3D11DeviceContext* context, const Camera& camera); + + void RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera); + void RenderBakeDataVisualizer(ID3D11DeviceContext* context, const Camera& camera, + const MeshBakerStatus& status); + +protected: + + void LoadShaders(); + void CreateShadowMaps(); + void ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx, Float3 cascadeScale); + + ID3D11DevicePtr device; + + BlendStates blendStates; + RasterizerStates rasterizerStates; + DepthStencilStates depthStencilStates; + SamplerStates samplerStates; + + const Model* sceneModel; + + DepthStencilBuffer sunShadowDepthMap; + RenderTarget2D sunVSM; + RenderTarget2D tempVSM; + + DepthStencilBuffer areaLightShadowMap; + + ID3D11RasterizerStatePtr noZClipRSState; + ID3D11SamplerStatePtr evsmSampler; + + std::vector meshInputLayouts; + VertexShaderPtr meshVS; + PixelShaderPtr meshPS; + + std::vector meshDepthInputLayouts; + VertexShaderPtr meshDepthVS; + + ID3D11BufferPtr hemisphereVB; + ID3D11BufferPtr hemisphereIB; + uint64 numHemisphereIndices; + + ID3D11InputLayoutPtr visualizerInputLayout; + VertexShaderPtr visualizerVS; + PixelShaderPtr visualizerPS; + + ID3D11BufferPtr areaLightVB; + ID3D11BufferPtr areaLightIB; + uint64 numAreaLightIndices; + + VertexShaderPtr areaLightVS; + PixelShaderPtr areaLightPS; + ID3D11InputLayoutPtr areaLightInputLayout; + + VertexShaderPtr fullScreenVS; + PixelShaderPtr evsmConvertPS; + PixelShaderPtr evsmBlurH; + PixelShaderPtr evsmBlurV; + + ComputeShaderPtr depthReductionInitialCS[2]; + ComputeShaderPtr depthReductionCS; + std::vector depthReductionTargets; + StagingTexture2D reductionStagingTextures[ReadbackLatency]; + uint32 currFrame; + + Float2 reductionDepth; + + Float4x4 prevVP; + Float4x4 currVP; + bool firstFrame = true; + + ID3D11ShaderResourceViewPtr shSpecularLookupA; + ID3D11ShaderResourceViewPtr shSpecularLookupB; + + // Constant buffers + struct MeshVSConstants + { + Float4Align Float4x4 World; + Float4Align Float4x4 View; + Float4Align Float4x4 WorldViewProjection; + Float4Align Float4x4 PrevWorldViewProjection; + }; + + struct MeshPSConstants + { + Float4Align Float3 SunDirectionWS; + float CosSunAngularRadius; + Float4Align Float3 SunIlluminance; + float SinSunAngularRadius; + Float4Align Float3 CameraPosWS; + + Float4Align Float4x4 ShadowMatrix; + Float4Align float CascadeSplits[NumCascades]; + + Float4Align Float4 CascadeOffsets[NumCascades]; + Float4Align Float4 CascadeScales[NumCascades]; + + float OffsetScale; + float PositiveExponent; + float NegativeExponent; + float LightBleedingReduction; + + Float2 RTSize; + Float2 JitterOffset; + + Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; + float SGSharpness; + }; + + struct AreaLightConstants + { + Float4x4 ViewProjection; + Float4x4 PrevViewProjection; + Float2 RTSize; + Float2 JitterOffset; + }; + + struct EVSMConstants + { + Float3 CascadeScale; + float PositiveExponent; + float NegativeExponent; + float FilterSize; + Float2 ShadowMapSize; + }; + + struct ReductionConstants + { + Float4x4 Projection; + float NearClip; + float FarClip; + Uint2 TextureSize; + uint32 NumSamples; + }; + + struct VisualizerConstants + { + Float4x4 ViewProjection; + Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; + float SGSharpness; + }; + + ConstantBuffer meshVSConstants; + ConstantBuffer meshPSConstants; + ConstantBuffer areaLightConstants; + ConstantBuffer visualizerConstants; + ConstantBuffer evsmConstants; + ConstantBuffer reductionConstants; }; \ No newline at end of file diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl new file mode 100644 index 0000000..620fe11 --- /dev/null +++ b/BakingLab/ProbeIntegrate.hlsl @@ -0,0 +1,177 @@ +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include + +cbuffer IntegrateConstants : register(b0) +{ + float2 OutputTextureSize; + uint OutputSliceOffset; +} + +TextureCube RadianceMap : register(t0); +RWTexture2DArray IrradianceMap : register(u0); + +SamplerState LinearSampler : register(s0); + +float3 ComputeCubemapDirection(in uint2 pos, in uint face, in float2 textureSize) +{ + float u = ((pos.x + 0.5f) / textureSize.x) * 2.0f - 1.0f; + float v = ((pos.y + 0.5f) / textureSize.y) * 2.0f - 1.0f; + v *= -1.0f; + + float3 dir = 0.0f; + + // +x, -x, +y, -y, +z, -z + switch(face) + { + case 0: + dir = normalize(float3(1.0f, v, -u)); + break; + case 1: + dir = normalize(float3(-1.0f, v, u)); + break; + case 2: + dir = normalize(float3(u, 1.0f, -v)); + break; + case 3: + dir = normalize(float3(u, -1.0f, v)); + break; + case 4: + dir = normalize(float3(u, v, 1.0f)); + break; + case 5: + dir = normalize(float3(-u, v, -1.0f)); + break; + } + + return dir; +} + +// Computes a radical inverse with base 2 using crazy bit-twiddling from "Hacker's Delight" +float RadicalInverseBase2(in 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-10f; // / 0x100000000 +} + +// Returns a single 2D point in a Hammersley sequence of length "numSamples", using base 1 and base 2 +float2 Hammersley2D(in uint sampleIdx, in uint numSamples) +{ + return float2(float(sampleIdx) / float(numSamples), RadicalInverseBase2(sampleIdx)); +} + +inline float2 SquareToConcentricDiskMapping(float x, float y) +{ + float phi = 0.0f; + float r = 0.0f; + + // -- (a,b) is now on [-1,1]ˆ2 + float a = 2.0f * x - 1.0f; + float b = 2.0f * y - 1.0f; + + if(a > -b) // region 1 or 2 + { + if(a > b) // region 1, also |a| > |b| + { + r = a; + phi = (Pi / 4.0f) * (b / a); + } + else // region 2, also |b| > |a| + { + r = b; + phi = (Pi / 4.0f) * (2.0f - (a / b)); + } + } + else // region 3 or 4 + { + if(a < b) // region 3, also |a| >= |b|, a != 0 + { + r = -a; + phi = (Pi / 4.0f) * (4.0f + (b / a)); + } + else // region 4, |b| >= |a|, but a==0 and b==0 could occur. + { + r = -b; + if(b != 0) + phi = (Pi / 4.0f) * (6.0f - (a / b)); + else + phi = 0; + } + } + + float2 result; + result.x = r * cos(phi); + result.y = r * sin(phi); + return result; +} + +inline float3 SampleCosineHemisphere(in float u1, in float u2) +{ + float2 uv = SquareToConcentricDiskMapping(u1, u2); + float u = uv.x; + float v = uv.y; + + // Project samples on the disk to the hemisphere to get a + // cosine weighted distribution + float3 dir; + float r = u * u + v * v; + dir.x = u; + dir.y = v; + dir.z = sqrt(max(0.0f, 1.0f - r)); + + return dir; +} + +[numthreads(8, 8, 1)] +void IntegrateIrradiance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + uint2 outputPos = GroupID.xy * 8 + GroupThreadID.xy; + uint outputFaceIdx = GroupID.z; + uint outputSliceIdx = OutputSliceOffset + outputFaceIdx; + + float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); + + float3 tangent = 0.0f; + if(outputFaceIdx == 0) + tangent = float3(0.0f, 0.0f, -1.0f); + else if(outputFaceIdx == 1) + tangent = float3(0.0f, 0.0f, 1.0f); + else if(outputFaceIdx == 2) + tangent = float3(1.0f, 0.0f, 0.0f); + else if(outputFaceIdx == 3) + tangent = float3(1.0f, 0.0f, 0.0f); + else if(outputFaceIdx == 4) + tangent = float3(1.0f, 0.0f, 0.0f); + else if(outputFaceIdx == 5) + tangent = float3(-1.0f, 0.0f, 0.0f); + + float3 bitangent = normalize(cross(normal, tangent)); + tangent = normalize(cross(bitangent, normal)); + + const uint numSamples = 64; + float3 irradiance = 0.0f; + for(uint i = 0; i < numSamples; ++i) + { + float2 samplePos = Hammersley2D(i, numSamples); + float3 sampleDir = SampleCosineHemisphere(samplePos.x, samplePos.y); + sampleDir = mul(sampleDir, float3x3(tangent, bitangent, normal)); + float3 radiance = RadianceMap.SampleLevel(LinearSampler, sampleDir, 0.0f).xyz; + irradiance += radiance; + } + + irradiance *= (Pi / numSamples); + + IrradianceMap[uint3(outputPos, outputSliceIdx)] = float4(irradiance, 0.0f); +} \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp b/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp index 88c6f47..0336e39 100644 --- a/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp +++ b/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp @@ -1,635 +1,629 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include "PCH.h" - -#include "GraphicsTypes.h" -#include "..\\Exceptions.h" -#include "..\\Utility.h" -#include "..\\Serialization.h" -#include "..\\FileIO.h" - -namespace SampleFramework11 -{ - -// == RenderTarget2D ============================================================================== - -RenderTarget2D::RenderTarget2D() : Width(0), - Height(0), - Format(DXGI_FORMAT_UNKNOWN), - NumMipLevels(0), - MultiSamples(0), - MSQuality(0), - AutoGenMipMaps(false), - UAView(nullptr), - ArraySize(1) -{ - -} - -void RenderTarget2D::Initialize(ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - uint32 numMipLevels, - uint32 multiSamples, - uint32 msQuality, - bool32 autoGenMipMaps, - bool32 createUAV, - uint32 arraySize, - bool32 cubeMap) -{ - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.ArraySize = arraySize; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET; - if(createUAV) - desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; - - desc.CPUAccessFlags = 0; - desc.Format = format; - desc.MipLevels = numMipLevels; - desc.MiscFlags = (autoGenMipMaps && numMipLevels != 1) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; - desc.SampleDesc.Count = multiSamples; - desc.SampleDesc.Quality = msQuality; - desc.Usage = D3D11_USAGE_DEFAULT; - - if(cubeMap) - { - Assert_(arraySize == 6); - desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; - } - - DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); - - RTVArraySlices.clear(); - RTVArraySlices.reserve(arraySize); - for(uint32 i = 0; i < arraySize; ++i) - { - ID3D11RenderTargetViewPtr rtView; - D3D11_RENDER_TARGET_VIEW_DESC rtDesc; - rtDesc.Format = format; - - if(arraySize == 1) - { - if(multiSamples > 1) - { - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; - } - else - { - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtDesc.Texture2D.MipSlice = 0; - } - } - else - { - if(multiSamples > 1) - { - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; - rtDesc.Texture2DMSArray.ArraySize = 1; - rtDesc.Texture2DMSArray.FirstArraySlice = i; - } - else - { - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtDesc.Texture2DArray.ArraySize = 1; - rtDesc.Texture2DArray.FirstArraySlice = i; - rtDesc.Texture2DArray.MipSlice = 0; - } - } - DXCall(device->CreateRenderTargetView(Texture, &rtDesc, &rtView)); - - RTVArraySlices.push_back(rtView); - } - - RTView = RTVArraySlices[0]; - - DXCall(device->CreateShaderResourceView(Texture, nullptr, &SRView)); - - SRVArraySlices.clear(); - for(uint32 i = 0; i < arraySize; ++i) - { - ID3D11ShaderResourceViewPtr srView; - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - - if(arraySize == 1) - { - if(multiSamples > 1) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; - } - else - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = -1; - srvDesc.Texture2D.MostDetailedMip = 0; - } - } - else - { - if(multiSamples > 1) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; - srvDesc.Texture2DMSArray.ArraySize = 1; - srvDesc.Texture2DMSArray.FirstArraySlice = i; - } - else - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.ArraySize = 1; - srvDesc.Texture2DArray.FirstArraySlice = i; - srvDesc.Texture2DArray.MipLevels = -1; - srvDesc.Texture2DArray.MostDetailedMip = 0; - } - } - - DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &srView)); - SRVArraySlices.push_back(srView); - } - - Width = width; - Height = height; - NumMipLevels = numMipLevels; - MultiSamples = multiSamples; - Format = format; - AutoGenMipMaps = autoGenMipMaps; - ArraySize = arraySize; - CubeMap = cubeMap; - - if(createUAV) - DXCall(device->CreateUnorderedAccessView(Texture, nullptr, &UAView)); -}; - -// == DepthStencilBuffer ========================================================================== - -DepthStencilBuffer::DepthStencilBuffer() : Width(0), - Height(0), - MultiSamples(0), - MSQuality(0), - Format(DXGI_FORMAT_UNKNOWN), - ArraySize(1), - CubeMap(false) -{ - -} - -void DepthStencilBuffer::Initialize(ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - bool32 useAsShaderResource, - uint32 multiSamples, - uint32 msQuality, - uint32 arraySize, - bool32 cubeMap) -{ - Width = width; - Height = height; - MultiSamples = multiSamples; - Format = format; - ArraySize = arraySize; - CubeMap = cubeMap; - - uint32 bindFlags = D3D11_BIND_DEPTH_STENCIL; - if(useAsShaderResource) - bindFlags |= D3D11_BIND_SHADER_RESOURCE; - - DXGI_FORMAT dsTexFormat; - if (!useAsShaderResource) - dsTexFormat = format; - else if (format == DXGI_FORMAT_D16_UNORM) - dsTexFormat = DXGI_FORMAT_R16_TYPELESS; - else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT) - dsTexFormat = DXGI_FORMAT_R24G8_TYPELESS; - else - dsTexFormat = DXGI_FORMAT_R32_TYPELESS; - - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.ArraySize = arraySize; - desc.BindFlags = bindFlags; - desc.CPUAccessFlags = 0; - desc.Format = dsTexFormat; - desc.MipLevels = 1; - desc.MiscFlags = 0; - if(cubeMap) - { - Assert_(arraySize == 6); - Assert_(multiSamples == 1); - desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; - } - desc.SampleDesc.Count = multiSamples; - desc.SampleDesc.Quality = msQuality; - desc.Usage = D3D11_USAGE_DEFAULT; - DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); - - ArraySlices.clear(); - for(uint32 i = 0; i < arraySize; ++i) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - ID3D11DepthStencilViewPtr dsView; - dsvDesc.Format = format; - - if(arraySize == 1) - { - dsvDesc.ViewDimension = multiSamples > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = 0; - } - else - { - if(multiSamples > 1) - { - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; - dsvDesc.Texture2DMSArray.ArraySize = 1; - dsvDesc.Texture2DMSArray.FirstArraySlice = i; - } - else - { - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; - dsvDesc.Texture2DArray.ArraySize = 1; - dsvDesc.Texture2DArray.FirstArraySlice = i; - dsvDesc.Texture2DArray.MipSlice = 0; - } - } - - dsvDesc.Flags = 0; - DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &dsView)); - ArraySlices.push_back(dsView); - - if (i == 0) - { - // Also create a read-only DSV - dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH; - if (format == DXGI_FORMAT_D24_UNORM_S8_UINT || format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT) - dsvDesc.Flags |= D3D11_DSV_READ_ONLY_STENCIL; - DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &ReadOnlyDSView)); - dsvDesc.Flags = 0; - } - } - - DSView = ArraySlices[0]; - - if(useAsShaderResource) - { - DXGI_FORMAT dsSRVFormat; - if (format == DXGI_FORMAT_D16_UNORM) - dsSRVFormat = DXGI_FORMAT_R16_UNORM; - else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT) - dsSRVFormat = DXGI_FORMAT_R24_UNORM_X8_TYPELESS ; - else - dsSRVFormat = DXGI_FORMAT_R32_FLOAT; - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = dsSRVFormat; - - if(arraySize == 1) - { - srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = 1; - srvDesc.Texture2D.MostDetailedMip = 0; - } - else if(cubeMap) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - srvDesc.TextureCube.MipLevels = 1; - srvDesc.TextureCube.MostDetailedMip = 0; - } - else - { - srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.ArraySize = arraySize; - srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.MostDetailedMip = 0; - } - - DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &SRView)); - } - else - SRView = nullptr; -} - -// == RWBuffer ==================================================================================== - -RWBuffer::RWBuffer() : Size(0), Stride(0), NumElements(0), Format(DXGI_FORMAT_UNKNOWN), RawBuffer(false) -{ - -} - -void RWBuffer::Initialize(ID3D11Device* device, DXGI_FORMAT format, uint32 stride, uint32 numElements, - bool32 rawBuffer, bool vertexBuffer, bool indexBuffer, bool indirectArgs, - const void* initData) -{ - if(rawBuffer) - { - stride = 4; - Format = DXGI_FORMAT_R32_TYPELESS; - } - - Format = format; - Size = stride * numElements; - Stride = stride; - NumElements = numElements; - RawBuffer = rawBuffer; - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = stride * numElements; - bufferDesc.Usage = D3D11_USAGE_DEFAULT; - bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; - bufferDesc.CPUAccessFlags = 0; - bufferDesc.MiscFlags = rawBuffer ? D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS : 0; - bufferDesc.StructureByteStride = 0; - - Assert_(vertexBuffer == false || indexBuffer == false); - - if(vertexBuffer) - bufferDesc.BindFlags |= D3D11_BIND_VERTEX_BUFFER; - - if(indexBuffer) - { - bufferDesc.BindFlags |= D3D11_BIND_INDEX_BUFFER; - Assert_(Format == DXGI_FORMAT_R32_TYPELESS || - Format == DXGI_FORMAT_R32_UINT || - Format == DXGI_FORMAT_R16_UINT); - } - - if(indirectArgs) - bufferDesc.MiscFlags |= D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; - - D3D11_SUBRESOURCE_DATA srData; - srData.pSysMem = initData; - srData.SysMemPitch = 0; - srData.SysMemSlicePitch = 0; - - DXCall(device->CreateBuffer(&bufferDesc, initData ? &srData : nullptr, &Buffer)); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = Format; - - if(rawBuffer) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; - srvDesc.BufferEx.FirstElement = 0; - srvDesc.BufferEx.NumElements = numElements; - srvDesc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW; - } - else - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - srvDesc.Buffer.ElementOffset = 0; - srvDesc.Buffer.NumElements = numElements; - } - - DXCall(device->CreateShaderResourceView(Buffer, &srvDesc, &SRView)); - - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; - uavDesc.Format = format; - uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - uavDesc.Buffer.FirstElement = 0; - uavDesc.Buffer.NumElements = numElements; - uavDesc.Buffer.Flags = rawBuffer ? D3D11_BUFFER_UAV_FLAG_RAW : 0; - - DXCall(device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView)); -} - -// == StructuredBuffer ============================================================================ - -StructuredBuffer::StructuredBuffer() : Size(0), Stride(0), NumElements(0) -{ -} - -void StructuredBuffer::Initialize(ID3D11Device* device, uint32 stride, uint32 numElements, bool32 useAsUAV, - bool32 appendConsume, bool32 hiddenCounter, const void* initData) -{ - Size = stride * numElements; - Stride = stride; - NumElements = numElements; - - Assert_(appendConsume == false || hiddenCounter == false); - - if(appendConsume || hiddenCounter) - useAsUAV = true; - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = stride * numElements; - bufferDesc.Usage = useAsUAV ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE; - bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - bufferDesc.BindFlags |= useAsUAV ? D3D11_BIND_UNORDERED_ACCESS : 0; - bufferDesc.CPUAccessFlags = 0; - bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - bufferDesc.StructureByteStride = stride; - - D3D11_SUBRESOURCE_DATA subresourceData; - subresourceData.pSysMem = initData; - subresourceData.SysMemPitch = 0; - subresourceData.SysMemSlicePitch = 0; - - DXCall(device->CreateBuffer(&bufferDesc, initData != nullptr ? &subresourceData : nullptr, &Buffer)); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - srvDesc.Buffer.FirstElement = 0; - srvDesc.Buffer.NumElements = numElements; - DXCall(device->CreateShaderResourceView(Buffer, &srvDesc, &SRView)); - - if(useAsUAV) - { - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; - uavDesc.Format = DXGI_FORMAT_UNKNOWN; - uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - uavDesc.Buffer.FirstElement = 0; - uavDesc.Buffer.Flags = 0; - uavDesc.Buffer.Flags |= appendConsume ? D3D11_BUFFER_UAV_FLAG_APPEND : 0; - uavDesc.Buffer.Flags |= hiddenCounter ? D3D11_BUFFER_UAV_FLAG_COUNTER : 0; - uavDesc.Buffer.NumElements = numElements; - DXCall(device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView)); - } -} - -void StructuredBuffer::WriteToFile(const wchar* path, ID3D11Device* device, ID3D11DeviceContext* context) -{ - Assert_(Buffer != nullptr); - - // Get the buffer info - D3D11_BUFFER_DESC desc; - Buffer->GetDesc(&desc); - - uint32 useAsUAV = (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) ? 1 : 0; - - uint32 appendConsume = 0; - uint32 hiddenCounter = 0; - if(useAsUAV) - { - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; - UAView->GetDesc(&uavDesc); - appendConsume = (uavDesc.Format & D3D11_BUFFER_UAV_FLAG_APPEND) ? 1 : 0; - hiddenCounter =(uavDesc.Format & D3D11_BUFFER_UAV_FLAG_COUNTER) ? 1 : 0; - } - - // If the exists, delete it - if(FileExists(path)) - Win32Call(DeleteFile(path)); - - // Create the file - HANDLE fileHandle = CreateFile(path, GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - if(fileHandle == INVALID_HANDLE_VALUE) - Win32Call(false); - - // Write the buffer info - DWORD bytesWritten = 0; - Win32Call(WriteFile(fileHandle, &Size, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &Stride, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &NumElements, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &useAsUAV, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &hiddenCounter, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &appendConsume, 4, &bytesWritten, nullptr)); - - // Get the buffer data - StagingBuffer stagingBuffer; - stagingBuffer.Initialize(device, Size); - context->CopyResource(stagingBuffer.Buffer, Buffer); - const void* bufferData= stagingBuffer.Map(context); - - // Write the data to the file - Win32Call(WriteFile(fileHandle, bufferData, Size, &bytesWritten, nullptr)); - - // Un-map the staging buffer - stagingBuffer.Unmap(context); - - // Close the file - Win32Call(CloseHandle(fileHandle)); -} - -void StructuredBuffer::ReadFromFile(const wchar* path, ID3D11Device* device) -{ - // Open the file - HANDLE fileHandle = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if(fileHandle == INVALID_HANDLE_VALUE) - Win32Call(false); - - // Read the buffer info - bool32 useAsUAV, hiddenCounter, appendConsume; - DWORD bytesRead = 0; - Win32Call(ReadFile(fileHandle, &Size, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &Stride, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &NumElements, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &useAsUAV, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &hiddenCounter, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &appendConsume, 4, &bytesRead, nullptr)); - - // Read the buffer data - UINT8* bufferData = new UINT8[Size]; - Win32Call(ReadFile(fileHandle, bufferData, Size, &bytesRead, nullptr)); - - // Close the file - Win32Call(CloseHandle(fileHandle)); - - // Init - Initialize(device, Stride, NumElements, useAsUAV, appendConsume, hiddenCounter, bufferData); - - // Clean up - delete [] bufferData; -} - -// == StagingBuffer =============================================================================== - -StagingBuffer::StagingBuffer() : Size(0) -{ -} - -void StagingBuffer::Initialize(ID3D11Device* device, uint32 size) -{ - Size = size; - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = Size; - bufferDesc.Usage = D3D11_USAGE_STAGING; - bufferDesc.BindFlags = 0; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - DXCall(device->CreateBuffer(&bufferDesc, nullptr, &Buffer)); -} - -void* StagingBuffer::Map(ID3D11DeviceContext* context) -{ - D3D11_MAPPED_SUBRESOURCE mapped; - DXCall(context->Map(Buffer, 0, D3D11_MAP_READ, 0, &mapped)); - - return mapped.pData; -} - -void StagingBuffer::Unmap(ID3D11DeviceContext* context) -{ - context->Unmap(Buffer, 0); -} - -// == StagingTexture2D ============================================================================ - -StagingTexture2D::StagingTexture2D() : Width(0), - Height(0), - Format(DXGI_FORMAT_UNKNOWN), - NumMipLevels(0), - MultiSamples(0), - MSQuality(0), - ArraySize(1) -{ -} - -void StagingTexture2D::Initialize(ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - uint32 numMipLevels, - uint32 multiSamples, - uint32 msQuality, - uint32 arraySize) -{ - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.ArraySize = arraySize; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.Format = format; - desc.MipLevels = numMipLevels; - desc.MiscFlags = 0; - desc.SampleDesc.Count = multiSamples; - desc.SampleDesc.Quality = msQuality; - desc.Usage = D3D11_USAGE_STAGING; - DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); - - - Width = width; - Height = height; - NumMipLevels = numMipLevels; - MultiSamples = multiSamples; - Format = format; - ArraySize = arraySize; -}; - -void* StagingTexture2D::Map(ID3D11DeviceContext* context, uint32 subResourceIndex, uint32& pitch) -{ - D3D11_MAPPED_SUBRESOURCE mapped; - DXCall(context->Map(Texture, subResourceIndex, D3D11_MAP_READ, 0, &mapped)); - pitch = mapped.RowPitch; - return mapped.pData; -} - -void StagingTexture2D::Unmap(ID3D11DeviceContext* context, uint32 subResourceIndex) -{ - context->Unmap(Texture, subResourceIndex); -} - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include "PCH.h" + +#include "GraphicsTypes.h" +#include "..\\Exceptions.h" +#include "..\\Utility.h" +#include "..\\Serialization.h" +#include "..\\FileIO.h" + +namespace SampleFramework11 +{ + +// == RenderTarget2D ============================================================================== + +RenderTarget2D::RenderTarget2D() : Width(0), + Height(0), + Format(DXGI_FORMAT_UNKNOWN), + NumMipLevels(0), + MultiSamples(0), + MSQuality(0), + AutoGenMipMaps(false), + UAView(nullptr), + ArraySize(0) +{ + +} + +void RenderTarget2D::Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + uint32 numMipLevels, + uint32 multiSamples, + uint32 msQuality, + bool32 autoGenMipMaps, + bool32 createUAV, + uint32 arraySize, + bool32 cubeMap) +{ + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.ArraySize = arraySize; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET; + if(createUAV) + desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; + + desc.CPUAccessFlags = 0; + desc.Format = format; + desc.MipLevels = numMipLevels; + desc.MiscFlags = (autoGenMipMaps && numMipLevels != 1) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; + desc.SampleDesc.Count = multiSamples; + desc.SampleDesc.Quality = msQuality; + desc.Usage = D3D11_USAGE_DEFAULT; + + if(cubeMap) + { + Assert_(arraySize % 6 == 0); + desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; + } + + DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); + + RTVArraySlices.clear(); + RTVArraySlices.reserve(arraySize); + for(uint32 i = 0; i < arraySize; ++i) + { + ID3D11RenderTargetViewPtr rtView; + D3D11_RENDER_TARGET_VIEW_DESC rtDesc; + rtDesc.Format = format; + + if(arraySize == 1) + { + if(multiSamples > 1) + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + } + else + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtDesc.Texture2D.MipSlice = 0; + } + } + else + { + if(multiSamples > 1) + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; + rtDesc.Texture2DMSArray.ArraySize = 1; + rtDesc.Texture2DMSArray.FirstArraySlice = i; + } + else + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtDesc.Texture2DArray.ArraySize = 1; + rtDesc.Texture2DArray.FirstArraySlice = i; + rtDesc.Texture2DArray.MipSlice = 0; + } + } + DXCall(device->CreateRenderTargetView(Texture, &rtDesc, &rtView)); + + RTVArraySlices.push_back(rtView); + } + + RTView = RTVArraySlices[0]; + + DXCall(device->CreateShaderResourceView(Texture, nullptr, &SRView)); + + uint32 numSRVSlices = cubeMap ? arraySize / 6 : arraySize; + SRVArraySlices.clear(); + SRVArraySlices.reserve(numSRVSlices); + for(uint32 i = 0; i < numSRVSlices; ++i) + { + ID3D11ShaderResourceViewPtr srView; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + + if(multiSamples > 1) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; + srvDesc.Texture2DMSArray.ArraySize = 1; + srvDesc.Texture2DMSArray.FirstArraySlice = i; + } + else if(cubeMap) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY; + srvDesc.TextureCubeArray.MostDetailedMip = 0; + srvDesc.TextureCubeArray.MipLevels = -1; + srvDesc.TextureCubeArray.First2DArrayFace = i; + srvDesc.TextureCubeArray.NumCubes = 1; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.ArraySize = 1; + srvDesc.Texture2DArray.FirstArraySlice = i; + srvDesc.Texture2DArray.MipLevels = -1; + srvDesc.Texture2DArray.MostDetailedMip = 0; + } + + DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &srView)); + SRVArraySlices.push_back(srView); + } + + Width = width; + Height = height; + NumMipLevels = numMipLevels; + MultiSamples = multiSamples; + Format = format; + AutoGenMipMaps = autoGenMipMaps; + ArraySize = arraySize; + CubeMap = cubeMap; + + if(createUAV) + DXCall(device->CreateUnorderedAccessView(Texture, nullptr, &UAView)); +}; + +// == DepthStencilBuffer ========================================================================== + +DepthStencilBuffer::DepthStencilBuffer() : Width(0), + Height(0), + MultiSamples(0), + MSQuality(0), + Format(DXGI_FORMAT_UNKNOWN), + ArraySize(1), + CubeMap(false) +{ + +} + +void DepthStencilBuffer::Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + bool32 useAsShaderResource, + uint32 multiSamples, + uint32 msQuality, + uint32 arraySize, + bool32 cubeMap) +{ + Width = width; + Height = height; + MultiSamples = multiSamples; + Format = format; + ArraySize = arraySize; + CubeMap = cubeMap; + + uint32 bindFlags = D3D11_BIND_DEPTH_STENCIL; + if(useAsShaderResource) + bindFlags |= D3D11_BIND_SHADER_RESOURCE; + + DXGI_FORMAT dsTexFormat; + if (!useAsShaderResource) + dsTexFormat = format; + else if (format == DXGI_FORMAT_D16_UNORM) + dsTexFormat = DXGI_FORMAT_R16_TYPELESS; + else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT) + dsTexFormat = DXGI_FORMAT_R24G8_TYPELESS; + else + dsTexFormat = DXGI_FORMAT_R32_TYPELESS; + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.ArraySize = arraySize; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = 0; + desc.Format = dsTexFormat; + desc.MipLevels = 1; + desc.MiscFlags = 0; + if(cubeMap) + { + Assert_(arraySize == 6); + Assert_(multiSamples == 1); + desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; + } + desc.SampleDesc.Count = multiSamples; + desc.SampleDesc.Quality = msQuality; + desc.Usage = D3D11_USAGE_DEFAULT; + DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); + + ArraySlices.clear(); + for(uint32 i = 0; i < arraySize; ++i) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + ID3D11DepthStencilViewPtr dsView; + dsvDesc.Format = format; + + if(arraySize == 1) + { + dsvDesc.ViewDimension = multiSamples > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = 0; + } + else + { + if(multiSamples > 1) + { + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; + dsvDesc.Texture2DMSArray.ArraySize = 1; + dsvDesc.Texture2DMSArray.FirstArraySlice = i; + } + else + { + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Texture2DArray.ArraySize = 1; + dsvDesc.Texture2DArray.FirstArraySlice = i; + dsvDesc.Texture2DArray.MipSlice = 0; + } + } + + dsvDesc.Flags = 0; + DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &dsView)); + ArraySlices.push_back(dsView); + + if (i == 0) + { + // Also create a read-only DSV + dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH; + if (format == DXGI_FORMAT_D24_UNORM_S8_UINT || format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT) + dsvDesc.Flags |= D3D11_DSV_READ_ONLY_STENCIL; + DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &ReadOnlyDSView)); + dsvDesc.Flags = 0; + } + } + + DSView = ArraySlices[0]; + + if(useAsShaderResource) + { + DXGI_FORMAT dsSRVFormat; + if (format == DXGI_FORMAT_D16_UNORM) + dsSRVFormat = DXGI_FORMAT_R16_UNORM; + else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT) + dsSRVFormat = DXGI_FORMAT_R24_UNORM_X8_TYPELESS ; + else + dsSRVFormat = DXGI_FORMAT_R32_FLOAT; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = dsSRVFormat; + + if(arraySize == 1) + { + srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MostDetailedMip = 0; + } + else if(cubeMap) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + srvDesc.TextureCube.MipLevels = 1; + srvDesc.TextureCube.MostDetailedMip = 0; + } + else + { + srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.ArraySize = arraySize; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.MostDetailedMip = 0; + } + + DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &SRView)); + } + else + SRView = nullptr; +} + +// == RWBuffer ==================================================================================== + +RWBuffer::RWBuffer() : Size(0), Stride(0), NumElements(0), Format(DXGI_FORMAT_UNKNOWN), RawBuffer(false) +{ + +} + +void RWBuffer::Initialize(ID3D11Device* device, DXGI_FORMAT format, uint32 stride, uint32 numElements, + bool32 rawBuffer, bool vertexBuffer, bool indexBuffer, bool indirectArgs, + const void* initData) +{ + if(rawBuffer) + { + stride = 4; + Format = DXGI_FORMAT_R32_TYPELESS; + } + + Format = format; + Size = stride * numElements; + Stride = stride; + NumElements = numElements; + RawBuffer = rawBuffer; + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = stride * numElements; + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = rawBuffer ? D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS : 0; + bufferDesc.StructureByteStride = 0; + + Assert_(vertexBuffer == false || indexBuffer == false); + + if(vertexBuffer) + bufferDesc.BindFlags |= D3D11_BIND_VERTEX_BUFFER; + + if(indexBuffer) + { + bufferDesc.BindFlags |= D3D11_BIND_INDEX_BUFFER; + Assert_(Format == DXGI_FORMAT_R32_TYPELESS || + Format == DXGI_FORMAT_R32_UINT || + Format == DXGI_FORMAT_R16_UINT); + } + + if(indirectArgs) + bufferDesc.MiscFlags |= D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; + + D3D11_SUBRESOURCE_DATA srData; + srData.pSysMem = initData; + srData.SysMemPitch = 0; + srData.SysMemSlicePitch = 0; + + DXCall(device->CreateBuffer(&bufferDesc, initData ? &srData : nullptr, &Buffer)); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = Format; + + if(rawBuffer) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; + srvDesc.BufferEx.FirstElement = 0; + srvDesc.BufferEx.NumElements = numElements; + srvDesc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.ElementOffset = 0; + srvDesc.Buffer.NumElements = numElements; + } + + DXCall(device->CreateShaderResourceView(Buffer, &srvDesc, &SRView)); + + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uavDesc.Format = format; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.NumElements = numElements; + uavDesc.Buffer.Flags = rawBuffer ? D3D11_BUFFER_UAV_FLAG_RAW : 0; + + DXCall(device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView)); +} + +// == StructuredBuffer ============================================================================ + +StructuredBuffer::StructuredBuffer() : Size(0), Stride(0), NumElements(0) +{ +} + +void StructuredBuffer::Initialize(ID3D11Device* device, uint32 stride, uint32 numElements, bool32 useAsUAV, + bool32 appendConsume, bool32 hiddenCounter, const void* initData) +{ + Size = stride * numElements; + Stride = stride; + NumElements = numElements; + + Assert_(appendConsume == false || hiddenCounter == false); + + if(appendConsume || hiddenCounter) + useAsUAV = true; + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = stride * numElements; + bufferDesc.Usage = useAsUAV ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE; + bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + bufferDesc.BindFlags |= useAsUAV ? D3D11_BIND_UNORDERED_ACCESS : 0; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + bufferDesc.StructureByteStride = stride; + + D3D11_SUBRESOURCE_DATA subresourceData; + subresourceData.pSysMem = initData; + subresourceData.SysMemPitch = 0; + subresourceData.SysMemSlicePitch = 0; + + DXCall(device->CreateBuffer(&bufferDesc, initData != nullptr ? &subresourceData : nullptr, &Buffer)); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.NumElements = numElements; + DXCall(device->CreateShaderResourceView(Buffer, &srvDesc, &SRView)); + + if(useAsUAV) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.Flags = 0; + uavDesc.Buffer.Flags |= appendConsume ? D3D11_BUFFER_UAV_FLAG_APPEND : 0; + uavDesc.Buffer.Flags |= hiddenCounter ? D3D11_BUFFER_UAV_FLAG_COUNTER : 0; + uavDesc.Buffer.NumElements = numElements; + DXCall(device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView)); + } +} + +void StructuredBuffer::WriteToFile(const wchar* path, ID3D11Device* device, ID3D11DeviceContext* context) +{ + Assert_(Buffer != nullptr); + + // Get the buffer info + D3D11_BUFFER_DESC desc; + Buffer->GetDesc(&desc); + + uint32 useAsUAV = (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) ? 1 : 0; + + uint32 appendConsume = 0; + uint32 hiddenCounter = 0; + if(useAsUAV) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + UAView->GetDesc(&uavDesc); + appendConsume = (uavDesc.Format & D3D11_BUFFER_UAV_FLAG_APPEND) ? 1 : 0; + hiddenCounter =(uavDesc.Format & D3D11_BUFFER_UAV_FLAG_COUNTER) ? 1 : 0; + } + + // If the exists, delete it + if(FileExists(path)) + Win32Call(DeleteFile(path)); + + // Create the file + HANDLE fileHandle = CreateFile(path, GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); + if(fileHandle == INVALID_HANDLE_VALUE) + Win32Call(false); + + // Write the buffer info + DWORD bytesWritten = 0; + Win32Call(WriteFile(fileHandle, &Size, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &Stride, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &NumElements, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &useAsUAV, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &hiddenCounter, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &appendConsume, 4, &bytesWritten, nullptr)); + + // Get the buffer data + StagingBuffer stagingBuffer; + stagingBuffer.Initialize(device, Size); + context->CopyResource(stagingBuffer.Buffer, Buffer); + const void* bufferData= stagingBuffer.Map(context); + + // Write the data to the file + Win32Call(WriteFile(fileHandle, bufferData, Size, &bytesWritten, nullptr)); + + // Un-map the staging buffer + stagingBuffer.Unmap(context); + + // Close the file + Win32Call(CloseHandle(fileHandle)); +} + +void StructuredBuffer::ReadFromFile(const wchar* path, ID3D11Device* device) +{ + // Open the file + HANDLE fileHandle = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if(fileHandle == INVALID_HANDLE_VALUE) + Win32Call(false); + + // Read the buffer info + bool32 useAsUAV, hiddenCounter, appendConsume; + DWORD bytesRead = 0; + Win32Call(ReadFile(fileHandle, &Size, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &Stride, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &NumElements, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &useAsUAV, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &hiddenCounter, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &appendConsume, 4, &bytesRead, nullptr)); + + // Read the buffer data + UINT8* bufferData = new UINT8[Size]; + Win32Call(ReadFile(fileHandle, bufferData, Size, &bytesRead, nullptr)); + + // Close the file + Win32Call(CloseHandle(fileHandle)); + + // Init + Initialize(device, Stride, NumElements, useAsUAV, appendConsume, hiddenCounter, bufferData); + + // Clean up + delete [] bufferData; +} + +// == StagingBuffer =============================================================================== + +StagingBuffer::StagingBuffer() : Size(0) +{ +} + +void StagingBuffer::Initialize(ID3D11Device* device, uint32 size) +{ + Size = size; + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = Size; + bufferDesc.Usage = D3D11_USAGE_STAGING; + bufferDesc.BindFlags = 0; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + DXCall(device->CreateBuffer(&bufferDesc, nullptr, &Buffer)); +} + +void* StagingBuffer::Map(ID3D11DeviceContext* context) +{ + D3D11_MAPPED_SUBRESOURCE mapped; + DXCall(context->Map(Buffer, 0, D3D11_MAP_READ, 0, &mapped)); + + return mapped.pData; +} + +void StagingBuffer::Unmap(ID3D11DeviceContext* context) +{ + context->Unmap(Buffer, 0); +} + +// == StagingTexture2D ============================================================================ + +StagingTexture2D::StagingTexture2D() : Width(0), + Height(0), + Format(DXGI_FORMAT_UNKNOWN), + NumMipLevels(0), + MultiSamples(0), + MSQuality(0), + ArraySize(1) +{ +} + +void StagingTexture2D::Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + uint32 numMipLevels, + uint32 multiSamples, + uint32 msQuality, + uint32 arraySize) +{ + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.ArraySize = arraySize; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Format = format; + desc.MipLevels = numMipLevels; + desc.MiscFlags = 0; + desc.SampleDesc.Count = multiSamples; + desc.SampleDesc.Quality = msQuality; + desc.Usage = D3D11_USAGE_STAGING; + DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); + + + Width = width; + Height = height; + NumMipLevels = numMipLevels; + MultiSamples = multiSamples; + Format = format; + ArraySize = arraySize; +}; + +void* StagingTexture2D::Map(ID3D11DeviceContext* context, uint32 subResourceIndex, uint32& pitch) +{ + D3D11_MAPPED_SUBRESOURCE mapped; + DXCall(context->Map(Texture, subResourceIndex, D3D11_MAP_READ, 0, &mapped)); + pitch = mapped.RowPitch; + return mapped.pData; +} + +void StagingTexture2D::Unmap(ID3D11DeviceContext* context, uint32 subResourceIndex) +{ + context->Unmap(Texture, subResourceIndex); +} + } \ No newline at end of file From faac7dbec18176ddef84abbcf04fb32330cd668d Mon Sep 17 00:00:00 2001 From: MJP Date: Fri, 29 Sep 2017 14:54:05 -0700 Subject: [PATCH 04/43] Basic probe interpolation --- BakingLab/BakingLab.cpp | 4 ++++ BakingLab/Mesh.hlsl | 44 ++++++++++++++++++++++++++++++++++---- BakingLab/MeshBaker.cpp | 6 ++++-- BakingLab/MeshBaker.h | 2 ++ BakingLab/MeshRenderer.cpp | 2 ++ BakingLab/MeshRenderer.h | 3 +++ 6 files changed, 55 insertions(+), 6 deletions(-) diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 4f8c46e..34f3b15 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -655,6 +655,8 @@ void BakingLab::RenderProbes() probeCam.SetPosition(probePos); MeshBakerStatus status; + status.SceneMinBounds = sceneMins[currSceneIdx]; + status.SceneMaxBounds = sceneMaxes[currSceneIdx]; for(uint64 i = 0; i < 6; ++i) { @@ -713,6 +715,8 @@ void BakingLab::Render(const Timer& timer) MeshBakerStatus status = meshBaker.Update(unJitteredCamera, colorTargetMSAA.Width, colorTargetMSAA.Height, context, &sceneModels[AppSettings::CurrentScene]); + status.SceneMinBounds = sceneMins[AppSettings::CurrentScene]; + status.SceneMaxBounds = sceneMaxes[AppSettings::CurrentScene]; RenderProbes(); diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 9decd63..7c6760b 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -50,6 +50,8 @@ cbuffer PSConstants : register(b0) float LightBleedingReduction; float2 RTSize; float2 JitterOffset; + float4 SceneMinBounds; + float4 SceneMaxBounds; float4 SGDirections[MaxSGCount]; float SGSharpness; } @@ -466,6 +468,43 @@ void ComputeIndirectFromLightmap(in SurfaceContext surface, in float2 lightMapUV } } +float3 SampleIrradianceProbe(in float3 samplePos, float3 direction) +{ + float probeIdx = uint(samplePos.z) * (ProbeResX * ProbeResY) + uint(samplePos.y) * ProbeResX + uint(samplePos.x); + return ProbeIrradiance.Sample(LinearSampler, float4(direction, probeIdx)).xyz; +} + +void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) +{ + float3 sampleUVW = saturate((surface.PositionWS - SceneMinBounds.xyz) / (SceneMaxBounds.xyz - SceneMinBounds.xyz)); + float3 probeDims = float3(ProbeResX, ProbeResY, ProbeResZ); + + float3 halfTexelSize = 0.5f / probeDims; + float3 samplePos = frac(sampleUVW - halfTexelSize); + samplePos *= probeDims; + samplePos = min(probeDims, probeDims - 1.0f); + float3 samplePosNext = min(samplePos + 1, probeDims - 1.0f); + + float3 lerpAmts = frac(samplePos); + + float3 samples[8]; + samples[0] = SampleIrradianceProbe(float3(samplePos.x , samplePos.y, samplePos.z), surface.NormalWS); + samples[1] = SampleIrradianceProbe(float3(samplePosNext.x , samplePos.y, samplePos.z), surface.NormalWS); + samples[2] = SampleIrradianceProbe(float3(samplePos.x , samplePosNext.y, samplePos.z), surface.NormalWS); + samples[3] = SampleIrradianceProbe(float3(samplePosNext.x , samplePosNext.y, samplePos.z), surface.NormalWS); + + samples[4] = SampleIrradianceProbe(float3(samplePos.x , samplePos.y, samplePosNext.z), surface.NormalWS); + samples[5] = SampleIrradianceProbe(float3(samplePosNext.x , samplePos.y, samplePosNext.z), surface.NormalWS); + samples[6] = SampleIrradianceProbe(float3(samplePos.x , samplePosNext.y, samplePosNext.z), surface.NormalWS); + samples[7] = SampleIrradianceProbe(float3(samplePosNext.x , samplePosNext.y, samplePosNext.z), surface.NormalWS); + + // lerp between the shadow values to calculate our light amount + float3 result0123 = lerp(lerp(samples[0], samples[1], lerpAmts.x), lerp(samples[2], samples[3], lerpAmts.x), lerpAmts.y); + float3 result4567 = lerp(lerp(samples[4], samples[5], lerpAmts.x), lerp(samples[6], samples[7], lerpAmts.x), lerpAmts.y); + indirectIrradiance = lerp(result0123, result4567, lerpAmts.z); + indirectSpecular = 0.0f; +} + //================================================================================================= // Pixel Shader //================================================================================================= @@ -560,10 +599,7 @@ PSOutput PS(in PSInput input) float3 indirectSpecular = 0.0f; if(UseProbes) - { - float probeIdx = 0.0f; - indirectIrradiance = ProbeIrradiance.Sample(LinearSampler, float4(surface.NormalWS, probeIdx)).xyz; - } + ComputeIndirectFromProbes(surface, indirectIrradiance, indirectSpecular); else ComputeIndirectFromLightmap(surface, input.LightMapUV, indirectIrradiance, indirectSpecular); diff --git a/BakingLab/MeshBaker.cpp b/BakingLab/MeshBaker.cpp index a9612f9..b2353f4 100644 --- a/BakingLab/MeshBaker.cpp +++ b/BakingLab/MeshBaker.cpp @@ -1256,9 +1256,11 @@ static uint32 __stdcall RenderThread(void* data) static uint64 GetNumThreads() { - SYSTEM_INFO sysInfo; + /*SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); - return std::max(1, sysInfo.dwNumberOfProcessors - 1); + return std::max(1, sysInfo.dwNumberOfProcessors - 1);*/ + + return 1; } MeshBaker::MeshBaker() diff --git a/BakingLab/MeshBaker.h b/BakingLab/MeshBaker.h index c18a325..a78f5ba 100644 --- a/BakingLab/MeshBaker.h +++ b/BakingLab/MeshBaker.h @@ -66,6 +66,8 @@ struct MeshBakerStatus uint64 GroundTruthSampleCount = 0; Float3 SGDirections[AppSettings::MaxSGCount]; float SGSharpness = 0.0f; + Float3 SceneMinBounds; + Float3 SceneMaxBounds; }; class MeshBaker diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index fb5e297..67de0b7 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -629,6 +629,8 @@ void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& ca meshPSConstants.Data.PositiveExponent = PositiveExponent; meshPSConstants.Data.NegativeExponent = NegativeExponent; meshPSConstants.Data.LightBleedingReduction = LightBleedingReduction; + meshPSConstants.Data.SceneMinBounds = Float4(status.SceneMinBounds, 0.0f); + meshPSConstants.Data.SceneMaxBounds = Float4(status.SceneMaxBounds, 0.0f); for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) meshPSConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); meshPSConstants.Data.SGSharpness = status.SGSharpness; diff --git a/BakingLab/MeshRenderer.h b/BakingLab/MeshRenderer.h index a4d31ee..21c468f 100644 --- a/BakingLab/MeshRenderer.h +++ b/BakingLab/MeshRenderer.h @@ -155,6 +155,9 @@ MeshRenderer(); Float2 RTSize; Float2 JitterOffset; + Float4 SceneMinBounds; + Float4 SceneMaxBounds; + Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; float SGSharpness; }; From df525bb856679ae9e28f31c82ab9f33864b3d7d1 Mon Sep 17 00:00:00 2001 From: MJP Date: Sat, 30 Sep 2017 16:10:09 -0700 Subject: [PATCH 05/43] Don't render the sky sun when capturing probes --- BakingLab/BakingLab.cpp | 11 ++++++----- BakingLab/BakingLab.h | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 34f3b15..20c7319 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -676,7 +676,7 @@ void BakingLab::RenderProbes() probeCam.SetOrientation(orientation); RenderScene(status, probeCaptureMap.RTVArraySlices[i], probeVelocityTarget.RTView, probeDepthBuffer, probeCam, - false, AppSettings::BakeDirectAreaLight); + false, AppSettings::BakeDirectAreaLight, false); } AppSettings::UseProbes.SetValue(prevUseProbes); @@ -741,7 +741,7 @@ void BakingLab::Render(const Timer& timer) { status.ProbeIrradiance = probeIrradianceMap.SRView; RenderScene(status, colorTargetMSAA.RTView, velocityTargetMSAA.RTView, depthBuffer, camera, - AppSettings::ShowBakeDataVisualizer, AppSettings::EnableAreaLight); + AppSettings::ShowBakeDataVisualizer, AppSettings::EnableAreaLight, true); RenderBackgroundVelocity(); } @@ -768,7 +768,8 @@ void BakingLab::Render(const Timer& timer) } void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, - const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 renderAreaLight) + const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 renderAreaLight, + bool32 enableSkySun) { PIXEvent event(L"Render Scene"); @@ -811,7 +812,7 @@ void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetVie if(AppSettings::SkyMode == SkyModes::Procedural) { - float sunSize = AppSettings::EnableSun ? AppSettings::SunSize : 0.0f; + float sunSize = (AppSettings::EnableSun && enableSkySun) ? AppSettings::SunSize : 0.0f; skybox.RenderSky(context, AppSettings::SunDirection, AppSettings::GroundAlbedo, AppSettings::SunLuminance(), sunSize, AppSettings::Turbidity, cam.ViewMatrix(), @@ -819,7 +820,7 @@ void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetVie } else if(AppSettings::SkyMode == SkyModes::Simple) { - float sunSize = AppSettings::EnableSun ? AppSettings::SunSize : 0.0f; + float sunSize = (AppSettings::EnableSun && enableSkySun) ? AppSettings::SunSize : 0.0f; skybox.RenderSimpleSky(context, AppSettings::SkyColor, AppSettings::SunDirection, AppSettings::SunLuminance(), sunSize, cam.ViewMatrix(), cam.ProjectionMatrix(), FP16Scale); diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index 93d3be8..52c5cdc 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -116,7 +116,8 @@ class BakingLab : public App void RenderProbes(); void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, - const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 renderAreaLight); + const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 renderAreaLight, + bool32 enableSkySun); void RenderAA(); void RenderBackgroundVelocity(); void RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, From 0ea3ae1f0bba6ac65adf7246c036f42c960790d6 Mon Sep 17 00:00:00 2001 From: MJP Date: Sat, 30 Sep 2017 17:19:05 -0700 Subject: [PATCH 06/43] Added a probe visualizer, and fixed incorrect interpolation --- BakingLab/AppSettings.cpp | 4 + BakingLab/AppSettings.cs | 3 + BakingLab/AppSettings.h | 6 + BakingLab/BakeDataVisualizer.hlsl | 372 +++++++++++++++--------------- BakingLab/BakingLab.cpp | 14 +- BakingLab/BakingLab.h | 4 +- BakingLab/Mesh.hlsl | 11 +- BakingLab/MeshBaker.cpp | 6 +- BakingLab/MeshRenderer.cpp | 83 +++++-- BakingLab/MeshRenderer.h | 27 ++- BakingLab/ProbeIntegrate.hlsl | 2 +- BakingLab/ProbeVisualizer.hlsl | 89 +++++++ 12 files changed, 396 insertions(+), 225 deletions(-) create mode 100644 BakingLab/ProbeVisualizer.hlsl diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 6009e7d..3a9f609 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -267,6 +267,7 @@ namespace AppSettings FloatSetting BloomBlurSigma; BoolSetting EnableLuminancePicker; BoolSetting ShowBakeDataVisualizer; + BoolSetting ShowProbeVisualizer; BoolSetting ViewIndirectSpecular; Button SaveLightSettings; Button LoadLightSettings; @@ -584,6 +585,9 @@ namespace AppSettings ShowBakeDataVisualizer.Initialize(tweakBar, "ShowBakeDataVisualizer", "Debug", "Show Bake Data Visualizer", "", false); Settings.AddSetting(&ShowBakeDataVisualizer); + ShowProbeVisualizer.Initialize(tweakBar, "ShowProbeVisualizer", "Debug", "Show Probe Visualizer", "", false); + Settings.AddSetting(&ShowProbeVisualizer); + ViewIndirectSpecular.Initialize(tweakBar, "ViewIndirectSpecular", "Debug", "View Indirect Specular", "", false); Settings.AddSetting(&ViewIndirectSpecular); diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index a864cb6..207868d 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -815,6 +815,9 @@ public class Debug [UseAsShaderConstant(false)] bool ShowBakeDataVisualizer = false; + [UseAsShaderConstant(false)] + bool ShowProbeVisualizer = false; + bool ViewIndirectSpecular = false; [DisplayName("Save Light Settings")] diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index 3d946dc..d818bbb 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -337,6 +337,7 @@ namespace AppSettings extern FloatSetting BloomBlurSigma; extern BoolSetting EnableLuminancePicker; extern BoolSetting ShowBakeDataVisualizer; + extern BoolSetting ShowProbeVisualizer; extern BoolSetting ViewIndirectSpecular; extern Button SaveLightSettings; extern Button LoadLightSettings; @@ -594,5 +595,10 @@ namespace AppSettings return true; } + inline uint64 NumProbes() + { + return ProbeResX * ProbeResY * ProbeResZ; + } + void UpdateUI(); } \ No newline at end of file diff --git a/BakingLab/BakeDataVisualizer.hlsl b/BakingLab/BakeDataVisualizer.hlsl index 3e66ed8..d2b7d60 100644 --- a/BakingLab/BakeDataVisualizer.hlsl +++ b/BakingLab/BakeDataVisualizer.hlsl @@ -1,186 +1,188 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -//================================================================================================= -// Includes -//================================================================================================= -#include "SharedConstants.h" -#include -#include "AppSettings.hlsl" -#include "SG.hlsl" - -//================================================================================================= -// Constant buffers -//================================================================================================= -cbuffer Constants : register(b0) -{ - float4x4 ViewProjection; - float4 SGDirections[MaxSGCount]; - float SGSharpness; -} - -//================================================================================================= -// Resources -//================================================================================================= -StructuredBuffer BakePoints : register(t0); -Texture2DArray BakedLightingMap : register(t0); -SamplerState LinearSampler : register(s0); - -//================================================================================================= -// Input/Output structs -//================================================================================================= -struct VSOutput -{ - float4 PositionCS : SV_Position; - float3 NormalTS : NORMALTS; - float2 LightMapUV : LIGHTMAPUV; -}; - -struct PSInput -{ - float4 PositionSS : SV_Position; - float3 NormalTS : NORMALTS; - float2 LightMapUV : LIGHTMAPUV; -}; - -//================================================================================================= -// Vertex shader -//================================================================================================= -VSOutput VS(in float3 SpherePosition : POSITION, in uint InstanceID : SV_InstanceID) -{ - VSOutput output; - - // Get the sample point for this sphere - BakePoint bakePoint = BakePoints[InstanceID]; - - // Transform the sphere the orientation and position of the sample point - float3 bitangent = normalize(cross(bakePoint.Normal, bakePoint.Tangent)); - bitangent *= sign(dot(bitangent, bakePoint.Bitangent)); - float4x4 transform = float4x4(float4(bakePoint.Tangent, 0.0f), - float4(bitangent, 0.0f), - float4(bakePoint.Normal, 0.0f), - float4(bakePoint.Position, 1.0f)); - - float size = min(bakePoint.Size.x, bakePoint.Size.y) * 0.3f; - float3 positionWS = mul(float4(SpherePosition * size, 1.0f), transform).xyz; - output.PositionCS = mul(float4(positionWS, 1.0f), ViewProjection); - output.NormalTS = SpherePosition; - output.LightMapUV = (bakePoint.TexelPos + 0.5f) / LightMapResolution; - - return output; -} - -float3 EvalSGs(in float2 lightMapUV, in uint numSGs, in float3 dir) -{ - float3 output = 0.0f; - - [unroll] - for(uint i = 0; i < numSGs; ++i) - { - SG sg; - sg.Amplitude = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; - sg.Axis = SGDirections[i].xyz; - sg.Sharpness = SGSharpness; - - output += EvaluateSG(sg, dir); - } - - return output; -} - -//================================================================================================= -// Pixel shader -//================================================================================================= -float4 PS(in PSInput input) : SV_Target0 -{ - float3 output = 0.0f; - - float3 normalTS = normalize(input.NormalTS); - float2 uv = input.LightMapUV; - - if(BakeMode == BakeModes_Diffuse) - { - output = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, 0.0f), 0.0f).xyz; - } - else if(BakeMode == BakeModes_HL2) - { - const float3 BasisDirs[3] = - { - float3(-1.0f / sqrt(6.0f), -1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), - float3(-1.0f / sqrt(6.0f), 1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), - float3(sqrt(2.0f / 3.0f), 0.0f, 1.0f / sqrt(3.0f)), - }; - - [unroll] - for(uint i = 0; i < 3; ++i) - { - float3 lightMap = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz;; - output += saturate(dot(normalTS, BasisDirs[i])) * lightMap * InvPi; - } - } - else if(BakeMode == BakeModes_SH4) - { - SH4Color shRadiance; - - [unroll] - for(uint i = 0; i < 4; ++i) - shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; - - output = EvalSH4(normalTS, shRadiance); - } - else if(BakeMode == BakeModes_SH9) - { - SH9Color shRadiance; - - [unroll] - for(uint i = 0; i < 9; ++i) - shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; - - output = EvalSH9(normalTS, shRadiance); - } - else if(BakeMode == BakeModes_H4) - { - H4Color hbIrradiance; - - [unroll] - for(uint i = 0; i < 4; ++i) - hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; - - output = EvalH4(normalTS, hbIrradiance) * InvPi; - } - else if(BakeMode == BakeModes_H6) - { - H6Color hbIrradiance; - - [unroll] - for(uint i = 0; i < 6; ++i) - hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; - - output = EvalH6(normalTS, hbIrradiance) * InvPi; - } - else if(BakeMode == BakeModes_SG5) - { - output = EvalSGs(uv, 5, normalTS); - } - else if(BakeMode == BakeModes_SG6) - { - output = EvalSGs(uv, 6, normalTS); - } - else if(BakeMode == BakeModes_SG9) - { - output = EvalSGs(uv, 9, normalTS); - } - else if(BakeMode == BakeModes_SG12) - { - output = EvalSGs(uv, 12, normalTS); - } - - return float4(output, 1.0f); +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include "SharedConstants.h" +#include +#include "AppSettings.hlsl" +#include "SG.hlsl" + +//================================================================================================= +// Constant buffers +//================================================================================================= +cbuffer Constants : register(b0) +{ + float4x4 ViewProjection; + float4 SGDirections[MaxSGCount]; + float SGSharpness; + float3 SceneMinBounds; + float3 SceneMaxBounds; +} + +//================================================================================================= +// Resources +//================================================================================================= +StructuredBuffer BakePoints : register(t0); +Texture2DArray BakedLightingMap : register(t0); +SamplerState LinearSampler : register(s0); + +//================================================================================================= +// Input/Output structs +//================================================================================================= +struct VSOutput +{ + float4 PositionCS : SV_Position; + float3 NormalTS : NORMALTS; + float2 LightMapUV : LIGHTMAPUV; +}; + +struct PSInput +{ + float4 PositionSS : SV_Position; + float3 NormalTS : NORMALTS; + float2 LightMapUV : LIGHTMAPUV; +}; + +//================================================================================================= +// Vertex shader +//================================================================================================= +VSOutput VS(in float3 SpherePosition : POSITION, in uint InstanceID : SV_InstanceID) +{ + VSOutput output; + + // Get the sample point for this sphere + BakePoint bakePoint = BakePoints[InstanceID]; + + // Transform the sphere the orientation and position of the sample point + float3 bitangent = normalize(cross(bakePoint.Normal, bakePoint.Tangent)); + bitangent *= sign(dot(bitangent, bakePoint.Bitangent)); + float4x4 transform = float4x4(float4(bakePoint.Tangent, 0.0f), + float4(bitangent, 0.0f), + float4(bakePoint.Normal, 0.0f), + float4(bakePoint.Position, 1.0f)); + + float size = min(bakePoint.Size.x, bakePoint.Size.y) * 0.3f; + float3 positionWS = mul(float4(SpherePosition * size, 1.0f), transform).xyz; + output.PositionCS = mul(float4(positionWS, 1.0f), ViewProjection); + output.NormalTS = SpherePosition; + output.LightMapUV = (bakePoint.TexelPos + 0.5f) / LightMapResolution; + + return output; +} + +float3 EvalSGs(in float2 lightMapUV, in uint numSGs, in float3 dir) +{ + float3 output = 0.0f; + + [unroll] + for(uint i = 0; i < numSGs; ++i) + { + SG sg; + sg.Amplitude = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + sg.Axis = SGDirections[i].xyz; + sg.Sharpness = SGSharpness; + + output += EvaluateSG(sg, dir); + } + + return output; +} + +//================================================================================================= +// Pixel shader +//================================================================================================= +float4 PS(in PSInput input) : SV_Target0 +{ + float3 output = 0.0f; + + float3 normalTS = normalize(input.NormalTS); + float2 uv = input.LightMapUV; + + if(BakeMode == BakeModes_Diffuse) + { + output = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, 0.0f), 0.0f).xyz; + } + else if(BakeMode == BakeModes_HL2) + { + const float3 BasisDirs[3] = + { + float3(-1.0f / sqrt(6.0f), -1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), + float3(-1.0f / sqrt(6.0f), 1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), + float3(sqrt(2.0f / 3.0f), 0.0f, 1.0f / sqrt(3.0f)), + }; + + [unroll] + for(uint i = 0; i < 3; ++i) + { + float3 lightMap = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz;; + output += saturate(dot(normalTS, BasisDirs[i])) * lightMap * InvPi; + } + } + else if(BakeMode == BakeModes_SH4) + { + SH4Color shRadiance; + + [unroll] + for(uint i = 0; i < 4; ++i) + shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; + + output = EvalSH4(normalTS, shRadiance); + } + else if(BakeMode == BakeModes_SH9) + { + SH9Color shRadiance; + + [unroll] + for(uint i = 0; i < 9; ++i) + shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; + + output = EvalSH9(normalTS, shRadiance); + } + else if(BakeMode == BakeModes_H4) + { + H4Color hbIrradiance; + + [unroll] + for(uint i = 0; i < 4; ++i) + hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; + + output = EvalH4(normalTS, hbIrradiance) * InvPi; + } + else if(BakeMode == BakeModes_H6) + { + H6Color hbIrradiance; + + [unroll] + for(uint i = 0; i < 6; ++i) + hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; + + output = EvalH6(normalTS, hbIrradiance) * InvPi; + } + else if(BakeMode == BakeModes_SG5) + { + output = EvalSGs(uv, 5, normalTS); + } + else if(BakeMode == BakeModes_SG6) + { + output = EvalSGs(uv, 6, normalTS); + } + else if(BakeMode == BakeModes_SG9) + { + output = EvalSGs(uv, 9, normalTS); + } + else if(BakeMode == BakeModes_SG12) + { + output = EvalSGs(uv, 12, normalTS); + } + + return float4(output, 1.0f); } \ No newline at end of file diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 20c7319..d98a8fb 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -619,7 +619,7 @@ void BakingLab::RenderProbes() ID3D11DevicePtr device = deviceManager.Device(); const uint64 currSceneIdx = AppSettings::CurrentScene; - const uint32 numProbes = AppSettings::ProbeResX * AppSettings::ProbeResY * AppSettings::ProbeResZ; + const uint32 numProbes = uint32(AppSettings::NumProbes()); if(probeCaptureMap.Width == 0) { @@ -676,7 +676,7 @@ void BakingLab::RenderProbes() probeCam.SetOrientation(orientation); RenderScene(status, probeCaptureMap.RTVArraySlices[i], probeVelocityTarget.RTView, probeDepthBuffer, probeCam, - false, AppSettings::BakeDirectAreaLight, false); + false, false, AppSettings::BakeDirectAreaLight, false); } AppSettings::UseProbes.SetValue(prevUseProbes); @@ -741,7 +741,8 @@ void BakingLab::Render(const Timer& timer) { status.ProbeIrradiance = probeIrradianceMap.SRView; RenderScene(status, colorTargetMSAA.RTView, velocityTargetMSAA.RTView, depthBuffer, camera, - AppSettings::ShowBakeDataVisualizer, AppSettings::EnableAreaLight, true); + AppSettings::ShowBakeDataVisualizer, AppSettings::ShowProbeVisualizer, + AppSettings::EnableAreaLight, true); RenderBackgroundVelocity(); } @@ -768,8 +769,8 @@ void BakingLab::Render(const Timer& timer) } void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, - const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 renderAreaLight, - bool32 enableSkySun) + const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, + bool32 renderAreaLight, bool32 enableSkySun) { PIXEvent event(L"Render Scene"); @@ -807,6 +808,9 @@ void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetVie if(showBakeDataVisualizer) meshRenderer.RenderBakeDataVisualizer(context, cam, status); + if(showProbeVisualizer) + meshRenderer.RenderProbeVisualizer(context, cam, status); + if(renderAreaLight) meshRenderer.RenderAreaLight(context, cam); diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index 52c5cdc..44ce6a3 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -116,8 +116,8 @@ class BakingLab : public App void RenderProbes(); void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, - const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 renderAreaLight, - bool32 enableSkySun); + const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, + bool32 renderAreaLight, bool32 enableSkySun); void RenderAA(); void RenderBackgroundVelocity(); void RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 7c6760b..ad43d3d 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -50,10 +50,10 @@ cbuffer PSConstants : register(b0) float LightBleedingReduction; float2 RTSize; float2 JitterOffset; - float4 SceneMinBounds; - float4 SceneMaxBounds; float4 SGDirections[MaxSGCount]; float SGSharpness; + float3 SceneMinBounds; + float3 SceneMaxBounds; } //================================================================================================= @@ -476,13 +476,14 @@ float3 SampleIrradianceProbe(in float3 samplePos, float3 direction) void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) { - float3 sampleUVW = saturate((surface.PositionWS - SceneMinBounds.xyz) / (SceneMaxBounds.xyz - SceneMinBounds.xyz)); + float3 sampleUVW = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); float3 probeDims = float3(ProbeResX, ProbeResY, ProbeResZ); float3 halfTexelSize = 0.5f / probeDims; - float3 samplePos = frac(sampleUVW - halfTexelSize); + float3 samplePos = max(sampleUVW - halfTexelSize, 0.0f); + samplePos *= probeDims; - samplePos = min(probeDims, probeDims - 1.0f); + samplePos = min(samplePos, probeDims - 1.0f); float3 samplePosNext = min(samplePos + 1, probeDims - 1.0f); float3 lerpAmts = frac(samplePos); diff --git a/BakingLab/MeshBaker.cpp b/BakingLab/MeshBaker.cpp index b2353f4..a9612f9 100644 --- a/BakingLab/MeshBaker.cpp +++ b/BakingLab/MeshBaker.cpp @@ -1256,11 +1256,9 @@ static uint32 __stdcall RenderThread(void* data) static uint64 GetNumThreads() { - /*SYSTEM_INFO sysInfo; + SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); - return std::max(1, sysInfo.dwNumberOfProcessors - 1);*/ - - return 1; + return std::max(1, sysInfo.dwNumberOfProcessors - 1); } MeshBaker::MeshBaker() diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index 67de0b7..2d9dabd 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -235,11 +235,6 @@ static void GenerateSphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* d DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); } -MeshRenderer::MeshRenderer() : currFrame(0), sceneModel(nullptr), - numHemisphereIndices(0), numAreaLightIndices(0) -{ -} - void MeshRenderer::LoadShaders() { // Load the mesh shaders @@ -253,6 +248,9 @@ void MeshRenderer::LoadShaders() visualizerVS = CompileVSFromFile(device, L"BakeDataVisualizer.hlsl", "VS", "vs_5_0"); visualizerPS = CompilePSFromFile(device, L"BakeDataVisualizer.hlsl", "PS", "ps_5_0"); + probeVisualizerVS = CompileVSFromFile(device, L"ProbeVisualizer.hlsl", "VS", "vs_5_0"); + probeVisualizerPS = CompilePSFromFile(device, L"ProbeVisualizer.hlsl", "PS", "ps_5_0"); + fullScreenVS = CompileVSFromFile(device, L"EVSMConvert.hlsl", "FullScreenVS"); CompileOptions opts; @@ -336,7 +334,7 @@ void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context GenerateHemisphere(16, 4, device, hemisphereVB, hemisphereIB, numHemisphereIndices); - GenerateSphere(256, 192, device, areaLightVB, areaLightIB, numAreaLightIndices); + GenerateSphere(256, 192, device, sphereVB, sphereIB, numSphereIndices); D3D11_INPUT_ELEMENT_DESC elements[1]; elements[0].AlignedByteOffset = 0; @@ -350,6 +348,9 @@ void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context DXCall(device->CreateInputLayout(elements, 1, visualizerVS->ByteCode->GetBufferPointer(), visualizerVS->ByteCode->GetBufferSize(), &visualizerInputLayout)); + DXCall(device->CreateInputLayout(elements, 1, probeVisualizerVS->ByteCode->GetBufferPointer(), + probeVisualizerVS->ByteCode->GetBufferSize(), &probeVisualizerInputLayout)); + DXCall(device->CreateInputLayout(elements, 1, areaLightVS->ByteCode->GetBufferPointer(), areaLightVS->ByteCode->GetBufferSize(), &areaLightInputLayout)); @@ -629,11 +630,11 @@ void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& ca meshPSConstants.Data.PositiveExponent = PositiveExponent; meshPSConstants.Data.NegativeExponent = NegativeExponent; meshPSConstants.Data.LightBleedingReduction = LightBleedingReduction; - meshPSConstants.Data.SceneMinBounds = Float4(status.SceneMinBounds, 0.0f); - meshPSConstants.Data.SceneMaxBounds = Float4(status.SceneMaxBounds, 0.0f); for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) meshPSConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); meshPSConstants.Data.SGSharpness = status.SGSharpness; + meshPSConstants.Data.SceneMinBounds = status.SceneMinBounds; + meshPSConstants.Data.SceneMaxBounds = status.SceneMaxBounds; meshPSConstants.ApplyChanges(context); meshPSConstants.SetPS(context, 0); @@ -1002,14 +1003,14 @@ void MeshRenderer::RenderAreaLight(ID3D11DeviceContext* context, const Camera& c context->PSSetShader(areaLightPS, nullptr, 0); // Draw the visualizer sphere - ID3D11Buffer* vertexBuffers[1] = { areaLightVB }; + ID3D11Buffer* vertexBuffers[1] = { sphereVB }; uint32 vertexStrides[1] = { sizeof(Float3) }; uint32 offsets[1] = { 0 }; context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); - context->IASetIndexBuffer(areaLightIB, DXGI_FORMAT_R32_UINT, 0); + context->IASetIndexBuffer(sphereIB, DXGI_FORMAT_R32_UINT, 0); context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); context->IASetInputLayout(areaLightInputLayout); - context->DrawIndexedInstanced(uint32(numAreaLightIndices), 1, 0, 0, 0); + context->DrawIndexedInstanced(uint32(numSphereIndices), 1, 0, 0, 0); } // Renders the bake data visualizer @@ -1028,6 +1029,8 @@ void MeshRenderer::RenderBakeDataVisualizer(ID3D11DeviceContext* context, const for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) visualizerConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); visualizerConstants.Data.SGSharpness = status.SGSharpness; + visualizerConstants.Data.SceneMinBounds = status.SceneMinBounds; + visualizerConstants.Data.SceneMaxBounds = status.SceneMaxBounds; visualizerConstants.ApplyChanges(context); visualizerConstants.SetVS(context, 0); visualizerConstants.SetPS(context, 0); @@ -1042,8 +1045,11 @@ void MeshRenderer::RenderBakeDataVisualizer(ID3D11DeviceContext* context, const ID3D11ShaderResourceView* vsSrvs[] = { status.BakePoints }; context->VSSetShaderResources(0, ArraySize_(vsSrvs), vsSrvs); - ID3D11ShaderResourceView* psSrvs[1] = { status.LightMap }; - context->PSSetShaderResources(0, 1, psSrvs); + ID3D11ShaderResourceView* psSrvs[] = { status.LightMap }; + context->PSSetShaderResources(0, ArraySize_(psSrvs), psSrvs); + + ID3D11SamplerState* psSamplers[] = { samplerStates.LinearClamp() }; + context->PSSetSamplers(0, ArraySize_(psSamplers), psSamplers); // Draw the visualizer hemispheres for all sample points ID3D11Buffer* vertexBuffers[1] = { hemisphereVB }; @@ -1060,4 +1066,55 @@ void MeshRenderer::RenderBakeDataVisualizer(ID3D11DeviceContext* context, const ID3D11ShaderResourceView* nullSRVs[] = { nullptr }; context->VSSetShaderResources(0, 1, nullSRVs); context->PSSetShaderResources(0, 1, nullSRVs); +} + +// Renders the probe visualizer +void MeshRenderer::RenderProbeVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) +{ + PIXEvent event(L"Probe Visualizer"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); + context->RSSetState(rasterizerStates.NoCull()); + + // Set constant buffers + visualizerConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) + visualizerConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); + visualizerConstants.Data.SGSharpness = status.SGSharpness; + visualizerConstants.Data.SceneMinBounds = status.SceneMinBounds; + visualizerConstants.Data.SceneMaxBounds = status.SceneMaxBounds; + visualizerConstants.ApplyChanges(context); + visualizerConstants.SetVS(context, 0); + visualizerConstants.SetPS(context, 0); + + // Set shaders + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->VSSetShader(probeVisualizerVS , nullptr, 0); + context->PSSetShader(probeVisualizerPS, nullptr, 0); + + ID3D11ShaderResourceView* psSrvs[] = { status.ProbeIrradiance }; + context->PSSetShaderResources(0, ArraySize_(psSrvs), psSrvs); + + ID3D11SamplerState* psSamplers[] = { samplerStates.LinearClamp() }; + context->PSSetSamplers(0, ArraySize_(psSamplers), psSamplers); + + // Draw the visualizer hemispheres for all sample points + ID3D11Buffer* vertexBuffers[1] = { sphereVB }; + uint32 vertexStrides[1] = { sizeof(Float3) }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(sphereIB, DXGI_FORMAT_R32_UINT, 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(probeVisualizerInputLayout); + + // Draw + context->DrawIndexedInstanced(uint32(numSphereIndices), uint32(AppSettings::NumProbes()), 0, 0, 0); + + ID3D11ShaderResourceView* nullSRVs[] = { nullptr }; + context->PSSetShaderResources(0, 1, nullSRVs); } \ No newline at end of file diff --git a/BakingLab/MeshRenderer.h b/BakingLab/MeshRenderer.h index 21c468f..7ec896f 100644 --- a/BakingLab/MeshRenderer.h +++ b/BakingLab/MeshRenderer.h @@ -35,7 +35,6 @@ class MeshRenderer static const uint32 ReadbackLatency = 1; public: -MeshRenderer(); void Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* sceneModel); void SetModel(const Model* model); @@ -56,6 +55,8 @@ MeshRenderer(); void RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera); void RenderBakeDataVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status); + void RenderProbeVisualizer(ID3D11DeviceContext* context, const Camera& camera, + const MeshBakerStatus& status); protected: @@ -70,7 +71,7 @@ MeshRenderer(); DepthStencilStates depthStencilStates; SamplerStates samplerStates; - const Model* sceneModel; + const Model* sceneModel = nullptr; DepthStencilBuffer sunShadowDepthMap; RenderTarget2D sunVSM; @@ -90,15 +91,19 @@ MeshRenderer(); ID3D11BufferPtr hemisphereVB; ID3D11BufferPtr hemisphereIB; - uint64 numHemisphereIndices; + uint64 numHemisphereIndices = 0; ID3D11InputLayoutPtr visualizerInputLayout; VertexShaderPtr visualizerVS; PixelShaderPtr visualizerPS; - ID3D11BufferPtr areaLightVB; - ID3D11BufferPtr areaLightIB; - uint64 numAreaLightIndices; + ID3D11InputLayoutPtr probeVisualizerInputLayout; + VertexShaderPtr probeVisualizerVS; + PixelShaderPtr probeVisualizerPS; + + ID3D11BufferPtr sphereVB; + ID3D11BufferPtr sphereIB; + uint64 numSphereIndices = 0; VertexShaderPtr areaLightVS; PixelShaderPtr areaLightPS; @@ -113,7 +118,7 @@ MeshRenderer(); ComputeShaderPtr depthReductionCS; std::vector depthReductionTargets; StagingTexture2D reductionStagingTextures[ReadbackLatency]; - uint32 currFrame; + uint32 currFrame = 0; Float2 reductionDepth; @@ -155,11 +160,11 @@ MeshRenderer(); Float2 RTSize; Float2 JitterOffset; - Float4 SceneMinBounds; - Float4 SceneMaxBounds; - Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; float SGSharpness; + + Float3 SceneMinBounds; + Float4Align Float3 SceneMaxBounds; }; struct AreaLightConstants @@ -193,6 +198,8 @@ MeshRenderer(); Float4x4 ViewProjection; Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; float SGSharpness; + Float3 SceneMinBounds; + Float4Align Float3 SceneMaxBounds; }; ConstantBuffer meshVSConstants; diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl index 620fe11..d327c7f 100644 --- a/BakingLab/ProbeIntegrate.hlsl +++ b/BakingLab/ProbeIntegrate.hlsl @@ -160,7 +160,7 @@ void IntegrateIrradiance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : float3 bitangent = normalize(cross(normal, tangent)); tangent = normalize(cross(bitangent, normal)); - const uint numSamples = 64; + const uint numSamples = 256; float3 irradiance = 0.0f; for(uint i = 0; i < numSamples; ++i) { diff --git a/BakingLab/ProbeVisualizer.hlsl b/BakingLab/ProbeVisualizer.hlsl new file mode 100644 index 0000000..5c83de1 --- /dev/null +++ b/BakingLab/ProbeVisualizer.hlsl @@ -0,0 +1,89 @@ +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include "SharedConstants.h" +#include +#include "AppSettings.hlsl" +#include "SG.hlsl" + +//================================================================================================= +// Constant buffers +//================================================================================================= +cbuffer Constants : register(b0) +{ + float4x4 ViewProjection; + float4 SGDirections[MaxSGCount]; + float SGSharpness; + float3 SceneMinBounds; + float3 SceneMaxBounds; +} + +//================================================================================================= +// Resources +//================================================================================================= +TextureCubeArray ProbeIrradiance : register(t0); +SamplerState LinearSampler : register(s0); + +//================================================================================================= +// Input/Output structs +//================================================================================================= +struct VSOutput +{ + float4 PositionCS : SV_Position; + float3 NormalWS : NORMALWS; + uint ProbeIdx : PROBEIDX; +}; + +struct PSInput +{ + float4 PositionSS : SV_Position; + float3 NormalWS : NORMALWS; + uint ProbeIdx : PROBEIDX; +}; + +//================================================================================================= +// Vertex shader +//================================================================================================= +VSOutput VS(in float3 SpherePosition : POSITION, in uint InstanceID : SV_InstanceID) +{ + VSOutput output; + + output.NormalWS = normalize(SpherePosition); + output.ProbeIdx = InstanceID; + + uint probeX = InstanceID % ProbeResX; + uint probeY = (InstanceID / ProbeResX) % ProbeResY; + uint probeZ = InstanceID / (ProbeResX * ProbeResY); + + float3 probePos; + probePos.x = lerp(SceneMinBounds.x, SceneMaxBounds.x, (probeX + 0.5f) / ProbeResX); + probePos.y = lerp(SceneMinBounds.y, SceneMaxBounds.y, (probeY + 0.5f) / ProbeResY); + probePos.z = lerp(SceneMinBounds.z, SceneMaxBounds.z, (probeZ + 0.5f) / ProbeResZ); + + float3 cellSizes = (SceneMaxBounds - SceneMinBounds) / float3(ProbeResX, ProbeResZ, ProbeResZ); + float probeSize = 0.15f * min(min(cellSizes.x, cellSizes.y), cellSizes.z); + + float3 vtxPositionWS = (SpherePosition * probeSize) + probePos; + output.PositionCS = mul(float4(vtxPositionWS, 1.0f), ViewProjection); + + return output; +} + +//================================================================================================= +// Pixel shader +//================================================================================================= +float4 PS(in PSInput input) : SV_Target0 +{ + float3 irradiance = ProbeIrradiance.Sample(LinearSampler, float4(input.NormalWS, input.ProbeIdx)).xyz; + return float4(irradiance * InvPi, 0.0f); +} \ No newline at end of file From 8d075f2fefd3c0eb1c696442f92898ce2df43684 Mon Sep 17 00:00:00 2001 From: MJP Date: Sat, 30 Sep 2017 19:44:24 -0700 Subject: [PATCH 07/43] Invalidate probe results when scene conditions change --- BakingLab/BakingLab.cpp | 11 +++++------ BakingLab/BakingLab.h | 2 +- BakingLab/MeshBaker.cpp | 5 ++++- BakingLab/MeshBaker.h | 1 + 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index d98a8fb..682b7f9 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -611,7 +611,7 @@ void BakingLab::Update(const Timer& timer) meshRenderer.Update(camera, jitterOffset); } -void BakingLab::RenderProbes() +void BakingLab::RenderProbes(const MeshBakerStatus& status) { PIXEvent pixEvent(L"Render Probes"); @@ -636,6 +636,9 @@ void BakingLab::RenderProbes() probeIrradianceMap.Initialize(device, 16, 16, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); } + if(status.BakingInvalidated) + currProbeIdx = 0; + if(currProbeIdx >= numProbes) return; @@ -654,10 +657,6 @@ void BakingLab::RenderProbes() PerspectiveCamera probeCam(1.0f, Pi_2, NearClip, FarClip); probeCam.SetPosition(probePos); - MeshBakerStatus status; - status.SceneMinBounds = sceneMins[currSceneIdx]; - status.SceneMaxBounds = sceneMaxes[currSceneIdx]; - for(uint64 i = 0; i < 6; ++i) { Quaternion orientation; @@ -718,7 +717,7 @@ void BakingLab::Render(const Timer& timer) status.SceneMinBounds = sceneMins[AppSettings::CurrentScene]; status.SceneMaxBounds = sceneMaxes[AppSettings::CurrentScene]; - RenderProbes(); + RenderProbes(status); if(AppSettings::ShowGroundTruth) { diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index 44ce6a3..5163236 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -114,7 +114,7 @@ class BakingLab : public App void CreateRenderTargets(); - void RenderProbes(); + void RenderProbes(const MeshBakerStatus& status); void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, bool32 renderAreaLight, bool32 enableSkySun); diff --git a/BakingLab/MeshBaker.cpp b/BakingLab/MeshBaker.cpp index a9612f9..61062bc 100644 --- a/BakingLab/MeshBaker.cpp +++ b/BakingLab/MeshBaker.cpp @@ -1330,6 +1330,8 @@ MeshBakerStatus MeshBaker::Update(const Camera& camera, uint32 screenWidth, uint const bool32 showGroundTruth = AppSettings::ShowGroundTruth; + MeshBakerStatus status; + if(currentModel != input.SceneModel) { KillBakeThreads(); @@ -1549,6 +1551,8 @@ MeshBakerStatus MeshBaker::Update(const Camera& camera, uint32 screenWidth, uint InterlockedIncrement64(&bakeTag); currTile = 0; currBakeBatch = 0; + + status.BakingInvalidated = true; } // Change checks for baking only @@ -1589,7 +1593,6 @@ MeshBakerStatus MeshBaker::Update(const Camera& camera, uint32 screenWidth, uint currTile = 0; } - MeshBakerStatus status; status.GroundTruth = renderTextureSRV; status.LightMap = bakeTextureSRV; status.BakePoints = bakePointBuffer.SRView; diff --git a/BakingLab/MeshBaker.h b/BakingLab/MeshBaker.h index a78f5ba..7bb90d7 100644 --- a/BakingLab/MeshBaker.h +++ b/BakingLab/MeshBaker.h @@ -68,6 +68,7 @@ struct MeshBakerStatus float SGSharpness = 0.0f; Float3 SceneMinBounds; Float3 SceneMaxBounds; + bool32 BakingInvalidated = false; }; class MeshBaker From 17e98dc18bdb827fdf06fd391831a5e5b7bd19e4 Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 1 Oct 2017 15:02:50 -0700 Subject: [PATCH 08/43] Refactored probe interpolation so that each probe has an explicit weight --- BakingLab/Mesh.hlsl | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index ad43d3d..adb70f6 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -476,33 +476,25 @@ float3 SampleIrradianceProbe(in float3 samplePos, float3 direction) void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) { - float3 sampleUVW = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); + float3 normalizedSamplePos = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); float3 probeDims = float3(ProbeResX, ProbeResY, ProbeResZ); float3 halfTexelSize = 0.5f / probeDims; - float3 samplePos = max(sampleUVW - halfTexelSize, 0.0f); + float3 baseSamplePos = saturate(normalizedSamplePos - halfTexelSize) * probeDims; + float3 lerpAmts = frac(baseSamplePos); - samplePos *= probeDims; - samplePos = min(samplePos, probeDims - 1.0f); - float3 samplePosNext = min(samplePos + 1, probeDims - 1.0f); - - float3 lerpAmts = frac(samplePos); - - float3 samples[8]; - samples[0] = SampleIrradianceProbe(float3(samplePos.x , samplePos.y, samplePos.z), surface.NormalWS); - samples[1] = SampleIrradianceProbe(float3(samplePosNext.x , samplePos.y, samplePos.z), surface.NormalWS); - samples[2] = SampleIrradianceProbe(float3(samplePos.x , samplePosNext.y, samplePos.z), surface.NormalWS); - samples[3] = SampleIrradianceProbe(float3(samplePosNext.x , samplePosNext.y, samplePos.z), surface.NormalWS); - - samples[4] = SampleIrradianceProbe(float3(samplePos.x , samplePos.y, samplePosNext.z), surface.NormalWS); - samples[5] = SampleIrradianceProbe(float3(samplePosNext.x , samplePos.y, samplePosNext.z), surface.NormalWS); - samples[6] = SampleIrradianceProbe(float3(samplePos.x , samplePosNext.y, samplePosNext.z), surface.NormalWS); - samples[7] = SampleIrradianceProbe(float3(samplePosNext.x , samplePosNext.y, samplePosNext.z), surface.NormalWS); + float3 irradianceSum = 0.0f; + for(uint i = 0; i < 8; ++i) + { + uint3 sampleOffset = uint3(i, i >> 1, i >> 2) & 0x1; + float3 samplePos = min(baseSamplePos + sampleOffset, probeDims - 1.0f); + float3 triLinear = lerp(1.0f - lerpAmts, lerpAmts, float3(sampleOffset)); + float sampleWeight = triLinear.x * triLinear.y * triLinear.z; + float3 sample = SampleIrradianceProbe(samplePos, surface.NormalWS); + irradianceSum += sample * sampleWeight; + } - // lerp between the shadow values to calculate our light amount - float3 result0123 = lerp(lerp(samples[0], samples[1], lerpAmts.x), lerp(samples[2], samples[3], lerpAmts.x), lerpAmts.y); - float3 result4567 = lerp(lerp(samples[4], samples[5], lerpAmts.x), lerp(samples[6], samples[7], lerpAmts.x), lerpAmts.y); - indirectIrradiance = lerp(result0123, result4567, lerpAmts.z); + indirectIrradiance = irradianceSum; indirectSpecular = 0.0f; } From 590460eb7ec49accd5b5a98f74f70b79d5ac24d4 Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 1 Oct 2017 15:46:52 -0700 Subject: [PATCH 09/43] Added scene bounds scaling and probe baking progress text --- BakingLab/AppSettings.cpp | 10 +++++--- BakingLab/AppSettings.cs | 15 +++++++----- BakingLab/AppSettings.h | 1 + BakingLab/BakingLab.cpp | 49 ++++++++++++++++++++++++++++++-------- BakingLab/BakingLab.h | 6 +++-- BakingLab/Mesh.hlsl | 7 ++++-- BakingLab/MeshBaker.h | 1 + BakingLab/MeshRenderer.cpp | 4 ++-- 8 files changed, 68 insertions(+), 25 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 3a9f609..cea844c 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -243,6 +243,7 @@ namespace AppSettings IntSetting ProbeResX; IntSetting ProbeResY; IntSetting ProbeResZ; + FloatSetting SceneBoundsScale; ScenesSetting CurrentScene; BoolSetting EnableDiffuse; BoolSetting EnableSpecular; @@ -504,15 +505,18 @@ namespace AppSettings UseProbes.Initialize(tweakBar, "UseProbes", "Probes", "Use Probes", "", true); Settings.AddSetting(&UseProbes); - ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 2, 2, 64); + ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 4, 2, 16); Settings.AddSetting(&ProbeResX); - ProbeResY.Initialize(tweakBar, "ProbeResY", "Probes", "Probe Res Y", "", 2, 2, 64); + ProbeResY.Initialize(tweakBar, "ProbeResY", "Probes", "Probe Res Y", "", 4, 2, 16); Settings.AddSetting(&ProbeResY); - ProbeResZ.Initialize(tweakBar, "ProbeResZ", "Probes", "Probe Res Z", "", 2, 2, 64); + ProbeResZ.Initialize(tweakBar, "ProbeResZ", "Probes", "Probe Res Z", "", 4, 2, 16); Settings.AddSetting(&ProbeResZ); + SceneBoundsScale.Initialize(tweakBar, "SceneBoundsScale", "Probes", "Scene Bounds Scale", "", 1.2500f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SceneBoundsScale); + CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); Settings.AddSetting(&CurrentScene); diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 207868d..80b04e6 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -666,16 +666,19 @@ public class Probes bool UseProbes = true; [MinValue(2)] - [MaxValue(64)] - int ProbeResX = 2; + [MaxValue(16)] + int ProbeResX = 4; [MinValue(2)] - [MaxValue(64)] - int ProbeResY = 2; + [MaxValue(16)] + int ProbeResY = 4; [MinValue(2)] - [MaxValue(64)] - int ProbeResZ = 2; + [MaxValue(16)] + int ProbeResZ = 4; + + [UseAsShaderConstant(false)] + float SceneBoundsScale = 1.25f; } [ExpandGroup(false)] diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index d818bbb..85624f9 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -313,6 +313,7 @@ namespace AppSettings extern IntSetting ProbeResX; extern IntSetting ProbeResY; extern IntSetting ProbeResZ; + extern FloatSetting SceneBoundsScale; extern ScenesSetting CurrentScene; extern BoolSetting EnableDiffuse; extern BoolSetting EnableSpecular; diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 682b7f9..12883ba 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -53,10 +53,15 @@ static const Float3 SceneCameraPositions[] = { Float3(0.0f, 2.5f, -15.0f), Float static const Float2 SceneCameraRotations[] = { Float2(0.0f, 0.0f), Float2(0.0f, Pi), Float2(0.414238036f, 1.39585948f) }; static const float SceneAlbedoScales[] = { 0.5f, 0.5f, 1.0f }; +static const Uint3 SceneDefaultProbeRes[] = { Uint3(4, 4, 4), Uint3(5, 3, 5), Uint3(5, 5, 5) }; +static const float SceneDefaultBoundsScales[] { 1.5f, 1.65f, 1.0f }; + StaticAssert_(ArraySize_(ScenePaths) >= uint64(Scenes::NumValues)); StaticAssert_(ArraySize_(SceneCameraPositions) >= uint64(Scenes::NumValues)); StaticAssert_(ArraySize_(SceneCameraRotations) >= uint64(Scenes::NumValues)); StaticAssert_(ArraySize_(SceneAlbedoScales) >= uint64(Scenes::NumValues)); +StaticAssert_(ArraySize_(SceneDefaultProbeRes) >= uint64(Scenes::NumValues)); +StaticAssert_(ArraySize_(SceneDefaultBoundsScales) >= uint64(Scenes::NumValues)); static Setting* LightSettings[] = { @@ -517,7 +522,7 @@ void BakingLab::Update(const Timer& timer) if(AppSettings::SaveLightSettings) SaveLightSettings(window.GetHwnd()); - if(AppSettings::CurrentScene.Changed()) + if(AppSettings::CurrentScene.Changed() || frameCount == 0) { uint64 currSceneIdx = uint64(AppSettings::CurrentScene); meshRenderer.SetModel(&sceneModels[currSceneIdx]); @@ -525,6 +530,10 @@ void BakingLab::Update(const Timer& timer) camera.SetXRotation(SceneCameraRotations[currSceneIdx].x); camera.SetYRotation(SceneCameraRotations[currSceneIdx].y); AppSettings::DiffuseAlbedoScale.SetValue(SceneAlbedoScales[currSceneIdx]); + AppSettings::ProbeResX.SetValue(SceneDefaultProbeRes[currSceneIdx].x); + AppSettings::ProbeResY.SetValue(SceneDefaultProbeRes[currSceneIdx].y); + AppSettings::ProbeResZ.SetValue(SceneDefaultProbeRes[currSceneIdx].z); + AppSettings::SceneBoundsScale.SetValue(SceneDefaultBoundsScales[currSceneIdx]); } mouseState = MouseState::GetMouseState(window); @@ -608,10 +617,14 @@ void BakingLab::Update(const Timer& timer) if(kbState.RisingEdge(KeyboardState::V)) deviceManager.SetVSYNCEnabled(!deviceManager.VSYNCEnabled()); + Float3 sceneCenter = (sceneMaxes[AppSettings::CurrentScene] + sceneMins[AppSettings::CurrentScene]) / 2.0f;; + currSceneMin = Lerp(sceneCenter, sceneMins[AppSettings::CurrentScene], AppSettings::SceneBoundsScale); + currSceneMax = Lerp(sceneCenter, sceneMaxes[AppSettings::CurrentScene], AppSettings::SceneBoundsScale); + meshRenderer.Update(camera, jitterOffset); } -void BakingLab::RenderProbes(const MeshBakerStatus& status) +void BakingLab::RenderProbes(MeshBakerStatus& status) { PIXEvent pixEvent(L"Render Probes"); @@ -636,11 +649,14 @@ void BakingLab::RenderProbes(const MeshBakerStatus& status) probeIrradianceMap.Initialize(device, 16, 16, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); } - if(status.BakingInvalidated) + if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed()) currProbeIdx = 0; if(currProbeIdx >= numProbes) + { + status.ProbeBakeProgress = 1.0f; return; + } bool32 prevUseProbes = AppSettings::UseProbes; AppSettings::UseProbes.SetValue(false); @@ -650,9 +666,9 @@ void BakingLab::RenderProbes(const MeshBakerStatus& status) uint64 probeZ = currProbeIdx / (AppSettings::ProbeResX * AppSettings::ProbeResY); Float3 probePos; - probePos.x = Lerp(sceneMins[currSceneIdx].x, sceneMaxes[currSceneIdx].x, (probeX + 0.5f) / AppSettings::ProbeResX); - probePos.y = Lerp(sceneMins[currSceneIdx].y, sceneMaxes[currSceneIdx].y, (probeY + 0.5f) / AppSettings::ProbeResY); - probePos.z = Lerp(sceneMins[currSceneIdx].z, sceneMaxes[currSceneIdx].z, (probeZ + 0.5f) / AppSettings::ProbeResZ); + probePos.x = Lerp(currSceneMin.x, currSceneMax.x, (probeX + 0.5f) / AppSettings::ProbeResX); + probePos.y = Lerp(currSceneMin.y, currSceneMax.y, (probeY + 0.5f) / AppSettings::ProbeResY); + probePos.z = Lerp(currSceneMin.z, currSceneMax.z, (probeZ + 0.5f) / AppSettings::ProbeResZ); PerspectiveCamera probeCam(1.0f, Pi_2, NearClip, FarClip); probeCam.SetPosition(probePos); @@ -701,6 +717,8 @@ void BakingLab::RenderProbes(const MeshBakerStatus& status) ++currProbeIdx; + status.ProbeBakeProgress = currProbeIdx / (numProbes - 1.0f); + /*if(currProbeIdx == numProbes) currProbeIdx = 0;*/ } @@ -714,8 +732,8 @@ void BakingLab::Render(const Timer& timer) MeshBakerStatus status = meshBaker.Update(unJitteredCamera, colorTargetMSAA.Width, colorTargetMSAA.Height, context, &sceneModels[AppSettings::CurrentScene]); - status.SceneMinBounds = sceneMins[AppSettings::CurrentScene]; - status.SceneMaxBounds = sceneMaxes[AppSettings::CurrentScene]; + status.SceneMinBounds = currSceneMin; + status.SceneMaxBounds = currSceneMax; RenderProbes(status); @@ -762,7 +780,7 @@ void BakingLab::Render(const Timer& timer) SetViewport(context, deviceManager.BackBufferWidth(), deviceManager.BackBufferHeight()); - RenderHUD(timer, status.GroundTruthProgress, status.BakeProgress, status.GroundTruthSampleCount); + RenderHUD(timer, status.GroundTruthProgress, status.BakeProgress, status.GroundTruthSampleCount, status.ProbeBakeProgress); ++frameCount; } @@ -929,7 +947,7 @@ void BakingLab::RenderBackgroundVelocity() } void BakingLab::RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, - uint64 groundTruthSampleCount) + uint64 groundTruthSampleCount, float probeBakeProgress) { PIXEvent event(L"HUD Pass"); @@ -983,6 +1001,17 @@ void BakingLab::RenderHUD(const Timer& timer, float groundTruthProgress, float b spriteRenderer.RenderText(font, progressText.c_str(), transform); } + if(probeBakeProgress < 1.0f) + { + float percent = Round(probeBakeProgress * 10000.0f); + percent /= 100.0f; + std::wstring progressText = L"Baking probes (" + ToString(percent) + L"%)"; + + transform._41 = 35.0f; + transform._42 = deviceManager.BackBufferHeight() - 40.0f; + spriteRenderer.RenderText(font, progressText.c_str(), transform); + } + if(AppSettings::EnableLuminancePicker && mouseState.IsOverWindow) { const uint8* texels = nullptr; diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index 5163236..6af20c6 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -52,6 +52,8 @@ class BakingLab : public App Model sceneModels[uint64(Scenes::NumValues)]; Float3 sceneMins[uint64(Scenes::NumValues)]; Float3 sceneMaxes[uint64(Scenes::NumValues)]; + Float3 currSceneMin; + Float3 currSceneMax; MeshRenderer meshRenderer; MeshBaker meshBaker; @@ -114,14 +116,14 @@ class BakingLab : public App void CreateRenderTargets(); - void RenderProbes(const MeshBakerStatus& status); + void RenderProbes(MeshBakerStatus& status); void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, bool32 renderAreaLight, bool32 enableSkySun); void RenderAA(); void RenderBackgroundVelocity(); void RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, - uint64 groundTruthSampleCount); + uint64 groundTruthSampleCount, float probeBakeProgress); public: diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index adb70f6..2439dbf 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -501,7 +501,7 @@ void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrr //================================================================================================= // Pixel Shader //================================================================================================= -PSOutput PS(in PSInput input) +PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) { SurfaceContext surface; surface.VtxNormalWS = normalize(input.NormalWS); @@ -612,7 +612,10 @@ PSOutput PS(in PSInput input) float illuminance = dot(irradiance, float3(0.2126f, 0.7152f, 0.0722f)); PSOutput output; - output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); + output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); + + if(isFrontFace == false) + output.Lighting = 0.0f; float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; prevPositionSS *= RTSize; diff --git a/BakingLab/MeshBaker.h b/BakingLab/MeshBaker.h index 7bb90d7..0a7be65 100644 --- a/BakingLab/MeshBaker.h +++ b/BakingLab/MeshBaker.h @@ -69,6 +69,7 @@ struct MeshBakerStatus Float3 SceneMinBounds; Float3 SceneMaxBounds; bool32 BakingInvalidated = false; + float ProbeBakeProgress = 0.0f; }; class MeshBaker diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index 2d9dabd..0c381be 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -602,7 +602,7 @@ void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& ca float blendFactor[4] = {1, 1, 1, 1}; context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); context->OMSetDepthStencilState(depthStencilStates.DepthEnabled(), 0); - context->RSSetState(rasterizerStates.BackFaceCull()); + context->RSSetState(rasterizerStates.NoCull()); ID3D11SamplerState* sampStates[] = { samplerStates.Anisotropic(), @@ -705,7 +705,7 @@ void MeshRenderer::RenderDepth(ID3D11DeviceContext* context, const Camera& camer if(noZClip) context->RSSetState(noZClipRSState); else - context->RSSetState(rasterizerStates.BackFaceCull()); + context->RSSetState(rasterizerStates.NoCull()); // Set constant buffers meshVSConstants.Data.World = Float4x4(); From 44aca19c8331b43b7a8d319b5a2e2221f3ba96c7 Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 1 Oct 2017 16:02:36 -0700 Subject: [PATCH 10/43] Add a setting to weight probes by normal to reject backfacing probes --- BakingLab/AppSettings.cpp | 5 +++++ BakingLab/AppSettings.cs | 2 ++ BakingLab/AppSettings.h | 2 ++ BakingLab/AppSettings.hlsl | 1 + BakingLab/Mesh.hlsl | 13 +++++++++++++ 5 files changed, 23 insertions(+) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index cea844c..9bf65b8 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -244,6 +244,7 @@ namespace AppSettings IntSetting ProbeResY; IntSetting ProbeResZ; FloatSetting SceneBoundsScale; + BoolSetting WeightProbesByNormal; ScenesSetting CurrentScene; BoolSetting EnableDiffuse; BoolSetting EnableSpecular; @@ -517,6 +518,9 @@ namespace AppSettings SceneBoundsScale.Initialize(tweakBar, "SceneBoundsScale", "Probes", "Scene Bounds Scale", "", 1.2500f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); Settings.AddSetting(&SceneBoundsScale); + WeightProbesByNormal.Initialize(tweakBar, "WeightProbesByNormal", "Probes", "Weight Probes By Normal", "", true); + Settings.AddSetting(&WeightProbesByNormal); + CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); Settings.AddSetting(&CurrentScene); @@ -698,6 +702,7 @@ namespace AppSettings CBuffer.Data.ProbeResX = ProbeResX; CBuffer.Data.ProbeResY = ProbeResY; CBuffer.Data.ProbeResZ = ProbeResZ; + CBuffer.Data.WeightProbesByNormal = WeightProbesByNormal; CBuffer.Data.EnableDiffuse = EnableDiffuse; CBuffer.Data.EnableSpecular = EnableSpecular; CBuffer.Data.EnableDirectLighting = EnableDirectLighting; diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 80b04e6..24ac1e1 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -679,6 +679,8 @@ public class Probes [UseAsShaderConstant(false)] float SceneBoundsScale = 1.25f; + + bool WeightProbesByNormal = true; } [ExpandGroup(false)] diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index 85624f9..7b248ca 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -314,6 +314,7 @@ namespace AppSettings extern IntSetting ProbeResY; extern IntSetting ProbeResZ; extern FloatSetting SceneBoundsScale; + extern BoolSetting WeightProbesByNormal; extern ScenesSetting CurrentScene; extern BoolSetting EnableDiffuse; extern BoolSetting EnableSpecular; @@ -398,6 +399,7 @@ namespace AppSettings int32 ProbeResX; int32 ProbeResY; int32 ProbeResZ; + bool32 WeightProbesByNormal; bool32 EnableDiffuse; bool32 EnableSpecular; bool32 EnableDirectLighting; diff --git a/BakingLab/AppSettings.hlsl b/BakingLab/AppSettings.hlsl index c6a8bb7..88c37a9 100644 --- a/BakingLab/AppSettings.hlsl +++ b/BakingLab/AppSettings.hlsl @@ -51,6 +51,7 @@ cbuffer AppSettings : register(b7) int ProbeResX; int ProbeResY; int ProbeResZ; + bool WeightProbesByNormal; bool EnableDiffuse; bool EnableSpecular; bool EnableDirectLighting; diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 2439dbf..0bd3dae 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -484,16 +484,29 @@ void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrr float3 lerpAmts = frac(baseSamplePos); float3 irradianceSum = 0.0f; + float weightSum = 0.0f; for(uint i = 0; i < 8; ++i) { uint3 sampleOffset = uint3(i, i >> 1, i >> 2) & 0x1; float3 samplePos = min(baseSamplePos + sampleOffset, probeDims - 1.0f); float3 triLinear = lerp(1.0f - lerpAmts, lerpAmts, float3(sampleOffset)); float sampleWeight = triLinear.x * triLinear.y * triLinear.z; + + float3 probePosWS = lerp(SceneMinBounds, SceneMaxBounds, samplePos / probeDims); + float3 dirToProbe = normalize(probePosWS - surface.PositionWS); + + if(WeightProbesByNormal) + sampleWeight *= max(0.05f, dot(dirToProbe, surface.NormalWS)); + + sampleWeight = max(0.0002f, sampleWeight); + float3 sample = SampleIrradianceProbe(samplePos, surface.NormalWS); irradianceSum += sample * sampleWeight; + weightSum += sampleWeight; } + irradianceSum *= 1.0f / weightSum; + indirectIrradiance = irradianceSum; indirectSpecular = 0.0f; } From e2c02c507566f4dafa1a421e008e420ef47fa2d0 Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 1 Oct 2017 17:34:30 -0700 Subject: [PATCH 11/43] WIP probe visibility weighting --- BakingLab/AppSettings.cpp | 11 +++-- BakingLab/AppSettings.cs | 8 ++-- BakingLab/AppSettings.h | 2 + BakingLab/AppSettings.hlsl | 1 + BakingLab/BakingLab.cpp | 33 ++++++++++---- BakingLab/BakingLab.h | 8 ++-- BakingLab/Mesh.hlsl | 53 +++++++++++++++-------- BakingLab/MeshBaker.h | 1 + BakingLab/MeshRenderer.cpp | 18 ++++++-- BakingLab/MeshRenderer.h | 5 ++- BakingLab/ProbeIntegrate.hlsl | 81 ++++++++++++++++++++++++++--------- 11 files changed, 158 insertions(+), 63 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 9bf65b8..67953bc 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -245,6 +245,7 @@ namespace AppSettings IntSetting ProbeResZ; FloatSetting SceneBoundsScale; BoolSetting WeightProbesByNormal; + BoolSetting WeightProbesByVisibility; ScenesSetting CurrentScene; BoolSetting EnableDiffuse; BoolSetting EnableSpecular; @@ -506,13 +507,13 @@ namespace AppSettings UseProbes.Initialize(tweakBar, "UseProbes", "Probes", "Use Probes", "", true); Settings.AddSetting(&UseProbes); - ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 4, 2, 16); + ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 4, 1, 16); Settings.AddSetting(&ProbeResX); - ProbeResY.Initialize(tweakBar, "ProbeResY", "Probes", "Probe Res Y", "", 4, 2, 16); + ProbeResY.Initialize(tweakBar, "ProbeResY", "Probes", "Probe Res Y", "", 4, 1, 16); Settings.AddSetting(&ProbeResY); - ProbeResZ.Initialize(tweakBar, "ProbeResZ", "Probes", "Probe Res Z", "", 4, 2, 16); + ProbeResZ.Initialize(tweakBar, "ProbeResZ", "Probes", "Probe Res Z", "", 4, 1, 16); Settings.AddSetting(&ProbeResZ); SceneBoundsScale.Initialize(tweakBar, "SceneBoundsScale", "Probes", "Scene Bounds Scale", "", 1.2500f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); @@ -521,6 +522,9 @@ namespace AppSettings WeightProbesByNormal.Initialize(tweakBar, "WeightProbesByNormal", "Probes", "Weight Probes By Normal", "", true); Settings.AddSetting(&WeightProbesByNormal); + WeightProbesByVisibility.Initialize(tweakBar, "WeightProbesByVisibility", "Probes", "Weight Probes By Visibility", "", true); + Settings.AddSetting(&WeightProbesByVisibility); + CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); Settings.AddSetting(&CurrentScene); @@ -703,6 +707,7 @@ namespace AppSettings CBuffer.Data.ProbeResY = ProbeResY; CBuffer.Data.ProbeResZ = ProbeResZ; CBuffer.Data.WeightProbesByNormal = WeightProbesByNormal; + CBuffer.Data.WeightProbesByVisibility = WeightProbesByVisibility; CBuffer.Data.EnableDiffuse = EnableDiffuse; CBuffer.Data.EnableSpecular = EnableSpecular; CBuffer.Data.EnableDirectLighting = EnableDirectLighting; diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 24ac1e1..57f09ab 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -665,15 +665,15 @@ public class Probes { bool UseProbes = true; - [MinValue(2)] + [MinValue(1)] [MaxValue(16)] int ProbeResX = 4; - [MinValue(2)] + [MinValue(1)] [MaxValue(16)] int ProbeResY = 4; - [MinValue(2)] + [MinValue(1)] [MaxValue(16)] int ProbeResZ = 4; @@ -681,6 +681,8 @@ public class Probes float SceneBoundsScale = 1.25f; bool WeightProbesByNormal = true; + + bool WeightProbesByVisibility = true; } [ExpandGroup(false)] diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index 7b248ca..edd5fce 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -315,6 +315,7 @@ namespace AppSettings extern IntSetting ProbeResZ; extern FloatSetting SceneBoundsScale; extern BoolSetting WeightProbesByNormal; + extern BoolSetting WeightProbesByVisibility; extern ScenesSetting CurrentScene; extern BoolSetting EnableDiffuse; extern BoolSetting EnableSpecular; @@ -400,6 +401,7 @@ namespace AppSettings int32 ProbeResY; int32 ProbeResZ; bool32 WeightProbesByNormal; + bool32 WeightProbesByVisibility; bool32 EnableDiffuse; bool32 EnableSpecular; bool32 EnableDirectLighting; diff --git a/BakingLab/AppSettings.hlsl b/BakingLab/AppSettings.hlsl index 88c37a9..d5f2b24 100644 --- a/BakingLab/AppSettings.hlsl +++ b/BakingLab/AppSettings.hlsl @@ -52,6 +52,7 @@ cbuffer AppSettings : register(b7) int ProbeResY; int ProbeResZ; bool WeightProbesByNormal; + bool WeightProbesByVisibility; bool EnableDiffuse; bool EnableSpecular; bool EnableDirectLighting; diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 12883ba..6ff319c 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -473,6 +473,7 @@ void BakingLab::Initialize() backgroundVelocityPS = CompilePSFromFile(device, L"BackgroundVelocity.hlsl", "BackgroundVelocityPS"); probeIntegrateIrradiance = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateIrradiance"); + probeIntegrateDistance = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateDistance"); resolveConstants.Initialize(device); backgroundVelocityConstants.Initialize(device); @@ -638,7 +639,7 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) { currProbeIdx = 0; probeCaptureMap.Initialize(device, 256, 256, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, false, 6, true); - probeVelocityTarget.Initialize(device, 256, 256, DXGI_FORMAT_R16G16_FLOAT); + probeDistanceCaptureMap.Initialize(device, 256, 256, DXGI_FORMAT_R16G16_FLOAT, 1, 1, 0, false, false, 6, true); probeDepthBuffer.Initialize(device, 256, 256, DXGI_FORMAT_D24_UNORM_S8_UINT, true); } @@ -647,6 +648,7 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) { currProbeIdx = 0; probeIrradianceMap.Initialize(device, 16, 16, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); + probeDistanceMap.Initialize(device, 32, 32, DXGI_FORMAT_R16G16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); } if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed()) @@ -690,8 +692,8 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) orientation = Quaternion::FromAxisAngle(Float3(0.0f, 1.0f, 0.0f), Pi); probeCam.SetOrientation(orientation); - RenderScene(status, probeCaptureMap.RTVArraySlices[i], probeVelocityTarget.RTView, probeDepthBuffer, probeCam, - false, false, AppSettings::BakeDirectAreaLight, false); + RenderScene(status, probeCaptureMap.RTVArraySlices[i], probeDistanceCaptureMap.RTVArraySlices[i], probeDepthBuffer, probeCam, + false, false, AppSettings::BakeDirectAreaLight, false, true); } AppSettings::UseProbes.SetValue(prevUseProbes); @@ -715,6 +717,15 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) ClearCSInputs(context); ClearCSOutputs(context); + SetCSInputs(context, probeDistanceCaptureMap.SRView); + SetCSOutputs(context, probeDistanceMap.UAView); + SetCSShader(context, probeIntegrateDistance); + + context->Dispatch(DispatchSize(8, probeDistanceMap.Width), DispatchSize(8, probeDistanceMap.Height), 6); + + ClearCSInputs(context); + ClearCSOutputs(context); + ++currProbeIdx; status.ProbeBakeProgress = currProbeIdx / (numProbes - 1.0f); @@ -757,9 +768,10 @@ void BakingLab::Render(const Timer& timer) else { status.ProbeIrradiance = probeIrradianceMap.SRView; + status.ProbeDistance = probeDistanceMap.SRView; RenderScene(status, colorTargetMSAA.RTView, velocityTargetMSAA.RTView, depthBuffer, camera, AppSettings::ShowBakeDataVisualizer, AppSettings::ShowProbeVisualizer, - AppSettings::EnableAreaLight, true); + AppSettings::EnableAreaLight, true, false); RenderBackgroundVelocity(); } @@ -785,9 +797,9 @@ void BakingLab::Render(const Timer& timer) ++frameCount; } -void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, +void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* secondRT, const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, - bool32 renderAreaLight, bool32 enableSkySun) + bool32 renderAreaLight, bool32 enableSkySun, bool32 probeRendering) { PIXEvent event(L"Render Scene"); @@ -812,15 +824,18 @@ void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetVie meshRenderer.RenderAreaLightShadowMap(context, cam); renderTargets[0] = colorTarget; - renderTargets[1] = velocityTarget; + renderTargets[1] = secondRT; context->OMSetRenderTargets(2, renderTargets, dsv); SetViewport(context, depth.Width, depth.Height); + float maxDistance = Float3::Length(FarClip); + float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float secondClearColor[4] = { maxDistance, maxDistance * maxDistance, 0.0f, 0.0f }; context->ClearRenderTargetView(colorTarget, clearColor); - context->ClearRenderTargetView(velocityTarget, clearColor); + context->ClearRenderTargetView(secondRT, secondClearColor); - meshRenderer.RenderMainPass(context, cam, status); + meshRenderer.RenderMainPass(context, cam, status, probeRendering); if(showBakeDataVisualizer) meshRenderer.RenderBakeDataVisualizer(context, cam, status); diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index 6af20c6..90d519f 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -75,13 +75,15 @@ class BakingLab : public App FirstPersonCamera unJitteredCamera; RenderTarget2D probeCaptureMap; - RenderTarget2D probeVelocityTarget; + RenderTarget2D probeDistanceCaptureMap; RenderTarget2D probeIrradianceMap; + RenderTarget2D probeDistanceMap; DepthStencilBuffer probeDepthBuffer; uint64 currProbeIdx = 0; ComputeShaderPtr probeIntegrateIrradiance; + ComputeShaderPtr probeIntegrateDistance; struct ResolveConstants { @@ -117,9 +119,9 @@ class BakingLab : public App void CreateRenderTargets(); void RenderProbes(MeshBakerStatus& status); - void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* velocityTarget, + void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* secondRT, const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, - bool32 renderAreaLight, bool32 enableSkySun); + bool32 renderAreaLight, bool32 enableSkySun, bool32 probeRendering); void RenderAA(); void RenderBackgroundVelocity(); void RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 0bd3dae..aef90cf 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -69,6 +69,7 @@ TextureCube AreaLightShadowMap : register(t6); Texture3D SHSpecularLookupA : register(t7); Texture3D SHSpecularLookupB : register(t8); TextureCubeArray ProbeIrradiance : register(t9); +TextureCubeArray ProbeDistance : register(t10); SamplerState AnisoSampler : register(s0); SamplerState EVSMSampler : register(s1); @@ -119,7 +120,11 @@ struct PSInput struct PSOutput { float4 Lighting : SV_Target0; - float2 Velocity : SV_Target1; + #if ProbeRendering_ + float2 ProbeDistance : SV_Target1; + #else + float2 Velocity : SV_Target1; + #endif }; //================================================================================================= @@ -468,12 +473,6 @@ void ComputeIndirectFromLightmap(in SurfaceContext surface, in float2 lightMapUV } } -float3 SampleIrradianceProbe(in float3 samplePos, float3 direction) -{ - float probeIdx = uint(samplePos.z) * (ProbeResX * ProbeResY) + uint(samplePos.y) * ProbeResX + uint(samplePos.x); - return ProbeIrradiance.Sample(LinearSampler, float4(direction, probeIdx)).xyz; -} - void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) { float3 normalizedSamplePos = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); @@ -488,20 +487,33 @@ void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrr for(uint i = 0; i < 8; ++i) { uint3 sampleOffset = uint3(i, i >> 1, i >> 2) & 0x1; - float3 samplePos = min(baseSamplePos + sampleOffset, probeDims - 1.0f); + uint3 probeIndices = min(uint3(baseSamplePos) + sampleOffset, probeDims - 1.0f); + float probeIdx = uint(probeIndices.z) * (ProbeResX * ProbeResY) + uint(probeIndices.y) * ProbeResX + uint(probeIndices.x); float3 triLinear = lerp(1.0f - lerpAmts, lerpAmts, float3(sampleOffset)); float sampleWeight = triLinear.x * triLinear.y * triLinear.z; - float3 probePosWS = lerp(SceneMinBounds, SceneMaxBounds, samplePos / probeDims); + float3 probePosWS = lerp(SceneMinBounds, SceneMaxBounds, (probeIndices + 0.5f) / probeDims); float3 dirToProbe = normalize(probePosWS - surface.PositionWS); + float distToProbe = length(probePosWS - surface.PositionWS); if(WeightProbesByNormal) - sampleWeight *= max(0.05f, dot(dirToProbe, surface.NormalWS)); + sampleWeight *= max(0.05f, dot(dirToProbe, surface.VtxNormalWS)); + + if(WeightProbesByVisibility) + { + float2 distSample = ProbeDistance.Sample(LinearSampler, float4(-dirToProbe, probeIdx)); + float mean = distSample.x; + float variance = abs(distSample.y - (mean * mean)); + + float tSubMean = distToProbe - mean; + float chebychev = variance / (variance + (tSubMean * tSubMean)); + sampleWeight *= ((distToProbe <= mean) ? 1.0f : max(chebychev, 0.0f)); + } sampleWeight = max(0.0002f, sampleWeight); - float3 sample = SampleIrradianceProbe(samplePos, surface.NormalWS); - irradianceSum += sample * sampleWeight; + float3 irradianceSample = ProbeIrradiance.Sample(LinearSampler, float4(surface.NormalWS, probeIdx)).xyz; + irradianceSum += irradianceSample * sampleWeight; weightSum += sampleWeight; } @@ -604,7 +616,7 @@ PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) float3 indirectIrradiance = 0.0f; float3 indirectSpecular = 0.0f; - if(UseProbes) + if(UseProbes || ProbeRendering_) ComputeIndirectFromProbes(surface, indirectIrradiance, indirectSpecular); else ComputeIndirectFromLightmap(surface, input.LightMapUV, indirectIrradiance, indirectSpecular); @@ -630,11 +642,16 @@ PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) if(isFrontFace == false) output.Lighting = 0.0f; - float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; - prevPositionSS *= RTSize; - output.Velocity = input.PositionSS.xy - prevPositionSS; - output.Velocity -= JitterOffset; - output.Velocity /= RTSize; + #if ProbeRendering_ + float distanceFromProbe = length(surface.PositionWS - CameraPosWS); + output.ProbeDistance = float2(distanceFromProbe, distanceFromProbe * distanceFromProbe); + #else + float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; + prevPositionSS *= RTSize; + output.Velocity = input.PositionSS.xy - prevPositionSS; + output.Velocity -= JitterOffset; + output.Velocity /= RTSize; + #endif return output; } diff --git a/BakingLab/MeshBaker.h b/BakingLab/MeshBaker.h index 0a7be65..29ccf44 100644 --- a/BakingLab/MeshBaker.h +++ b/BakingLab/MeshBaker.h @@ -60,6 +60,7 @@ struct MeshBakerStatus ID3D11ShaderResourceView* LightMap = nullptr; ID3D11ShaderResourceView* BakePoints = nullptr; ID3D11ShaderResourceView* ProbeIrradiance = nullptr; + ID3D11ShaderResourceView* ProbeDistance = nullptr; uint64 NumBakePoints = 0; float GroundTruthProgress = 0.0f; float BakeProgress = 0.0f; diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index 0c381be..c1507e1 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -239,8 +239,16 @@ void MeshRenderer::LoadShaders() { // Load the mesh shaders meshDepthVS = CompileVSFromFile(device, L"DepthOnly.hlsl", "VS", "vs_5_0"); - meshVS = CompileVSFromFile(device, L"Mesh.hlsl", "VS", "vs_5_0"); - meshPS = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0"); + { + CompileOptions opts; + opts.Add("ProbeRendering_", 0); + meshVS = CompileVSFromFile(device, L"Mesh.hlsl", "VS", "vs_5_0", opts); + meshPS[0] = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0", opts); + + opts.Reset(); + opts.Add("ProbeRendering_", 1); + meshPS[1] = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0", opts); + } areaLightVS = CompileVSFromFile(device, L"AreaLight.hlsl", "VS", "vs_5_0"); areaLightPS = CompilePSFromFile(device, L"AreaLight.hlsl", "PS", "ps_5_0"); @@ -594,7 +602,8 @@ void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx } // Renders all meshes in the model, with shadows -void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) +void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status, + bool32 probeRendering) { PIXEvent event(L"Mesh Rendering"); @@ -643,7 +652,7 @@ void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& ca context->HSSetShader(nullptr, nullptr, 0); context->GSSetShader(nullptr, nullptr, 0); context->VSSetShader(meshVS, nullptr, 0); - context->PSSetShader(meshPS, nullptr, 0); + context->PSSetShader(meshPS[probeRendering ? 1 : 0], nullptr, 0); // Draw all meshes for(uint64 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) @@ -680,6 +689,7 @@ void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& ca shSpecularLookupA, shSpecularLookupB, status.ProbeIrradiance, + status.ProbeDistance, }; context->PSSetShaderResources(0, ArraySize_(psTextures), psTextures); diff --git a/BakingLab/MeshRenderer.h b/BakingLab/MeshRenderer.h index 7ec896f..14f9377 100644 --- a/BakingLab/MeshRenderer.h +++ b/BakingLab/MeshRenderer.h @@ -40,7 +40,8 @@ class MeshRenderer void SetModel(const Model* model); void RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange); - void RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status); + void RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status, + bool32 probeRendering); void Update(const Camera& camera, Float2 jitterOffset); @@ -84,7 +85,7 @@ class MeshRenderer std::vector meshInputLayouts; VertexShaderPtr meshVS; - PixelShaderPtr meshPS; + PixelShaderPtr meshPS[2]; std::vector meshDepthInputLayouts; VertexShaderPtr meshDepthVS; diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl index d327c7f..84e683d 100644 --- a/BakingLab/ProbeIntegrate.hlsl +++ b/BakingLab/ProbeIntegrate.hlsl @@ -16,9 +16,6 @@ cbuffer IntegrateConstants : register(b0) uint OutputSliceOffset; } -TextureCube RadianceMap : register(t0); -RWTexture2DArray IrradianceMap : register(u0); - SamplerState LinearSampler : register(s0); float3 ComputeCubemapDirection(in uint2 pos, in uint face, in float2 textureSize) @@ -72,7 +69,7 @@ float2 Hammersley2D(in uint sampleIdx, in uint numSamples) return float2(float(sampleIdx) / float(numSamples), RadicalInverseBase2(sampleIdx)); } -inline float2 SquareToConcentricDiskMapping(float x, float y) +float2 SquareToConcentricDiskMapping(float x, float y) { float phi = 0.0f; float r = 0.0f; @@ -117,7 +114,7 @@ inline float2 SquareToConcentricDiskMapping(float x, float y) return result; } -inline float3 SampleCosineHemisphere(in float u1, in float u2) +float3 SampleCosineHemisphere(in float u1, in float u2) { float2 uv = SquareToConcentricDiskMapping(u1, u2); float u = uv.x; @@ -134,44 +131,86 @@ inline float3 SampleCosineHemisphere(in float u1, in float u2) return dir; } -[numthreads(8, 8, 1)] -void IntegrateIrradiance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +float3x3 MakeTangentFrame(in float3 normal, in uint faceIdx) { - uint2 outputPos = GroupID.xy * 8 + GroupThreadID.xy; - uint outputFaceIdx = GroupID.z; - uint outputSliceIdx = OutputSliceOffset + outputFaceIdx; - - float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); - float3 tangent = 0.0f; - if(outputFaceIdx == 0) + if(faceIdx == 0) tangent = float3(0.0f, 0.0f, -1.0f); - else if(outputFaceIdx == 1) + else if(faceIdx == 1) tangent = float3(0.0f, 0.0f, 1.0f); - else if(outputFaceIdx == 2) + else if(faceIdx == 2) tangent = float3(1.0f, 0.0f, 0.0f); - else if(outputFaceIdx == 3) + else if(faceIdx == 3) tangent = float3(1.0f, 0.0f, 0.0f); - else if(outputFaceIdx == 4) + else if(faceIdx == 4) tangent = float3(1.0f, 0.0f, 0.0f); - else if(outputFaceIdx == 5) + else if(faceIdx == 5) tangent = float3(-1.0f, 0.0f, 0.0f); float3 bitangent = normalize(cross(normal, tangent)); tangent = normalize(cross(bitangent, normal)); + return float3x3(tangent, bitangent, normal); +} + +TextureCube RadianceCaptureMap : register(t0); +RWTexture2DArray IrradianceMap : register(u0); + +[numthreads(8, 8, 1)] +void IntegrateIrradiance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + uint2 outputPos = GroupID.xy * 8 + GroupThreadID.xy; + uint outputFaceIdx = GroupID.z; + uint outputSliceIdx = OutputSliceOffset + outputFaceIdx; + + float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); + float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); + const uint numSamples = 256; float3 irradiance = 0.0f; for(uint i = 0; i < numSamples; ++i) { float2 samplePos = Hammersley2D(i, numSamples); float3 sampleDir = SampleCosineHemisphere(samplePos.x, samplePos.y); - sampleDir = mul(sampleDir, float3x3(tangent, bitangent, normal)); - float3 radiance = RadianceMap.SampleLevel(LinearSampler, sampleDir, 0.0f).xyz; + sampleDir = mul(sampleDir, tangentFrame); + float3 radiance = RadianceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f).xyz; irradiance += radiance; } irradiance *= (Pi / numSamples); IrradianceMap[uint3(outputPos, outputSliceIdx)] = float4(irradiance, 0.0f); +} + +TextureCube DistanceCaptureMap : register(t0); +RWTexture2DArray DistanceOutputMap : register(u0); + +[numthreads(8, 8, 1)] +void IntegrateDistance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + uint2 outputPos = GroupID.xy * 8 + GroupThreadID.xy; + uint outputFaceIdx = GroupID.z; + uint outputSliceIdx = OutputSliceOffset + outputFaceIdx; + + float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); + float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); + + const uint numSamples = 256; + float2 outputDistance = 0.0f; + float weightSum = 0.0f; + for(uint i = 0; i < numSamples; ++i) + { + float2 samplePos = Hammersley2D(i, numSamples); + float3 sampleDir = SampleCosineHemisphere(samplePos.x, samplePos.y); + sampleDir = mul(sampleDir, tangentFrame); + float2 sampleDistance = DistanceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f); + + float sampleWeight = pow(saturate(dot(sampleDir, normal)), 4.0f); + outputDistance += sampleDistance * sampleWeight; + weightSum += sampleWeight; + } + + outputDistance *= (1.0f / weightSum); + + DistanceOutputMap[uint3(outputPos, outputSliceIdx)] = outputDistance; } \ No newline at end of file From b80a5ff5c8719800ccce33162602c158b96eb856 Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 1 Oct 2017 22:11:25 -0700 Subject: [PATCH 12/43] More WIP probe visibility --- BakingLab/AppSettings.cpp | 4 ++++ BakingLab/AppSettings.cs | 3 +++ BakingLab/AppSettings.h | 1 + BakingLab/BakingLab.cpp | 12 +++++++++--- BakingLab/Mesh.hlsl | 21 +++++++++++++++------ BakingLab/MeshRenderer.cpp | 6 +++--- BakingLab/ProbeIntegrate.hlsl | 4 +++- BakingLab/ProbeVisualizer.hlsl | 3 +++ 8 files changed, 41 insertions(+), 13 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 67953bc..5a605f9 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -276,6 +276,7 @@ namespace AppSettings Button LoadLightSettings; Button SaveEXRScreenshot; BoolSetting ShowSunIntensity; + BoolSetting AlwaysRegenerateProbes; ConstantBuffer CBuffer; @@ -615,6 +616,9 @@ namespace AppSettings ShowSunIntensity.Initialize(tweakBar, "ShowSunIntensity", "Debug", "Show Sun Intensity", "", false); Settings.AddSetting(&ShowSunIntensity); + AlwaysRegenerateProbes.Initialize(tweakBar, "AlwaysRegenerateProbes", "Debug", "Always Regenerate Probes", "", false); + Settings.AddSetting(&AlwaysRegenerateProbes); + TwHelper::SetOpened(tweakBar, "Sun Light", true); TwHelper::SetOpened(tweakBar, "Sky", true); diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 57f09ab..f9adb28 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -841,5 +841,8 @@ public class Debug [UseAsShaderConstant(false)] bool ShowSunIntensity = false; + + [UseAsShaderConstant(false)] + bool AlwaysRegenerateProbes = false; } } \ No newline at end of file diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index edd5fce..7ccdf9b 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -346,6 +346,7 @@ namespace AppSettings extern Button LoadLightSettings; extern Button SaveEXRScreenshot; extern BoolSetting ShowSunIntensity; + extern BoolSetting AlwaysRegenerateProbes; struct AppSettingsCBuffer { diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 6ff319c..c8f273a 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -651,7 +651,8 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) probeDistanceMap.Initialize(device, 32, 32, DXGI_FORMAT_R16G16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); } - if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed()) + if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed() || + AppSettings::AlwaysRegenerateProbes.Changed()) currProbeIdx = 0; if(currProbeIdx >= numProbes) @@ -721,6 +722,11 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) SetCSOutputs(context, probeDistanceMap.UAView); SetCSShader(context, probeIntegrateDistance); + integrateConstants.Data.OutputTextureSize.x = float(probeDistanceMap.Width); + integrateConstants.Data.OutputTextureSize.y = float(probeDistanceMap.Height); + integrateConstants.Data.OutputSliceOffset = uint32(currProbeIdx * 6); + integrateConstants.ApplyChanges(context); + context->Dispatch(DispatchSize(8, probeDistanceMap.Width), DispatchSize(8, probeDistanceMap.Height), 6); ClearCSInputs(context); @@ -730,8 +736,8 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) status.ProbeBakeProgress = currProbeIdx / (numProbes - 1.0f); - /*if(currProbeIdx == numProbes) - currProbeIdx = 0;*/ + if(currProbeIdx == numProbes && AppSettings::AlwaysRegenerateProbes) + currProbeIdx = 0; } void BakingLab::Render(const Timer& timer) diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index aef90cf..8c0b9c2 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -473,6 +473,20 @@ void ComputeIndirectFromLightmap(in SurfaceContext surface, in float2 lightMapUV } } +float ChebyshevUpperBound(float2 moments, float mean, float minVariance) +{ + // Compute variance + float variance = moments.y - (moments.x * moments.x); + variance = max(variance, minVariance); + + // Compute probabilistic upper bound + float d = mean - moments.x; + float pMax = variance / (variance + (d * d)); + + // One-tailed Chebyshev + return (mean <= moments.x ? 1.0f : pMax); +} + void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) { float3 normalizedSamplePos = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); @@ -502,12 +516,7 @@ void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrr if(WeightProbesByVisibility) { float2 distSample = ProbeDistance.Sample(LinearSampler, float4(-dirToProbe, probeIdx)); - float mean = distSample.x; - float variance = abs(distSample.y - (mean * mean)); - - float tSubMean = distToProbe - mean; - float chebychev = variance / (variance + (tSubMean * tSubMean)); - sampleWeight *= ((distToProbe <= mean) ? 1.0f : max(chebychev, 0.0f)); + sampleWeight *= ChebyshevUpperBound(distSample, distToProbe, 0.0001f); } sampleWeight = max(0.0002f, sampleWeight); diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index c1507e1..b64f139 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -1107,7 +1107,7 @@ void MeshRenderer::RenderProbeVisualizer(ID3D11DeviceContext* context, const Cam context->VSSetShader(probeVisualizerVS , nullptr, 0); context->PSSetShader(probeVisualizerPS, nullptr, 0); - ID3D11ShaderResourceView* psSrvs[] = { status.ProbeIrradiance }; + ID3D11ShaderResourceView* psSrvs[] = { status.ProbeIrradiance, status.ProbeDistance }; context->PSSetShaderResources(0, ArraySize_(psSrvs), psSrvs); ID3D11SamplerState* psSamplers[] = { samplerStates.LinearClamp() }; @@ -1125,6 +1125,6 @@ void MeshRenderer::RenderProbeVisualizer(ID3D11DeviceContext* context, const Cam // Draw context->DrawIndexedInstanced(uint32(numSphereIndices), uint32(AppSettings::NumProbes()), 0, 0, 0); - ID3D11ShaderResourceView* nullSRVs[] = { nullptr }; - context->PSSetShaderResources(0, 1, nullSRVs); + ID3D11ShaderResourceView* nullSRVs[2] = { }; + context->PSSetShaderResources(0, ArraySize_(nullSRVs), nullSRVs); } \ No newline at end of file diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl index 84e683d..470b383 100644 --- a/BakingLab/ProbeIntegrate.hlsl +++ b/BakingLab/ProbeIntegrate.hlsl @@ -205,12 +205,14 @@ void IntegrateDistance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : S sampleDir = mul(sampleDir, tangentFrame); float2 sampleDistance = DistanceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f); - float sampleWeight = pow(saturate(dot(sampleDir, normal)), 4.0f); + float sampleWeight = pow(saturate(dot(sampleDir, normal)), 32.0f); outputDistance += sampleDistance * sampleWeight; weightSum += sampleWeight; } outputDistance *= (1.0f / weightSum); + // outputDistance = DistanceCaptureMap.SampleLevel(LinearSampler, normal, 0.0f).xy; + DistanceOutputMap[uint3(outputPos, outputSliceIdx)] = outputDistance; } \ No newline at end of file diff --git a/BakingLab/ProbeVisualizer.hlsl b/BakingLab/ProbeVisualizer.hlsl index 5c83de1..c567c30 100644 --- a/BakingLab/ProbeVisualizer.hlsl +++ b/BakingLab/ProbeVisualizer.hlsl @@ -32,6 +32,7 @@ cbuffer Constants : register(b0) // Resources //================================================================================================= TextureCubeArray ProbeIrradiance : register(t0); +TextureCubeArray ProbeDistance : register(t1); SamplerState LinearSampler : register(s0); //================================================================================================= @@ -85,5 +86,7 @@ VSOutput VS(in float3 SpherePosition : POSITION, in uint InstanceID : SV_Instanc float4 PS(in PSInput input) : SV_Target0 { float3 irradiance = ProbeIrradiance.Sample(LinearSampler, float4(input.NormalWS, input.ProbeIdx)).xyz; + float2 distance = ProbeDistance.Sample(LinearSampler, float4(input.NormalWS, input.ProbeIdx)); return float4(irradiance * InvPi, 0.0f); + // return float4(distance * 0.01f, 0.0f, 1.0f); } \ No newline at end of file From 642aa82f50c479932b81ad90bc5a637a110e7e63 Mon Sep 17 00:00:00 2001 From: MJP Date: Mon, 2 Oct 2017 14:11:06 -0700 Subject: [PATCH 13/43] Better filtering for probe distance --- BakingLab/AppSettings.cpp | 12 ++++++++++++ BakingLab/AppSettings.cs | 15 +++++++++++++++ BakingLab/AppSettings.h | 3 +++ BakingLab/BakingLab.cpp | 9 ++++++++- BakingLab/ProbeIntegrate.hlsl | 23 ++++++++++++++++++++--- 5 files changed, 58 insertions(+), 4 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 5a605f9..e82f689 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -277,6 +277,9 @@ namespace AppSettings Button SaveEXRScreenshot; BoolSetting ShowSunIntensity; BoolSetting AlwaysRegenerateProbes; + FloatSetting SceneBoundsOffsetX; + FloatSetting SceneBoundsOffsetY; + FloatSetting SceneBoundsOffsetZ; ConstantBuffer CBuffer; @@ -619,6 +622,15 @@ namespace AppSettings AlwaysRegenerateProbes.Initialize(tweakBar, "AlwaysRegenerateProbes", "Debug", "Always Regenerate Probes", "", false); Settings.AddSetting(&AlwaysRegenerateProbes); + SceneBoundsOffsetX.Initialize(tweakBar, "SceneBoundsOffsetX", "Debug", "Scene Bounds Offset X", "", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SceneBoundsOffsetX); + + SceneBoundsOffsetY.Initialize(tweakBar, "SceneBoundsOffsetY", "Debug", "Scene Bounds Offset Y", "", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SceneBoundsOffsetY); + + SceneBoundsOffsetZ.Initialize(tweakBar, "SceneBoundsOffsetZ", "Debug", "Scene Bounds Offset Z", "", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SceneBoundsOffsetZ); + TwHelper::SetOpened(tweakBar, "Sun Light", true); TwHelper::SetOpened(tweakBar, "Sky", true); diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index f9adb28..02392d4 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -844,5 +844,20 @@ public class Debug [UseAsShaderConstant(false)] bool AlwaysRegenerateProbes = false; + + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [UseAsShaderConstant(false)] + float SceneBoundsOffsetX = 0.0f; + + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [UseAsShaderConstant(false)] + float SceneBoundsOffsetY = 0.0f; + + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [UseAsShaderConstant(false)] + float SceneBoundsOffsetZ = 0.0f; } } \ No newline at end of file diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index 7ccdf9b..5e92dff 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -347,6 +347,9 @@ namespace AppSettings extern Button SaveEXRScreenshot; extern BoolSetting ShowSunIntensity; extern BoolSetting AlwaysRegenerateProbes; + extern FloatSetting SceneBoundsOffsetX; + extern FloatSetting SceneBoundsOffsetY; + extern FloatSetting SceneBoundsOffsetZ; struct AppSettingsCBuffer { diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index c8f273a..cc02474 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -621,6 +621,12 @@ void BakingLab::Update(const Timer& timer) Float3 sceneCenter = (sceneMaxes[AppSettings::CurrentScene] + sceneMins[AppSettings::CurrentScene]) / 2.0f;; currSceneMin = Lerp(sceneCenter, sceneMins[AppSettings::CurrentScene], AppSettings::SceneBoundsScale); currSceneMax = Lerp(sceneCenter, sceneMaxes[AppSettings::CurrentScene], AppSettings::SceneBoundsScale); + currSceneMin.x += AppSettings::SceneBoundsOffsetX; + currSceneMin.y += AppSettings::SceneBoundsOffsetY; + currSceneMin.z += AppSettings::SceneBoundsOffsetZ; + currSceneMax.x += AppSettings::SceneBoundsOffsetX; + currSceneMax.y += AppSettings::SceneBoundsOffsetY; + currSceneMax.z += AppSettings::SceneBoundsOffsetZ; meshRenderer.Update(camera, jitterOffset); } @@ -652,7 +658,8 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) } if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed() || - AppSettings::AlwaysRegenerateProbes.Changed()) + AppSettings::AlwaysRegenerateProbes.Changed() || AppSettings::SceneBoundsOffsetX.Changed() || + AppSettings::SceneBoundsOffsetY.Changed() || AppSettings::SceneBoundsOffsetZ.Changed()) currProbeIdx = 0; if(currProbeIdx >= numProbes) diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl index 470b383..6232843 100644 --- a/BakingLab/ProbeIntegrate.hlsl +++ b/BakingLab/ProbeIntegrate.hlsl @@ -166,7 +166,7 @@ void IntegrateIrradiance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); - const uint numSamples = 256; + const uint numSamples = 1024; float3 irradiance = 0.0f; for(uint i = 0; i < numSamples; ++i) { @@ -179,12 +179,27 @@ void IntegrateIrradiance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : irradiance *= (Pi / numSamples); + // irradiance = 16.0f; + IrradianceMap[uint3(outputPos, outputSliceIdx)] = float4(irradiance, 0.0f); } TextureCube DistanceCaptureMap : register(t0); RWTexture2DArray DistanceOutputMap : register(u0); +float3 SampleCosinePower(in float2 xi, in float n) +{ + float phi = 2.0f * Pi * xi.x; + float theta = acos(pow(1.0f - xi.y, 1.0f /(n + 1.0f))); + + float3 dir; + dir.x = sin(theta) * cos(phi); + dir.y = sin(theta) * sin(phi); + dir.z = cos(theta); + + return dir; +} + [numthreads(8, 8, 1)] void IntegrateDistance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) { @@ -196,16 +211,18 @@ void IntegrateDistance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : S float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); const uint numSamples = 256; + const float cosinePower = exp2(12.0f); + float2 outputDistance = 0.0f; float weightSum = 0.0f; for(uint i = 0; i < numSamples; ++i) { float2 samplePos = Hammersley2D(i, numSamples); - float3 sampleDir = SampleCosineHemisphere(samplePos.x, samplePos.y); + float3 sampleDir = SampleCosinePower(samplePos, cosinePower); sampleDir = mul(sampleDir, tangentFrame); float2 sampleDistance = DistanceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f); - float sampleWeight = pow(saturate(dot(sampleDir, normal)), 32.0f); + float sampleWeight = ((cosinePower + 1.0f) / Pi2) * pow(saturate(dot(sampleDir, normal)), cosinePower); outputDistance += sampleDistance * sampleWeight; weightSum += sampleWeight; } From 04b3500e8973f36a103bfbda4bbc422fd85d76bb Mon Sep 17 00:00:00 2001 From: MJP Date: Tue, 3 Oct 2017 22:49:43 -0700 Subject: [PATCH 14/43] Normalize distance before storing it in the captured probe map --- BakingLab/BakingLab.cpp | 4 ++-- BakingLab/Mesh.hlsl | 23 ++++++++--------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index cc02474..3780eb6 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -645,7 +645,7 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) { currProbeIdx = 0; probeCaptureMap.Initialize(device, 256, 256, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, false, 6, true); - probeDistanceCaptureMap.Initialize(device, 256, 256, DXGI_FORMAT_R16G16_FLOAT, 1, 1, 0, false, false, 6, true); + probeDistanceCaptureMap.Initialize(device, 256, 256, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, false, 6, true); probeDepthBuffer.Initialize(device, 256, 256, DXGI_FORMAT_D24_UNORM_S8_UINT, true); } @@ -654,7 +654,7 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) { currProbeIdx = 0; probeIrradianceMap.Initialize(device, 16, 16, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); - probeDistanceMap.Initialize(device, 32, 32, DXGI_FORMAT_R16G16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); + probeDistanceMap.Initialize(device, 128, 128, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true, numProbes * 6, true); } if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed() || diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 8c0b9c2..a85856e 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -473,20 +473,6 @@ void ComputeIndirectFromLightmap(in SurfaceContext surface, in float2 lightMapUV } } -float ChebyshevUpperBound(float2 moments, float mean, float minVariance) -{ - // Compute variance - float variance = moments.y - (moments.x * moments.x); - variance = max(variance, minVariance); - - // Compute probabilistic upper bound - float d = mean - moments.x; - float pMax = variance / (variance + (d * d)); - - // One-tailed Chebyshev - return (mean <= moments.x ? 1.0f : pMax); -} - void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) { float3 normalizedSamplePos = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); @@ -515,8 +501,12 @@ void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrr if(WeightProbesByVisibility) { + float maxDistance = length((SceneMaxBounds - SceneMinBounds) * rcp(float3(ProbeResX, ProbeResY, ProbeResZ))); + float compareDistance = saturate(distToProbe * rcp(maxDistance)); + float2 distSample = ProbeDistance.Sample(LinearSampler, float4(-dirToProbe, probeIdx)); - sampleWeight *= ChebyshevUpperBound(distSample, distToProbe, 0.0001f); + float visTerm = ChebyshevUpperBound(distSample, compareDistance, 0.0001f, 0.25f); + sampleWeight *= visTerm; } sampleWeight = max(0.0002f, sampleWeight); @@ -527,6 +517,7 @@ void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrr } irradianceSum *= 1.0f / weightSum; + // irradianceSum *= 1.0f / max(weightSum, 0.0002f); indirectIrradiance = irradianceSum; indirectSpecular = 0.0f; @@ -653,6 +644,8 @@ PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) #if ProbeRendering_ float distanceFromProbe = length(surface.PositionWS - CameraPosWS); + float maxDistance = length((SceneMaxBounds - SceneMinBounds) * rcp(float3(ProbeResX, ProbeResY, ProbeResZ))); + distanceFromProbe = saturate(distanceFromProbe * rcp(maxDistance)); output.ProbeDistance = float2(distanceFromProbe, distanceFromProbe * distanceFromProbe); #else float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; From 2f49139b521736184c3d24d44b4c68f89a470cd0 Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 19 Nov 2017 22:23:10 -0800 Subject: [PATCH 15/43] Added more configurable settings for probe capture --- BakingLab/AppSettings.cpp | 20 ++++++++++++++++++++ BakingLab/AppSettings.cs | 16 ++++++++++++++++ BakingLab/AppSettings.h | 8 ++++++++ BakingLab/AppSettings.hlsl | 4 ++++ BakingLab/BakingLab.cpp | 23 +++++++++++++++-------- BakingLab/ProbeIntegrate.hlsl | 5 +++-- 6 files changed, 66 insertions(+), 10 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index e82f689..fe86107 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -243,9 +243,13 @@ namespace AppSettings IntSetting ProbeResX; IntSetting ProbeResY; IntSetting ProbeResZ; + IntSetting ProbeCubemapCaptureRes; + IntSetting ProbeIrradianceCubemapRes; + IntSetting ProbeDistanceCubemapRes; FloatSetting SceneBoundsScale; BoolSetting WeightProbesByNormal; BoolSetting WeightProbesByVisibility; + FloatSetting DistanceFilterSharpness; ScenesSetting CurrentScene; BoolSetting EnableDiffuse; BoolSetting EnableSpecular; @@ -520,6 +524,15 @@ namespace AppSettings ProbeResZ.Initialize(tweakBar, "ProbeResZ", "Probes", "Probe Res Z", "", 4, 1, 16); Settings.AddSetting(&ProbeResZ); + ProbeCubemapCaptureRes.Initialize(tweakBar, "ProbeCubemapCaptureRes", "Probes", "Probe Cubemap Capture Res", "", 256, 1, 4096); + Settings.AddSetting(&ProbeCubemapCaptureRes); + + ProbeIrradianceCubemapRes.Initialize(tweakBar, "ProbeIrradianceCubemapRes", "Probes", "Probe Irradiance Cubemap Res", "", 16, 1, 4096); + Settings.AddSetting(&ProbeIrradianceCubemapRes); + + ProbeDistanceCubemapRes.Initialize(tweakBar, "ProbeDistanceCubemapRes", "Probes", "Probe Distance Cubemap Res", "", 128, 1, 4096); + Settings.AddSetting(&ProbeDistanceCubemapRes); + SceneBoundsScale.Initialize(tweakBar, "SceneBoundsScale", "Probes", "Scene Bounds Scale", "", 1.2500f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); Settings.AddSetting(&SceneBoundsScale); @@ -529,6 +542,9 @@ namespace AppSettings WeightProbesByVisibility.Initialize(tweakBar, "WeightProbesByVisibility", "Probes", "Weight Probes By Visibility", "", true); Settings.AddSetting(&WeightProbesByVisibility); + DistanceFilterSharpness.Initialize(tweakBar, "DistanceFilterSharpness", "Probes", "Distance Filter Sharpness", "", 10.0000f, 1.0000f, 20.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&DistanceFilterSharpness); + CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); Settings.AddSetting(&CurrentScene); @@ -722,8 +738,12 @@ namespace AppSettings CBuffer.Data.ProbeResX = ProbeResX; CBuffer.Data.ProbeResY = ProbeResY; CBuffer.Data.ProbeResZ = ProbeResZ; + CBuffer.Data.ProbeCubemapCaptureRes = ProbeCubemapCaptureRes; + CBuffer.Data.ProbeIrradianceCubemapRes = ProbeIrradianceCubemapRes; + CBuffer.Data.ProbeDistanceCubemapRes = ProbeDistanceCubemapRes; CBuffer.Data.WeightProbesByNormal = WeightProbesByNormal; CBuffer.Data.WeightProbesByVisibility = WeightProbesByVisibility; + CBuffer.Data.DistanceFilterSharpness = DistanceFilterSharpness; CBuffer.Data.EnableDiffuse = EnableDiffuse; CBuffer.Data.EnableSpecular = EnableSpecular; CBuffer.Data.EnableDirectLighting = EnableDirectLighting; diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 02392d4..d36ff7d 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -677,12 +677,28 @@ public class Probes [MaxValue(16)] int ProbeResZ = 4; + [MinValue(1)] + [MaxValue(4096)] + int ProbeCubemapCaptureRes = 256; + + [MinValue(1)] + [MaxValue(4096)] + int ProbeIrradianceCubemapRes = 16; + + [MinValue(1)] + [MaxValue(4096)] + int ProbeDistanceCubemapRes = 128; + [UseAsShaderConstant(false)] float SceneBoundsScale = 1.25f; bool WeightProbesByNormal = true; bool WeightProbesByVisibility = true; + + [MinValue(1.0f)] + [MaxValue(20.0f)] + float DistanceFilterSharpness = 10.0f; } [ExpandGroup(false)] diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index 5e92dff..d6876b2 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -313,9 +313,13 @@ namespace AppSettings extern IntSetting ProbeResX; extern IntSetting ProbeResY; extern IntSetting ProbeResZ; + extern IntSetting ProbeCubemapCaptureRes; + extern IntSetting ProbeIrradianceCubemapRes; + extern IntSetting ProbeDistanceCubemapRes; extern FloatSetting SceneBoundsScale; extern BoolSetting WeightProbesByNormal; extern BoolSetting WeightProbesByVisibility; + extern FloatSetting DistanceFilterSharpness; extern ScenesSetting CurrentScene; extern BoolSetting EnableDiffuse; extern BoolSetting EnableSpecular; @@ -404,8 +408,12 @@ namespace AppSettings int32 ProbeResX; int32 ProbeResY; int32 ProbeResZ; + int32 ProbeCubemapCaptureRes; + int32 ProbeIrradianceCubemapRes; + int32 ProbeDistanceCubemapRes; bool32 WeightProbesByNormal; bool32 WeightProbesByVisibility; + float DistanceFilterSharpness; bool32 EnableDiffuse; bool32 EnableSpecular; bool32 EnableDirectLighting; diff --git a/BakingLab/AppSettings.hlsl b/BakingLab/AppSettings.hlsl index d5f2b24..9fc32fa 100644 --- a/BakingLab/AppSettings.hlsl +++ b/BakingLab/AppSettings.hlsl @@ -51,8 +51,12 @@ cbuffer AppSettings : register(b7) int ProbeResX; int ProbeResY; int ProbeResZ; + int ProbeCubemapCaptureRes; + int ProbeIrradianceCubemapRes; + int ProbeDistanceCubemapRes; bool WeightProbesByNormal; bool WeightProbesByVisibility; + float DistanceFilterSharpness; bool EnableDiffuse; bool EnableSpecular; bool EnableDirectLighting; diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 3780eb6..70df850 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -641,25 +641,32 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) const uint64 currSceneIdx = AppSettings::CurrentScene; const uint32 numProbes = uint32(AppSettings::NumProbes()); - if(probeCaptureMap.Width == 0) + if(probeCaptureMap.Width == 0 || AppSettings::ProbeCubemapCaptureRes.Changed()) { currProbeIdx = 0; - probeCaptureMap.Initialize(device, 256, 256, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, false, 6, true); - probeDistanceCaptureMap.Initialize(device, 256, 256, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, false, 6, true); - probeDepthBuffer.Initialize(device, 256, 256, DXGI_FORMAT_D24_UNORM_S8_UINT, true); + + const uint32 resolution = AppSettings::ProbeCubemapCaptureRes; + probeCaptureMap.Initialize(device, resolution, resolution, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, false, 6, true); + probeDistanceCaptureMap.Initialize(device, resolution, resolution, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, false, 6, true); + probeDepthBuffer.Initialize(device, resolution, resolution, DXGI_FORMAT_D24_UNORM_S8_UINT, true); } if(AppSettings::ProbeResX.Changed() || AppSettings::ProbeResY.Changed() || - AppSettings::ProbeResZ.Changed() || probeIrradianceMap.ArraySize == 0) + AppSettings::ProbeResZ.Changed() || probeIrradianceMap.ArraySize == 0 || + AppSettings::ProbeIrradianceCubemapRes.Changed() || AppSettings::ProbeDistanceCubemapRes.Changed()) { currProbeIdx = 0; - probeIrradianceMap.Initialize(device, 16, 16, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); - probeDistanceMap.Initialize(device, 128, 128, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true, numProbes * 6, true); + + const uint32 irrResolution = AppSettings::ProbeIrradianceCubemapRes; + const uint32 distResolution = AppSettings::ProbeDistanceCubemapRes; + probeIrradianceMap.Initialize(device, irrResolution, irrResolution, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); + probeDistanceMap.Initialize(device, distResolution, distResolution, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true, numProbes * 6, true); } if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed() || AppSettings::AlwaysRegenerateProbes.Changed() || AppSettings::SceneBoundsOffsetX.Changed() || - AppSettings::SceneBoundsOffsetY.Changed() || AppSettings::SceneBoundsOffsetZ.Changed()) + AppSettings::SceneBoundsOffsetY.Changed() || AppSettings::SceneBoundsOffsetZ.Changed() || + AppSettings::DistanceFilterSharpness.Changed()) currProbeIdx = 0; if(currProbeIdx >= numProbes) diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl index 6232843..f35bac3 100644 --- a/BakingLab/ProbeIntegrate.hlsl +++ b/BakingLab/ProbeIntegrate.hlsl @@ -9,6 +9,7 @@ //================================================================================================= #include +#include "AppSettings.hlsl" cbuffer IntegrateConstants : register(b0) { @@ -185,7 +186,7 @@ void IntegrateIrradiance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : } TextureCube DistanceCaptureMap : register(t0); -RWTexture2DArray DistanceOutputMap : register(u0); +RWTexture2DArray DistanceOutputMap : register(u0); float3 SampleCosinePower(in float2 xi, in float n) { @@ -211,7 +212,7 @@ void IntegrateDistance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : S float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); const uint numSamples = 256; - const float cosinePower = exp2(12.0f); + const float cosinePower = exp2(DistanceFilterSharpness); float2 outputDistance = 0.0f; float weightSum = 0.0f; From 87654a5652a4f65b9cc99360e2db5bff563f30be Mon Sep 17 00:00:00 2001 From: MJP Date: Wed, 22 Nov 2017 17:42:10 -0800 Subject: [PATCH 16/43] Prevent going over the max number of probes in a texture --- BakingLab/AppSettings.cpp | 6 +++--- BakingLab/AppSettings.cs | 6 +++--- BakingLab/BakingLab.cpp | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index fe86107..72784c2 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -515,13 +515,13 @@ namespace AppSettings UseProbes.Initialize(tweakBar, "UseProbes", "Probes", "Use Probes", "", true); Settings.AddSetting(&UseProbes); - ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 4, 1, 16); + ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 4, 1, 2048); Settings.AddSetting(&ProbeResX); - ProbeResY.Initialize(tweakBar, "ProbeResY", "Probes", "Probe Res Y", "", 4, 1, 16); + ProbeResY.Initialize(tweakBar, "ProbeResY", "Probes", "Probe Res Y", "", 4, 1, 2048); Settings.AddSetting(&ProbeResY); - ProbeResZ.Initialize(tweakBar, "ProbeResZ", "Probes", "Probe Res Z", "", 4, 1, 16); + ProbeResZ.Initialize(tweakBar, "ProbeResZ", "Probes", "Probe Res Z", "", 4, 1, 2048); Settings.AddSetting(&ProbeResZ); ProbeCubemapCaptureRes.Initialize(tweakBar, "ProbeCubemapCaptureRes", "Probes", "Probe Cubemap Capture Res", "", 256, 1, 4096); diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index d36ff7d..ed77044 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -666,15 +666,15 @@ public class Probes bool UseProbes = true; [MinValue(1)] - [MaxValue(16)] + [MaxValue(2048)] int ProbeResX = 4; [MinValue(1)] - [MaxValue(16)] + [MaxValue(2048)] int ProbeResY = 4; [MinValue(1)] - [MaxValue(16)] + [MaxValue(2048)] int ProbeResZ = 4; [MinValue(1)] diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 70df850..f5503aa 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -628,6 +628,22 @@ void BakingLab::Update(const Timer& timer) currSceneMax.y += AppSettings::SceneBoundsOffsetY; currSceneMax.z += AppSettings::SceneBoundsOffsetZ; + // Make sure that our probes fit within a single texture resource + const uint64 maxProbes = D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION / 6; + uint64 numProbes = AppSettings::NumProbes(); + if(numProbes > maxProbes) + { + const uint64 biggestDimRes = Max(Max(AppSettings::ProbeResX, AppSettings::ProbeResY), AppSettings::ProbeResZ); + const uint64 probesPerBiggestDimSlice = numProbes / biggestDimRes; + const int32 newRes = int32(maxProbes / float(probesPerBiggestDimSlice)); + if(biggestDimRes == AppSettings::ProbeResX) + AppSettings::ProbeResX.SetValue(newRes); + else if(biggestDimRes == AppSettings::ProbeResY) + AppSettings::ProbeResY.SetValue(newRes); + else + AppSettings::ProbeResZ.SetValue(newRes); + } + meshRenderer.Update(camera, jitterOffset); } From 8133747e3d7269a4175b0ec6a7ca1e72d2795037 Mon Sep 17 00:00:00 2001 From: MJP Date: Wed, 22 Nov 2017 19:20:52 -0800 Subject: [PATCH 17/43] WIP on probe basis modes --- BakingLab/AppSettings.cpp | 11 + BakingLab/AppSettings.cs | 8 + BakingLab/AppSettings.h | 45 ++ BakingLab/AppSettings.hlsl | 4 + BakingLab/BakingLab.cpp | 90 ++- BakingLab/BakingLab.h | 16 +- BakingLab/Mesh.hlsl | 8 +- BakingLab/MeshBaker.cpp | 4 +- BakingLab/MeshBaker.h | 6 +- BakingLab/MeshRenderer.cpp | 19 +- BakingLab/ProbeIntegrate.hlsl | 116 +++- .../v1.02/Graphics/DeviceManager.cpp | 502 +++++++------- .../v1.02/Graphics/GraphicsTypes.cpp | 46 ++ .../v1.02/Graphics/GraphicsTypes.h | 637 +++++++++--------- 14 files changed, 896 insertions(+), 616 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 72784c2..06d3cfe 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -161,6 +161,12 @@ static const char* SolveModesLabels[3] = "Non-Negative Least Squares", }; +static const char* ProbeModesLabels[2] = +{ + "CubeMap", + "AmbientCube", +}; + static const char* ScenesLabels[3] = { "Box", @@ -240,6 +246,7 @@ namespace AppSettings BakeModesSetting BakeMode; SolveModesSetting SolveMode; BoolSetting UseProbes; + ProbeModesSetting ProbeMode; IntSetting ProbeResX; IntSetting ProbeResY; IntSetting ProbeResZ; @@ -515,6 +522,9 @@ namespace AppSettings UseProbes.Initialize(tweakBar, "UseProbes", "Probes", "Use Probes", "", true); Settings.AddSetting(&UseProbes); + ProbeMode.Initialize(tweakBar, "ProbeMode", "Probes", "Probe Mode", "", ProbeModes::CubeMap, 2, ProbeModesLabels); + Settings.AddSetting(&ProbeMode); + ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 4, 1, 2048); Settings.AddSetting(&ProbeResX); @@ -735,6 +745,7 @@ namespace AppSettings CBuffer.Data.BakeMode = BakeMode; CBuffer.Data.SolveMode = SolveMode; CBuffer.Data.UseProbes = UseProbes; + CBuffer.Data.ProbeMode = ProbeMode; CBuffer.Data.ProbeResX = ProbeResX; CBuffer.Data.ProbeResY = ProbeResY; CBuffer.Data.ProbeResZ = ProbeResZ; diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index ed77044..927111f 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -300,6 +300,12 @@ enum SGDiffuseModes Fitted, } +enum ProbeModes +{ + CubeMap, + AmbientCube +} + public class Settings { const float BaseSunSize = 0.27f; @@ -665,6 +671,8 @@ public class Probes { bool UseProbes = true; + ProbeModes ProbeMode = ProbeModes.CubeMap; + [MinValue(1)] [MaxValue(2048)] int ProbeResX = 4; diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index d6876b2..9d88f58 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -223,6 +223,16 @@ enum class SolveModes typedef EnumSettingT SolveModesSetting; +enum class ProbeModes +{ + CubeMap = 0, + AmbientCube = 1, + + NumValues +}; + +typedef EnumSettingT ProbeModesSetting; + enum class Scenes { Box = 0, @@ -310,6 +320,7 @@ namespace AppSettings extern BakeModesSetting BakeMode; extern SolveModesSetting SolveMode; extern BoolSetting UseProbes; + extern ProbeModesSetting ProbeMode; extern IntSetting ProbeResX; extern IntSetting ProbeResY; extern IntSetting ProbeResZ; @@ -405,6 +416,7 @@ namespace AppSettings int32 BakeMode; int32 SolveMode; bool32 UseProbes; + int32 ProbeMode; int32 ProbeResX; int32 ProbeResY; int32 ProbeResZ; @@ -617,5 +629,38 @@ namespace AppSettings return ProbeResX * ProbeResY * ProbeResZ; } + inline uint64 ProbeBasisCount(uint64 probeMode) + { + Assert_(probeMode < uint64(ProbeModes::NumValues)); + static const uint64 BasisCounts[] = { 1, 6, }; // 4, 9, 4, 6, 5, 6, 9, 12 }; + StaticAssert_(ArraySize_(BasisCounts) == uint64(ProbeModes::NumValues)); + Assert_(BasisCounts[probeMode] <= MaxBasisCount); + return BasisCounts[probeMode]; + } + + inline uint64 ProbeBasisCount(ProbeModes probeMode) + { + return BasisCount(uint64(probeMode)); + } + + inline uint64 ProbeBasisCount() + { + return BasisCount(uint64(ProbeMode)); + } + + inline uint64 ProbeSGCount(ProbeModes probeMode) + { + /*Assert_(uint64(probeMode) < uint64(ProbeModes::NumValues)); + if(uint64(probeMode) >= uint64(ProbeModes::SG5)) + return BasisCount(probeMode); + else*/ + return 0; + } + + inline uint64 ProbeSGCount() + { + return SGCount(BakeMode); + } + void UpdateUI(); } \ No newline at end of file diff --git a/BakingLab/AppSettings.hlsl b/BakingLab/AppSettings.hlsl index 9fc32fa..0dc6264 100644 --- a/BakingLab/AppSettings.hlsl +++ b/BakingLab/AppSettings.hlsl @@ -48,6 +48,7 @@ cbuffer AppSettings : register(b7) int BakeMode; int SolveMode; bool UseProbes; + int ProbeMode; int ProbeResX; int ProbeResY; int ProbeResZ; @@ -186,6 +187,9 @@ static const int SolveModes_Projection = 0; static const int SolveModes_SVD = 1; static const int SolveModes_NNLS = 2; +static const int ProbeModes_CubeMap = 0; +static const int ProbeModes_AmbientCube = 1; + static const int Scenes_Box = 0; static const int Scenes_WhiteRoom = 1; static const int Scenes_Sponza = 2; diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index f5503aa..3f490cc 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -472,8 +472,11 @@ void BakingLab::Initialize() backgroundVelocityVS = CompileVSFromFile(device, L"BackgroundVelocity.hlsl", "BackgroundVelocityVS"); backgroundVelocityPS = CompilePSFromFile(device, L"BackgroundVelocity.hlsl", "BackgroundVelocityPS"); - probeIntegrateIrradiance = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateIrradiance"); - probeIntegrateDistance = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateDistance"); + probeIntegrateIrradianceCubeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateIrradianceCubeMap"); + probeIntegrateDistanceCubeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateDistanceCubeMap"); + + probeIntegrateVolumeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateVolumeMap"); + probeIntegrateDistanceVolumeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateDistanceVolumeMap"); resolveConstants.Initialize(device); backgroundVelocityConstants.Initialize(device); @@ -628,20 +631,23 @@ void BakingLab::Update(const Timer& timer) currSceneMax.y += AppSettings::SceneBoundsOffsetY; currSceneMax.z += AppSettings::SceneBoundsOffsetZ; - // Make sure that our probes fit within a single texture resource - const uint64 maxProbes = D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION / 6; - uint64 numProbes = AppSettings::NumProbes(); - if(numProbes > maxProbes) + if(AppSettings::ProbeMode == ProbeModes::CubeMap) { - const uint64 biggestDimRes = Max(Max(AppSettings::ProbeResX, AppSettings::ProbeResY), AppSettings::ProbeResZ); - const uint64 probesPerBiggestDimSlice = numProbes / biggestDimRes; - const int32 newRes = int32(maxProbes / float(probesPerBiggestDimSlice)); - if(biggestDimRes == AppSettings::ProbeResX) - AppSettings::ProbeResX.SetValue(newRes); - else if(biggestDimRes == AppSettings::ProbeResY) - AppSettings::ProbeResY.SetValue(newRes); - else - AppSettings::ProbeResZ.SetValue(newRes); + // Make sure that our probes fit within a single texture resource + const uint64 maxProbes = D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION / 6; + uint64 numProbes = AppSettings::NumProbes(); + if(numProbes > maxProbes) + { + const uint64 biggestDimRes = Max(Max(AppSettings::ProbeResX, AppSettings::ProbeResY), AppSettings::ProbeResZ); + const uint64 probesPerBiggestDimSlice = numProbes / biggestDimRes; + const int32 newRes = int32(maxProbes / float(probesPerBiggestDimSlice)); + if(biggestDimRes == AppSettings::ProbeResX) + AppSettings::ProbeResX.SetValue(newRes); + else if(biggestDimRes == AppSettings::ProbeResY) + AppSettings::ProbeResY.SetValue(newRes); + else + AppSettings::ProbeResZ.SetValue(newRes); + } } meshRenderer.Update(camera, jitterOffset); @@ -668,15 +674,23 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) } if(AppSettings::ProbeResX.Changed() || AppSettings::ProbeResY.Changed() || - AppSettings::ProbeResZ.Changed() || probeIrradianceMap.ArraySize == 0 || - AppSettings::ProbeIrradianceCubemapRes.Changed() || AppSettings::ProbeDistanceCubemapRes.Changed()) + AppSettings::ProbeResZ.Changed() || probeIrradianceCubeMap.ArraySize == 0 || + AppSettings::ProbeIrradianceCubemapRes.Changed() || AppSettings::ProbeDistanceCubemapRes.Changed() || + AppSettings::ProbeMode.Changed()) { currProbeIdx = 0; - const uint32 irrResolution = AppSettings::ProbeIrradianceCubemapRes; - const uint32 distResolution = AppSettings::ProbeDistanceCubemapRes; - probeIrradianceMap.Initialize(device, irrResolution, irrResolution, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); - probeDistanceMap.Initialize(device, distResolution, distResolution, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true, numProbes * 6, true); + if(AppSettings::ProbeMode == ProbeModes::CubeMap) + { + const uint32 irrResolution = AppSettings::ProbeIrradianceCubemapRes; + const uint32 distResolution = AppSettings::ProbeDistanceCubemapRes; + probeIrradianceCubeMap.Initialize(device, irrResolution, irrResolution, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); + probeDistanceCubeMap.Initialize(device, distResolution, distResolution, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true, numProbes * 6, true); + } + else + { + + } } if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed() || @@ -733,31 +747,31 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) context->OMSetRenderTargets(2, rtvs, nullptr); SetCSInputs(context, probeCaptureMap.SRView); - SetCSOutputs(context, probeIrradianceMap.UAView); + SetCSOutputs(context, probeIrradianceCubeMap.UAView); SetCSSamplers(context, samplerStates.LinearClamp()); - SetCSShader(context, probeIntegrateIrradiance); + SetCSShader(context, probeIntegrateIrradianceCubeMap); - integrateConstants.Data.OutputTextureSize.x = float(probeIrradianceMap.Width); - integrateConstants.Data.OutputTextureSize.y = float(probeIrradianceMap.Height); - integrateConstants.Data.OutputSliceOffset = uint32(currProbeIdx * 6); + integrateConstants.Data.OutputTextureSize.x = float(probeIrradianceCubeMap.Width); + integrateConstants.Data.OutputTextureSize.y = float(probeIrradianceCubeMap.Height); + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); integrateConstants.ApplyChanges(context); integrateConstants.SetCS(context, 0); - context->Dispatch(DispatchSize(8, probeIrradianceMap.Width), DispatchSize(8, probeIrradianceMap.Height), 6); + context->Dispatch(DispatchSize(8, probeIrradianceCubeMap.Width), DispatchSize(8, probeIrradianceCubeMap.Height), 6); ClearCSInputs(context); ClearCSOutputs(context); SetCSInputs(context, probeDistanceCaptureMap.SRView); - SetCSOutputs(context, probeDistanceMap.UAView); - SetCSShader(context, probeIntegrateDistance); + SetCSOutputs(context, probeDistanceCubeMap.UAView); + SetCSShader(context, probeIntegrateDistanceCubeMap); - integrateConstants.Data.OutputTextureSize.x = float(probeDistanceMap.Width); - integrateConstants.Data.OutputTextureSize.y = float(probeDistanceMap.Height); - integrateConstants.Data.OutputSliceOffset = uint32(currProbeIdx * 6); + integrateConstants.Data.OutputTextureSize.x = float(probeDistanceCubeMap.Width); + integrateConstants.Data.OutputTextureSize.y = float(probeDistanceCubeMap.Height); + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); integrateConstants.ApplyChanges(context); - context->Dispatch(DispatchSize(8, probeDistanceMap.Width), DispatchSize(8, probeDistanceMap.Height), 6); + context->Dispatch(DispatchSize(8, probeDistanceCubeMap.Width), DispatchSize(8, probeDistanceCubeMap.Height), 6); ClearCSInputs(context); ClearCSOutputs(context); @@ -803,8 +817,14 @@ void BakingLab::Render(const Timer& timer) } else { - status.ProbeIrradiance = probeIrradianceMap.SRView; - status.ProbeDistance = probeDistanceMap.SRView; + status.ProbeIrradianceCubeMap = probeIrradianceCubeMap.SRView; + status.ProbeDistanceCubeMap = probeDistanceCubeMap.SRView; + for(uint64 i = 0; i < AppSettings::MaxBasisCount; ++i) + { + status.ProbeVolumeMaps[i] = probeVolumeMaps[i].SRView; + status.ProbeDistanceVolumeMaps[i] = probeDistanceVolumeMaps[i].SRView; + } + RenderScene(status, colorTargetMSAA.RTView, velocityTargetMSAA.RTView, depthBuffer, camera, AppSettings::ShowBakeDataVisualizer, AppSettings::ShowProbeVisualizer, AppSettings::EnableAreaLight, true, false); diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index 90d519f..e08d2ad 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -76,14 +76,20 @@ class BakingLab : public App RenderTarget2D probeCaptureMap; RenderTarget2D probeDistanceCaptureMap; - RenderTarget2D probeIrradianceMap; - RenderTarget2D probeDistanceMap; + RenderTarget2D probeIrradianceCubeMap; + RenderTarget2D probeDistanceCubeMap; DepthStencilBuffer probeDepthBuffer; + RenderTarget3D probeVolumeMaps[AppSettings::MaxBasisCount]; + RenderTarget3D probeDistanceVolumeMaps[AppSettings::MaxBasisCount]; + uint64 currProbeIdx = 0; - ComputeShaderPtr probeIntegrateIrradiance; - ComputeShaderPtr probeIntegrateDistance; + ComputeShaderPtr probeIntegrateIrradianceCubeMap; + ComputeShaderPtr probeIntegrateDistanceCubeMap; + + ComputeShaderPtr probeIntegrateVolumeMap; + ComputeShaderPtr probeIntegrateDistanceVolumeMap; struct ResolveConstants { @@ -103,7 +109,7 @@ class BakingLab : public App struct IntegrateConstants { Float2 OutputTextureSize; - uint32 OutputSliceOffset; + uint32 OutputProbeIdx; }; ConstantBuffer resolveConstants; diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index a85856e..5ad6e1f 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -68,8 +68,8 @@ Texture2DArray BakedLightingMap : register(t5); TextureCube AreaLightShadowMap : register(t6); Texture3D SHSpecularLookupA : register(t7); Texture3D SHSpecularLookupB : register(t8); -TextureCubeArray ProbeIrradiance : register(t9); -TextureCubeArray ProbeDistance : register(t10); +TextureCubeArray ProbeIrradianceCubeMaps : register(t9); +TextureCubeArray ProbeDistanceCubeMaps : register(t10); SamplerState AnisoSampler : register(s0); SamplerState EVSMSampler : register(s1); @@ -504,14 +504,14 @@ void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrr float maxDistance = length((SceneMaxBounds - SceneMinBounds) * rcp(float3(ProbeResX, ProbeResY, ProbeResZ))); float compareDistance = saturate(distToProbe * rcp(maxDistance)); - float2 distSample = ProbeDistance.Sample(LinearSampler, float4(-dirToProbe, probeIdx)); + float2 distSample = ProbeDistanceCubeMaps.Sample(LinearSampler, float4(-dirToProbe, probeIdx)); float visTerm = ChebyshevUpperBound(distSample, compareDistance, 0.0001f, 0.25f); sampleWeight *= visTerm; } sampleWeight = max(0.0002f, sampleWeight); - float3 irradianceSample = ProbeIrradiance.Sample(LinearSampler, float4(surface.NormalWS, probeIdx)).xyz; + float3 irradianceSample = ProbeIrradianceCubeMaps.Sample(LinearSampler, float4(surface.NormalWS, probeIdx)).xyz; irradianceSum += irradianceSample * sampleWeight; weightSum += sampleWeight; } diff --git a/BakingLab/MeshBaker.cpp b/BakingLab/MeshBaker.cpp index 61062bc..ef900e9 100644 --- a/BakingLab/MeshBaker.cpp +++ b/BakingLab/MeshBaker.cpp @@ -43,7 +43,7 @@ struct GutterTexel // Returns the final monte-carlo weighting factor using the PDF of a cosine-weighted hemisphere static float CosineWeightedMonteCarloFactor(uint64 numSamples) { - // Integrating cosine factor about the hemisphere gives you Pi, and the PDF + // Integrating the cosine factor about the hemisphere gives you Pi, and the PDF // of a cosine-weighted hemisphere function is 1 / Pi. // So the final monte-carlo weighting factor is 1 / NumSamples return (1.0f / numSamples); @@ -57,7 +57,7 @@ static float HemisphereMonteCarloFactor(uint64 numSamples) static float SphereMonteCarloFactor(uint64 numSamples) { - // The area of a unit hemisphere is 2 * Pi, so the PDF is 1 / (2 * Pi) + // The area of a unit sphere is 4 * Pi, so the PDF is 1 / (4 * Pi) return ((4.0f * Pi) / numSamples); } diff --git a/BakingLab/MeshBaker.h b/BakingLab/MeshBaker.h index 29ccf44..91fc8e3 100644 --- a/BakingLab/MeshBaker.h +++ b/BakingLab/MeshBaker.h @@ -59,8 +59,10 @@ struct MeshBakerStatus ID3D11ShaderResourceView* GroundTruth = nullptr; ID3D11ShaderResourceView* LightMap = nullptr; ID3D11ShaderResourceView* BakePoints = nullptr; - ID3D11ShaderResourceView* ProbeIrradiance = nullptr; - ID3D11ShaderResourceView* ProbeDistance = nullptr; + ID3D11ShaderResourceView* ProbeIrradianceCubeMap = nullptr; + ID3D11ShaderResourceView* ProbeDistanceCubeMap = nullptr; + ID3D11ShaderResourceView* ProbeVolumeMaps[AppSettings::MaxBasisCount] = { }; + ID3D11ShaderResourceView* ProbeDistanceVolumeMaps[AppSettings::MaxBasisCount] = { }; uint64 NumBakePoints = 0; float GroundTruthProgress = 0.0f; float BakeProgress = 0.0f; diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index b64f139..7f658dd 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -688,11 +688,18 @@ void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& ca areaLightShadowMap.SRView, shSpecularLookupA, shSpecularLookupB, - status.ProbeIrradiance, - status.ProbeDistance, + status.ProbeIrradianceCubeMap, + status.ProbeDistanceCubeMap, }; context->PSSetShaderResources(0, ArraySize_(psTextures), psTextures); + + uint32 offset = ArraySize_(psTextures); + context->PSSetShaderResources(offset, ArraySize_(status.ProbeVolumeMaps), status.ProbeVolumeMaps); + + offset += ArraySize_(status.ProbeVolumeMaps); + context->PSSetShaderResources(offset, ArraySize_(status.ProbeDistanceVolumeMaps), status.ProbeDistanceVolumeMaps); + context->DrawIndexed(part.IndexCount, part.IndexStart, 0); } } @@ -1107,9 +1114,15 @@ void MeshRenderer::RenderProbeVisualizer(ID3D11DeviceContext* context, const Cam context->VSSetShader(probeVisualizerVS , nullptr, 0); context->PSSetShader(probeVisualizerPS, nullptr, 0); - ID3D11ShaderResourceView* psSrvs[] = { status.ProbeIrradiance, status.ProbeDistance }; + ID3D11ShaderResourceView* psSrvs[] = { status.ProbeIrradianceCubeMap, status.ProbeDistanceCubeMap }; context->PSSetShaderResources(0, ArraySize_(psSrvs), psSrvs); + uint32 offset = ArraySize_(psSrvs); + context->PSSetShaderResources(offset, ArraySize_(status.ProbeVolumeMaps), status.ProbeVolumeMaps); + + offset += ArraySize_(status.ProbeVolumeMaps); + context->PSSetShaderResources(offset, ArraySize_(status.ProbeDistanceVolumeMaps), status.ProbeDistanceVolumeMaps); + ID3D11SamplerState* psSamplers[] = { samplerStates.LinearClamp() }; context->PSSetSamplers(0, ArraySize_(psSamplers), psSamplers); diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl index f35bac3..7019e92 100644 --- a/BakingLab/ProbeIntegrate.hlsl +++ b/BakingLab/ProbeIntegrate.hlsl @@ -14,7 +14,7 @@ cbuffer IntegrateConstants : register(b0) { float2 OutputTextureSize; - uint OutputSliceOffset; + uint OutputProbeIdx; } SamplerState LinearSampler : register(s0); @@ -132,6 +132,18 @@ float3 SampleCosineHemisphere(in float u1, in float u2) return dir; } +// Returns a random direction on the unit sphere +float3 SampleDirectionSphere(float u1, float u2) +{ + float z = u1 * 2.0f - 1.0f; + float r = sqrt(max(0.0f, 1.0f - z * z)); + float phi = 2 * Pi * u2; + float x = r * cos(phi); + float y = r * sin(phi); + + return float3(x, y, z); +} + float3x3 MakeTangentFrame(in float3 normal, in uint faceIdx) { float3 tangent = 0.0f; @@ -154,15 +166,30 @@ float3x3 MakeTangentFrame(in float3 normal, in uint faceIdx) return float3x3(tangent, bitangent, normal); } +void IntegrateOntoBasis(in float3 dir, in float3 value, inout float3 output[MaxBasisCount]) +{ + if(ProbeMode == ProbeModes_AmbientCube) + { + output[0] += value * dir.x; + output[1] += value * dir.y; + output[2] += value * dir.z; + output[3] += value * -dir.x; + output[4] += value * -dir.y; + output[5] += value * -dir.z; + } +} + +// ================================================================================================ + TextureCube RadianceCaptureMap : register(t0); -RWTexture2DArray IrradianceMap : register(u0); +RWTexture2DArray IrradianceCubeMap : register(u0); [numthreads(8, 8, 1)] -void IntegrateIrradiance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +void IntegrateIrradianceCubeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) { uint2 outputPos = GroupID.xy * 8 + GroupThreadID.xy; uint outputFaceIdx = GroupID.z; - uint outputSliceIdx = OutputSliceOffset + outputFaceIdx; + uint outputSliceIdx = (OutputProbeIdx * 6) + outputFaceIdx; float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); @@ -182,11 +209,48 @@ void IntegrateIrradiance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : // irradiance = 16.0f; - IrradianceMap[uint3(outputPos, outputSliceIdx)] = float4(irradiance, 0.0f); + IrradianceCubeMap[uint3(outputPos, outputSliceIdx)] = float4(irradiance, 0.0f); +} + +// ================================================================================================ + +RWTexture3D OutputVolumeMaps[MaxBasisCount] : register(u0); + +[numthreads(1, 1, 1)] +void IntegrateVolumeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + uint3 outputTexelIdx; + outputTexelIdx.x = OutputProbeIdx % ProbeResX; + outputTexelIdx.y = (OutputProbeIdx / ProbeResX) % ProbeResY; + outputTexelIdx.z = OutputProbeIdx / (ProbeResX * ProbeResY); + + float3 output[MaxBasisCount]; + for(int b = 0; b < MaxBasisCount; ++b) + output[b] = 0.0f; + + const uint numSamples = 1024; + for(uint sampleIdx = 0; sampleIdx < numSamples; ++sampleIdx) + { + float2 samplePos = Hammersley2D(sampleIdx, numSamples); + float3 sampleDir = SampleDirectionSphere(samplePos.x, samplePos.y); + float3 radiance = RadianceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f).xyz; + + + IntegrateOntoBasis(sampleDir, radiance, output); + } + + [unroll] + for(int i = 0; i < MaxBasisCount; ++i) + { + float3 outputValue = output[i] * (4 * Pi / numSamples); + OutputVolumeMaps[i][outputTexelIdx] = float4(clamp(outputValue, -FP16Max, FP16Max), 0.0f); + } } +// ================================================================================================ + TextureCube DistanceCaptureMap : register(t0); -RWTexture2DArray DistanceOutputMap : register(u0); +RWTexture2DArray DistanceOutputCubeMap : register(u0); float3 SampleCosinePower(in float2 xi, in float n) { @@ -202,11 +266,11 @@ float3 SampleCosinePower(in float2 xi, in float n) } [numthreads(8, 8, 1)] -void IntegrateDistance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +void IntegrateDistanceCubeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) { uint2 outputPos = GroupID.xy * 8 + GroupThreadID.xy; uint outputFaceIdx = GroupID.z; - uint outputSliceIdx = OutputSliceOffset + outputFaceIdx; + uint outputSliceIdx = (OutputProbeIdx * 6) + outputFaceIdx; float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); @@ -232,5 +296,39 @@ void IntegrateDistance(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : S // outputDistance = DistanceCaptureMap.SampleLevel(LinearSampler, normal, 0.0f).xy; - DistanceOutputMap[uint3(outputPos, outputSliceIdx)] = outputDistance; + DistanceOutputCubeMap[uint3(outputPos, outputSliceIdx)] = outputDistance; +} + +// ================================================================================================ + +RWTexture3D OutputVolumeDistanceMaps[MaxBasisCount] : register(u0); + +[numthreads(1, 1, 1)] +void IntegrateDistanceVolumeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + uint3 outputTexelIdx; + outputTexelIdx.x = OutputProbeIdx % ProbeResX; + outputTexelIdx.y = (OutputProbeIdx / ProbeResX) % ProbeResY; + outputTexelIdx.z = OutputProbeIdx / (ProbeResX * ProbeResY); + + float3 output[MaxBasisCount]; + for(int b = 0; b < MaxBasisCount; ++b) + output[b] = 0.0f; + + const uint numSamples = 1024; + for(uint sampleIdx = 0; sampleIdx < numSamples; ++sampleIdx) + { + float2 samplePos = Hammersley2D(sampleIdx, numSamples); + float3 sampleDir = SampleDirectionSphere(samplePos.x, samplePos.y); + float2 sampleDistance = DistanceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f); + + IntegrateOntoBasis(sampleDir, float3(sampleDistance, 0.0f), output); + } + + [unroll] + for(int i = 0; i < MaxBasisCount; ++i) + { + float2 outputValue = output[i].xy * (4 * Pi / numSamples); + OutputVolumeDistanceMaps[i][outputTexelIdx] = clamp(outputValue, -FP16Max, FP16Max); + } } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/DeviceManager.cpp b/SampleFramework11/v1.02/Graphics/DeviceManager.cpp index 0d626d0..bc11897 100644 --- a/SampleFramework11/v1.02/Graphics/DeviceManager.cpp +++ b/SampleFramework11/v1.02/Graphics/DeviceManager.cpp @@ -1,251 +1,253 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include "PCH.h" - -#include "DeviceManager.h" -#include "..\\Exceptions.h" -#include "..\\Utility.h" - -using std::wstring; - -#if _DEBUG - #define UseDebugDevice_ 1 - #define BreakOnDXError_ (UseDebugDevice_ && 1) -#else - #define UseDebugDevice_ 0 - #define BreakOnDXError_ 0 -#endif - -namespace SampleFramework11 -{ - -DeviceManager::DeviceManager() : backBufferFormat(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB), - backBufferWidth(1280), - backBufferHeight(720), - msCount(1), - msQuality(0), - fullScreen(false), - featureLevel(D3D_FEATURE_LEVEL_11_0), - minFeatureLevel(D3D_FEATURE_LEVEL_10_0), - vsync(true), - numVSYNCIntervals(1) -{ - refreshRate.Numerator = 60; - refreshRate.Denominator = 1; - - // Try to figure out if we should default to 1280x720 or 1920x1080 - POINT point; - point.x = 0; - point.y = 0; - HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY); - if(monitor != 0) - { - MONITORINFOEX info; - ZeroMemory(&info, sizeof(info)); - info.cbSize = sizeof(MONITORINFOEX); - if(GetMonitorInfo(monitor, &info) != 0) - { - int32 width = info.rcWork.right - info.rcWork.left; - int32 height = info.rcWork.bottom - info.rcWork.top; - if(width > 1920 && height > 1080) - { - backBufferWidth = 1920; - backBufferHeight = 1080; - } - } - } -} - -DeviceManager::~DeviceManager() -{ - if(immediateContext) - { - immediateContext->ClearState(); - immediateContext->Flush(); - } -} - -void DeviceManager::Initialize(HWND outputWindow) -{ - CheckForSuitableOutput(); - - DXGI_SWAP_CHAIN_DESC desc; - ZeroMemory(&desc, sizeof(DXGI_SWAP_CHAIN_DESC)); - - if(fullScreen) - { - PrepareFullScreenSettings(); - } - else - { - refreshRate.Numerator = 60; - refreshRate.Denominator = 1; - } - - desc.BufferCount = 2; - desc.BufferDesc.Format = backBufferFormat; - desc.BufferDesc.Width = backBufferWidth; - desc.BufferDesc.Height = backBufferHeight; - desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - desc.BufferDesc.RefreshRate = refreshRate; - desc.SampleDesc.Count = msCount; - desc.SampleDesc.Quality = msQuality; - desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - desc.OutputWindow = outputWindow; - desc.Windowed = !fullScreen; - - uint32 flags = D3D11_CREATE_DEVICE_SINGLETHREADED; - #if UseDebugDevice_ - flags |= D3D11_CREATE_DEVICE_DEBUG; - #endif - - DXCall(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, - NULL, 0, D3D11_SDK_VERSION, &desc, &swapChain, - &device, NULL, &immediateContext)); - - featureLevel = device->GetFeatureLevel(); - - if(featureLevel < minFeatureLevel) - { - wstring majorLevel = ToString(minFeatureLevel >> 12); - wstring minorLevel = ToString((minFeatureLevel >> 8) & 0xF); - throw Exception(L"The device doesn't support the minimum feature level required to run this sample (DX" + majorLevel + L"." + minorLevel + L")"); - } - - if(BreakOnDXError_ && D3DPERF_GetStatus() == 0) - { - ID3D11InfoQueuePtr infoQueue; - DXCall(device->QueryInterface(__uuidof(ID3D11InfoQueue), reinterpret_cast(&infoQueue))); - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, TRUE); - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE); - } - - AfterReset(); -} - -void DeviceManager::AfterReset() -{ - DXCall(swapChain->GetBuffer(0, __uuidof(bbTexture), reinterpret_cast(&bbTexture))); - DXCall(device->CreateRenderTargetView(bbTexture, NULL, &bbRTView)); - - // Set default render targets - immediateContext->OMSetRenderTargets(1, &(bbRTView.GetInterfacePtr()), NULL); - - // Setup the viewport - D3D11_VIEWPORT vp; - vp.Width = static_cast(backBufferWidth); - vp.Height = static_cast(backBufferHeight); - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - vp.TopLeftX = 0; - vp.TopLeftY = 0; - immediateContext->RSSetViewports(1, &vp); -} - -void DeviceManager::CheckForSuitableOutput() -{ - HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast(&factory)); - if(FAILED(hr)) - throw Exception(L"Unable to create a DXGI 1.1 device.\n " - L"Make sure that your OS and driver support DirectX 11"); - - // Look for an adapter that supports D3D11 - IDXGIAdapter1Ptr curAdapter; - uint32 adapterIdx = 0; - LARGE_INTEGER umdVersion; - while(!adapter && SUCCEEDED(factory->EnumAdapters1(0, &adapter))) - if(SUCCEEDED(adapter->CheckInterfaceSupport(__uuidof(ID3D11Device), &umdVersion))) - adapter = curAdapter; - - if(!adapter) - throw Exception(L"Unable to locate a DXGI 1.1 adapter that supports a D3D11 device.\n" - L"Make sure that your OS and driver support DirectX 11"); - - // We'll just use the first output - DXCall(adapter->EnumOutputs(0, &output)); -} - -void DeviceManager::PrepareFullScreenSettings() -{ - Assert_(output); - - // Have the Output look for the closest matching mode - DXGI_MODE_DESC desiredMode; - desiredMode.Format = backBufferFormat; - desiredMode.Width = backBufferWidth; - desiredMode.Height = backBufferHeight; - desiredMode.RefreshRate.Numerator = 0; - desiredMode.RefreshRate.Denominator = 0; - desiredMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - desiredMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - - DXGI_MODE_DESC closestMatch; - DXCall(output->FindClosestMatchingMode(&desiredMode, &closestMatch, device.GetInterfacePtr())); - - backBufferFormat = closestMatch.Format; - backBufferWidth = closestMatch.Width; - backBufferHeight = closestMatch.Height; - refreshRate = closestMatch.RefreshRate; -} - -void DeviceManager::Reset() -{ - Assert_(swapChain); - - // Release all references - if(bbTexture) - bbTexture.Release(); - - if(bbRTView) - bbRTView.Release(); - - immediateContext->ClearState(); - - if(fullScreen) - PrepareFullScreenSettings(); - else - { - refreshRate.Numerator = 60; - refreshRate.Denominator = 1; - } - - DXCall(swapChain->SetFullscreenState(fullScreen, NULL)); - - DXCall(swapChain->ResizeBuffers(2, backBufferWidth, backBufferHeight, - backBufferFormat, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)); - - if(fullScreen) - { - DXGI_MODE_DESC mode; - mode.Format = backBufferFormat; - mode.Width = backBufferWidth; - mode.Height = backBufferHeight; - mode.RefreshRate.Numerator = 0; - mode.RefreshRate.Denominator = 0; - mode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - DXCall(swapChain->ResizeTarget(&mode)); - } - - AfterReset(); -} - -void DeviceManager::Present() -{ - Assert_(device); - - uint32 interval = vsync ? numVSYNCIntervals : 0; - DXCall(swapChain->Present(interval, 0)); -} - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include "PCH.h" + +#include "DeviceManager.h" +#include "..\\Exceptions.h" +#include "..\\Utility.h" + +using std::wstring; + +#if _DEBUG + #define UseDebugDevice_ 1 + #define BreakOnDXError_ (UseDebugDevice_ && 1) +#else + #define UseDebugDevice_ 0 + #define BreakOnDXError_ 0 +#endif + +namespace SampleFramework11 +{ + +DeviceManager::DeviceManager() : backBufferFormat(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB), + backBufferWidth(1280), + backBufferHeight(720), + msCount(1), + msQuality(0), + fullScreen(false), + featureLevel(D3D_FEATURE_LEVEL_11_1), + minFeatureLevel(D3D_FEATURE_LEVEL_11_1), + vsync(true), + numVSYNCIntervals(1) +{ + refreshRate.Numerator = 60; + refreshRate.Denominator = 1; + + // Try to figure out if we should default to 1280x720 or 1920x1080 + POINT point; + point.x = 0; + point.y = 0; + HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY); + if(monitor != 0) + { + MONITORINFOEX info; + ZeroMemory(&info, sizeof(info)); + info.cbSize = sizeof(MONITORINFOEX); + if(GetMonitorInfo(monitor, &info) != 0) + { + int32 width = info.rcWork.right - info.rcWork.left; + int32 height = info.rcWork.bottom - info.rcWork.top; + if(width > 1920 && height > 1080) + { + backBufferWidth = 1920; + backBufferHeight = 1080; + } + } + } +} + +DeviceManager::~DeviceManager() +{ + if(immediateContext) + { + immediateContext->ClearState(); + immediateContext->Flush(); + } +} + +void DeviceManager::Initialize(HWND outputWindow) +{ + CheckForSuitableOutput(); + + DXGI_SWAP_CHAIN_DESC desc; + ZeroMemory(&desc, sizeof(DXGI_SWAP_CHAIN_DESC)); + + if(fullScreen) + { + PrepareFullScreenSettings(); + } + else + { + refreshRate.Numerator = 60; + refreshRate.Denominator = 1; + } + + desc.BufferCount = 2; + desc.BufferDesc.Format = backBufferFormat; + desc.BufferDesc.Width = backBufferWidth; + desc.BufferDesc.Height = backBufferHeight; + desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + desc.BufferDesc.RefreshRate = refreshRate; + desc.SampleDesc.Count = msCount; + desc.SampleDesc.Quality = msQuality; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + desc.OutputWindow = outputWindow; + desc.Windowed = !fullScreen; + + uint32 flags = D3D11_CREATE_DEVICE_SINGLETHREADED; + #if UseDebugDevice_ + flags |= D3D11_CREATE_DEVICE_DEBUG; + #endif + + D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1 }; + + DXCall(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, + featureLevels, ArraySize_(featureLevels), D3D11_SDK_VERSION, &desc, &swapChain, + &device, NULL, &immediateContext)); + + featureLevel = device->GetFeatureLevel(); + + if(featureLevel < minFeatureLevel) + { + wstring majorLevel = ToString(minFeatureLevel >> 12); + wstring minorLevel = ToString((minFeatureLevel >> 8) & 0xF); + throw Exception(L"The device doesn't support the minimum feature level required to run this sample (DX" + majorLevel + L"." + minorLevel + L")"); + } + + if(BreakOnDXError_ && D3DPERF_GetStatus() == 0) + { + ID3D11InfoQueuePtr infoQueue; + DXCall(device->QueryInterface(__uuidof(ID3D11InfoQueue), reinterpret_cast(&infoQueue))); + infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, TRUE); + infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE); + } + + AfterReset(); +} + +void DeviceManager::AfterReset() +{ + DXCall(swapChain->GetBuffer(0, __uuidof(bbTexture), reinterpret_cast(&bbTexture))); + DXCall(device->CreateRenderTargetView(bbTexture, NULL, &bbRTView)); + + // Set default render targets + immediateContext->OMSetRenderTargets(1, &(bbRTView.GetInterfacePtr()), NULL); + + // Setup the viewport + D3D11_VIEWPORT vp; + vp.Width = static_cast(backBufferWidth); + vp.Height = static_cast(backBufferHeight); + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + vp.TopLeftX = 0; + vp.TopLeftY = 0; + immediateContext->RSSetViewports(1, &vp); +} + +void DeviceManager::CheckForSuitableOutput() +{ + HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast(&factory)); + if(FAILED(hr)) + throw Exception(L"Unable to create a DXGI 1.1 device.\n " + L"Make sure that your OS and driver support DirectX 11"); + + // Look for an adapter that supports D3D11 + IDXGIAdapter1Ptr curAdapter; + uint32 adapterIdx = 0; + LARGE_INTEGER umdVersion; + while(!adapter && SUCCEEDED(factory->EnumAdapters1(0, &adapter))) + if(SUCCEEDED(adapter->CheckInterfaceSupport(__uuidof(ID3D11Device), &umdVersion))) + adapter = curAdapter; + + if(!adapter) + throw Exception(L"Unable to locate a DXGI 1.1 adapter that supports a D3D11 device.\n" + L"Make sure that your OS and driver support DirectX 11"); + + // We'll just use the first output + DXCall(adapter->EnumOutputs(0, &output)); +} + +void DeviceManager::PrepareFullScreenSettings() +{ + Assert_(output); + + // Have the Output look for the closest matching mode + DXGI_MODE_DESC desiredMode; + desiredMode.Format = backBufferFormat; + desiredMode.Width = backBufferWidth; + desiredMode.Height = backBufferHeight; + desiredMode.RefreshRate.Numerator = 0; + desiredMode.RefreshRate.Denominator = 0; + desiredMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + desiredMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + + DXGI_MODE_DESC closestMatch; + DXCall(output->FindClosestMatchingMode(&desiredMode, &closestMatch, device.GetInterfacePtr())); + + backBufferFormat = closestMatch.Format; + backBufferWidth = closestMatch.Width; + backBufferHeight = closestMatch.Height; + refreshRate = closestMatch.RefreshRate; +} + +void DeviceManager::Reset() +{ + Assert_(swapChain); + + // Release all references + if(bbTexture) + bbTexture.Release(); + + if(bbRTView) + bbRTView.Release(); + + immediateContext->ClearState(); + + if(fullScreen) + PrepareFullScreenSettings(); + else + { + refreshRate.Numerator = 60; + refreshRate.Denominator = 1; + } + + DXCall(swapChain->SetFullscreenState(fullScreen, NULL)); + + DXCall(swapChain->ResizeBuffers(2, backBufferWidth, backBufferHeight, + backBufferFormat, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)); + + if(fullScreen) + { + DXGI_MODE_DESC mode; + mode.Format = backBufferFormat; + mode.Width = backBufferWidth; + mode.Height = backBufferHeight; + mode.RefreshRate.Numerator = 0; + mode.RefreshRate.Denominator = 0; + mode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + DXCall(swapChain->ResizeTarget(&mode)); + } + + AfterReset(); +} + +void DeviceManager::Present() +{ + Assert_(device); + + uint32 interval = vsync ? numVSYNCIntervals : 0; + DXCall(swapChain->Present(interval, 0)); +} + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp b/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp index 0336e39..275159b 100644 --- a/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp +++ b/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp @@ -163,6 +163,52 @@ void RenderTarget2D::Initialize(ID3D11Device* device, DXCall(device->CreateUnorderedAccessView(Texture, nullptr, &UAView)); }; +// == RenderTarget3D ============================================================================== + +void RenderTarget3D::Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + uint32 depth, + DXGI_FORMAT format, + uint32 numMipLevels, + bool32 autoGenMipMaps, + bool32 createRTV, + bool32 createUAV) +{ + D3D11_TEXTURE3D_DESC desc = { }; + desc.Width = width; + desc.Height = height; + desc.Depth = depth; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + if(createRTV | autoGenMipMaps) + desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + if(createUAV) + desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; + + desc.CPUAccessFlags = 0; + desc.Format = format; + desc.MipLevels = numMipLevels; + desc.MiscFlags = (autoGenMipMaps && numMipLevels != 1) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; + desc.Usage = D3D11_USAGE_DEFAULT; + + DXCall(device->CreateTexture3D(&desc, nullptr, &Texture)); + + DXCall(device->CreateShaderResourceView(Texture, nullptr, &SRView)); + + if(createRTV) + DXCall(device->CreateRenderTargetView(Texture, nullptr, &RTView)); + + if(createUAV) + DXCall(device->CreateUnorderedAccessView(Texture, nullptr, &UAView)); + + Width = width; + Height = height; + Depth = depth; + NumMipLevels = numMipLevels; + Format = format; + AutoGenMipMaps = autoGenMipMaps; +}; + // == DepthStencilBuffer ========================================================================== DepthStencilBuffer::DepthStencilBuffer() : Width(0), diff --git a/SampleFramework11/v1.02/Graphics/GraphicsTypes.h b/SampleFramework11/v1.02/Graphics/GraphicsTypes.h index c39ac06..86a7d1c 100644 --- a/SampleFramework11/v1.02/Graphics/GraphicsTypes.h +++ b/SampleFramework11/v1.02/Graphics/GraphicsTypes.h @@ -1,307 +1,332 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include "..\\PCH.h" - -#include "..\\InterfacePointers.h" -#include "..\\Utility.h" - -namespace SampleFramework11 -{ - -struct RenderTarget2D -{ - ID3D11Texture2DPtr Texture; - ID3D11RenderTargetViewPtr RTView; - ID3D11ShaderResourceViewPtr SRView; - ID3D11UnorderedAccessViewPtr UAView; - uint32 Width; - uint32 Height; - uint32 NumMipLevels; - uint32 MultiSamples; - uint32 MSQuality; - DXGI_FORMAT Format; - bool32 AutoGenMipMaps; - uint32 ArraySize; - bool32 CubeMap; - std::vector RTVArraySlices; - std::vector SRVArraySlices; - - RenderTarget2D(); - - void Initialize( ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - uint32 numMipLevels = 1, - uint32 multiSamples = 1, - uint32 msQuality = 0, - bool32 autoGenMipMaps = false, - bool32 createUAV = false, - uint32 arraySize = 1, - bool32 cubeMap = false); -}; - -struct DepthStencilBuffer -{ - ID3D11Texture2DPtr Texture; - ID3D11DepthStencilViewPtr DSView; - ID3D11DepthStencilViewPtr ReadOnlyDSView; - ID3D11ShaderResourceViewPtr SRView; - uint32 Width; - uint32 Height; - uint32 MultiSamples; - uint32 MSQuality; - DXGI_FORMAT Format; - uint32 ArraySize; - bool32 CubeMap; - std::vector ArraySlices; - - DepthStencilBuffer(); - - void Initialize( ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT, - bool32 useAsShaderResource = false, - uint32 multiSamples = 1, - uint32 msQuality = 0, - uint32 arraySize = 1, - bool32 cubeMap = false); -}; - -struct RWBuffer -{ - ID3D11BufferPtr Buffer; - ID3D11ShaderResourceViewPtr SRView; - ID3D11UnorderedAccessViewPtr UAView; - uint32 Size; - uint32 Stride; - uint32 NumElements; - bool32 RawBuffer; - DXGI_FORMAT Format; - - RWBuffer(); - - void Initialize(ID3D11Device* device, DXGI_FORMAT format, uint32 stride, uint32 numElements, bool32 rawBuffer = false, - bool vertexBuffer = false, bool indexBuffer = false, bool indirectArgs = false, - const void* initData = nullptr); -}; - -struct StagingBuffer -{ - ID3D11BufferPtr Buffer; - uint32 Size; - - StagingBuffer(); - - void Initialize(ID3D11Device* device, uint32 size); - void* Map(ID3D11DeviceContext* context); - void Unmap(ID3D11DeviceContext* context); -}; - -struct StagingTexture2D -{ - ID3D11Texture2DPtr Texture; - uint32 Width; - uint32 Height; - uint32 NumMipLevels; - uint32 MultiSamples; - uint32 MSQuality; - DXGI_FORMAT Format; - uint32 ArraySize; - - StagingTexture2D(); - - void Initialize( ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - uint32 numMipLevels = 1, - uint32 multiSamples = 1, - uint32 msQuality = 0, - uint32 arraySize = 1); - - void* Map(ID3D11DeviceContext* context, uint32 subResourceIndex, uint32& pitch); - void Unmap(ID3D11DeviceContext* context, uint32 subResourceIndex); -}; - -struct StructuredBuffer -{ - ID3D11BufferPtr Buffer; - ID3D11ShaderResourceViewPtr SRView; - ID3D11UnorderedAccessViewPtr UAView; - uint32 Size; - uint32 Stride; - uint32 NumElements; - StagingBuffer DebugBuffer; - - StructuredBuffer(); - - void Initialize(ID3D11Device* device, uint32 stride, uint32 numElements, bool32 useAsUAV = false, - bool32 appendConsume = false, bool32 hiddenCounter = false, const void* initData = nullptr); - - void WriteToFile(const wchar* path, ID3D11Device* device, ID3D11DeviceContext* context); - void ReadFromFile(const wchar* path, ID3D11Device* device); - - template void DebugPrint(ID3D11DeviceContext* context, const char* name) - { - Assert_(Buffer != nullptr); - if(DebugBuffer.Size != Size) - { - ID3D11DevicePtr device; - context->GetDevice(&device); - DebugBuffer.Initialize(device, Size); - } - - std::printf("%s\n", name); - - context->CopyResource(DebugBuffer.Buffer, Buffer); - const T* data = reinterpret_cast(DebugBuffer.Map(context)); - for(uint32 i = 0; i < NumElements; ++i) - { - std::string elemPrint = data[i].Print(); - std::printf(" [%u] %s", i, elemPrint.c_str()); - } - } -}; - -template class ConstantBuffer -{ -public: - - T Data; - - ID3D11BufferPtr Buffer; - bool GPUWritable; - -public: - - ConstantBuffer() : GPUWritable(false) - { - ZeroMemory(&Data, sizeof(T)); - } - - void Initialize(ID3D11Device* device, bool gpuWritable = false) - { - D3D11_BUFFER_DESC desc; - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - desc.ByteWidth = static_cast(sizeof(T) + (16 - (sizeof(T) % 16))); - - if(gpuWritable) - { - desc.Usage = D3D11_USAGE_DEFAULT; - desc.CPUAccessFlags = 0; - } - GPUWritable = gpuWritable; - - DXCall(device->CreateBuffer(&desc, nullptr, &Buffer)); - } - - void ApplyChanges(ID3D11DeviceContext* deviceContext) - { - Assert_(Buffer != nullptr); - - if(GPUWritable) - { - deviceContext->UpdateSubresource(Buffer, 0, nullptr, &Data, 0, 0); - } - else - { - D3D11_MAPPED_SUBRESOURCE mappedResource; - DXCall(deviceContext->Map(Buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)); - CopyMemory(mappedResource.pData, &Data, sizeof(T)); - deviceContext->Unmap(Buffer, 0); - } - } - - void SetVS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->VSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetPS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->PSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetGS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->GSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetHS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->HSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetDS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->DSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetCS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->CSSetConstantBuffers(slot, 1, bufferArray); - } -}; - -// For aligning to float4 boundaries -#define Float4Align __declspec(align(16)) - -class PIXEvent -{ -public: - - PIXEvent(const wchar* markerName) - { - D3DPERF_BeginEvent(0xFFFFFFFF, markerName); - } - - PIXEvent(const std::wstring& markerName) - { - D3DPERF_BeginEvent(0xFFFFFFFF, markerName.c_str()); - } - - ~PIXEvent() - { - D3DPERF_EndEvent(); - } -}; - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include "..\\PCH.h" + +#include "..\\InterfacePointers.h" +#include "..\\Utility.h" + +namespace SampleFramework11 +{ + +struct RenderTarget2D +{ + ID3D11Texture2DPtr Texture; + ID3D11RenderTargetViewPtr RTView; + ID3D11ShaderResourceViewPtr SRView; + ID3D11UnorderedAccessViewPtr UAView; + uint32 Width; + uint32 Height; + uint32 NumMipLevels; + uint32 MultiSamples; + uint32 MSQuality; + DXGI_FORMAT Format; + bool32 AutoGenMipMaps; + uint32 ArraySize; + bool32 CubeMap; + std::vector RTVArraySlices; + std::vector SRVArraySlices; + + RenderTarget2D(); + + void Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + uint32 numMipLevels = 1, + uint32 multiSamples = 1, + uint32 msQuality = 0, + bool32 autoGenMipMaps = false, + bool32 createUAV = false, + uint32 arraySize = 1, + bool32 cubeMap = false); +}; + +struct RenderTarget3D +{ + ID3D11Texture3DPtr Texture; + ID3D11RenderTargetViewPtr RTView; + ID3D11ShaderResourceViewPtr SRView; + ID3D11UnorderedAccessViewPtr UAView; + uint32 Width = 0; + uint32 Height = 0; + uint32 Depth = 0; + uint32 NumMipLevels = 0; + DXGI_FORMAT Format; + bool32 AutoGenMipMaps = false; + + + void Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + uint32 depth, + DXGI_FORMAT format, + uint32 numMipLevels, + bool32 autoGenMipMaps, + bool32 createRTV, + bool32 createUAV); +}; + +struct DepthStencilBuffer +{ + ID3D11Texture2DPtr Texture; + ID3D11DepthStencilViewPtr DSView; + ID3D11DepthStencilViewPtr ReadOnlyDSView; + ID3D11ShaderResourceViewPtr SRView; + uint32 Width; + uint32 Height; + uint32 MultiSamples; + uint32 MSQuality; + DXGI_FORMAT Format; + uint32 ArraySize; + bool32 CubeMap; + std::vector ArraySlices; + + DepthStencilBuffer(); + + void Initialize( ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT, + bool32 useAsShaderResource = false, + uint32 multiSamples = 1, + uint32 msQuality = 0, + uint32 arraySize = 1, + bool32 cubeMap = false); +}; + +struct RWBuffer +{ + ID3D11BufferPtr Buffer; + ID3D11ShaderResourceViewPtr SRView; + ID3D11UnorderedAccessViewPtr UAView; + uint32 Size; + uint32 Stride; + uint32 NumElements; + bool32 RawBuffer; + DXGI_FORMAT Format; + + RWBuffer(); + + void Initialize(ID3D11Device* device, DXGI_FORMAT format, uint32 stride, uint32 numElements, bool32 rawBuffer = false, + bool vertexBuffer = false, bool indexBuffer = false, bool indirectArgs = false, + const void* initData = nullptr); +}; + +struct StagingBuffer +{ + ID3D11BufferPtr Buffer; + uint32 Size; + + StagingBuffer(); + + void Initialize(ID3D11Device* device, uint32 size); + void* Map(ID3D11DeviceContext* context); + void Unmap(ID3D11DeviceContext* context); +}; + +struct StagingTexture2D +{ + ID3D11Texture2DPtr Texture; + uint32 Width; + uint32 Height; + uint32 NumMipLevels; + uint32 MultiSamples; + uint32 MSQuality; + DXGI_FORMAT Format; + uint32 ArraySize; + + StagingTexture2D(); + + void Initialize( ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + uint32 numMipLevels = 1, + uint32 multiSamples = 1, + uint32 msQuality = 0, + uint32 arraySize = 1); + + void* Map(ID3D11DeviceContext* context, uint32 subResourceIndex, uint32& pitch); + void Unmap(ID3D11DeviceContext* context, uint32 subResourceIndex); +}; + +struct StructuredBuffer +{ + ID3D11BufferPtr Buffer; + ID3D11ShaderResourceViewPtr SRView; + ID3D11UnorderedAccessViewPtr UAView; + uint32 Size; + uint32 Stride; + uint32 NumElements; + StagingBuffer DebugBuffer; + + StructuredBuffer(); + + void Initialize(ID3D11Device* device, uint32 stride, uint32 numElements, bool32 useAsUAV = false, + bool32 appendConsume = false, bool32 hiddenCounter = false, const void* initData = nullptr); + + void WriteToFile(const wchar* path, ID3D11Device* device, ID3D11DeviceContext* context); + void ReadFromFile(const wchar* path, ID3D11Device* device); + + template void DebugPrint(ID3D11DeviceContext* context, const char* name) + { + Assert_(Buffer != nullptr); + if(DebugBuffer.Size != Size) + { + ID3D11DevicePtr device; + context->GetDevice(&device); + DebugBuffer.Initialize(device, Size); + } + + std::printf("%s\n", name); + + context->CopyResource(DebugBuffer.Buffer, Buffer); + const T* data = reinterpret_cast(DebugBuffer.Map(context)); + for(uint32 i = 0; i < NumElements; ++i) + { + std::string elemPrint = data[i].Print(); + std::printf(" [%u] %s", i, elemPrint.c_str()); + } + } +}; + +template class ConstantBuffer +{ +public: + + T Data; + + ID3D11BufferPtr Buffer; + bool GPUWritable; + +public: + + ConstantBuffer() : GPUWritable(false) + { + ZeroMemory(&Data, sizeof(T)); + } + + void Initialize(ID3D11Device* device, bool gpuWritable = false) + { + D3D11_BUFFER_DESC desc; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + desc.ByteWidth = static_cast(sizeof(T) + (16 - (sizeof(T) % 16))); + + if(gpuWritable) + { + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + } + GPUWritable = gpuWritable; + + DXCall(device->CreateBuffer(&desc, nullptr, &Buffer)); + } + + void ApplyChanges(ID3D11DeviceContext* deviceContext) + { + Assert_(Buffer != nullptr); + + if(GPUWritable) + { + deviceContext->UpdateSubresource(Buffer, 0, nullptr, &Data, 0, 0); + } + else + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + DXCall(deviceContext->Map(Buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)); + CopyMemory(mappedResource.pData, &Data, sizeof(T)); + deviceContext->Unmap(Buffer, 0); + } + } + + void SetVS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->VSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetPS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->PSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetGS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->GSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetHS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->HSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetDS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->DSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetCS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->CSSetConstantBuffers(slot, 1, bufferArray); + } +}; + +// For aligning to float4 boundaries +#define Float4Align __declspec(align(16)) + +class PIXEvent +{ +public: + + PIXEvent(const wchar* markerName) + { + D3DPERF_BeginEvent(0xFFFFFFFF, markerName); + } + + PIXEvent(const std::wstring& markerName) + { + D3DPERF_BeginEvent(0xFFFFFFFF, markerName.c_str()); + } + + ~PIXEvent() + { + D3DPERF_EndEvent(); + } +}; + } \ No newline at end of file From 3e443ed0abd9ebbf64a50d05898cfe01be11a1fb Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 26 Nov 2017 23:28:10 -0800 Subject: [PATCH 18/43] More work on probe basis modes --- BakingLab/BakingLab.cpp | 91 ++++++++++++++++++++++++++--------- BakingLab/Mesh.hlsl | 34 ++++++++++++- BakingLab/ProbeIntegrate.hlsl | 13 +++-- 3 files changed, 107 insertions(+), 31 deletions(-) diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 3f490cc..9456be4 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -689,7 +689,13 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) } else { - + for(uint64 i = 0; i < AppSettings::MaxBasisCount; ++i) + { + probeVolumeMaps[i].Initialize(device, AppSettings::ProbeResX, AppSettings::ProbeResY, AppSettings::ProbeResZ, + DXGI_FORMAT_R16G16B16A16_FLOAT, 1, false, false, true); + probeDistanceVolumeMaps[i].Initialize(device, AppSettings::ProbeResX, AppSettings::ProbeResY, AppSettings::ProbeResZ, + DXGI_FORMAT_R16G16_UNORM, 1, false, false, true); + } } } @@ -746,35 +752,76 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) ID3D11RenderTargetView* rtvs[2] = { }; context->OMSetRenderTargets(2, rtvs, nullptr); - SetCSInputs(context, probeCaptureMap.SRView); - SetCSOutputs(context, probeIrradianceCubeMap.UAView); - SetCSSamplers(context, samplerStates.LinearClamp()); - SetCSShader(context, probeIntegrateIrradianceCubeMap); + if(AppSettings::ProbeMode == ProbeModes::CubeMap) + { + SetCSInputs(context, probeCaptureMap.SRView); + SetCSOutputs(context, probeIrradianceCubeMap.UAView); + SetCSSamplers(context, samplerStates.LinearClamp()); + SetCSShader(context, probeIntegrateIrradianceCubeMap); + + integrateConstants.Data.OutputTextureSize.x = float(probeIrradianceCubeMap.Width); + integrateConstants.Data.OutputTextureSize.y = float(probeIrradianceCubeMap.Height); + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); + integrateConstants.ApplyChanges(context); + integrateConstants.SetCS(context, 0); - integrateConstants.Data.OutputTextureSize.x = float(probeIrradianceCubeMap.Width); - integrateConstants.Data.OutputTextureSize.y = float(probeIrradianceCubeMap.Height); - integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); - integrateConstants.ApplyChanges(context); - integrateConstants.SetCS(context, 0); + context->Dispatch(DispatchSize(8, probeIrradianceCubeMap.Width), DispatchSize(8, probeIrradianceCubeMap.Height), 6); - context->Dispatch(DispatchSize(8, probeIrradianceCubeMap.Width), DispatchSize(8, probeIrradianceCubeMap.Height), 6); + ClearCSInputs(context); + ClearCSOutputs(context); - ClearCSInputs(context); - ClearCSOutputs(context); + SetCSInputs(context, probeDistanceCaptureMap.SRView); + SetCSOutputs(context, probeDistanceCubeMap.UAView); + SetCSShader(context, probeIntegrateDistanceCubeMap); + + integrateConstants.Data.OutputTextureSize.x = float(probeDistanceCubeMap.Width); + integrateConstants.Data.OutputTextureSize.y = float(probeDistanceCubeMap.Height); + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); + integrateConstants.ApplyChanges(context); + + context->Dispatch(DispatchSize(8, probeDistanceCubeMap.Width), DispatchSize(8, probeDistanceCubeMap.Height), 6); + } + else + { + SetCSInputs(context, probeCaptureMap.SRView); + SetCSSamplers(context, samplerStates.LinearClamp()); + SetCSShader(context, probeIntegrateVolumeMap); + + ID3D11UnorderedAccessView* uavs[AppSettings::MaxBasisCount] = { }; + for(uint64 i = 0; i < AppSettings::MaxBasisCount; ++i) + uavs[i] = probeVolumeMaps[i].UAView; + context->CSSetUnorderedAccessViews(0, AppSettings::MaxBasisCount, uavs, nullptr); + + integrateConstants.Data.OutputTextureSize.x = 0.0f; + integrateConstants.Data.OutputTextureSize.y = 0.0f; + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); + integrateConstants.ApplyChanges(context); + integrateConstants.SetCS(context, 0); - SetCSInputs(context, probeDistanceCaptureMap.SRView); - SetCSOutputs(context, probeDistanceCubeMap.UAView); - SetCSShader(context, probeIntegrateDistanceCubeMap); + context->Dispatch(1, 1, 1); - integrateConstants.Data.OutputTextureSize.x = float(probeDistanceCubeMap.Width); - integrateConstants.Data.OutputTextureSize.y = float(probeDistanceCubeMap.Height); - integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); - integrateConstants.ApplyChanges(context); + ClearCSInputs(context); + ClearCSOutputs(context); - context->Dispatch(DispatchSize(8, probeDistanceCubeMap.Width), DispatchSize(8, probeDistanceCubeMap.Height), 6); + SetCSInputs(context, probeDistanceCaptureMap.SRView); + SetCSShader(context, probeIntegrateDistanceVolumeMap); + + for(uint64 i = 0; i < AppSettings::MaxBasisCount; ++i) + uavs[i] = probeDistanceVolumeMaps[i].UAView; + context->CSSetUnorderedAccessViews(0, AppSettings::MaxBasisCount, uavs, nullptr); + + integrateConstants.Data.OutputTextureSize.x = 0.0f; + integrateConstants.Data.OutputTextureSize.y = 0.0f; + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); + integrateConstants.ApplyChanges(context); + + context->Dispatch(1, 1, 1); + } ClearCSInputs(context); - ClearCSOutputs(context); + + ID3D11UnorderedAccessView* uavs[AppSettings::MaxBasisCount] = { }; + context->CSSetUnorderedAccessViews(0, AppSettings::MaxBasisCount, uavs, nullptr); ++currProbeIdx; diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 5ad6e1f..809ebd4 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -70,6 +70,8 @@ Texture3D SHSpecularLookupA : register(t7); Texture3D SHSpecularLookupB : register(t8); TextureCubeArray ProbeIrradianceCubeMaps : register(t9); TextureCubeArray ProbeDistanceCubeMaps : register(t10); +Texture3D ProbeVolumeMaps[MaxBasisCount]; +Texture3D ProbeDistanceVolumeMaps[MaxBasisCount]; SamplerState AnisoSampler : register(s0); SamplerState EVSMSampler : register(s1); @@ -473,7 +475,7 @@ void ComputeIndirectFromLightmap(in SurfaceContext surface, in float2 lightMapUV } } -void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) +void ComputeIndirectFromProbeCubeMaps(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) { float3 normalizedSamplePos = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); float3 probeDims = float3(ProbeResX, ProbeResY, ProbeResZ); @@ -523,6 +525,29 @@ void ComputeIndirectFromProbes(in SurfaceContext surface, out float3 indirectIrr indirectSpecular = 0.0f; } +void ComputeIndirectFromProbeVolumeMaps(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) +{ + float3 normalizedSamplePos = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); + float3 uvw = normalizedSamplePos; + + indirectIrradiance = 0.0f; + indirectSpecular = 0.0f; + + float3 cubeDirs[6] = { float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1), float3(-1, 0, 0), float3(0, -1, 0), float3(0, 0, -1) }; + float weightSum = 0.0f; + + [unroll] + for(uint i = 0; i < 6; ++i) + { + float weight = saturate(dot(surface.NormalWS, cubeDirs[i])); + if(weight > 0.0f) + indirectIrradiance += ProbeVolumeMaps[i].SampleLevel(LinearSampler, uvw, 0.0f).xyz * weight; + weightSum += weight; + } + + indirectIrradiance /= weightSum; +} + //================================================================================================= // Pixel Shader //================================================================================================= @@ -617,7 +642,12 @@ PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) float3 indirectSpecular = 0.0f; if(UseProbes || ProbeRendering_) - ComputeIndirectFromProbes(surface, indirectIrradiance, indirectSpecular); + { + if(ProbeMode == ProbeModes_CubeMap) + ComputeIndirectFromProbeCubeMaps(surface, indirectIrradiance, indirectSpecular); + else + ComputeIndirectFromProbeVolumeMaps(surface, indirectIrradiance, indirectSpecular); + } else ComputeIndirectFromLightmap(surface, input.LightMapUV, indirectIrradiance, indirectSpecular); diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl index 7019e92..d62b76c 100644 --- a/BakingLab/ProbeIntegrate.hlsl +++ b/BakingLab/ProbeIntegrate.hlsl @@ -170,12 +170,12 @@ void IntegrateOntoBasis(in float3 dir, in float3 value, inout float3 output[MaxB { if(ProbeMode == ProbeModes_AmbientCube) { - output[0] += value * dir.x; - output[1] += value * dir.y; - output[2] += value * dir.z; - output[3] += value * -dir.x; - output[4] += value * -dir.y; - output[5] += value * -dir.z; + output[0] += value * saturate(dir.x); + output[1] += value * saturate(dir.y); + output[2] += value * saturate(dir.z); + output[3] += value * saturate(-dir.x); + output[4] += value * saturate(-dir.y); + output[5] += value * saturate(-dir.z); } } @@ -235,7 +235,6 @@ void IntegrateVolumeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : float3 sampleDir = SampleDirectionSphere(samplePos.x, samplePos.y); float3 radiance = RadianceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f).xyz; - IntegrateOntoBasis(sampleDir, radiance, output); } From 4e809f6cbdc0d51906c76a05824e5c03d2dc8abf Mon Sep 17 00:00:00 2001 From: MJP Date: Mon, 27 Nov 2017 22:57:23 -0800 Subject: [PATCH 19/43] Updated the probe visualizer to work with basis modes --- BakingLab/Mesh.hlsl | 4 ++-- BakingLab/MeshRenderer.cpp | 2 +- BakingLab/ProbeVisualizer.hlsl | 44 ++++++++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 809ebd4..8870978 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -533,13 +533,13 @@ void ComputeIndirectFromProbeVolumeMaps(in SurfaceContext surface, out float3 in indirectIrradiance = 0.0f; indirectSpecular = 0.0f; - float3 cubeDirs[6] = { float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1), float3(-1, 0, 0), float3(0, -1, 0), float3(0, 0, -1) }; + float3 ambientCubeDirs[6] = { float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1), float3(-1, 0, 0), float3(0, -1, 0), float3(0, 0, -1) }; float weightSum = 0.0f; [unroll] for(uint i = 0; i < 6; ++i) { - float weight = saturate(dot(surface.NormalWS, cubeDirs[i])); + float weight = saturate(dot(surface.NormalWS, ambientCubeDirs[i])); if(weight > 0.0f) indirectIrradiance += ProbeVolumeMaps[i].SampleLevel(LinearSampler, uvw, 0.0f).xyz * weight; weightSum += weight; diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index 7f658dd..b672e61 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -342,7 +342,7 @@ void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context GenerateHemisphere(16, 4, device, hemisphereVB, hemisphereIB, numHemisphereIndices); - GenerateSphere(256, 192, device, sphereVB, sphereIB, numSphereIndices); + GenerateSphere(16, 8, device, sphereVB, sphereIB, numSphereIndices); D3D11_INPUT_ELEMENT_DESC elements[1]; elements[0].AlignedByteOffset = 0; diff --git a/BakingLab/ProbeVisualizer.hlsl b/BakingLab/ProbeVisualizer.hlsl index c567c30..33dd86b 100644 --- a/BakingLab/ProbeVisualizer.hlsl +++ b/BakingLab/ProbeVisualizer.hlsl @@ -31,8 +31,10 @@ cbuffer Constants : register(b0) //================================================================================================= // Resources //================================================================================================= -TextureCubeArray ProbeIrradiance : register(t0); -TextureCubeArray ProbeDistance : register(t1); +TextureCubeArray ProbeIrradianceCubeMap : register(t0); +TextureCubeArray ProbeDistanceCubeMap : register(t1); +Texture3D ProbeVolumeMaps[MaxBasisCount]; +Texture3D ProbeDistanceVolumeMaps[MaxBasisCount]; SamplerState LinearSampler : register(s0); //================================================================================================= @@ -42,6 +44,7 @@ struct VSOutput { float4 PositionCS : SV_Position; float3 NormalWS : NORMALWS; + float3 ProbeUVW : PROBEUVW; uint ProbeIdx : PROBEIDX; }; @@ -49,6 +52,7 @@ struct PSInput { float4 PositionSS : SV_Position; float3 NormalWS : NORMALWS; + float3 ProbeUVW : PROBEUVW; uint ProbeIdx : PROBEIDX; }; @@ -66,16 +70,15 @@ VSOutput VS(in float3 SpherePosition : POSITION, in uint InstanceID : SV_Instanc uint probeY = (InstanceID / ProbeResX) % ProbeResY; uint probeZ = InstanceID / (ProbeResX * ProbeResY); - float3 probePos; - probePos.x = lerp(SceneMinBounds.x, SceneMaxBounds.x, (probeX + 0.5f) / ProbeResX); - probePos.y = lerp(SceneMinBounds.y, SceneMaxBounds.y, (probeY + 0.5f) / ProbeResY); - probePos.z = lerp(SceneMinBounds.z, SceneMaxBounds.z, (probeZ + 0.5f) / ProbeResZ); + float3 probeUVW = (float3(probeX, probeY, probeZ) + 0.5f) / float3(ProbeResX, ProbeResY, ProbeResZ); + float3 probePos = lerp(SceneMinBounds, SceneMaxBounds, probeUVW); float3 cellSizes = (SceneMaxBounds - SceneMinBounds) / float3(ProbeResX, ProbeResZ, ProbeResZ); float probeSize = 0.15f * min(min(cellSizes.x, cellSizes.y), cellSizes.z); float3 vtxPositionWS = (SpherePosition * probeSize) + probePos; output.PositionCS = mul(float4(vtxPositionWS, 1.0f), ViewProjection); + output.ProbeUVW = probeUVW; return output; } @@ -85,8 +88,29 @@ VSOutput VS(in float3 SpherePosition : POSITION, in uint InstanceID : SV_Instanc //================================================================================================= float4 PS(in PSInput input) : SV_Target0 { - float3 irradiance = ProbeIrradiance.Sample(LinearSampler, float4(input.NormalWS, input.ProbeIdx)).xyz; - float2 distance = ProbeDistance.Sample(LinearSampler, float4(input.NormalWS, input.ProbeIdx)); - return float4(irradiance * InvPi, 0.0f); - // return float4(distance * 0.01f, 0.0f, 1.0f); + float3 output = 0.0f; + + if(ProbeMode == ProbeModes_CubeMap) + { + output = ProbeIrradianceCubeMap.Sample(LinearSampler, float4(input.NormalWS, input.ProbeIdx)).xyz * InvPi; + } + else if(ProbeMode == ProbeModes_AmbientCube) + { + float3 ambientCubeDirs[6] = { float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1), float3(-1, 0, 0), float3(0, -1, 0), float3(0, 0, -1) }; + + float weightSum = 0.0f; + + [unroll] + for(uint i = 0; i < 6; ++i) + { + float weight = saturate(dot(input.NormalWS, ambientCubeDirs[i])); + if(weight > 0.0f) + output += ProbeVolumeMaps[i].SampleLevel(LinearSampler, input.ProbeUVW, 0.0f).xyz * weight; + weightSum += weight; + } + + output *= rcp(weightSum) * InvPi; + } + + return float4(output, 1.0f); } \ No newline at end of file From 57fc91ba02f8a554a6023ae46dadf04584c7cc10 Mon Sep 17 00:00:00 2001 From: MJP Date: Mon, 27 Nov 2017 23:12:50 -0800 Subject: [PATCH 20/43] Changed default probe settings --- BakingLab/AppSettings.cpp | 4 ++-- BakingLab/AppSettings.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 06d3cfe..b816ee2 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -546,10 +546,10 @@ namespace AppSettings SceneBoundsScale.Initialize(tweakBar, "SceneBoundsScale", "Probes", "Scene Bounds Scale", "", 1.2500f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); Settings.AddSetting(&SceneBoundsScale); - WeightProbesByNormal.Initialize(tweakBar, "WeightProbesByNormal", "Probes", "Weight Probes By Normal", "", true); + WeightProbesByNormal.Initialize(tweakBar, "WeightProbesByNormal", "Probes", "Weight Probes By Normal", "", false); Settings.AddSetting(&WeightProbesByNormal); - WeightProbesByVisibility.Initialize(tweakBar, "WeightProbesByVisibility", "Probes", "Weight Probes By Visibility", "", true); + WeightProbesByVisibility.Initialize(tweakBar, "WeightProbesByVisibility", "Probes", "Weight Probes By Visibility", "", false); Settings.AddSetting(&WeightProbesByVisibility); DistanceFilterSharpness.Initialize(tweakBar, "DistanceFilterSharpness", "Probes", "Distance Filter Sharpness", "", 10.0000f, 1.0000f, 20.0000f, 0.0100f, ConversionMode::None, 1.0000f); diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 927111f..02f1621 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -700,9 +700,9 @@ public class Probes [UseAsShaderConstant(false)] float SceneBoundsScale = 1.25f; - bool WeightProbesByNormal = true; + bool WeightProbesByNormal = false; - bool WeightProbesByVisibility = true; + bool WeightProbesByVisibility = false; [MinValue(1.0f)] [MaxValue(20.0f)] From b00c1469723122cccb8ca73f970177f820173a85 Mon Sep 17 00:00:00 2001 From: MJP Date: Tue, 28 Nov 2017 00:01:11 -0800 Subject: [PATCH 21/43] Added SH probe modes --- BakingLab/AppSettings.cpp | 6 ++- BakingLab/AppSettings.cs | 8 +++- BakingLab/AppSettings.h | 4 +- BakingLab/AppSettings.hlsl | 2 + BakingLab/Mesh.hlsl | 83 ++++++++++++++++++++++++++++++---- BakingLab/ProbeIntegrate.hlsl | 17 +++++++ BakingLab/ProbeVisualizer.hlsl | 20 ++++++++ 7 files changed, 126 insertions(+), 14 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index b816ee2..143caf4 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -161,10 +161,12 @@ static const char* SolveModesLabels[3] = "Non-Negative Least Squares", }; -static const char* ProbeModesLabels[2] = +static const char* ProbeModesLabels[4] = { "CubeMap", "AmbientCube", + "L1 SH", + "L2 SH", }; static const char* ScenesLabels[3] = @@ -522,7 +524,7 @@ namespace AppSettings UseProbes.Initialize(tweakBar, "UseProbes", "Probes", "Use Probes", "", true); Settings.AddSetting(&UseProbes); - ProbeMode.Initialize(tweakBar, "ProbeMode", "Probes", "Probe Mode", "", ProbeModes::CubeMap, 2, ProbeModesLabels); + ProbeMode.Initialize(tweakBar, "ProbeMode", "Probes", "Probe Mode", "", ProbeModes::CubeMap, 4, ProbeModesLabels); Settings.AddSetting(&ProbeMode); ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 4, 1, 2048); diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 02f1621..74f4953 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -303,7 +303,13 @@ enum SGDiffuseModes enum ProbeModes { CubeMap, - AmbientCube + AmbientCube, + + [EnumLabel("L1 SH")] + L1_SH, + + [EnumLabel("L2 SH")] + L2_SH, } public class Settings diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index 9d88f58..d6b4bdd 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -227,6 +227,8 @@ enum class ProbeModes { CubeMap = 0, AmbientCube = 1, + L1_SH = 2, + L2_SH = 3, NumValues }; @@ -632,7 +634,7 @@ namespace AppSettings inline uint64 ProbeBasisCount(uint64 probeMode) { Assert_(probeMode < uint64(ProbeModes::NumValues)); - static const uint64 BasisCounts[] = { 1, 6, }; // 4, 9, 4, 6, 5, 6, 9, 12 }; + static const uint64 BasisCounts[] = { 1, 6, 4, 9 }; StaticAssert_(ArraySize_(BasisCounts) == uint64(ProbeModes::NumValues)); Assert_(BasisCounts[probeMode] <= MaxBasisCount); return BasisCounts[probeMode]; diff --git a/BakingLab/AppSettings.hlsl b/BakingLab/AppSettings.hlsl index 0dc6264..a2ec95d 100644 --- a/BakingLab/AppSettings.hlsl +++ b/BakingLab/AppSettings.hlsl @@ -189,6 +189,8 @@ static const int SolveModes_NNLS = 2; static const int ProbeModes_CubeMap = 0; static const int ProbeModes_AmbientCube = 1; +static const int ProbeModes_L1_SH = 2; +static const int ProbeModes_L2_SH = 3; static const int Scenes_Box = 0; static const int Scenes_WhiteRoom = 1; diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 8870978..1618b67 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -525,6 +525,73 @@ void ComputeIndirectFromProbeCubeMaps(in SurfaceContext surface, out float3 indi indirectSpecular = 0.0f; } +float3 EvaluateProbeIrradiance(in float3 basis[MaxBasisCount], in float3 dir) +{ + float3 output = 0.0f; + + if(ProbeMode == ProbeModes_AmbientCube) + { + float3 ambientCubeDirs[6] = { float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1), float3(-1, 0, 0), float3(0, -1, 0), float3(0, 0, -1) }; + float weightSum = 0.0f; + + [unroll] + for(uint i = 0; i < 6; ++i) + { + float weight = saturate(dot(dir, ambientCubeDirs[i])); + output += basis[i] * weight; + weightSum += weight; + } + + output /= weightSum; + } + else if(ProbeMode == ProbeModes_L1_SH) + { + SH4Color sh; + + [unroll] + for(uint i = 0; i < 4; ++i) + sh.c[i] = basis[i]; + + output = EvalSH4Irradiance(dir, sh); + } + else if(ProbeMode == ProbeModes_L2_SH) + { + SH9Color sh; + + [unroll] + for(uint i = 0; i < 9; ++i) + sh.c[i] = basis[i]; + + + output = EvalSH9Irradiance(dir, sh); + } + + return output; +} + + +void SampleVolumeTextures(in SurfaceContext surface, in float3 uvw, out float3 basis[MaxBasisCount]) +{ + if(ProbeMode == ProbeModes_AmbientCube) + { + [unroll] + for(uint i = 0; i < 6; ++i) + basis[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, uvw, 0.0f).xyz; + } + else if(ProbeMode == ProbeModes_L1_SH) + { + [unroll] + for(uint i = 0; i < 4; ++i) + basis[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, uvw, 0.0f).xyz; + } + else if(ProbeMode == ProbeModes_L2_SH) + { + [unroll] + for(uint i = 0; i < 9; ++i) + basis[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, uvw, 0.0f).xyz; + } +} + void ComputeIndirectFromProbeVolumeMaps(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) { float3 normalizedSamplePos = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); @@ -533,19 +600,15 @@ void ComputeIndirectFromProbeVolumeMaps(in SurfaceContext surface, out float3 in indirectIrradiance = 0.0f; indirectSpecular = 0.0f; - float3 ambientCubeDirs[6] = { float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1), float3(-1, 0, 0), float3(0, -1, 0), float3(0, 0, -1) }; - float weightSum = 0.0f; + float3 basis[MaxBasisCount]; [unroll] - for(uint i = 0; i < 6; ++i) - { - float weight = saturate(dot(surface.NormalWS, ambientCubeDirs[i])); - if(weight > 0.0f) - indirectIrradiance += ProbeVolumeMaps[i].SampleLevel(LinearSampler, uvw, 0.0f).xyz * weight; - weightSum += weight; - } + for(uint i = 0; i < uint(MaxBasisCount); ++i) + basis[i] = 0.0f; + + SampleVolumeTextures(surface, uvw, basis); - indirectIrradiance /= weightSum; + indirectIrradiance = EvaluateProbeIrradiance(basis, surface.NormalWS); } //================================================================================================= diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl index d62b76c..64cf797 100644 --- a/BakingLab/ProbeIntegrate.hlsl +++ b/BakingLab/ProbeIntegrate.hlsl @@ -9,6 +9,7 @@ //================================================================================================= #include +#include #include "AppSettings.hlsl" cbuffer IntegrateConstants : register(b0) @@ -177,6 +178,22 @@ void IntegrateOntoBasis(in float3 dir, in float3 value, inout float3 output[MaxB output[4] += value * saturate(-dir.y); output[5] += value * saturate(-dir.z); } + else if(ProbeMode == ProbeModes_L1_SH) + { + SH4Color sh = ProjectOntoSH4Color(dir, value); + + [unroll] + for(uint i = 0; i < 4; ++i) + output[i] += sh.c[i]; + } + else if(ProbeMode == ProbeModes_L2_SH) + { + SH9Color sh = ProjectOntoSH9Color(dir, value); + + [unroll] + for(uint i = 0; i < 9; ++i) + output[i] += sh.c[i]; + } } // ================================================================================================ diff --git a/BakingLab/ProbeVisualizer.hlsl b/BakingLab/ProbeVisualizer.hlsl index 33dd86b..a32424c 100644 --- a/BakingLab/ProbeVisualizer.hlsl +++ b/BakingLab/ProbeVisualizer.hlsl @@ -111,6 +111,26 @@ float4 PS(in PSInput input) : SV_Target0 output *= rcp(weightSum) * InvPi; } + else if(ProbeMode == ProbeModes_L1_SH) + { + SH4Color sh; + + [unroll] + for(uint i = 0; i < 4; ++i) + sh.c[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, input.ProbeUVW, 0.0f).xyz; + + output = EvalSH4(input.NormalWS, sh); + } + else if(ProbeMode == ProbeModes_L2_SH) + { + SH9Color sh; + + [unroll] + for(uint i = 0; i < 9; ++i) + sh.c[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, input.ProbeUVW, 0.0f).xyz; + + output = EvalSH9(input.NormalWS, sh); + } return float4(output, 1.0f); } \ No newline at end of file From 114d4aae7833e04ef4b183855f0beb2ddbc72a34 Mon Sep 17 00:00:00 2001 From: MJP Date: Tue, 28 Nov 2017 23:23:29 -0800 Subject: [PATCH 22/43] WIP VCT baking --- BakingLab/AppSettings.cpp | 28 ++++++++++++-- BakingLab/AppSettings.cs | 24 ++++++++++-- BakingLab/AppSettings.h | 8 ++++ BakingLab/AppSettings.hlsl | 4 ++ BakingLab/BakingLab.cpp | 30 +++++++++++++-- BakingLab/BakingLab.h | 1 + BakingLab/Mesh.hlsl | 75 +++++++++++++++++++++++--------------- BakingLab/MeshRenderer.cpp | 26 ++++++++++--- BakingLab/MeshRenderer.h | 6 +-- 9 files changed, 156 insertions(+), 46 deletions(-) diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 143caf4..c44985c 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -259,6 +259,10 @@ namespace AppSettings BoolSetting WeightProbesByNormal; BoolSetting WeightProbesByVisibility; FloatSetting DistanceFilterSharpness; + BoolSetting BakeWithVCT; + IntSetting VoxelResX; + IntSetting VoxelResY; + IntSetting VoxelResZ; ScenesSetting CurrentScene; BoolSetting EnableDiffuse; BoolSetting EnableSpecular; @@ -515,13 +519,13 @@ namespace AppSettings BakeRussianRouletteProbability.Initialize(tweakBar, "BakeRussianRouletteProbability", "Baking", "Russian Roullette Probability", "Maximum probability for continuing when Russian roulette is used", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); Settings.AddSetting(&BakeRussianRouletteProbability); - BakeMode.Initialize(tweakBar, "BakeMode", "Baking", "Bake Mode", "", BakeModes::SG9, 10, BakeModesLabels); + BakeMode.Initialize(tweakBar, "BakeMode", "Baking", "Bake Mode", "", BakeModes::H4, 10, BakeModesLabels); Settings.AddSetting(&BakeMode); SolveMode.Initialize(tweakBar, "SolveMode", "Baking", "Solve Mode", "", SolveModes::NNLS, 3, SolveModesLabels); Settings.AddSetting(&SolveMode); - UseProbes.Initialize(tweakBar, "UseProbes", "Probes", "Use Probes", "", true); + UseProbes.Initialize(tweakBar, "UseProbes", "Probes", "Use Probes", "", false); Settings.AddSetting(&UseProbes); ProbeMode.Initialize(tweakBar, "ProbeMode", "Probes", "Probe Mode", "", ProbeModes::CubeMap, 4, ProbeModesLabels); @@ -557,6 +561,18 @@ namespace AppSettings DistanceFilterSharpness.Initialize(tweakBar, "DistanceFilterSharpness", "Probes", "Distance Filter Sharpness", "", 10.0000f, 1.0000f, 20.0000f, 0.0100f, ConversionMode::None, 1.0000f); Settings.AddSetting(&DistanceFilterSharpness); + BakeWithVCT.Initialize(tweakBar, "BakeWithVCT", "VCT", "Bake With VCT", "", false); + Settings.AddSetting(&BakeWithVCT); + + VoxelResX.Initialize(tweakBar, "VoxelResX", "VCT", "Voxel Res X", "", 32, 1, 2048); + Settings.AddSetting(&VoxelResX); + + VoxelResY.Initialize(tweakBar, "VoxelResY", "VCT", "Voxel Res Y", "", 32, 1, 2048); + Settings.AddSetting(&VoxelResY); + + VoxelResZ.Initialize(tweakBar, "VoxelResZ", "VCT", "Voxel Res Z", "", 32, 1, 2048); + Settings.AddSetting(&VoxelResZ); + CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); Settings.AddSetting(&CurrentScene); @@ -575,7 +591,7 @@ namespace AppSettings EnableIndirectDiffuse.Initialize(tweakBar, "EnableIndirectDiffuse", "Scene", "Enable Indirect Diffuse", "Enables indirect diffuse lighting", true); Settings.AddSetting(&EnableIndirectDiffuse); - EnableIndirectSpecular.Initialize(tweakBar, "EnableIndirectSpecular", "Scene", "Enable Indirect Specular", "Enables indirect specular lighting", true); + EnableIndirectSpecular.Initialize(tweakBar, "EnableIndirectSpecular", "Scene", "Enable Indirect Specular", "Enables indirect specular lighting", false); Settings.AddSetting(&EnableIndirectSpecular); EnableAlbedoMaps.Initialize(tweakBar, "EnableAlbedoMaps", "Scene", "Enable Albedo Maps", "Enables albedo maps", true); @@ -677,6 +693,8 @@ namespace AppSettings TwHelper::SetOpened(tweakBar, "Probes", true); + TwHelper::SetOpened(tweakBar, "VCT", true); + TwHelper::SetOpened(tweakBar, "Scene", false); TwHelper::SetOpened(tweakBar, "Ground Truth", false); @@ -757,6 +775,10 @@ namespace AppSettings CBuffer.Data.WeightProbesByNormal = WeightProbesByNormal; CBuffer.Data.WeightProbesByVisibility = WeightProbesByVisibility; CBuffer.Data.DistanceFilterSharpness = DistanceFilterSharpness; + CBuffer.Data.BakeWithVCT = BakeWithVCT; + CBuffer.Data.VoxelResX = VoxelResX; + CBuffer.Data.VoxelResY = VoxelResY; + CBuffer.Data.VoxelResZ = VoxelResZ; CBuffer.Data.EnableDiffuse = EnableDiffuse; CBuffer.Data.EnableSpecular = EnableSpecular; CBuffer.Data.EnableDirectLighting = EnableDirectLighting; diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 74f4953..a60073b 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -667,7 +667,7 @@ public class Baking [DisplayName("Russian Roullette Probability")] float BakeRussianRouletteProbability = 0.5f; - BakeModes BakeMode = BakeModes.SG9; + BakeModes BakeMode = BakeModes.H4; SolveModes SolveMode = SolveModes.NNLS; } @@ -675,7 +675,7 @@ public class Baking [ExpandGroup(true)] public class Probes { - bool UseProbes = true; + bool UseProbes = false; ProbeModes ProbeMode = ProbeModes.CubeMap; @@ -715,6 +715,24 @@ public class Probes float DistanceFilterSharpness = 10.0f; } + [ExpandGroup(true)] + public class VCT + { + bool BakeWithVCT = false; + + [MinValue(1)] + [MaxValue(2048)] + int VoxelResX = 32; + + [MinValue(1)] + [MaxValue(2048)] + int VoxelResY = 32; + + [MinValue(1)] + [MaxValue(2048)] + int VoxelResZ = 32; + } + [ExpandGroup(false)] public class Scene { @@ -743,7 +761,7 @@ public class Scene [DisplayName("Enable Indirect Specular")] [HelpText("Enables indirect specular lighting")] - bool EnableIndirectSpecular = true; + bool EnableIndirectSpecular = false; [DisplayName("Enable Albedo Maps")] [HelpText("Enables albedo maps")] diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index d6b4bdd..40e0a74 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -333,6 +333,10 @@ namespace AppSettings extern BoolSetting WeightProbesByNormal; extern BoolSetting WeightProbesByVisibility; extern FloatSetting DistanceFilterSharpness; + extern BoolSetting BakeWithVCT; + extern IntSetting VoxelResX; + extern IntSetting VoxelResY; + extern IntSetting VoxelResZ; extern ScenesSetting CurrentScene; extern BoolSetting EnableDiffuse; extern BoolSetting EnableSpecular; @@ -428,6 +432,10 @@ namespace AppSettings bool32 WeightProbesByNormal; bool32 WeightProbesByVisibility; float DistanceFilterSharpness; + bool32 BakeWithVCT; + int32 VoxelResX; + int32 VoxelResY; + int32 VoxelResZ; bool32 EnableDiffuse; bool32 EnableSpecular; bool32 EnableDirectLighting; diff --git a/BakingLab/AppSettings.hlsl b/BakingLab/AppSettings.hlsl index a2ec95d..3ada977 100644 --- a/BakingLab/AppSettings.hlsl +++ b/BakingLab/AppSettings.hlsl @@ -58,6 +58,10 @@ cbuffer AppSettings : register(b7) bool WeightProbesByNormal; bool WeightProbesByVisibility; float DistanceFilterSharpness; + bool BakeWithVCT; + int VoxelResX; + int VoxelResY; + int VoxelResZ; bool EnableDiffuse; bool EnableSpecular; bool EnableDirectLighting; diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 9456be4..1e38e5d 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -819,7 +819,7 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) } ClearCSInputs(context); - + ID3D11UnorderedAccessView* uavs[AppSettings::MaxBasisCount] = { }; context->CSSetUnorderedAccessViews(0, AppSettings::MaxBasisCount, uavs, nullptr); @@ -831,6 +831,30 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) currProbeIdx = 0; } +void BakingLab::VoxelizeScene() +{ + PIXEvent pixEvent(L"Voxelize Scene"); + + OrthographicCamera voxelCameraZ(currSceneMin.x, currSceneMin.y, currSceneMax.x, currSceneMax.y, 0.0f, currSceneMax.z - currSceneMax.z); + voxelCameraZ.SetPosition(Float3((currSceneMin.x + currSceneMax.x) / 2.0f, (currSceneMin.y + currSceneMax.y) / 2.0f, currSceneMin.z)); + + OrthographicCamera voxelCameraX = voxelCameraZ; + voxelCameraX.SetPosition(Float3(currSceneMin.x, (currSceneMin.y + currSceneMax.y) / 2.0f, (currSceneMin.z + currSceneMax.z) / 2.0f)); + voxelCameraX.SetOrientation(Quaternion::FromAxisAngle(Float3(0.0f, 1.0f, 0.0f), Pi_2)); + + OrthographicCamera voxelCameraY = voxelCameraZ; + voxelCameraY.SetPosition(Float3((currSceneMin.x + currSceneMax.x) / 2.0f, currSceneMin.y, (currSceneMin.z + currSceneMax.z) / 2.0f)); + voxelCameraY.SetOrientation(Quaternion::FromAxisAngle(Float3(1.0f, 0.0f, 0.0f), -Pi_2)); + + ID3D11DeviceContext* context = deviceManager.ImmediateContext(); + + if(AppSettings::EnableSun) + meshRenderer.RenderSunShadowMap(context, voxelCameraZ, false); + + if(AppSettings::EnableAreaLight) + meshRenderer.RenderAreaLightShadowMap(context, voxelCameraZ); +} + void BakingLab::Render(const Timer& timer) { if(AppSettings::MSAAMode.Changed()) @@ -921,7 +945,7 @@ void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetVie meshRenderer.ReduceDepth(context, depth, cam); if(AppSettings::EnableSun) - meshRenderer.RenderSunShadowMap(context, cam); + meshRenderer.RenderSunShadowMap(context, cam, true); if(AppSettings::EnableAreaLight) meshRenderer.RenderAreaLightShadowMap(context, cam); @@ -938,7 +962,7 @@ void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetVie context->ClearRenderTargetView(colorTarget, clearColor); context->ClearRenderTargetView(secondRT, secondClearColor); - meshRenderer.RenderMainPass(context, cam, status, probeRendering); + meshRenderer.RenderMainPass(context, cam, status, probeRendering, false); if(showBakeDataVisualizer) meshRenderer.RenderBakeDataVisualizer(context, cam, status); diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index e08d2ad..c6946ee 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -125,6 +125,7 @@ class BakingLab : public App void CreateRenderTargets(); void RenderProbes(MeshBakerStatus& status); + void VoxelizeScene(); void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* secondRT, const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, bool32 renderAreaLight, bool32 enableSkySun, bool32 probeRendering); diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 1618b67..437f934 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -78,6 +78,10 @@ SamplerState EVSMSampler : register(s1); SamplerState LinearSampler : register(s2); SamplerComparisonState PCFSampler : register(s3); +#if Voxelize_ + RWTexture3D VoxelOutput[2] : register(u0); +#endif + //================================================================================================= // Input/Output structs //================================================================================================= @@ -119,15 +123,19 @@ struct PSInput float3 PrevPosition : PREVPOSITION; }; -struct PSOutput -{ - float4 Lighting : SV_Target0; - #if ProbeRendering_ - float2 ProbeDistance : SV_Target1; - #else - float2 Velocity : SV_Target1; - #endif -}; +#if Voxelize_ + #define PSOutput void +#else + struct PSOutput + { + float4 Lighting : SV_Target0; + #if ProbeRendering_ + float2 ProbeDistance : SV_Target1; + #else + float2 Velocity : SV_Target1; + #endif + }; +#endif //================================================================================================= // Vertex Shader @@ -143,8 +151,7 @@ VSOutput VS(in VSInput input, in uint VertexID : SV_VertexID) // Calc the clip-space position output.PositionCS = mul(float4(positionOS, 1.0f), WorldViewProjection); - output.DepthVS = output.PositionCS.w; - + output.DepthVS = mul(float4(output.PositionWS, 1.0f), View).z; // Rotate the normal into world space output.NormalWS = normalize(mul(input.NormalOS, (float3x3)World)); @@ -699,7 +706,7 @@ PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) } // Add in the indirect - if(EnableIndirectLighting || ViewIndirectSpecular) + if((EnableIndirectLighting || ViewIndirectSpecular) && Voxelize_ == false) { float3 indirectIrradiance = 0.0f; float3 indirectSpecular = 0.0f; @@ -729,24 +736,34 @@ PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) float illuminance = dot(irradiance, float3(0.2126f, 0.7152f, 0.0722f)); - PSOutput output; - output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); + #if Voxelize_ + float3 voxelRadiance = clamp(irradiance * surface.DiffuseAlbedo * InvPi, 0.0f, FP16Max); + float3 voxelUVW = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); + uint3 voxelCoord = uint3(voxelUVW * float3(VoxelResX, VoxelResY, VoxelResZ)); + if(isFrontFace) + VoxelOutput[0][voxelCoord] = float4(voxelRadiance, 1.0f); + else + VoxelOutput[1][voxelCoord] = float4(voxelRadiance, 1.0f); + #else + PSOutput output; + output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); - if(isFrontFace == false) - output.Lighting = 0.0f; + if(isFrontFace == false) + output.Lighting = 0.0f; - #if ProbeRendering_ - float distanceFromProbe = length(surface.PositionWS - CameraPosWS); - float maxDistance = length((SceneMaxBounds - SceneMinBounds) * rcp(float3(ProbeResX, ProbeResY, ProbeResZ))); - distanceFromProbe = saturate(distanceFromProbe * rcp(maxDistance)); - output.ProbeDistance = float2(distanceFromProbe, distanceFromProbe * distanceFromProbe); - #else - float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; - prevPositionSS *= RTSize; - output.Velocity = input.PositionSS.xy - prevPositionSS; - output.Velocity -= JitterOffset; - output.Velocity /= RTSize; + #if ProbeRendering_ + float distanceFromProbe = length(surface.PositionWS - CameraPosWS); + float maxDistance = length((SceneMaxBounds - SceneMinBounds) * rcp(float3(ProbeResX, ProbeResY, ProbeResZ))); + distanceFromProbe = saturate(distanceFromProbe * rcp(maxDistance)); + output.ProbeDistance = float2(distanceFromProbe, distanceFromProbe * distanceFromProbe); + #else + float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; + prevPositionSS *= RTSize; + output.Velocity = input.PositionSS.xy - prevPositionSS; + output.Velocity -= JitterOffset; + output.Velocity /= RTSize; + #endif + + return output; #endif - - return output; } diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index b672e61..32fdd85 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -242,12 +242,19 @@ void MeshRenderer::LoadShaders() { CompileOptions opts; opts.Add("ProbeRendering_", 0); + opts.Add("Voxelize_", 0); meshVS = CompileVSFromFile(device, L"Mesh.hlsl", "VS", "vs_5_0", opts); meshPS[0] = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0", opts); opts.Reset(); opts.Add("ProbeRendering_", 1); + opts.Add("Voxelize_", 0); meshPS[1] = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0", opts); + + opts.Reset(); + opts.Add("ProbeRendering_", 0); + opts.Add("Voxelize_", 1); + meshPS[2] = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0", opts); } areaLightVS = CompileVSFromFile(device, L"AreaLight.hlsl", "VS", "vs_5_0"); @@ -603,8 +610,10 @@ void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx // Renders all meshes in the model, with shadows void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status, - bool32 probeRendering) + bool32 probeRendering, bool voxelizing) { + Assert_(probeRendering == false || voxelizing == false); + PIXEvent event(L"Mesh Rendering"); // Set states @@ -652,7 +661,14 @@ void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& ca context->HSSetShader(nullptr, nullptr, 0); context->GSSetShader(nullptr, nullptr, 0); context->VSSetShader(meshVS, nullptr, 0); - context->PSSetShader(meshPS[probeRendering ? 1 : 0], nullptr, 0); + + uint32 psIdx = 0; + if(voxelizing) + psIdx = 2; + else if(probeRendering) + psIdx = 1; + + context->PSSetShader(meshPS[psIdx], nullptr, 0); // Draw all meshes for(uint64 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) @@ -763,12 +779,12 @@ void MeshRenderer::RenderDepth(ID3D11DeviceContext* context, const Camera& camer } // Renders meshes using cascaded shadow mapping -void MeshRenderer::RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera) +void MeshRenderer::RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera, bool useReductionDepth) { PIXEvent event(L"Sun Shadow Map Rendering"); - const float MinDistance = reductionDepth.x; - const float MaxDistance = reductionDepth.y; + const float MinDistance = useReductionDepth ? reductionDepth.x : 0.0f; + const float MaxDistance = useReductionDepth ? reductionDepth.y : 1.0f; // Compute the split distances based on the partitioning mode float CascadeSplits[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; diff --git a/BakingLab/MeshRenderer.h b/BakingLab/MeshRenderer.h index 14f9377..3422aca 100644 --- a/BakingLab/MeshRenderer.h +++ b/BakingLab/MeshRenderer.h @@ -41,7 +41,7 @@ class MeshRenderer void RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange); void RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status, - bool32 probeRendering); + bool32 probeRendering, bool voxelizing); void Update(const Camera& camera, Float2 jitterOffset); @@ -50,7 +50,7 @@ class MeshRenderer void ReduceDepth(ID3D11DeviceContext* context, const DepthStencilBuffer& depthTarget, const Camera& camera); - void RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera); + void RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera, bool useReductionDepth); void RenderAreaLightShadowMap(ID3D11DeviceContext* context, const Camera& camera); void RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera); @@ -85,7 +85,7 @@ class MeshRenderer std::vector meshInputLayouts; VertexShaderPtr meshVS; - PixelShaderPtr meshPS[2]; + PixelShaderPtr meshPS[3]; std::vector meshDepthInputLayouts; VertexShaderPtr meshDepthVS; From 28f40dff76f5fac54654cd666191e0f774ef61b4 Mon Sep 17 00:00:00 2001 From: MJP Date: Wed, 29 Nov 2017 22:20:27 -0800 Subject: [PATCH 23/43] First pass at quick and dirty voxelization --- BakingLab/AppSettings.cpp | 14 + BakingLab/AppSettings.cs | 11 + BakingLab/AppSettings.h | 5 + BakingLab/AppSettings.hlsl | 2 + BakingLab/BakingLab.cpp | 79 ++++- BakingLab/BakingLab.h | 6 +- BakingLab/ClearVoxelTextures.hlsl | 19 ++ BakingLab/Mesh.hlsl | 6 +- BakingLab/MeshRenderer.cpp | 6 + BakingLab/ProbeIntegrate.hlsl | 12 +- SampleFramework11/v1.02/Graphics/Camera.h | 284 +++++++++--------- .../v1.02/Graphics/GraphicsTypes.h | 1 - 12 files changed, 289 insertions(+), 156 deletions(-) create mode 100644 BakingLab/ClearVoxelTextures.hlsl diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index c44985c..ce657f2 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -259,6 +259,8 @@ namespace AppSettings BoolSetting WeightProbesByNormal; BoolSetting WeightProbesByVisibility; FloatSetting DistanceFilterSharpness; + IntSetting ProbeIntegrationSamples; + IntSetting ProbeDistanceIntegrationSamples; BoolSetting BakeWithVCT; IntSetting VoxelResX; IntSetting VoxelResY; @@ -294,6 +296,7 @@ namespace AppSettings Button SaveEXRScreenshot; BoolSetting ShowSunIntensity; BoolSetting AlwaysRegenerateProbes; + BoolSetting AlwaysRevoxelize; FloatSetting SceneBoundsOffsetX; FloatSetting SceneBoundsOffsetY; FloatSetting SceneBoundsOffsetZ; @@ -561,6 +564,12 @@ namespace AppSettings DistanceFilterSharpness.Initialize(tweakBar, "DistanceFilterSharpness", "Probes", "Distance Filter Sharpness", "", 10.0000f, 1.0000f, 20.0000f, 0.0100f, ConversionMode::None, 1.0000f); Settings.AddSetting(&DistanceFilterSharpness); + ProbeIntegrationSamples.Initialize(tweakBar, "ProbeIntegrationSamples", "Probes", "Probe Integration Samples", "", 32, 1, 64); + Settings.AddSetting(&ProbeIntegrationSamples); + + ProbeDistanceIntegrationSamples.Initialize(tweakBar, "ProbeDistanceIntegrationSamples", "Probes", "Probe Distance Integration Samples", "", 32, 1, 64); + Settings.AddSetting(&ProbeDistanceIntegrationSamples); + BakeWithVCT.Initialize(tweakBar, "BakeWithVCT", "VCT", "Bake With VCT", "", false); Settings.AddSetting(&BakeWithVCT); @@ -666,6 +675,9 @@ namespace AppSettings AlwaysRegenerateProbes.Initialize(tweakBar, "AlwaysRegenerateProbes", "Debug", "Always Regenerate Probes", "", false); Settings.AddSetting(&AlwaysRegenerateProbes); + AlwaysRevoxelize.Initialize(tweakBar, "AlwaysRevoxelize", "Debug", "Always Revoxelize", "", false); + Settings.AddSetting(&AlwaysRevoxelize); + SceneBoundsOffsetX.Initialize(tweakBar, "SceneBoundsOffsetX", "Debug", "Scene Bounds Offset X", "", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); Settings.AddSetting(&SceneBoundsOffsetX); @@ -775,6 +787,8 @@ namespace AppSettings CBuffer.Data.WeightProbesByNormal = WeightProbesByNormal; CBuffer.Data.WeightProbesByVisibility = WeightProbesByVisibility; CBuffer.Data.DistanceFilterSharpness = DistanceFilterSharpness; + CBuffer.Data.ProbeIntegrationSamples = ProbeIntegrationSamples; + CBuffer.Data.ProbeDistanceIntegrationSamples = ProbeDistanceIntegrationSamples; CBuffer.Data.BakeWithVCT = BakeWithVCT; CBuffer.Data.VoxelResX = VoxelResX; CBuffer.Data.VoxelResY = VoxelResY; diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index a60073b..4bae325 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -713,6 +713,14 @@ public class Probes [MinValue(1.0f)] [MaxValue(20.0f)] float DistanceFilterSharpness = 10.0f; + + [MinValue(1)] + [MaxValue(64)] + int ProbeIntegrationSamples = 32; + + [MinValue(1)] + [MaxValue(64)] + int ProbeDistanceIntegrationSamples = 32; } [ExpandGroup(true)] @@ -893,6 +901,9 @@ public class Debug [UseAsShaderConstant(false)] bool AlwaysRegenerateProbes = false; + [UseAsShaderConstant(false)] + bool AlwaysRevoxelize = false; + [MinValue(-100.0f)] [MaxValue(100.0f)] [UseAsShaderConstant(false)] diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index 40e0a74..eec4810 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -333,6 +333,8 @@ namespace AppSettings extern BoolSetting WeightProbesByNormal; extern BoolSetting WeightProbesByVisibility; extern FloatSetting DistanceFilterSharpness; + extern IntSetting ProbeIntegrationSamples; + extern IntSetting ProbeDistanceIntegrationSamples; extern BoolSetting BakeWithVCT; extern IntSetting VoxelResX; extern IntSetting VoxelResY; @@ -368,6 +370,7 @@ namespace AppSettings extern Button SaveEXRScreenshot; extern BoolSetting ShowSunIntensity; extern BoolSetting AlwaysRegenerateProbes; + extern BoolSetting AlwaysRevoxelize; extern FloatSetting SceneBoundsOffsetX; extern FloatSetting SceneBoundsOffsetY; extern FloatSetting SceneBoundsOffsetZ; @@ -432,6 +435,8 @@ namespace AppSettings bool32 WeightProbesByNormal; bool32 WeightProbesByVisibility; float DistanceFilterSharpness; + int32 ProbeIntegrationSamples; + int32 ProbeDistanceIntegrationSamples; bool32 BakeWithVCT; int32 VoxelResX; int32 VoxelResY; diff --git a/BakingLab/AppSettings.hlsl b/BakingLab/AppSettings.hlsl index 3ada977..1de247a 100644 --- a/BakingLab/AppSettings.hlsl +++ b/BakingLab/AppSettings.hlsl @@ -58,6 +58,8 @@ cbuffer AppSettings : register(b7) bool WeightProbesByNormal; bool WeightProbesByVisibility; float DistanceFilterSharpness; + int ProbeIntegrationSamples; + int ProbeDistanceIntegrationSamples; bool BakeWithVCT; int VoxelResX; int VoxelResY; diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index 1e38e5d..a609b73 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -478,6 +478,8 @@ void BakingLab::Initialize() probeIntegrateVolumeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateVolumeMap"); probeIntegrateDistanceVolumeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateDistanceVolumeMap"); + clearVoxelTextures = CompileCSFromFile(device, L"ClearVoxelTextures.hlsl", "ClearVoxelTextures"); + resolveConstants.Initialize(device); backgroundVelocityConstants.Initialize(device); integrateConstants.Initialize(device); @@ -702,7 +704,8 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed() || AppSettings::AlwaysRegenerateProbes.Changed() || AppSettings::SceneBoundsOffsetX.Changed() || AppSettings::SceneBoundsOffsetY.Changed() || AppSettings::SceneBoundsOffsetZ.Changed() || - AppSettings::DistanceFilterSharpness.Changed()) + AppSettings::DistanceFilterSharpness.Changed() || AppSettings::ProbeIntegrationSamples.Changed() || + AppSettings::ProbeDistanceIntegrationSamples.Changed()) currProbeIdx = 0; if(currProbeIdx >= numProbes) @@ -711,6 +714,9 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) return; } + if(AppSettings::UseProbes == false) + return; + bool32 prevUseProbes = AppSettings::UseProbes; AppSettings::UseProbes.SetValue(false); @@ -831,11 +837,48 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) currProbeIdx = 0; } -void BakingLab::VoxelizeScene() +void BakingLab::VoxelizeScene(MeshBakerStatus& status) { + ID3D11Device* device = deviceManager.Device(); + ID3D11DeviceContext* context = deviceManager.ImmediateContext(); + + bool reVoxelize = false; + + if(status.BakingInvalidated || AppSettings::AlwaysRevoxelize) + reVoxelize = true; + + if(voxelTextures[0].Texture == nullptr || AppSettings::VoxelResX.Changed() || AppSettings::VoxelResY.Changed() || AppSettings::VoxelResZ.Changed()) + { + reVoxelize = true; + for(uint64 i = 0; i < 6; ++i) + voxelTextures[i].Initialize(device, AppSettings::VoxelResX, AppSettings::VoxelResY, AppSettings::VoxelResZ, + DXGI_FORMAT_R16G16B16A16_FLOAT, 1, false, false, true); + } + + if(reVoxelize == false) + return; + + currVoxelIdx = 0; + PIXEvent pixEvent(L"Voxelize Scene"); - OrthographicCamera voxelCameraZ(currSceneMin.x, currSceneMin.y, currSceneMax.x, currSceneMax.y, 0.0f, currSceneMax.z - currSceneMax.z); + { + SetCSShader(context, clearVoxelTextures); + + ID3D11UnorderedAccessView* uavs[6]; + for(uint64 i = 0; i < 6; ++i) + uavs[i] = voxelTextures[i].UAView; + context->CSSetUnorderedAccessViews(0, 6, uavs, nullptr); + + + context->Dispatch(DispatchSize(4, AppSettings::VoxelResX), DispatchSize(4, AppSettings::VoxelResY), DispatchSize(4, AppSettings::VoxelResZ)); + + for(uint64 i = 0; i < 6; ++i) + uavs[i] = nullptr; + context->CSSetUnorderedAccessViews(0, 6, uavs, nullptr); + } + + OrthographicCamera voxelCameraZ(currSceneMin.x, currSceneMin.y, currSceneMax.x, currSceneMax.y, 0.0f, currSceneMax.z - currSceneMin.z); voxelCameraZ.SetPosition(Float3((currSceneMin.x + currSceneMax.x) / 2.0f, (currSceneMin.y + currSceneMax.y) / 2.0f, currSceneMin.z)); OrthographicCamera voxelCameraX = voxelCameraZ; @@ -846,13 +889,37 @@ void BakingLab::VoxelizeScene() voxelCameraY.SetPosition(Float3((currSceneMin.x + currSceneMax.x) / 2.0f, currSceneMin.y, (currSceneMin.z + currSceneMax.z) / 2.0f)); voxelCameraY.SetOrientation(Quaternion::FromAxisAngle(Float3(1.0f, 0.0f, 0.0f), -Pi_2)); - ID3D11DeviceContext* context = deviceManager.ImmediateContext(); - if(AppSettings::EnableSun) meshRenderer.RenderSunShadowMap(context, voxelCameraZ, false); if(AppSettings::EnableAreaLight) meshRenderer.RenderAreaLightShadowMap(context, voxelCameraZ); + + for(uint64 i = 0; i < 3; ++i) + { + OrthographicCamera* voxelCamera = nullptr; + + if(i == 0) + { + voxelCamera = &voxelCameraX; + SetViewport(context, AppSettings::VoxelResZ, AppSettings::VoxelResY); + } + else if(i == 1) + { + voxelCamera = &voxelCameraY; + SetViewport(context, AppSettings::VoxelResX, AppSettings::VoxelResZ); + } + else if(i == 2) + { + voxelCamera = &voxelCameraZ; + SetViewport(context, AppSettings::VoxelResX, AppSettings::VoxelResY); + } + + ID3D11UnorderedAccessView* uavs[2] = { voxelTextures[i].UAView, voxelTextures[i + 3].UAView }; + context->OMSetRenderTargetsAndUnorderedAccessViews(0, nullptr, nullptr, 0, 2, uavs, nullptr); + + meshRenderer.RenderMainPass(context, *voxelCamera, status, false, true); + } } void BakingLab::Render(const Timer& timer) @@ -867,6 +934,8 @@ void BakingLab::Render(const Timer& timer) status.SceneMinBounds = currSceneMin; status.SceneMaxBounds = currSceneMax; + VoxelizeScene(status); + RenderProbes(status); if(AppSettings::ShowGroundTruth) diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index c6946ee..c001f77 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -91,6 +91,10 @@ class BakingLab : public App ComputeShaderPtr probeIntegrateVolumeMap; ComputeShaderPtr probeIntegrateDistanceVolumeMap; + RenderTarget3D voxelTextures[6]; + ComputeShaderPtr clearVoxelTextures; + uint64 currVoxelIdx = 0; + struct ResolveConstants { uint32 SampleRadius; @@ -125,7 +129,7 @@ class BakingLab : public App void CreateRenderTargets(); void RenderProbes(MeshBakerStatus& status); - void VoxelizeScene(); + void VoxelizeScene(MeshBakerStatus& status); void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* secondRT, const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, bool32 renderAreaLight, bool32 enableSkySun, bool32 probeRendering); diff --git a/BakingLab/ClearVoxelTextures.hlsl b/BakingLab/ClearVoxelTextures.hlsl new file mode 100644 index 0000000..fc67247 --- /dev/null +++ b/BakingLab/ClearVoxelTextures.hlsl @@ -0,0 +1,19 @@ +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +RWTexture3D VoxelTextures[6]; + +[numthreads(4, 4, 4)] +void ClearVoxelTextures(in uint3 voxelCood : SV_DispatchThreadID) +{ + [unroll] + for(uint i = 0; i < 6; ++i) + VoxelTextures[i][voxelCood] = 0.0f; +} \ No newline at end of file diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 437f934..6705560 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -79,7 +79,7 @@ SamplerState LinearSampler : register(s2); SamplerComparisonState PCFSampler : register(s3); #if Voxelize_ - RWTexture3D VoxelOutput[2] : register(u0); + RWTexture3D VoxelTextures[2] : register(u0); #endif //================================================================================================= @@ -741,9 +741,9 @@ PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) float3 voxelUVW = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); uint3 voxelCoord = uint3(voxelUVW * float3(VoxelResX, VoxelResY, VoxelResZ)); if(isFrontFace) - VoxelOutput[0][voxelCoord] = float4(voxelRadiance, 1.0f); + VoxelTextures[0][voxelCoord] = float4(voxelRadiance, 1.0f); else - VoxelOutput[1][voxelCoord] = float4(voxelRadiance, 1.0f); + VoxelTextures[1][voxelCoord] = float4(voxelRadiance, 1.0f); #else PSOutput output; output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index 32fdd85..987517a 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -789,6 +789,12 @@ void MeshRenderer::RenderSunShadowMap(ID3D11DeviceContext* context, const Camera // Compute the split distances based on the partitioning mode float CascadeSplits[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + if(camera.IsOrthographic()) + { + for(uint32 i = 0; i < NumCascades; ++i) + CascadeSplits[i] = Lerp(MinDistance, MaxDistance, (i + 1.0f) / NumCascades); + } + else { float lambda = 1.0f; diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl index 64cf797..ab012db 100644 --- a/BakingLab/ProbeIntegrate.hlsl +++ b/BakingLab/ProbeIntegrate.hlsl @@ -90,7 +90,7 @@ float2 SquareToConcentricDiskMapping(float x, float y) else // region 2, also |b| > |a| { r = b; - phi = (Pi / 4.0f) * (2.0f - (a / b)); + phi = (Pi / 4.0f) * (2.0f - (a / max(b, 0.00001f))); } } else // region 3 or 4 @@ -104,7 +104,7 @@ float2 SquareToConcentricDiskMapping(float x, float y) { r = -b; if(b != 0) - phi = (Pi / 4.0f) * (6.0f - (a / b)); + phi = (Pi / 4.0f) * (6.0f - (a / max(b, 0.00001f))); else phi = 0; } @@ -211,7 +211,7 @@ void IntegrateIrradianceCubeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThr float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); - const uint numSamples = 1024; + const uint numSamples = max(ProbeIntegrationSamples * ProbeIntegrationSamples, 1); float3 irradiance = 0.0f; for(uint i = 0; i < numSamples; ++i) { @@ -245,7 +245,7 @@ void IntegrateVolumeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : for(int b = 0; b < MaxBasisCount; ++b) output[b] = 0.0f; - const uint numSamples = 1024; + const uint numSamples = max(ProbeIntegrationSamples * ProbeIntegrationSamples, 1); for(uint sampleIdx = 0; sampleIdx < numSamples; ++sampleIdx) { float2 samplePos = Hammersley2D(sampleIdx, numSamples); @@ -291,7 +291,7 @@ void IntegrateDistanceCubeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThrea float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); - const uint numSamples = 256; + const uint numSamples = max(ProbeDistanceIntegrationSamples * ProbeDistanceIntegrationSamples, 1); const float cosinePower = exp2(DistanceFilterSharpness); float2 outputDistance = 0.0f; @@ -331,7 +331,7 @@ void IntegrateDistanceVolumeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThr for(int b = 0; b < MaxBasisCount; ++b) output[b] = 0.0f; - const uint numSamples = 1024; + const uint numSamples = max(ProbeIntegrationSamples * ProbeIntegrationSamples, 1); for(uint sampleIdx = 0; sampleIdx < numSamples; ++sampleIdx) { float2 samplePos = Hammersley2D(sampleIdx, numSamples); diff --git a/SampleFramework11/v1.02/Graphics/Camera.h b/SampleFramework11/v1.02/Graphics/Camera.h index 0268311..51b98ce 100644 --- a/SampleFramework11/v1.02/Graphics/Camera.h +++ b/SampleFramework11/v1.02/Graphics/Camera.h @@ -1,141 +1,145 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include "..\\PCH.h" -#include "..\\SF11_Math.h" - -namespace SampleFramework11 -{ - -// Abstract base class for camera types -class Camera -{ - -protected: - - Float4x4 view; - Float4x4 projection; - Float4x4 viewProjection; - - Float4x4 world; - Float3 position; - Quaternion orientation; - - float nearZ; - float farZ; - - virtual void CreateProjection() = 0; - void WorldMatrixChanged(); - -public: - - Camera(float nearZ, float farZ); - ~Camera(); - - const Float4x4& ViewMatrix() const { return view; }; - const Float4x4& ProjectionMatrix() const { return projection; }; - const Float4x4& ViewProjectionMatrix() const { return viewProjection; }; - const Float4x4& WorldMatrix() const { return world; }; - const Float3& Position() const { return position; }; - const Quaternion& Orientation() const { return orientation; }; - const float& NearClip() const { return nearZ; }; - const float& FarClip() const { return farZ; }; - - Float3 Forward() const; - Float3 Back() const; - Float3 Up() const; - Float3 Down() const; - Float3 Right() const; - Float3 Left() const; - - void SetLookAt(const Float3& eye, const Float3& lookAt, const Float3& up); - void SetWorldMatrix(const Float4x4& newWorld); - void SetPosition(const Float3& newPosition); - void SetOrientation(const Quaternion& newOrientation); - void SetNearClip(float newNearClip); - void SetFarClip(float newFarClip); - void SetProjection(const Float4x4& newProjection); -}; - -// Camera with an orthographic projection -class OrthographicCamera : public Camera -{ - -protected: - - float xMin; - float xMax; - float yMin; - float yMax; - - virtual void CreateProjection() override; - -public: - - OrthographicCamera(float minX, float minY, float maxX, float maxY, float nearClip, float farClip); - ~OrthographicCamera(); - - float MinX() const { return xMin; }; - float MinY() const { return yMin; }; - float MaxX() const { return xMax; }; - float MaxY() const { return yMax; }; - - void SetMinX(float minX); - void SetMinY(float minY); - void SetMaxX(float maxX); - void SetMaxY(float maxY); -}; - -// Camera with a perspective projection -class PerspectiveCamera : public Camera -{ - -protected: - - float aspect; - float fov; - - virtual void CreateProjection() override; - -public: - - PerspectiveCamera(float aspectRatio, float fieldOfView, float nearClip, float farClip); - ~PerspectiveCamera(); - - float AspectRatio() const { return aspect; }; - float FieldOfView() const { return fov; }; - - void SetAspectRatio(float aspectRatio); - void SetFieldOfView(float fieldOfView); -}; - -// Perspective camera that rotates about Z and Y axes -class FirstPersonCamera : public PerspectiveCamera -{ - -protected: - - float xRot; - float yRot; - -public: - - FirstPersonCamera(float aspectRatio = 16.0f / 9.0f, float fieldOfView = Pi_4, float nearClip = 0.01f, float farClip = 100.0f); - ~FirstPersonCamera(); - - float XRotation() const { return xRot; }; - float YRotation() const { return yRot; }; - - void SetXRotation(float xRotation); - void SetYRotation(float yRotation); -}; - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include "..\\PCH.h" +#include "..\\SF11_Math.h" + +namespace SampleFramework11 +{ + +// Abstract base class for camera types +class Camera +{ + +protected: + + Float4x4 view; + Float4x4 projection; + Float4x4 viewProjection; + + Float4x4 world; + Float3 position; + Quaternion orientation; + + float nearZ; + float farZ; + + virtual void CreateProjection() = 0; + void WorldMatrixChanged(); + +public: + + Camera(float nearZ, float farZ); + ~Camera(); + + const Float4x4& ViewMatrix() const { return view; }; + const Float4x4& ProjectionMatrix() const { return projection; }; + const Float4x4& ViewProjectionMatrix() const { return viewProjection; }; + const Float4x4& WorldMatrix() const { return world; }; + const Float3& Position() const { return position; }; + const Quaternion& Orientation() const { return orientation; }; + const float& NearClip() const { return nearZ; }; + const float& FarClip() const { return farZ; }; + + Float3 Forward() const; + Float3 Back() const; + Float3 Up() const; + Float3 Down() const; + Float3 Right() const; + Float3 Left() const; + + void SetLookAt(const Float3& eye, const Float3& lookAt, const Float3& up); + void SetWorldMatrix(const Float4x4& newWorld); + void SetPosition(const Float3& newPosition); + void SetOrientation(const Quaternion& newOrientation); + void SetNearClip(float newNearClip); + void SetFarClip(float newFarClip); + void SetProjection(const Float4x4& newProjection); + + virtual bool IsOrthographic() const { return false; } +}; + +// Camera with an orthographic projection +class OrthographicCamera : public Camera +{ + +protected: + + float xMin; + float xMax; + float yMin; + float yMax; + + virtual void CreateProjection() override; + +public: + + OrthographicCamera(float minX, float minY, float maxX, float maxY, float nearClip, float farClip); + ~OrthographicCamera(); + + float MinX() const { return xMin; }; + float MinY() const { return yMin; }; + float MaxX() const { return xMax; }; + float MaxY() const { return yMax; }; + + void SetMinX(float minX); + void SetMinY(float minY); + void SetMaxX(float maxX); + void SetMaxY(float maxY); + + bool IsOrthographic() const override { return true; } +}; + +// Camera with a perspective projection +class PerspectiveCamera : public Camera +{ + +protected: + + float aspect; + float fov; + + virtual void CreateProjection() override; + +public: + + PerspectiveCamera(float aspectRatio, float fieldOfView, float nearClip, float farClip); + ~PerspectiveCamera(); + + float AspectRatio() const { return aspect; }; + float FieldOfView() const { return fov; }; + + void SetAspectRatio(float aspectRatio); + void SetFieldOfView(float fieldOfView); +}; + +// Perspective camera that rotates about Z and Y axes +class FirstPersonCamera : public PerspectiveCamera +{ + +protected: + + float xRot; + float yRot; + +public: + + FirstPersonCamera(float aspectRatio = 16.0f / 9.0f, float fieldOfView = Pi_4, float nearClip = 0.01f, float farClip = 100.0f); + ~FirstPersonCamera(); + + float XRotation() const { return xRot; }; + float YRotation() const { return yRot; }; + + void SetXRotation(float xRotation); + void SetYRotation(float yRotation); +}; + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/GraphicsTypes.h b/SampleFramework11/v1.02/Graphics/GraphicsTypes.h index 86a7d1c..a15ad96 100644 --- a/SampleFramework11/v1.02/Graphics/GraphicsTypes.h +++ b/SampleFramework11/v1.02/Graphics/GraphicsTypes.h @@ -63,7 +63,6 @@ struct RenderTarget3D DXGI_FORMAT Format; bool32 AutoGenMipMaps = false; - void Initialize(ID3D11Device* device, uint32 width, uint32 height, From 5b29f2ee198b80582b8a2c99571ac956556999be Mon Sep 17 00:00:00 2001 From: MJP Date: Sun, 3 Dec 2017 16:22:20 -0800 Subject: [PATCH 24/43] Use ROV's for voxelizing, and added a voxel visualizer --- BakingLab/AppSettings.cpp | 10 +- BakingLab/AppSettings.cs | 6 + BakingLab/AppSettings.h | 1 + BakingLab/BakingLab.cpp | 70 +-- BakingLab/BakingLab.h | 7 +- BakingLab/BakingLab.vcxproj | 510 +++++++++--------- ...lTextures.hlsl => ClearVoxelRadiance.hlsl} | 8 +- BakingLab/Mesh.hlsl | 11 +- BakingLab/MeshBaker.cpp | 3 +- BakingLab/MeshBaker.h | 1 + BakingLab/MeshRenderer.cpp | 226 +++++++- BakingLab/MeshRenderer.h | 16 + BakingLab/VoxelVisualizer.hlsl | 78 +++ Externals/d3dcompiler_47.dll | Bin 4173928 -> 4310328 bytes .../v1.02/Graphics/DeviceManager.cpp | 2 +- 15 files changed, 617 insertions(+), 332 deletions(-) rename BakingLab/{ClearVoxelTextures.hlsl => ClearVoxelRadiance.hlsl} (63%) create mode 100644 BakingLab/VoxelVisualizer.hlsl diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index ce657f2..03037c2 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -291,6 +291,7 @@ namespace AppSettings BoolSetting ShowBakeDataVisualizer; BoolSetting ShowProbeVisualizer; BoolSetting ViewIndirectSpecular; + BoolSetting VisualizeVoxels; Button SaveLightSettings; Button LoadLightSettings; Button SaveEXRScreenshot; @@ -573,13 +574,13 @@ namespace AppSettings BakeWithVCT.Initialize(tweakBar, "BakeWithVCT", "VCT", "Bake With VCT", "", false); Settings.AddSetting(&BakeWithVCT); - VoxelResX.Initialize(tweakBar, "VoxelResX", "VCT", "Voxel Res X", "", 32, 1, 2048); + VoxelResX.Initialize(tweakBar, "VoxelResX", "VCT", "Voxel Resolution (X)", "", 32, 1, 2048); Settings.AddSetting(&VoxelResX); - VoxelResY.Initialize(tweakBar, "VoxelResY", "VCT", "Voxel Res Y", "", 32, 1, 2048); + VoxelResY.Initialize(tweakBar, "VoxelResY", "VCT", "Voxel Resolution (Y)", "", 32, 1, 2048); Settings.AddSetting(&VoxelResY); - VoxelResZ.Initialize(tweakBar, "VoxelResZ", "VCT", "Voxel Res Z", "", 32, 1, 2048); + VoxelResZ.Initialize(tweakBar, "VoxelResZ", "VCT", "Voxel Resolution (Z)", "", 32, 1, 2048); Settings.AddSetting(&VoxelResZ); CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); @@ -660,6 +661,9 @@ namespace AppSettings ViewIndirectSpecular.Initialize(tweakBar, "ViewIndirectSpecular", "Debug", "View Indirect Specular", "", false); Settings.AddSetting(&ViewIndirectSpecular); + VisualizeVoxels.Initialize(tweakBar, "VisualizeVoxels", "Debug", "Visualize Voxels", "", false); + Settings.AddSetting(&VisualizeVoxels); + SaveLightSettings.Initialize(tweakBar, "SaveLightSettings", "Debug", "Save Light Settings", "Saves the lighting settings to a file"); Settings.AddSetting(&SaveLightSettings); diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 4bae325..4aee072 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -730,14 +730,17 @@ public class VCT [MinValue(1)] [MaxValue(2048)] + [DisplayName("Voxel Resolution (X)")] int VoxelResX = 32; [MinValue(1)] [MaxValue(2048)] + [DisplayName("Voxel Resolution (Y)")] int VoxelResY = 32; [MinValue(1)] [MaxValue(2048)] + [DisplayName("Voxel Resolution (Z)")] int VoxelResZ = 32; } @@ -883,6 +886,9 @@ public class Debug bool ViewIndirectSpecular = false; + [UseAsShaderConstant(false)] + bool VisualizeVoxels = false; + [DisplayName("Save Light Settings")] [HelpText("Saves the lighting settings to a file")] Button SaveLightSettings; diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index eec4810..de4901a 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -365,6 +365,7 @@ namespace AppSettings extern BoolSetting ShowBakeDataVisualizer; extern BoolSetting ShowProbeVisualizer; extern BoolSetting ViewIndirectSpecular; + extern BoolSetting VisualizeVoxels; extern Button SaveLightSettings; extern Button LoadLightSettings; extern Button SaveEXRScreenshot; diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index a609b73..8d49fcc 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -478,7 +478,7 @@ void BakingLab::Initialize() probeIntegrateVolumeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateVolumeMap"); probeIntegrateDistanceVolumeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateDistanceVolumeMap"); - clearVoxelTextures = CompileCSFromFile(device, L"ClearVoxelTextures.hlsl", "ClearVoxelTextures"); + clearVoxelRadiance = CompileCSFromFile(device, L"ClearVoxelRadiance.hlsl", "ClearVoxelRadiance"); resolveConstants.Initialize(device); backgroundVelocityConstants.Initialize(device); @@ -585,8 +585,14 @@ void BakingLab::Update(const Timer& timer) camera.SetFieldOfView(AppSettings::VerticalFOV(camera.AspectRatio())); unJitteredCamera = camera; + enableTAA = AppSettings::EnableTemporalAA && + AppSettings::VisualizeVoxels == false && + AppSettings::ShowProbeVisualizer == false && + AppSettings::ShowBakeDataVisualizer == false && + AppSettings::ShowGroundTruth == false; + Float2 jitter = 0.0f; - if(AppSettings::EnableTemporalAA && AppSettings::EnableLuminancePicker == false && AppSettings::JitterMode != JitterModes::None) + if(enableTAA && AppSettings::EnableLuminancePicker == false && AppSettings::JitterMode != JitterModes::None) { if(AppSettings::JitterMode == JitterModes::Uniform2x) { @@ -750,7 +756,7 @@ void BakingLab::RenderProbes(MeshBakerStatus& status) probeCam.SetOrientation(orientation); RenderScene(status, probeCaptureMap.RTVArraySlices[i], probeDistanceCaptureMap.RTVArraySlices[i], probeDepthBuffer, probeCam, - false, false, AppSettings::BakeDirectAreaLight, false, true); + false, false, AppSettings::BakeDirectAreaLight, false, false, true); } AppSettings::UseProbes.SetValue(prevUseProbes); @@ -847,12 +853,11 @@ void BakingLab::VoxelizeScene(MeshBakerStatus& status) if(status.BakingInvalidated || AppSettings::AlwaysRevoxelize) reVoxelize = true; - if(voxelTextures[0].Texture == nullptr || AppSettings::VoxelResX.Changed() || AppSettings::VoxelResY.Changed() || AppSettings::VoxelResZ.Changed()) + if(voxelRadiance.Texture == nullptr || AppSettings::VoxelResX.Changed() || AppSettings::VoxelResY.Changed() || AppSettings::VoxelResZ.Changed()) { reVoxelize = true; - for(uint64 i = 0; i < 6; ++i) - voxelTextures[i].Initialize(device, AppSettings::VoxelResX, AppSettings::VoxelResY, AppSettings::VoxelResZ, - DXGI_FORMAT_R16G16B16A16_FLOAT, 1, false, false, true); + voxelRadiance.Initialize(device, AppSettings::VoxelResX, AppSettings::VoxelResY, AppSettings::VoxelResZ, + DXGI_FORMAT_R16G16B16A16_FLOAT, 1, false, false, true); } if(reVoxelize == false) @@ -862,21 +867,13 @@ void BakingLab::VoxelizeScene(MeshBakerStatus& status) PIXEvent pixEvent(L"Voxelize Scene"); - { - SetCSShader(context, clearVoxelTextures); - - ID3D11UnorderedAccessView* uavs[6]; - for(uint64 i = 0; i < 6; ++i) - uavs[i] = voxelTextures[i].UAView; - context->CSSetUnorderedAccessViews(0, 6, uavs, nullptr); + // Clear the voxel radiance texture + SetCSShader(context, clearVoxelRadiance); + SetCSOutputs(context, voxelRadiance.UAView); + context->Dispatch(DispatchSize(4, AppSettings::VoxelResX), DispatchSize(4, AppSettings::VoxelResY), DispatchSize(4, AppSettings::VoxelResZ)); - context->Dispatch(DispatchSize(4, AppSettings::VoxelResX), DispatchSize(4, AppSettings::VoxelResY), DispatchSize(4, AppSettings::VoxelResZ)); - - for(uint64 i = 0; i < 6; ++i) - uavs[i] = nullptr; - context->CSSetUnorderedAccessViews(0, 6, uavs, nullptr); - } + ClearCSOutputs(context); OrthographicCamera voxelCameraZ(currSceneMin.x, currSceneMin.y, currSceneMax.x, currSceneMax.y, 0.0f, currSceneMax.z - currSceneMin.z); voxelCameraZ.SetPosition(Float3((currSceneMin.x + currSceneMax.x) / 2.0f, (currSceneMin.y + currSceneMax.y) / 2.0f, currSceneMin.z)); @@ -895,6 +892,9 @@ void BakingLab::VoxelizeScene(MeshBakerStatus& status) if(AppSettings::EnableAreaLight) meshRenderer.RenderAreaLightShadowMap(context, voxelCameraZ); + ID3D11UnorderedAccessView* uavs[] = { voxelRadiance.UAView }; + context->OMSetRenderTargetsAndUnorderedAccessViews(0, nullptr, nullptr, 0, ArraySize_(uavs), uavs, nullptr); + for(uint64 i = 0; i < 3; ++i) { OrthographicCamera* voxelCamera = nullptr; @@ -915,9 +915,6 @@ void BakingLab::VoxelizeScene(MeshBakerStatus& status) SetViewport(context, AppSettings::VoxelResX, AppSettings::VoxelResY); } - ID3D11UnorderedAccessView* uavs[2] = { voxelTextures[i].UAView, voxelTextures[i + 3].UAView }; - context->OMSetRenderTargetsAndUnorderedAccessViews(0, nullptr, nullptr, 0, 2, uavs, nullptr); - meshRenderer.RenderMainPass(context, *voxelCamera, status, false, true); } } @@ -938,6 +935,8 @@ void BakingLab::Render(const Timer& timer) RenderProbes(status); + status.VoxelRadiance = voxelRadiance.SRView; + if(AppSettings::ShowGroundTruth) { ID3D11RenderTargetView* rtvs[1] = { colorTargetMSAA.RTView }; @@ -967,7 +966,7 @@ void BakingLab::Render(const Timer& timer) RenderScene(status, colorTargetMSAA.RTView, velocityTargetMSAA.RTView, depthBuffer, camera, AppSettings::ShowBakeDataVisualizer, AppSettings::ShowProbeVisualizer, - AppSettings::EnableAreaLight, true, false); + AppSettings::EnableAreaLight, AppSettings::VisualizeVoxels, true, false); RenderBackgroundVelocity(); } @@ -995,7 +994,7 @@ void BakingLab::Render(const Timer& timer) void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* secondRT, const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, - bool32 renderAreaLight, bool32 enableSkySun, bool32 probeRendering) + bool32 renderAreaLight, bool32 showVoxelVisualizer, bool32 enableSkySun, bool32 probeRendering) { PIXEvent event(L"Render Scene"); @@ -1031,13 +1030,22 @@ void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetVie context->ClearRenderTargetView(colorTarget, clearColor); context->ClearRenderTargetView(secondRT, secondClearColor); - meshRenderer.RenderMainPass(context, cam, status, probeRendering, false); + if(showVoxelVisualizer) + { + context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); - if(showBakeDataVisualizer) - meshRenderer.RenderBakeDataVisualizer(context, cam, status); + meshRenderer.RenderVoxelVisualizer(context, cam, status); + } + else + { + meshRenderer.RenderMainPass(context, cam, status, probeRendering, false); + + if(showBakeDataVisualizer) + meshRenderer.RenderBakeDataVisualizer(context, cam, status); - if(showProbeVisualizer) - meshRenderer.RenderProbeVisualizer(context, cam, status); + if(showProbeVisualizer) + meshRenderer.RenderProbeVisualizer(context, cam, status); + } if(renderAreaLight) meshRenderer.RenderAreaLight(context, cam); @@ -1081,7 +1089,7 @@ void BakingLab::RenderAA() resolveConstants.Data.TextureSize = Float2(float(colorTargetMSAA.Width), float(colorTargetMSAA.Height)); resolveConstants.Data.SampleRadius = SampleRadius; - resolveConstants.Data.EnableTemporalAA = AppSettings::EnableTemporalAA && AppSettings::ShowGroundTruth == false; + resolveConstants.Data.EnableTemporalAA = enableTAA; resolveConstants.ApplyChanges(context); resolveConstants.SetPS(context, 0); diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index c001f77..2c8d269 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -73,6 +73,7 @@ class BakingLab : public App Float2 prevJitter; uint64 frameCount = 0; FirstPersonCamera unJitteredCamera; + bool enableTAA = false; RenderTarget2D probeCaptureMap; RenderTarget2D probeDistanceCaptureMap; @@ -91,8 +92,8 @@ class BakingLab : public App ComputeShaderPtr probeIntegrateVolumeMap; ComputeShaderPtr probeIntegrateDistanceVolumeMap; - RenderTarget3D voxelTextures[6]; - ComputeShaderPtr clearVoxelTextures; + RenderTarget3D voxelRadiance; + ComputeShaderPtr clearVoxelRadiance; uint64 currVoxelIdx = 0; struct ResolveConstants @@ -132,7 +133,7 @@ class BakingLab : public App void VoxelizeScene(MeshBakerStatus& status); void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* secondRT, const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, - bool32 renderAreaLight, bool32 enableSkySun, bool32 probeRendering); + bool32 renderAreaLight, bool32 showVoxelVisualizer, bool32 enableSkySun, bool32 probeRendering); void RenderAA(); void RenderBackgroundVelocity(); void RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, diff --git a/BakingLab/BakingLab.vcxproj b/BakingLab/BakingLab.vcxproj index 23d6f28..b4d2cbd 100644 --- a/BakingLab/BakingLab.vcxproj +++ b/BakingLab/BakingLab.vcxproj @@ -1,256 +1,256 @@ - - - - - Debug - x64 - - - Release - x64 - - - - {1D9C887B-E727-438B-8977-A0E7363B1FC6} - SampleTest - Win32Proj - BakingLab - 8.1 - - - - Application - Unicode - true - v140 - - - Application - Unicode - v140 - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30128.1 - $(SolutionDir)$(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - true - $(SolutionDir)$(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - false - AllRules.ruleset - - - AllRules.ruleset - - - $(IncludePath) - $(IncludePath) - $(LibraryPath) - $(LibraryPath) - - - $(ExecutablePath) - - - - Disabled - Debug_;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - Use - PCH.h - ProgramDatabase - $(IntDir)$(TargetName).pch - Fast - - - true - Windows - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - Release_;WIN32;NDEBUG;_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) - MultiThreadedDLL - true - Use - ProgramDatabase - PCH.h - Fast - - - true - Windows - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)\SettingsCompiler.exe %(FullPath) - Compiling settings and generating C++ code - false - $(ProjectDir)\%(Filename).deps - $(ProjectDir)\SettingsCompiler.exe %(FullPath) - Compiling settings and generating C++ code - $(ProjectDir)\%(Filename).deps - false - - - Document - - - Document - - - Document - - - Document - - - Document - - - Document - - - - - - - - - false - false - Document - - - false - false - Document - - - false - false - Document - - - false - false - Document - - - - - + + + + + Debug + x64 + + + Release + x64 + + + + {1D9C887B-E727-438B-8977-A0E7363B1FC6} + SampleTest + Win32Proj + BakingLab + 10.0.16299.0 + + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + true + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + $(IncludePath) + $(IncludePath) + $(LibraryPath) + $(LibraryPath) + + + $(ExecutablePath) + + + + Disabled + Debug_;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + PCH.h + ProgramDatabase + $(IntDir)$(TargetName).pch + Fast + + + true + Windows + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MaxSpeed + true + Release_;WIN32;NDEBUG;_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) + MultiThreadedDLL + true + Use + ProgramDatabase + PCH.h + Fast + + + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(ProjectDir)\SettingsCompiler.exe %(FullPath) + Compiling settings and generating C++ code + false + $(ProjectDir)\%(Filename).deps + $(ProjectDir)\SettingsCompiler.exe %(FullPath) + Compiling settings and generating C++ code + $(ProjectDir)\%(Filename).deps + false + + + Document + + + Document + + + Document + + + Document + + + Document + + + Document + + + + + + + + + false + false + Document + + + false + false + Document + + + false + false + Document + + + false + false + Document + + + + + \ No newline at end of file diff --git a/BakingLab/ClearVoxelTextures.hlsl b/BakingLab/ClearVoxelRadiance.hlsl similarity index 63% rename from BakingLab/ClearVoxelTextures.hlsl rename to BakingLab/ClearVoxelRadiance.hlsl index fc67247..f0a9101 100644 --- a/BakingLab/ClearVoxelTextures.hlsl +++ b/BakingLab/ClearVoxelRadiance.hlsl @@ -8,12 +8,10 @@ // //================================================================================================= -RWTexture3D VoxelTextures[6]; +RWTexture3D VoxelRadiance; [numthreads(4, 4, 4)] -void ClearVoxelTextures(in uint3 voxelCood : SV_DispatchThreadID) +void ClearVoxelRadiance(in uint3 voxelCoord : SV_DispatchThreadID) { - [unroll] - for(uint i = 0; i < 6; ++i) - VoxelTextures[i][voxelCood] = 0.0f; + VoxelRadiance[voxelCoord] = 0.0f; } \ No newline at end of file diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 6705560..9b7d2f1 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -79,7 +79,7 @@ SamplerState LinearSampler : register(s2); SamplerComparisonState PCFSampler : register(s3); #if Voxelize_ - RWTexture3D VoxelTextures[2] : register(u0); + RasterizerOrderedTexture3D VoxelRadiance : register(u0); #endif //================================================================================================= @@ -740,10 +740,11 @@ PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) float3 voxelRadiance = clamp(irradiance * surface.DiffuseAlbedo * InvPi, 0.0f, FP16Max); float3 voxelUVW = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); uint3 voxelCoord = uint3(voxelUVW * float3(VoxelResX, VoxelResY, VoxelResZ)); - if(isFrontFace) - VoxelTextures[0][voxelCoord] = float4(voxelRadiance, 1.0f); - else - VoxelTextures[1][voxelCoord] = float4(voxelRadiance, 1.0f); + + float3 prevVoxelRadiance = VoxelRadiance[voxelCoord].xyz; + float prevVoxelCount = VoxelRadiance[voxelCoord].w; + float3 newVoxelRadiance = lerp(prevVoxelRadiance, voxelRadiance, 1.0f / (prevVoxelCount + 1.0f)); + VoxelRadiance[voxelCoord] = float4(newVoxelRadiance, prevVoxelCount + 1.0f); #else PSOutput output; output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); diff --git a/BakingLab/MeshBaker.cpp b/BakingLab/MeshBaker.cpp index ef900e9..653e650 100644 --- a/BakingLab/MeshBaker.cpp +++ b/BakingLab/MeshBaker.cpp @@ -1545,7 +1545,8 @@ MeshBakerStatus MeshBaker::Update(const Camera& camera, uint32 screenWidth, uint || AppSettings::Turbidity.Changed() || AppSettings::HasSunDirChanged() || AppSettings::SunTintColor.Changed() || AppSettings::SunIntensityScale.Changed() || AppSettings::SunSize.Changed() || AppSettings::NormalizeSunIntensity.Changed() - || AppSettings::DiffuseAlbedoScale.Changed() || AppSettings::EnableAlbedoMaps.Changed()) + || AppSettings::DiffuseAlbedoScale.Changed() || AppSettings::EnableAlbedoMaps.Changed() + || AppSettings::CurrentScene.Changed()) { InterlockedIncrement64(&renderTag); InterlockedIncrement64(&bakeTag); diff --git a/BakingLab/MeshBaker.h b/BakingLab/MeshBaker.h index 91fc8e3..4ee86fa 100644 --- a/BakingLab/MeshBaker.h +++ b/BakingLab/MeshBaker.h @@ -63,6 +63,7 @@ struct MeshBakerStatus ID3D11ShaderResourceView* ProbeDistanceCubeMap = nullptr; ID3D11ShaderResourceView* ProbeVolumeMaps[AppSettings::MaxBasisCount] = { }; ID3D11ShaderResourceView* ProbeDistanceVolumeMaps[AppSettings::MaxBasisCount] = { }; + ID3D11ShaderResourceView* VoxelRadiance = nullptr; uint64 NumBakePoints = 0; float GroundTruthProgress = 0.0f; float BakeProgress = 0.0f; diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index 987517a..ac0be17 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -235,6 +235,122 @@ static void GenerateSphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* d DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); } +const uint32 NumBoxVerts = 24; +const uint32 NumBoxIndices = 36; + +static void GenerateBox(ID3D11Device* device, ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer) +{ + std::vector boxVerts(NumBoxVerts); + std::vector boxIndices(NumBoxIndices, 0); + + uint64 vIdx = 0; + + // Top + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, -0.5f); + + // Bottom + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, 0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, 0.5f); + + // Front + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, -0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, -0.5f); + + // Back + boxVerts[vIdx++] = Float3(0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, 0.5f); + + // Left + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, -0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, 0.5f); + + // Right + boxVerts[vIdx++] = Float3(0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, -0.5f); + + uint64 iIdx = 0; + + // Top + boxIndices[iIdx++] = 0; + boxIndices[iIdx++] = 1; + boxIndices[iIdx++] = 2; + boxIndices[iIdx++] = 2; + boxIndices[iIdx++] = 3; + boxIndices[iIdx++] = 0; + + // Bottom + boxIndices[iIdx++] = 4 + 0; + boxIndices[iIdx++] = 4 + 1; + boxIndices[iIdx++] = 4 + 2; + boxIndices[iIdx++] = 4 + 2; + boxIndices[iIdx++] = 4 + 3; + boxIndices[iIdx++] = 4 + 0; + + // Front + boxIndices[iIdx++] = 8 + 0; + boxIndices[iIdx++] = 8 + 1; + boxIndices[iIdx++] = 8 + 2; + boxIndices[iIdx++] = 8 + 2; + boxIndices[iIdx++] = 8 + 3; + boxIndices[iIdx++] = 8 + 0; + + // Back + boxIndices[iIdx++] = 12 + 0; + boxIndices[iIdx++] = 12 + 1; + boxIndices[iIdx++] = 12 + 2; + boxIndices[iIdx++] = 12 + 2; + boxIndices[iIdx++] = 12 + 3; + boxIndices[iIdx++] = 12 + 0; + + // Left + boxIndices[iIdx++] = 16 + 0; + boxIndices[iIdx++] = 16 + 1; + boxIndices[iIdx++] = 16 + 2; + boxIndices[iIdx++] = 16 + 2; + boxIndices[iIdx++] = 16 + 3; + boxIndices[iIdx++] = 16 + 0; + + // Right + boxIndices[iIdx++] = 20 + 0; + boxIndices[iIdx++] = 20 + 1; + boxIndices[iIdx++] = 20 + 2; + boxIndices[iIdx++] = 20 + 2; + boxIndices[iIdx++] = 20 + 3; + boxIndices[iIdx++] = 20 + 0; + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = sizeof(Float3) * NumBoxVerts; + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = boxVerts.data(); + initData.SysMemPitch = 0; + initData.SysMemSlicePitch = 0; + DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); + + bufferDesc.ByteWidth = sizeof(uint16) * NumBoxIndices; + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + initData.pSysMem = boxIndices.data(); + DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); +} + void MeshRenderer::LoadShaders() { // Load the mesh shaders @@ -266,6 +382,9 @@ void MeshRenderer::LoadShaders() probeVisualizerVS = CompileVSFromFile(device, L"ProbeVisualizer.hlsl", "VS", "vs_5_0"); probeVisualizerPS = CompilePSFromFile(device, L"ProbeVisualizer.hlsl", "PS", "ps_5_0"); + voxelVisualizerVS = CompileVSFromFile(device, L"VoxelVisualizer.hlsl", "VS", "vs_5_0"); + voxelVisualizerPS = CompilePSFromFile(device, L"VoxelVisualizer.hlsl", "PS", "ps_5_0"); + fullScreenVS = CompileVSFromFile(device, L"EVSMConvert.hlsl", "FullScreenVS"); CompileOptions opts; @@ -327,6 +446,7 @@ void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context visualizerConstants.Initialize(device); evsmConstants.Initialize(device); reductionConstants.Initialize(device); + voxelVisualizerConstants.Initialize(device); shSpecularLookupA = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularA.dds"); shSpecularLookupB = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularB.dds"); @@ -351,6 +471,8 @@ void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context GenerateSphere(16, 8, device, sphereVB, sphereIB, numSphereIndices); + GenerateBox(device, voxelVisualizerVB, voxelVisualizerIB); + D3D11_INPUT_ELEMENT_DESC elements[1]; elements[0].AlignedByteOffset = 0; elements[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; @@ -369,6 +491,9 @@ void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context DXCall(device->CreateInputLayout(elements, 1, areaLightVS->ByteCode->GetBufferPointer(), areaLightVS->ByteCode->GetBufferSize(), &areaLightInputLayout)); + DXCall(device->CreateInputLayout(elements, 1, voxelVisualizerVS->ByteCode->GetBufferPointer(), + voxelVisualizerVS->ByteCode->GetBufferSize(), &voxelVisualizerIL)); + SetModel(model); } @@ -445,11 +570,11 @@ void MeshRenderer::ReduceDepth(ID3D11DeviceContext* context, const DepthStencilB reductionConstants.ApplyChanges(context); reductionConstants.SetCS(context, 0); - ID3D11RenderTargetView* rtvs[1] = { NULL }; - context->OMSetRenderTargets(1, rtvs, NULL); + ID3D11RenderTargetView* rtvs[1] = { nullptr }; + context->OMSetRenderTargets(1, rtvs, nullptr); ID3D11UnorderedAccessView* uavs[1] = { depthReductionTargets[0].UAView }; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); ID3D11ShaderResourceView* srvs[1] = { depthTarget.SRView }; context->CSSetShaderResources(0, 1, srvs); @@ -457,19 +582,19 @@ void MeshRenderer::ReduceDepth(ID3D11DeviceContext* context, const DepthStencilB const bool msaa = depthTarget.MultiSamples > 1; ID3D11ComputeShader* shader = depthReductionInitialCS[msaa ? 1 : 0]; - context->CSSetShader(shader, NULL, 0); + context->CSSetShader(shader, nullptr, 0); uint32 dispatchX = depthReductionTargets[0].Width; uint32 dispatchY = depthReductionTargets[0].Height; context->Dispatch(dispatchX, dispatchY, 1); - uavs[0] = NULL; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); + uavs[0] = nullptr; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); - srvs[0] = NULL; + srvs[0] = nullptr; context->CSSetShaderResources(0, 1, srvs); - context->CSSetShader(depthReductionCS, NULL, 0); + context->CSSetShader(depthReductionCS, nullptr, 0); for(uint32 i = 1; i < depthReductionTargets.size(); ++i) { @@ -480,7 +605,7 @@ void MeshRenderer::ReduceDepth(ID3D11DeviceContext* context, const DepthStencilB reductionConstants.ApplyChanges(context); uavs[0] = depthReductionTargets[i].UAView; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); srvs[0] = srcTexture.SRView; context->CSSetShaderResources(0, 1, srvs); @@ -489,10 +614,10 @@ void MeshRenderer::ReduceDepth(ID3D11DeviceContext* context, const DepthStencilB dispatchY = depthReductionTargets[i].Height; context->Dispatch(dispatchX, dispatchY, 1); - uavs[0] = NULL; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); + uavs[0] = nullptr; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); - srvs[0] = NULL; + srvs[0] = nullptr; context->CSSetShaderResources(0, 1, srvs); } @@ -528,12 +653,12 @@ void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); context->RSSetState(rasterizerStates.NoCull()); context->OMSetDepthStencilState(depthStencilStates.DepthDisabled(), 0); - ID3D11Buffer* vbs[1] = { NULL }; + ID3D11Buffer* vbs[1] = { nullptr }; uint32 strides[1] = { 0 }; uint32 offsets[1] = { 0 }; context->IASetVertexBuffers(0, 1, vbs, strides, offsets); - context->IASetIndexBuffer(NULL, DXGI_FORMAT_R32_UINT, 0); - context->IASetInputLayout(NULL); + context->IASetIndexBuffer(nullptr, DXGI_FORMAT_R32_UINT, 0); + context->IASetInputLayout(nullptr); SetViewport(context, sunVSM.Width, sunVSM.Height); @@ -546,18 +671,18 @@ void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx evsmConstants.ApplyChanges(context); evsmConstants.SetPS(context, 0); - context->VSSetShader(fullScreenVS, NULL, 0); - context->PSSetShader(evsmConvertPS, NULL, 0); + context->VSSetShader(fullScreenVS, nullptr, 0); + context->PSSetShader(evsmConvertPS, nullptr, 0); ID3D11RenderTargetView* rtvs[1] = { sunVSM.RTVArraySlices[cascadeIdx] }; - context->OMSetRenderTargets(1, rtvs, NULL); + context->OMSetRenderTargets(1, rtvs, nullptr); ID3D11ShaderResourceView* srvs[1] = { sunShadowDepthMap.SRView }; context->PSSetShaderResources(0, 1, srvs); context->Draw(3, 0); - srvs[0] = NULL; + srvs[0] = nullptr; context->PSSetShaderResources(0, 1, srvs); const float FilterSizeU = std::max(FilterSize * cascadeScale.x, 1.0f); @@ -572,16 +697,16 @@ void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx uint32 sampleRadiusU = static_cast((FilterSizeU / 2) + 0.499f); rtvs[0] = tempVSM.RTView; - context->OMSetRenderTargets(1, rtvs, NULL); + context->OMSetRenderTargets(1, rtvs, nullptr); srvs[0] = sunVSM.SRVArraySlices[cascadeIdx]; context->PSSetShaderResources(0, 1, srvs); - context->PSSetShader(evsmBlurH, NULL, 0); + context->PSSetShader(evsmBlurH, nullptr, 0); context->Draw(3, 0); - srvs[0] = NULL; + srvs[0] = nullptr; context->PSSetShaderResources(0, 1, srvs); // Vertical pass @@ -591,16 +716,16 @@ void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx uint32 sampleRadiusV = static_cast((FilterSizeV / 2) + 0.499f); rtvs[0] = sunVSM.RTVArraySlices[cascadeIdx]; - context->OMSetRenderTargets(1, rtvs, NULL); + context->OMSetRenderTargets(1, rtvs, nullptr); srvs[0] = tempVSM.SRView; context->PSSetShaderResources(0, 1, srvs); - context->PSSetShader(evsmBlurV, NULL, 0); + context->PSSetShader(evsmBlurV, nullptr, 0); context->Draw(3, 0); - srvs[0] = NULL; + srvs[0] = nullptr; context->PSSetShaderResources(0, 1, srvs); } @@ -720,7 +845,7 @@ void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& ca } } - ID3D11ShaderResourceView* nullSRVs[10] = { NULL }; + ID3D11ShaderResourceView* nullSRVs[10] = { nullptr }; context->PSSetShaderResources(0, ArraySize_(nullSRVs), nullSRVs); } @@ -833,7 +958,7 @@ void MeshRenderer::RenderSunShadowMap(ID3D11DeviceContext* context, const Camera // Set the shadow map as the depth target ID3D11DepthStencilView* dsv = sunShadowDepthMap.DSView; - ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { NULL }; + ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { nullptr }; context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); @@ -983,7 +1108,7 @@ void MeshRenderer::RenderAreaLightShadowMap(ID3D11DeviceContext* context, const // Set the shadow map as the depth target ID3D11DepthStencilView* dsv = areaLightShadowMap.ArraySlices[face]; - ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { NULL }; + ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { nullptr }; context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 0.0f, 0); @@ -1162,4 +1287,49 @@ void MeshRenderer::RenderProbeVisualizer(ID3D11DeviceContext* context, const Cam ID3D11ShaderResourceView* nullSRVs[2] = { }; context->PSSetShaderResources(0, ArraySize_(nullSRVs), nullSRVs); +} + +void MeshRenderer::RenderVoxelVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) +{ + PIXEvent event(L"Voxel Visualizer"); + + // Set constant buffers + voxelVisualizerConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + voxelVisualizerConstants.Data.SceneMinBounds = status.SceneMinBounds; + voxelVisualizerConstants.Data.SceneMaxBounds = status.SceneMaxBounds; + voxelVisualizerConstants.ApplyChanges(context); + voxelVisualizerConstants.SetVS(context, 0); + voxelVisualizerConstants.SetPS(context, 0); + + // Set shaders + context->VSSetShader(voxelVisualizerVS , nullptr, 0); + context->PSSetShader(voxelVisualizerPS, nullptr, 0); + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); + context->RSSetState(rasterizerStates.BackFaceCull()); + + ID3D11ShaderResourceView* srvs[1] = { status.VoxelRadiance }; + + context->VSSetShaderResources(0, 1, srvs); + + // Draw a bx for each voxel + ID3D11Buffer* vertexBuffers[1] = { voxelVisualizerVB }; + uint32 vertexStrides[1] = { sizeof(Float3) }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(voxelVisualizerIB, DXGI_FORMAT_R16_UINT, 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(voxelVisualizerIL); + + const uint32 numVoxels = AppSettings::VoxelResX * AppSettings::VoxelResY * AppSettings::VoxelResZ; + context->DrawIndexedInstanced(NumBoxIndices, numVoxels, 0, 0, 0); + + srvs[0] = nullptr; + context->VSSetShaderResources(0, 1, srvs); } \ No newline at end of file diff --git a/BakingLab/MeshRenderer.h b/BakingLab/MeshRenderer.h index 3422aca..366d1f4 100644 --- a/BakingLab/MeshRenderer.h +++ b/BakingLab/MeshRenderer.h @@ -58,6 +58,8 @@ class MeshRenderer const MeshBakerStatus& status); void RenderProbeVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status); + void MeshRenderer::RenderVoxelVisualizer(ID3D11DeviceContext* context, const Camera& camera, + const MeshBakerStatus& status); protected: @@ -130,6 +132,12 @@ class MeshRenderer ID3D11ShaderResourceViewPtr shSpecularLookupA; ID3D11ShaderResourceViewPtr shSpecularLookupB; + VertexShaderPtr voxelVisualizerVS; + PixelShaderPtr voxelVisualizerPS; + ID3D11BufferPtr voxelVisualizerVB; + ID3D11BufferPtr voxelVisualizerIB; + ID3D11InputLayoutPtr voxelVisualizerIL; + // Constant buffers struct MeshVSConstants { @@ -203,10 +211,18 @@ class MeshRenderer Float4Align Float3 SceneMaxBounds; }; + struct VoxelVisualizerConstants + { + Float4x4 ViewProjection; + Float4Align Float3 SceneMinBounds; + Float4Align Float3 SceneMaxBounds; + }; + ConstantBuffer meshVSConstants; ConstantBuffer meshPSConstants; ConstantBuffer areaLightConstants; ConstantBuffer visualizerConstants; ConstantBuffer evsmConstants; ConstantBuffer reductionConstants; + ConstantBuffer voxelVisualizerConstants; }; \ No newline at end of file diff --git a/BakingLab/VoxelVisualizer.hlsl b/BakingLab/VoxelVisualizer.hlsl new file mode 100644 index 0000000..36469b2 --- /dev/null +++ b/BakingLab/VoxelVisualizer.hlsl @@ -0,0 +1,78 @@ +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include "AppSettings.hlsl" + +//================================================================================================= +// Constant buffers +//================================================================================================= +cbuffer Constants : register(b0) +{ + float4x4 ViewProjection; + float3 SceneMinBounds; + float3 SceneMaxBounds; +} + +Texture3D VoxelRadiance : register(t0); + +struct VSOutput +{ + float4 PositionCS : SV_Position; + float3 VoxelRadiance : VOXELRADIANCE; +}; + +//================================================================================================= +// Vertex shader for "raw" voxel visualization +//================================================================================================= +VSOutput VS(in float3 VertexPosition : POSITION, in uint InstanceID : SV_InstanceID) +{ + const uint voxelIdx = InstanceID; + const uint3 voxelCoord = uint3(voxelIdx % VoxelResX, + (voxelIdx / VoxelResX) % VoxelResY, + voxelIdx / (VoxelResX * VoxelResY)); + + const float3 voxelRadiance = VoxelRadiance[voxelCoord].xyz; + const float voxelOccupancy = VoxelRadiance[voxelCoord].w; + + if(voxelOccupancy <= 0.0f) + { + VSOutput output; + output.PositionCS = float4(-10000.0f, -10000.0f, -10000.0f, 1.0f); + output.VoxelRadiance = 0.0f; + return output; + } + + const float3 uvw = float3((voxelCoord.x + 0.5f) / VoxelResX, + (voxelCoord.y + 0.5f) / VoxelResY, + (voxelCoord.z + 0.5f) / VoxelResZ); + + const float3 sceneSize = (SceneMaxBounds - SceneMinBounds); + const float3 voxelSize = sceneSize / float3(VoxelResX, VoxelResY, VoxelResZ); + + const float3 voxelCenter = SceneMinBounds + sceneSize * uvw; + const float3 vtxPositionWS = voxelCenter + VertexPosition * voxelSize; + + VSOutput output; + output.PositionCS = mul(float4(vtxPositionWS, 1.0f), ViewProjection); + output.VoxelRadiance = voxelRadiance; + + return output; +} + +//================================================================================================= +// Pixel shader for "raw" voxel visualization +//================================================================================================= +float4 PS(in VSOutput input) : SV_Target0 +{ + return float4(input.VoxelRadiance, 1.0f); +} \ No newline at end of file diff --git a/Externals/d3dcompiler_47.dll b/Externals/d3dcompiler_47.dll index 356a777f8551e77fd0a2e2308ae53866029f8d73..adf8e21576d54b387251ad0d55da42359e9294f5 100644 GIT binary patch literal 4310328 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–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ǞhWwX_8 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

V^d8}CDnBfe!|6_1kgHJNF)Iuu<-vrM%&3*wAW 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

3e0E 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

d-B$I{PJ1J|-ul_vI>AVodKCBZ;g}rX`V# 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 z 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


WslBf3=e-y1a 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