diff --git a/Examples/Common/LightControllers.cpp b/Examples/Common/LightControllers.cpp index 9ab5e65f..baeac98e 100644 --- a/Examples/Common/LightControllers.cpp +++ b/Examples/Common/LightControllers.cpp @@ -37,6 +37,7 @@ static void InitCube(const LightParams& p, auto rc = cube->Components().GetComponent().component; auto local = cube->Components().GetComponent().component; cube->Components().DisableComponent(); + //cube->Components().DisableComponent(); local->SetLocalScale(glm::vec3(0.25f)); local->SetLocalPosition(p.position); float multiplier = 1.0f; @@ -187,6 +188,16 @@ static bool EntityIsRelevant(const stratus::EntityPtr& entity) { } void LightProcess::Process(const double deltaSeconds) { + // const auto& lights = ConvertHandlerToLightDelete(input)->entities; + // for (const auto& light : lights) { + // auto ptr = stratus::GetComponent(light)->light; + // if (!ptr->IsVirtualLight()) continue; + // auto cube = stratus::GetComponent(light); + // if (cube) { + // stratus::GetComponent(cube->cube)->SetLocalPosition(ptr->GetPosition()); + // } + // } + if (ConvertHandlerToLightDelete(input)->printLights) { ConvertHandlerToLightDelete(input)->printLights = false; const auto& lights = ConvertHandlerToLightDelete(input)->entities; diff --git a/Examples/ExampleEnv02/Sponza.cpp b/Examples/ExampleEnv02/Sponza.cpp index d637b399..09e515d8 100644 --- a/Examples/ExampleEnv02/Sponza.cpp +++ b/Examples/ExampleEnv02/Sponza.cpp @@ -174,7 +174,7 @@ class Sponza : public stratus::Application { received.clear(); int spawned = 0; for (int x = 60; x > -30; x -= 10) { - for (int y = 15; y < 240; y += 20) { + for (int y = 0; y < 240; y += 20) { for (int z = -140; z < 180; z += 20) { ++spawned; LightCreator::CreateVirtualPointLight( diff --git a/Examples/ExampleEnv04/SanMiguel.cpp b/Examples/ExampleEnv04/SanMiguel.cpp index 873bbdab..b51c63f4 100644 --- a/Examples/ExampleEnv04/SanMiguel.cpp +++ b/Examples/ExampleEnv04/SanMiguel.cpp @@ -161,7 +161,7 @@ class SanMiguel : public stratus::Application { int spawned = 0; for (int x = 40; x < 240; x += 10) { - for (int y = 5; y < 150; y += 20) { + for (int y = 0; y < 150; y += 20) { for (int z = -30; z < 120; z += 20) { ++spawned; LightCreator::CreateVirtualPointLight( diff --git a/Examples/ExampleEnv05/Bistro.cpp b/Examples/ExampleEnv05/Bistro.cpp index 1c54454f..308114fe 100644 --- a/Examples/ExampleEnv05/Bistro.cpp +++ b/Examples/ExampleEnv05/Bistro.cpp @@ -25,7 +25,7 @@ static void setupDayTime() { int spawned = 0; for (int x = -150; x < 200; x += 50) { - for (int y = 10; y < 150; y += 20) { + for (int y = 0; y < 150; y += 20) { for (int z = -400; z < -50; z += 50) { ++spawned; LightCreator::CreateVirtualPointLight( @@ -37,7 +37,7 @@ static void setupDayTime() { } for (int x = -200; x < 95; x += 30) { - for (int y = 10; y < 150; y += 15) { + for (int y = 0; y < 150; y += 15) { for (int z = -50; z < 200; z += 30) { ++spawned; LightCreator::CreateVirtualPointLight( @@ -49,7 +49,7 @@ static void setupDayTime() { } for (int x = 300; x < 555; x += 30) { - for (int y = 10; y < 50; y += 10) { + for (int y = 0; y < 50; y += 10) { for (int z = 150; z < 400; z += 30) { ++spawned; LightCreator::CreateVirtualPointLight( @@ -61,7 +61,7 @@ static void setupDayTime() { } for (int x = 180; x < 310; x += 30) { - for (int y = 10; y < 160; y += 10) { + for (int y = 0; y < 160; y += 10) { for (int z = 100; z < 265; z += 30) { ++spawned; LightCreator::CreateVirtualPointLight( @@ -73,7 +73,7 @@ static void setupDayTime() { } for (int x = 240; x < 340; x += 30) { - for (int y = 10; y < 160; y += 10) { + for (int y = 0; y < 160; y += 10) { for (int z = 130; z < 180; z += 30) { ++spawned; LightCreator::CreateVirtualPointLight( @@ -85,7 +85,7 @@ static void setupDayTime() { } for (int x = -270; x < -160; x += 30) { - for (int y = 10; y < 160; y += 10) { + for (int y = 0; y < 160; y += 10) { ++spawned; LightCreator::CreateVirtualPointLight( LightParams(glm::vec3(float(x), float(y), -250.0f), glm::vec3(1.0f), 1.0f), diff --git a/README.md b/README.md index fb2b8835..4722c94b 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Because of the MPL license, any community changes made to the rendering code wil # Downloading Sample 3D Model Data -1) A zip file containing Sponza, Interrogation Room, San Miguel, Bistro, Bathroom, etc. can be found here: [https://drive.google.com/file/d/1m56T8cWMwAOHTAIbxAn-891trehgJpzH/view?usp=drive_link](https://drive.google.com/file/d/1m56T8cWMwAOHTAIbxAn-891trehgJpzH/view?usp=drive_link) +1) A zip file containing Sponza, Interrogation Room, San Miguel, Bistro, Bathroom, etc. can be found here: [https://drive.google.com/file/d/1nVkEuhDaSK61XmTSoNOUUEU5a-U-mtKO/view?usp=share_link](https://drive.google.com/file/d/1nVkEuhDaSK61XmTSoNOUUEU5a-U-mtKO/view?usp=share_link) 2) Extract the Resources.zip folder into the root of StratusGFX. It will then be at the same level as Bin/, Examples/, Source/, Tests/. Make sure that the folder structure looks like StratusGFX/Resources/* where * will be folders such as Sponza, Bistro, etc. diff --git a/Source/Engine/StratusGpuCommandBuffer.cpp b/Source/Engine/StratusGpuCommandBuffer.cpp index 7ced82ad..9d22557d 100644 --- a/Source/Engine/StratusGpuCommandBuffer.cpp +++ b/Source/Engine/StratusGpuCommandBuffer.cpp @@ -13,6 +13,7 @@ namespace stratus { visibleCommands_ = GpuTypedBuffer::Create(commandBlockSize, true); selectedLodCommands_ = GpuTypedBuffer::Create(commandBlockSize, true); + visibleLowestLodCommands_ = GpuTypedBuffer::Create(commandBlockSize, true); prevFrameModelTransforms_ = GpuTypedBuffer::Create(commandBlockSize, true); modelTransforms_ = GpuTypedBuffer::Create(commandBlockSize, true); aabbs_ = GpuTypedBuffer::Create(commandBlockSize, true); @@ -67,6 +68,7 @@ namespace stratus { // Record the lod commands visibleCommands_->Add(GpuDrawElementsIndirectCommand()); selectedLodCommands_->Add(GpuDrawElementsIndirectCommand()); + visibleLowestLodCommands_->Add(GpuDrawElementsIndirectCommand()); for (size_t lod = 0; lod < NumLods(); ++lod) { GpuDrawElementsIndirectCommand command; @@ -104,6 +106,7 @@ namespace stratus { // Remove top level data visibleCommands_->Remove(index); selectedLodCommands_->Remove(index); + visibleLowestLodCommands_->Remove(index); prevFrameModelTransforms_->Remove(index); modelTransforms_->Remove(index); aabbs_->Remove(index); @@ -276,6 +279,10 @@ namespace stratus { return selectedLodCommands_->GetBuffer(); } + GpuBuffer GpuCommandBuffer2::GetVisibleLowestLodDrawCommandsBuffer() const { + return visibleLowestLodCommands_->GetBuffer(); + } + bool GpuCommandBuffer2::InsertMeshPending_(RenderComponent* component, MeshPtr mesh) { if (!mesh->IsFinalized()) { diff --git a/Source/Engine/StratusGpuCommandBuffer.h b/Source/Engine/StratusGpuCommandBuffer.h index 518616b6..43e231b6 100644 --- a/Source/Engine/StratusGpuCommandBuffer.h +++ b/Source/Engine/StratusGpuCommandBuffer.h @@ -50,6 +50,7 @@ namespace stratus { GpuBuffer GetIndirectDrawCommandsBuffer(const size_t lod) const; GpuBuffer GetVisibleDrawCommandsBuffer() const; GpuBuffer GetSelectedLodDrawCommandsBuffer() const; + GpuBuffer GetVisibleLowestLodDrawCommandsBuffer() const; static inline GpuCommandBuffer2Ptr Create(const RenderFaceCulling& cull, const size_t numLods, const size_t commandBlockSize) { return GpuCommandBuffer2Ptr(new GpuCommandBuffer2(cull, numLods, commandBlockSize)); @@ -62,6 +63,7 @@ namespace stratus { std::vector> drawCommands_; GpuTypedBufferPtr visibleCommands_; GpuTypedBufferPtr selectedLodCommands_; + GpuTypedBufferPtr visibleLowestLodCommands_; GpuTypedBufferPtr prevFrameModelTransforms_; GpuTypedBufferPtr modelTransforms_; GpuTypedBufferPtr aabbs_; diff --git a/Source/Engine/StratusGpuCommon.h b/Source/Engine/StratusGpuCommon.h index 12cfc2aa..778146a5 100644 --- a/Source/Engine/StratusGpuCommon.h +++ b/Source/Engine/StratusGpuCommon.h @@ -13,7 +13,7 @@ // Synchronized with definitions in pbr.glsl #define MAX_TOTAL_SHADOW_ATLASES (14) -#define MAX_TOTAL_SHADOWS_PER_ATLAS (300) +#define MAX_TOTAL_SHADOWS_PER_ATLAS (320) #define MAX_TOTAL_SHADOW_MAPS (MAX_TOTAL_SHADOW_ATLASES * MAX_TOTAL_SHADOWS_PER_ATLAS) // Once a VPL is further than this distance away it is automatically culled @@ -31,7 +31,7 @@ #define GPU_METALLIC_ROUGHNESS_MAPPED (BITMASK_POW2(7)) // Matches the definitions in vpl_common.glsl -#define MAX_TOTAL_VPLS_BEFORE_CULLING (8192) +#define MAX_TOTAL_VPLS_BEFORE_CULLING (10000) #define MAX_TOTAL_VPLS_PER_FRAME (MAX_TOTAL_SHADOW_MAPS) #define MAX_VPLS_PER_TILE (12) @@ -217,7 +217,7 @@ namespace stratus { struct PACKED_STRUCT_ATTRIBUTE GpuVplData { GpuVec position; GpuVec color; - GpuVec placeholder1_; + GpuVec specularPosition; float radius; float farPlane; float intensity; diff --git a/Source/Engine/StratusMath.h b/Source/Engine/StratusMath.h index cd086df8..5bd5720d 100644 --- a/Source/Engine/StratusMath.h +++ b/Source/Engine/StratusMath.h @@ -16,6 +16,7 @@ #include #include #include +#include "StratusGpuCommon.h" #define STRATUS_PI 3.14159265358979323846 @@ -361,6 +362,55 @@ namespace stratus { return result; } + template + bool IsAabbInFrustum(const GpuAABB& aabb, const Array& frustumPlanes) { + const glm::vec4& vmin = aabb.vmin; + const glm::vec4& vmax = aabb.vmax; + + for (int i = 0; i < 6; ++i) { + const glm::vec4& g = frustumPlanes[i]; + if ((glm::dot(g, glm::vec4(vmin.x, vmin.y, vmin.z, 1.0f)) < 0.0) && + (glm::dot(g, glm::vec4(vmax.x, vmin.y, vmin.z, 1.0f)) < 0.0) && + (glm::dot(g, glm::vec4(vmin.x, vmax.y, vmin.z, 1.0f)) < 0.0) && + (glm::dot(g, glm::vec4(vmax.x, vmax.y, vmin.z, 1.0f)) < 0.0) && + (glm::dot(g, glm::vec4(vmin.x, vmin.y, vmax.z, 1.0f)) < 0.0) && + (glm::dot(g, glm::vec4(vmax.x, vmin.y, vmax.z, 1.0f)) < 0.0) && + (glm::dot(g, glm::vec4(vmin.x, vmax.y, vmax.z, 1.0f)) < 0.0) && + (glm::dot(g, glm::vec4(vmax.x, vmax.y, vmax.z, 1.0f)) < 0.0)) + { + return false; + } + } + + return true; + } + + template + bool IsPointInFrustum(const glm::vec3& point, const Array& frustumPlanes) { + for (int i = 0; i < 6; ++i) { + const glm::vec4& g = frustumPlanes[i]; + if (glm::dot(g, glm::vec4(point, 1.0f)) < 0.0) { + return false; + } + } + + return true; + } + + template + bool IsSphereInFrustum(const glm::vec3& center, const float radius, const Array& frustumPlanes) { + for (int i = 0; i < 6; ++i) { + const glm::vec4& g = frustumPlanes[i]; + const float distance = glm::dot(g, glm::vec4(center, 1.0f)); + + if (distance < -radius) { + return false; + } + } + + return true; + } + // These are the first 512 values of the Halton sequence. For more information see: // https://en.wikipedia.org/wiki/Halton_sequence // https://www.pbr-book.org/3ed-2018/Sampling_and_Reconstruction/The_Halton_Sampler diff --git a/Source/Engine/StratusRenderComponents.cpp b/Source/Engine/StratusRenderComponents.cpp index 789be63d..d97dc4e3 100644 --- a/Source/Engine/StratusRenderComponents.cpp +++ b/Source/Engine/StratusRenderComponents.cpp @@ -300,6 +300,16 @@ namespace stratus { if (size < 1024) break; } + // One last lod computed more aggressively than the previous ones + auto& prevIndices = cpuData_->indicesPerLod[0]; + std::vector simplified(prevIndices.size()); + const size_t targetIndices = std::min(prevIndices.size(), 1024); + auto size = meshopt_simplify(simplified.data(), prevIndices.data(), prevIndices.size(), &cpuData_->vertices[0][0], numVertices_, sizeof(float) * 3, targetIndices, 0.8f); + simplified.resize(size); + meshopt_optimizeVertexCache(simplified.data(), simplified.data(), size, numVertices_); + cpuData_->indicesPerLod.push_back(std::move(simplified)); + numIndicesPerLod_.push_back(size); + meshopt_optimizeVertexCache(cpuData_->indices.data(), cpuData_->indices.data(), cpuData_->indices.size(), cpuData_->vertices.size()); cpuData_->indicesPerLod[0] = cpuData_->indices; } diff --git a/Source/Engine/StratusRenderComponents.h b/Source/Engine/StratusRenderComponents.h index fad3d696..b8a26a3c 100644 --- a/Source/Engine/StratusRenderComponents.h +++ b/Source/Engine/StratusRenderComponents.h @@ -104,6 +104,8 @@ namespace stratus { uint32_t vertexOffset_; // Into global GpuBuffer std::vector numIndicesPerLod_; std::vector indexOffsetPerLod_; // Into global GpuBuffer + uint32_t numIndicesApproximateLod_; + RenderFaceCulling cullMode_ = RenderFaceCulling::CULLING_CCW; }; diff --git a/Source/Engine/StratusRendererBackend.cpp b/Source/Engine/StratusRendererBackend.cpp index 9d8e2fc7..eb2872c7 100644 --- a/Source/Engine/StratusRendererBackend.cpp +++ b/Source/Engine/StratusRendererBackend.cpp @@ -408,7 +408,7 @@ void RendererBackend::InitGBuffer_() { // Create the depth buffer buffer.depth = Texture(TextureConfig{ TextureType::TEXTURE_2D, TextureComponentFormat::DEPTH, TextureComponentSize::BITS_DEFAULT, TextureComponentType::FLOAT, frame_->viewportWidth, frame_->viewportHeight, 0, false }, NoTextureData); - buffer.depth.SetMinMagFilter(TextureMinificationFilter::NEAREST, TextureMagnificationFilter::NEAREST); + buffer.depth.SetMinMagFilter(TextureMinificationFilter::LINEAR, TextureMagnificationFilter::LINEAR); buffer.depth.SetCoordinateWrapping(TextureCoordinateWrapping::CLAMP_TO_EDGE); // Create the frame buffer with all its texture attachments @@ -1120,7 +1120,7 @@ void RendererBackend::RenderCSMDepth_() { auto& csm = frame_->csc.cascades[cascade]; shader->SetMat4("shadowMatrix", csm.projectionViewRender); // const size_t lod = cascade * 2 + 1; - const size_t lod = frame_->drawCommands->NumLods() - 1; + const size_t lod = frame_->drawCommands->NumLods() - 2; if (cascade < 2) { const CommandBufferSelectionFunction select = [](GpuCommandBuffer2Ptr& b) { return b->GetSelectedLodDrawCommandsBuffer(); @@ -1269,10 +1269,10 @@ void RendererBackend::RenderAtmosphericShadowing_() { glEnable(GL_DEPTH_TEST); } -void RendererBackend::InitVplFrameData_(const std::vector, LightDistancePairAllocator>& perVPLDistToViewer) { +void RendererBackend::InitVplFrameData_(const VplDistVector_& perVPLDistToViewer) { std::vector vplData(perVPLDistToViewer.size()); for (size_t i = 0; i < perVPLDistToViewer.size(); ++i) { - VirtualPointLight * point = (VirtualPointLight *)perVPLDistToViewer[i].first.get(); + const VirtualPointLight* point = (const VirtualPointLight *)perVPLDistToViewer[i].key.get(); GpuVplData& data = vplData[i]; data.position = GpuVec(glm::vec4(point->GetPosition(), 1.0f)); data.farPlane = point->GetFarPlane(); @@ -1282,91 +1282,92 @@ void RendererBackend::InitVplFrameData_(const std::vector, LightDistancePairAllocator>& perLightDistToViewer, - std::vector, LightDistancePairAllocator>& perLightShadowCastingDistToViewer, - std::vector, LightDistancePairAllocator>& perVPLDistToViewer, - std::vector>& visibleVplIndices) { +void RendererBackend::UpdatePointLights_( + VplDistMultiSet_& perLightDistToViewerSet, + VplDistVector_& perLightDistToViewerVec, + VplDistMultiSet_& perLightShadowCastingDistToViewerSet, + VplDistVector_& perLightShadowCastingDistToViewerVec, + VplDistMultiSet_& perVPLDistToViewerSet, + VplDistVector_& perVPLDistToViewerVec, + std::vector>& visibleVplIndices) { + const Camera& c = *frame_->camera; const bool worldLightEnabled = frame_->csc.worldLight->GetEnabled(); + const bool giEnabled = worldLightEnabled && frame_->settings.globalIlluminationEnabled; + + perLightDistToViewerSet.clear(); + perLightDistToViewerVec.clear(); + + perLightShadowCastingDistToViewerSet.clear(); + perLightShadowCastingDistToViewerVec.clear(); + + perVPLDistToViewerSet.clear(); + perVPLDistToViewerVec.clear(); - perLightDistToViewer.clear(); - perLightShadowCastingDistToViewer.clear(); - perVPLDistToViewer.clear(); visibleVplIndices.clear(); - perLightDistToViewer.reserve(state_.maxTotalRegularLightsPerFrame); - perLightShadowCastingDistToViewer.reserve(state_.maxShadowCastingLightsPerFrame); + perLightDistToViewerVec.reserve(state_.maxTotalRegularLightsPerFrame); + perLightShadowCastingDistToViewerVec.reserve(state_.maxShadowCastingLightsPerFrame); if (worldLightEnabled) { - perVPLDistToViewer.reserve(MAX_TOTAL_VPLS_BEFORE_CULLING); + perVPLDistToViewerVec.reserve(MAX_TOTAL_VPLS_BEFORE_CULLING); } // Init per light instance data for (auto& light : frame_->lights) { const double distance = glm::distance(c.GetPosition(), light->GetPosition()); if (light->IsVirtualLight()) { - if (worldLightEnabled && distance <= MAX_VPL_DISTANCE_TO_VIEWER) { - perVPLDistToViewer.push_back(std::make_pair(light, distance)); + //if (giEnabled && distance <= MAX_VPL_DISTANCE_TO_VIEWER) { + if (giEnabled && IsSphereInFrustum(light->GetPosition(), light->GetRadius(), frame_->viewFrustumPlanes)) { + //if (giEnabled) { + perVPLDistToViewerSet.insert(VplDistKey_(light, distance)); } } else { - perLightDistToViewer.push_back(std::make_pair(light, distance)); + perLightDistToViewerSet.insert(VplDistKey_(light, distance)); } if ( !light->IsVirtualLight() && light->CastsShadows() ) { - perLightShadowCastingDistToViewer.push_back(std::make_pair(light, distance)); + perLightShadowCastingDistToViewerSet.insert(VplDistKey_(light, distance)); } } - // Sort lights based on distance to viewer - const auto comparison = [](const std::pair & a, const std::pair & b) { - return a.second < b.second; - }; - - const bool regularLightsMaxExceeded = perLightDistToViewer.size() > state_.maxTotalRegularLightsPerFrame; - const bool regularShadowLightsMaxExceeded = perLightShadowCastingDistToViewer.size() > state_.numRegularShadowMaps; - - if (regularLightsMaxExceeded || regularShadowLightsMaxExceeded) { - std::sort(perLightDistToViewer.begin(), perLightDistToViewer.end(), comparison); - std::sort(perLightShadowCastingDistToViewer.begin(), perLightShadowCastingDistToViewer.end(), comparison); - } - - // Remove lights exceeding the absolute maximum - if (regularLightsMaxExceeded) { - //std::sort(perLightDistToViewer.begin(), perLightDistToViewer.end(), comparison); - perLightDistToViewer.resize(state_.maxTotalRegularLightsPerFrame); + for (auto& entry : perLightDistToViewerSet) { + perLightDistToViewerVec.push_back(entry); + if (perLightDistToViewerVec.size() >= perLightDistToViewerVec.capacity()) break; } - // Remove shadow-casting lights that exceed our max count - if (regularShadowLightsMaxExceeded) { - //std::sort(perLightShadowCastingDistToViewer.begin(), perLightShadowCastingDistToViewer.end(), comparison); - perLightShadowCastingDistToViewer.resize(state_.maxShadowCastingLightsPerFrame); + for (auto& entry : perLightShadowCastingDistToViewerSet) { + perLightShadowCastingDistToViewerVec.push_back(entry); + if (perLightShadowCastingDistToViewerVec.size() >= perLightShadowCastingDistToViewerVec.capacity()) break; } // Remove vpls exceeding absolute maximum - if (worldLightEnabled) { - //std::sort(perVPLDistToViewer.begin(), perVPLDistToViewer.end(), comparison); - if (perVPLDistToViewer.size() > MAX_TOTAL_VPLS_BEFORE_CULLING) { - std::sort(perVPLDistToViewer.begin(), perVPLDistToViewer.end(), comparison); - perVPLDistToViewer.resize(MAX_TOTAL_VPLS_BEFORE_CULLING); + if (giEnabled) { + for (auto& entry : perVPLDistToViewerSet) { + perVPLDistToViewerVec.push_back(entry); + if (perVPLDistToViewerVec.size() >= perVPLDistToViewerVec.capacity()) break; } - InitVplFrameData_(perVPLDistToViewer); - PerformVirtualPointLightCullingStage1_(perVPLDistToViewer, visibleVplIndices); + InitVplFrameData_(perVPLDistToViewerVec); + PerformVirtualPointLightCullingStage1_(perVPLDistToViewerVec, visibleVplIndices); } // Check if any need to have a new shadow map pulled from the cache - for (const auto&[light, _] : perLightShadowCastingDistToViewer) { + for (const auto&[light, _] : perLightShadowCastingDistToViewerVec) { if (!ShadowMapExistsForLight_(light)) { frame_->lightsToUpdate.PushBack(light); } } - for (size_t i = 0; i < visibleVplIndices.size(); ++i) { + for (size_t i = 0, updates = 0; i < visibleVplIndices.size() && updates < state_.maxShadowUpdatesPerFrame; ++i) { const int index = visibleVplIndices[i]; - auto light = perVPLDistToViewer[index].first; + auto light = perVPLDistToViewerVec[index].key; if (!ShadowMapExistsForLight_(light)) { - frame_->lightsToUpdate.PushBack(light); + // Pushing to front will cause the light update queue to be reordered biased towards VPLs + // close to the camera + frame_->lightsToUpdate.PushFront(light); + ++updates; } } @@ -1383,6 +1384,16 @@ void RendererBackend::UpdatePointLights_(std::vector // TODO: Make this work with spotlights //PointLightPtr point = (PointLightPtr)light; PointLight * point = (PointLight *)light.get(); + + // if (point->IsVirtualLight() && !IsPointInFrustum(point->GetPosition(), frame_->viewFrustumPlanes)) { + // frame_->lightsToUpdate.PushBack(light); + // continue; + // } + if (point->IsVirtualLight() && !IsSphereInFrustum(point->GetPosition(), point->GetRadius(), frame_->viewFrustumPlanes)) { + frame_->lightsToUpdate.PushBack(light); + continue; + } + auto& cache = GetSmapCacheForLight_(light); GpuAtlasEntry smap = GetOrAllocateShadowMapForLight_(light); @@ -1420,6 +1431,7 @@ void RendererBackend::UpdatePointLights_(std::vector // Use lower LOD const size_t lod = frame_->drawCommands->NumLods() - 1; const CommandBufferSelectionFunction select = [lod](GpuCommandBuffer2Ptr& b) { + //return b->GetVisibleLowestLodDrawCommandsBuffer(); return b->GetIndirectDrawCommandsBuffer(lod); }; RenderImmediate_(frame_->drawCommands->staticPbrMeshes, select, false); @@ -1427,6 +1439,8 @@ void RendererBackend::UpdatePointLights_(std::vector const glm::mat4 projectionViewNoTranslate = lightPerspective * glm::mat4(glm::mat3(transforms[i])); + glDepthFunc(GL_LEQUAL); + BindShader_(state_.skyboxLayered.get()); state_.skyboxLayered->SetInt("layer", int(smap.layer * 6 + i)); @@ -1440,6 +1454,8 @@ void RendererBackend::UpdatePointLights_(std::vector if (tmp > 1.0f) { frame_->settings.SetSkyboxIntensity(tmp); } + + glDepthFunc(GL_LESS); } else { const CommandBufferSelectionFunction select = [](GpuCommandBuffer2Ptr& b) { @@ -1458,7 +1474,7 @@ void RendererBackend::UpdatePointLights_(std::vector } void RendererBackend::PerformVirtualPointLightCullingStage1_( - std::vector, LightDistancePairAllocator>& perVPLDistToViewer, + VplDistVector_& perVPLDistToViewer, std::vector>& visibleVplIndices) { if (perVPLDistToViewer.size() == 0) return; @@ -1541,7 +1557,7 @@ void RendererBackend::PerformVirtualPointLightCullingStage1_( // const std::vector>& perVPLDistToViewer, // const std::vector& visibleVplIndices) { void RendererBackend::PerformVirtualPointLightCullingStage2_( - const std::vector, LightDistancePairAllocator>& perVPLDistToViewer) { + const VplDistVector_& perVPLDistToViewer) { // int totalVisible = *(int *)state_.vpls.vplNumVisible.MapMemory(); // state_.vpls.vplNumVisible.UnmapMemory(); @@ -1550,6 +1566,7 @@ void RendererBackend::PerformVirtualPointLightCullingStage2_( if (perVPLDistToViewer.size() == 0) return; int* visibleVplIndices = (int*)state_.vpls.vplVisibleIndices.MapMemory(GPU_MAP_READ); + // First index is reserved for the size of the array const int totalVisible = visibleVplIndices[0]; visibleVplIndices += 1; @@ -1565,8 +1582,8 @@ void RendererBackend::PerformVirtualPointLightCullingStage2_( shadowDiffuseIndices.reserve(totalVisible); for (size_t i = 0; i < totalVisible; ++i) { const int index = visibleVplIndices[i]; - VirtualPointLight * point = (VirtualPointLight *)perVPLDistToViewer[index].first.get(); - auto smap = GetOrAllocateShadowMapForLight_(perVPLDistToViewer[index].first); + const VirtualPointLight * point = (const VirtualPointLight *)perVPLDistToViewer[index].key.get(); + auto smap = GetOrAllocateShadowMapForLight_(perVPLDistToViewer[index].key); shadowDiffuseIndices.push_back(smap); } @@ -1588,12 +1605,15 @@ void RendererBackend::PerformVirtualPointLightCullingStage2_( state_.vplColoring->SetVec3("infiniteLightColor", frame_->csc.worldLight->GetLuminance()); for (size_t i = 0; i < cache.buffers.size(); ++i) { state_.vplColoring->BindTexture("diffuseCubeMaps[" + std::to_string(i) + "]", cache.buffers[i].GetColorAttachments()[0]); + state_.vplColoring->BindTexture("shadowCubeMaps[" + std::to_string(i) + "]", *cache.buffers[i].GetDepthStencilAttachment()); } state_.vpls.vplVisibleIndices.BindBase(GpuBaseBindingPoint::SHADER_STORAGE_BUFFER, 1); //state_.vpls.vplVisibleIndices.BindBase(GpuBaseBindingPoint::SHADER_STORAGE_BUFFER, 3); state_.vpls.shadowDiffuseIndices.BindBase(GpuBaseBindingPoint::SHADER_STORAGE_BUFFER, 4); + InitCoreCSMData_(state_.vplColoring.get()); + // Bind outputs state_.vpls.vplUpdatedData.BindBase(GpuBaseBindingPoint::SHADER_STORAGE_BUFFER, 0); @@ -1686,7 +1706,7 @@ void RendererBackend::PerformVirtualPointLightCullingStage2_( // _state.vpls.vplNumVisible.UnmapMemory(); } -void RendererBackend::ComputeVirtualPointLightGlobalIllumination_(const std::vector, LightDistancePairAllocator>& perVPLDistToViewer, const double deltaSeconds) { +void RendererBackend::ComputeVirtualPointLightGlobalIllumination_(const VplDistVector_& perVPLDistToViewer, const double deltaSeconds) { if (perVPLDistToViewer.size() == 0) return; // auto space = LogSpace(1, 512, 30); @@ -1779,14 +1799,17 @@ void RendererBackend::ComputeVirtualPointLightGlobalIllumination_(const std::vec state_.vplGlobalIlluminationDenoising->SetBool("final", false); state_.vplGlobalIlluminationDenoising->SetFloat("time", milliseconds); state_.vplGlobalIlluminationDenoising->SetFloat("framesPerSecond", float(1.0 / deltaSeconds)); + state_.vplGlobalIlluminationDenoising->SetMat4("invProjectionView", frame_->invProjectionView); + state_.vplGlobalIlluminationDenoising->SetMat4("prevInvProjectionView", frame_->prevInvProjectionView); size_t bufferIndex = 0; - const int maxIterations = 3; + const int maxReservoirMergingPasses = 1; + const int maxIterations = 4; for (; bufferIndex < maxIterations; ++bufferIndex) { - // The first iteration is used for reservoir merging so we don't - // start increasing the multiplier until after the 2nd pass - const int i = bufferIndex; //bufferIndex == 0 ? 0 : bufferIndex - 1; + // The first iteration(s) is used for reservoir merging so we don't + // start increasing the multiplier until after the reservoir merging passes + const int i = bufferIndex; // bufferIndex < maxReservoirMergingPasses ? 0 : bufferIndex - maxReservoirMergingPasses + 1; const int multiplier = std::pow(2, i) - 1; FrameBuffer * buffer = buffers[bufferIndex % buffers.size()]; @@ -1795,7 +1818,7 @@ void RendererBackend::ComputeVirtualPointLightGlobalIllumination_(const std::vec state_.vplGlobalIlluminationDenoising->BindTexture("indirectShadows", indirectShadows); state_.vplGlobalIlluminationDenoising->SetInt("multiplier", multiplier); state_.vplGlobalIlluminationDenoising->SetInt("passNumber", i); - state_.vplGlobalIlluminationDenoising->SetBool("mergeReservoirs", bufferIndex == 0); + state_.vplGlobalIlluminationDenoising->SetBool("mergeReservoirs", bufferIndex < maxReservoirMergingPasses); if (bufferIndex + 1 == maxIterations) { state_.vplGlobalIlluminationDenoising->SetBool("final", true); @@ -1836,14 +1859,25 @@ void RendererBackend::RenderScene(const double deltaSeconds) { RenderCSMDepth_(); } - std::vector, LightDistancePairAllocator> perLightDistToViewer(LightDistancePairAllocator(frame_->perFrameScratchMemory)); + VplDistMultiSet_ perLightDistToViewerSet(StackBasedPoolAllocator(frame_->perFrameScratchMemory)); + VplDistVector_ perLightDistToViewerVec(StackBasedPoolAllocator(frame_->perFrameScratchMemory)); + // // This one is just for shadow-casting lights - std::vector, LightDistancePairAllocator> perLightShadowCastingDistToViewer(LightDistancePairAllocator(frame_->perFrameScratchMemory)); - std::vector, LightDistancePairAllocator> perVPLDistToViewer(LightDistancePairAllocator(frame_->perFrameScratchMemory)); + VplDistMultiSet_ perLightShadowCastingDistToViewerSet(StackBasedPoolAllocator(frame_->perFrameScratchMemory)); + VplDistVector_ perLightShadowCastingDistToViewerVec(StackBasedPoolAllocator(frame_->perFrameScratchMemory)); + + VplDistMultiSet_ perVPLDistToViewerSet(StackBasedPoolAllocator(frame_->perFrameScratchMemory)); + VplDistVector_ perVPLDistToViewerVec(StackBasedPoolAllocator(frame_->perFrameScratchMemory)); + std::vector> visibleVplIndices(StackBasedPoolAllocator(frame_->perFrameScratchMemory)); // Perform point light pass - UpdatePointLights_(perLightDistToViewer, perLightShadowCastingDistToViewer, perVPLDistToViewer, visibleVplIndices); + UpdatePointLights_( + perLightDistToViewerSet, perLightDistToViewerVec, + perLightShadowCastingDistToViewerSet, perLightShadowCastingDistToViewerVec, + perVPLDistToViewerSet, perVPLDistToViewerVec, + visibleVplIndices + ); // TEMP: Set up the light source //glm::vec3 lightPos(0.0f, 0.0f, 0.0f); @@ -1878,7 +1912,7 @@ void RendererBackend::RenderScene(const double deltaSeconds) { } BindShader_(lighting); - InitLights_(lighting, perLightDistToViewer, state_.maxShadowCastingLightsPerFrame); + InitLights_(lighting, perLightDistToViewerVec, state_.maxShadowCastingLightsPerFrame); lighting->BindTexture("atmosphereBuffer", state_.atmosphericTexture); lighting->SetMat4("invProjectionView", frame_->invProjectionView); lighting->BindTexture("gDepth", state_.currentFrame.depth); @@ -1899,8 +1933,8 @@ void RendererBackend::RenderScene(const double deltaSeconds) { // If world light is enabled perform VPL Global Illumination pass if (frame_->csc.worldLight->GetEnabled() && frame_->settings.globalIlluminationEnabled) { // Handle VPLs for global illumination (can't do this earlier due to needing position data from GBuffer) - PerformVirtualPointLightCullingStage2_(perVPLDistToViewer); - ComputeVirtualPointLightGlobalIllumination_(perVPLDistToViewer, deltaSeconds); + PerformVirtualPointLightCullingStage2_(perVPLDistToViewerVec); + ComputeVirtualPointLightGlobalIllumination_(perVPLDistToViewerVec, deltaSeconds); } // Forward pass for all objects that don't interact with light (may also be used for transparency later as well) @@ -2332,7 +2366,7 @@ void RendererBackend::InitCoreCSMData_(Pipeline * s) { } } -void RendererBackend::InitLights_(Pipeline * s, const std::vector, LightDistancePairAllocator> & lights, const size_t maxShadowLights) { +void RendererBackend::InitLights_(Pipeline * s, const VplDistVector_& lights, const size_t maxShadowLights) { // Set up point lights // Make sure everything is set to some sort of default to prevent shader crashes or huge performance drops @@ -2386,7 +2420,7 @@ void RendererBackend::InitLights_(Pipeline * s, const std::vectorIsVirtualLight()) { diff --git a/Source/Engine/StratusRendererBackend.h b/Source/Engine/StratusRendererBackend.h index fb433e90..86ac8194 100644 --- a/Source/Engine/StratusRendererBackend.h +++ b/Source/Engine/StratusRendererBackend.h @@ -28,6 +28,7 @@ #include "StratusGpuCommandBuffer.h" #include #include "StratusStackAllocator.h" +#include namespace stratus { class Pipeline; @@ -113,10 +114,29 @@ namespace stratus { } } + void PushFront(const LightPtr& ptr) { + auto existing = existing_.find(ptr); + // Allow lights further in the queue to be bumped higher up + // with this function + if (existing != existing_.end()) { + queue_.erase(existing->second); + existing_.erase(ptr); + } + + queue_.push_front(ptr); + auto it = queue_.begin(); + existing_.insert(std::make_pair(ptr, it)); + } + void PushBack(const LightPtr& ptr) { + // If a light is already in the queue, don't reorder since it would + // result in the light losing its better place in line if (existing_.find(ptr) != existing_.end() || !ptr->CastsShadows()) return; + queue_.push_back(ptr); - existing_.insert(ptr); + auto it = queue_.end(); + --it; + existing_.insert(std::make_pair(ptr, it)); } LightPtr PopFront() { @@ -157,7 +177,7 @@ namespace stratus { private: std::list queue_; - std::unordered_set existing_; + std::unordered_map::iterator> existing_; }; // Settings which can be changed at runtime by the application @@ -277,6 +297,7 @@ namespace stratus { uint32_t viewportHeight; Radians fovy; CameraPtr camera; + std::vector> viewFrustumPlanes; GpuMaterialBufferPtr materialInfo; RendererCascadeContainer csc; GpuCommandManagerPtr drawCommands; @@ -292,6 +313,7 @@ namespace stratus { glm::mat4 jitterProjectionView; glm::mat4 invProjectionView; glm::mat4 prevProjectionView = glm::mat4(1.0f); + glm::mat4 prevInvProjectionView = glm::mat4(1.0f); glm::vec4 clearColor; RendererSettings settings; UnsafePtr perFrameScratchMemory; @@ -515,9 +537,6 @@ namespace stratus { // Contains some number of Halton sequence values GpuBuffer haltonSequence_; - // Used for point light sorting and culling - using LightDistancePairAllocator = StackBasedPoolAllocator>; - /** * If the renderer was setup properly then this will be marked * true. @@ -574,6 +593,30 @@ namespace stratus { // // Returns the mouse status as of the most recent frame // RendererMouseState GetMouseState() const; + private: + struct VplDistKey_ { + LightPtr key; + double distance = 0.0; + + VplDistKey_(const LightPtr& key = nullptr, const double distance = 0.0) + : key(key), distance(distance) {} + + bool operator<(const VplDistKey_& other) const { + return distance < other.distance; + } + }; + + struct VplDistKeyLess_ { + bool operator()(const VplDistKey_& left, const VplDistKey_& right) const { + return left < right; + } + }; + + // Used for point light sorting and culling + using VplDistKeyAllocator_ = StackBasedPoolAllocator; + typedef std::multiset VplDistMultiSet_; + typedef std::vector VplDistVector_; + private: void InitializeVplData_(); void ClearGBuffer_(); @@ -583,7 +626,7 @@ namespace stratus { void InitPointShadowMaps_(); // void _InitAllEntityMeshData(); void InitCoreCSMData_(Pipeline *); - void InitLights_(Pipeline * s, const std::vector, LightDistancePairAllocator> & lights, const size_t maxShadowLights); + void InitLights_(Pipeline * s, const VplDistVector_& lights, const size_t maxShadowLights); void InitSSAO_(); void InitAtmosphericShadowing_(); // void _InitEntityMeshData(RendererEntityData &); @@ -604,16 +647,21 @@ namespace stratus { void RenderImmediate_(const RenderFaceCulling, GpuCommandBuffer2Ptr&, const CommandBufferSelectionFunction&); void Render_(Pipeline&, const RenderFaceCulling, GpuCommandBuffer2Ptr&, const CommandBufferSelectionFunction&, bool isLightInteracting, bool removeViewTranslation = false); void Render_(Pipeline&, std::unordered_map&, const CommandBufferSelectionFunction&, bool isLightInteracting, bool removeViewTranslation = false); - void InitVplFrameData_(const std::vector, LightDistancePairAllocator>& perVPLDistToViewer); + void InitVplFrameData_(const VplDistVector_& perVPLDistToViewer); void RenderImmediate_(std::unordered_map&, const CommandBufferSelectionFunction&, const bool reverseCullFace); - void UpdatePointLights_(std::vector, LightDistancePairAllocator>&, - std::vector, LightDistancePairAllocator>&, - std::vector, LightDistancePairAllocator>&, - std::vector>& visibleVplIndices); - void PerformVirtualPointLightCullingStage1_(std::vector, LightDistancePairAllocator>&, std::vector>& visibleVplIndices); + void UpdatePointLights_( + VplDistMultiSet_&, + VplDistVector_&, + VplDistMultiSet_&, + VplDistVector_&, + VplDistMultiSet_&, + VplDistVector_&, + std::vector>& visibleVplIndices + ); + void PerformVirtualPointLightCullingStage1_(VplDistVector_&, std::vector>& visibleVplIndices); //void PerformVirtualPointLightCullingStage2_(const std::vector>&, const std::vector& visibleVplIndices); - void PerformVirtualPointLightCullingStage2_(const std::vector, LightDistancePairAllocator>&); - void ComputeVirtualPointLightGlobalIllumination_(const std::vector, LightDistancePairAllocator>&, const double); + void PerformVirtualPointLightCullingStage2_(const VplDistVector_&); + void ComputeVirtualPointLightGlobalIllumination_(const VplDistVector_&, const double); void RenderCSMDepth_(); void RenderQuad_(); void RenderSkybox_(Pipeline *, const glm::mat4&); diff --git a/Source/Engine/StratusRendererFrontend.cpp b/Source/Engine/StratusRendererFrontend.cpp index 0a582014..f29f2f57 100644 --- a/Source/Engine/StratusRendererFrontend.cpp +++ b/Source/Engine/StratusRendererFrontend.cpp @@ -424,6 +424,7 @@ namespace stratus { // Set previous projection view frame_->prevProjectionView = frame_->projectionView; + frame_->prevInvProjectionView = frame_->invProjectionView; // Reset the per frame scratch memory frame_->perFrameScratchMemory->Deallocate(); @@ -1029,6 +1030,8 @@ namespace stratus { Vec4Allocator(frame_->perFrameScratchMemory) ); + frame_->viewFrustumPlanes = frustumPlanes; + pipeline.Bind(); for (size_t i = 0; i < 6; ++i) { @@ -1046,10 +1049,13 @@ namespace stratus { it->second->GetVisibleDrawCommandsBuffer().BindBase(GpuBaseBindingPoint::SHADER_STORAGE_BUFFER, 14); it->second->BindModelTransformBuffer(2); it->second->BindAabbBuffer(3); + it->second->GetVisibleLowestLodDrawCommandsBuffer().BindBase(GpuBaseBindingPoint::SHADER_STORAGE_BUFFER, 15); if (selectLods) { it->second->GetSelectedLodDrawCommandsBuffer().BindBase(GpuBaseBindingPoint::SHADER_STORAGE_BUFFER, 13); - for (size_t k = 0; k < it->second->NumLods(); ++k) { + // The render component has code to deal with indexing past the last lod (returns the highest lod it has) + const size_t numLods = 8; + for (size_t k = 0; k < numLods; ++k) { it->second->GetIndirectDrawCommandsBuffer(k).BindBase(GpuBaseBindingPoint::SHADER_STORAGE_BUFFER, k + 5); } } diff --git a/Source/Engine/StratusResourceManager.cpp b/Source/Engine/StratusResourceManager.cpp index 53c0ee14..9f8b39e8 100644 --- a/Source/Engine/StratusResourceManager.cpp +++ b/Source/Engine/StratusResourceManager.cpp @@ -13,6 +13,7 @@ #include "StratusRenderComponents.h" #include "StratusTransformComponent.h" #include +#include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" @@ -653,7 +654,7 @@ namespace stratus { aiProcess_JoinIdenticalVertices | aiProcess_SortByPType | aiProcess_GenNormals | - aiProcess_ValidateDataStructure | + //aiProcess_ValidateDataStructure | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType | //aiProcess_GenSmoothNormals | @@ -752,7 +753,9 @@ namespace stratus { #define FREE_ALL_STBI_IMAGE_DATA for (uint8_t * ptr : texdata->data) stbi_image_free((void *)ptr); - for (const std::string& file : files) { + for (const std::string& fileOrig : files) { + std::string file = fileOrig; + std::replace(file.begin(), file.end(), '\\', '/'); STRATUS_LOG << "Attempting to load texture from file: " << file << " (handle = " << handle << ")" << std::endl; int width, height, numChannels; diff --git a/Source/Engine/StratusStackAllocator.h b/Source/Engine/StratusStackAllocator.h index c412cec9..3e29ec6d 100644 --- a/Source/Engine/StratusStackAllocator.h +++ b/Source/Engine/StratusStackAllocator.h @@ -60,6 +60,11 @@ namespace stratus { uint8_t * current_ = nullptr; }; + inline static UnsafePtr GetDefaultStackAllocator_() { + thread_local static UnsafePtr allocator = MakeUnsafe(1024); + return allocator; + } + // This is designed to work with C++ standard library containers so // it follows Allocator requirements // @@ -78,6 +83,9 @@ namespace stratus { typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; + StackBasedPoolAllocator() + : StackBasedPoolAllocator(GetDefaultStackAllocator_()) {} + StackBasedPoolAllocator(const size_t maxObjects) : StackBasedPoolAllocator(MakeUnsafe(sizeof(value_type) * maxObjects)) {} @@ -134,6 +142,14 @@ namespace stratus { p->~U(); } + bool operator==(const StackBasedPoolAllocator& other) const noexcept { + return allocator_ == other.allocator_; + } + + bool operator!=(const StackBasedPoolAllocator& other) const noexcept { + return !(operator==(other)); + } + private: UnsafePtr allocator_; }; diff --git a/Source/Shaders/pbr.glsl b/Source/Shaders/pbr.glsl index 5e875988..a7a2427b 100644 --- a/Source/Shaders/pbr.glsl +++ b/Source/Shaders/pbr.glsl @@ -68,7 +68,7 @@ uniform float ambientIntensity = 0.00025; // Synchronized with definition found in StratusGpuCommon.h #define MAX_TOTAL_SHADOW_ATLASES (14) -#define MAX_TOTAL_SHADOWS_PER_ATLAS (300) +#define MAX_TOTAL_SHADOWS_PER_ATLAS (320) #define MAX_TOTAL_SHADOW_MAPS (MAX_TOTAL_SHADOW_ATLASES * MAX_TOTAL_SHADOWS_PER_ATLAS) // Synchronized with definition found in StratusGpuCommon.h @@ -257,7 +257,7 @@ float quadraticAttenuation(vec3 lightDir) { return 1.0 / (1.0 + lightDist * lightDist); } -float vplAttenuation(vec3 lightDir, float lightRadius) { +float vplDiffuseAttenuation(vec3 lightDir, float lightRadius) { float lightDist = length(lightDir); float ratio = min(lightDist / lightRadius, 1.0); float minDist = mix(10, 1, exp(-3.0 * ratio)) * lightRadius; @@ -266,6 +266,10 @@ float vplAttenuation(vec3 lightDir, float lightRadius) { return 1.0 / (minDist + 1.0 * lightDist * lightDist); } +float vplSpecularAttenuation(vec3 lightDir, float lightRadius) { + return vplDiffuseAttenuation(lightDir, lightRadius); +} + vec3 calculateLighting(vec3 lightColor, vec3 lightDir, vec3 viewDir, vec3 normal, vec3 baseColor, float roughness, float metallic, float ao, float shadowFactor, vec3 baseReflectivity, float attenuationFactor, float ambientIntensity) { @@ -328,13 +332,4 @@ vec3 calculatePointLighting(vec3 fragPosition, vec3 baseColor, vec3 normal, vec3 vec3 lightDir = lightPos - fragPosition; return calculateLighting(lightColor, lightDir, viewDir, normal, baseColor, roughness, metallic, ao, 1.0 - shadowFactor, baseReflectivity, quadraticAttenuation(lightDir), pointLightAmbientIntensity); -} - -vec3 calculateVirtualPointLighting(vec3 fragPosition, vec3 baseColor, vec3 normal, vec3 viewDir, vec3 lightPos, vec3 lightColor, - float lightRadius, float roughness, float metallic, float ao, float shadowFactor, vec3 baseReflectivity) { - - vec3 lightDir = lightPos - fragPosition; - - //return calculateLighting(lightColor, lightDir, viewDir, normal, baseColor, roughness, metallic, ao, 1.0 - shadowFactor, baseReflectivity, vplAttenuation(lightDir, lightRadius), 0.0); - return calculateDiffuseOnlyLighting(lightColor, lightDir, viewDir, normal, baseColor, metallic, ao, 1.0 - shadowFactor, baseReflectivity, vplAttenuation(lightDir, lightRadius), 0.003); } \ No newline at end of file diff --git a/Source/Shaders/pbr2.glsl b/Source/Shaders/pbr2.glsl index 23105941..7d63e4c9 100644 --- a/Source/Shaders/pbr2.glsl +++ b/Source/Shaders/pbr2.glsl @@ -144,9 +144,6 @@ float RemapRoughness(float roughness) { } void BRDF_Base( - in vec3 lightDir, - in vec3 viewDir, - in vec3 normal, in vec3 baseColor, in vec3 baseReflectance, in float roughness, @@ -155,11 +152,7 @@ void BRDF_Base( in vec3 specularMultiplier, out float remappedRoughness, out vec3 diffuseColor, - out vec3 f0, - out float NdotV, - out float NdotL, - out float NdotH, - out float LdotH) { + out vec3 f0) { // Remaps from perceptually linear roughness to roughness remappedRoughness = RemapRoughness(roughness); @@ -172,6 +165,16 @@ void BRDF_Base( // Compute reflectance - for purely metallic materials this is used as the diffuse color f0 = 0.16 * baseReflectance * baseReflectance * (1.0 - metallic) + baseColor * metallic; f0 = f0 * specularMultiplier; +} + +void BRDF_DotProducts( + vec3 viewDir, + vec3 lightDir, + vec3 normal, + out float NdotV, + out float NdotL, + out float NdotH, + out float LdotH) { vec3 V = viewDir; vec3 L = normalize(lightDir); @@ -215,9 +218,6 @@ vec3 BRDF_Burley( float LdotH = 0.0; BRDF_Base( - lightDir, - viewDir, - normal, baseColor, baseReflectance, roughness, @@ -226,7 +226,13 @@ vec3 BRDF_Burley( specularMultiplier, remappedRoughness, diffuseColor, - f0, + f0 + ); + + BRDF_DotProducts( + viewDir, + lightDir, + normal, NdotV, NdotL, NdotH, @@ -270,9 +276,6 @@ vec3 BRDF_Lambert( float LdotH = 0.0; BRDF_Base( - lightDir, - viewDir, - normal, baseColor, baseReflectance, roughness, @@ -281,7 +284,13 @@ vec3 BRDF_Lambert( specularMultiplier, remappedRoughness, diffuseColor, - f0, + f0 + ); + + BRDF_DotProducts( + viewDir, + lightDir, + normal, NdotV, NdotL, NdotH, @@ -298,6 +307,150 @@ vec3 BRDF_Lambert( return (Fd + Fr) * NdotL; } +void BRDF_Burley_SeparateDiffuseSpecular( + vec3 specularLightDir, + vec3 diffuseLightDir, + vec3 viewDir, + vec3 normal, + vec3 baseColor, + vec3 baseReflectance, + float roughness, + float metallic, + vec3 diffuseDivisor, + vec3 specularMultiplier, + out vec3 specular, + out vec3 diffuse) { + + // Remaps from perceptually linear roughness to roughness + float remappedRoughness = 0.0; + + // Compute diffuse from base using metallic value + //vec3 diffuseColor = (1.0 - clamp(metallic, 0.0, 0.95)) * baseColor; + vec3 diffuseColor = vec3(0.0); + + // Compute reflectance - for purely metallic materials this is used as the diffuse color + vec3 f0 = vec3(0.0); + + float NdotV = 0.0; + float NdotL = 0.0; + float NdotH = 0.0; + float LdotH = 0.0; + + BRDF_Base( + baseColor, + baseReflectance, + roughness, + metallic, + diffuseDivisor, + specularMultiplier, + remappedRoughness, + diffuseColor, + f0 + ); + + BRDF_DotProducts( + viewDir, + specularLightDir, + normal, + NdotV, + NdotL, + NdotH, + LdotH + ); + + // Specular + vec3 Fr = singleScatteringBRDF_Specular(NdotV, NdotL, NdotH, LdotH, remappedRoughness, f0) * NdotL; + + BRDF_DotProducts( + viewDir, + diffuseLightDir, + normal, + NdotV, + NdotL, + NdotH, + LdotH + ); + + // Diffuse + vec3 Fd = singleScatteringBRDF_Diffuse_Burley(NdotV, NdotL, NdotH, LdotH, remappedRoughness, diffuseColor) * NdotL; + + // Does not account for light color/intensity (functions below do that) + specular = Fr; + diffuse = Fd; +} + +void BRDF_Lambert_SeparateDiffuseSpecular( + vec3 specularLightDir, + vec3 diffuseLightDir, + vec3 viewDir, + vec3 normal, + vec3 baseColor, + vec3 baseReflectance, + float roughness, + float metallic, + vec3 diffuseDivisor, + vec3 specularMultiplier, + out vec3 specular, + out vec3 diffuse) { + + // Remaps from perceptually linear roughness to roughness + float remappedRoughness = 0.0; + + // Compute diffuse from base using metallic value + //vec3 diffuseColor = (1.0 - clamp(metallic, 0.0, 0.95)) * baseColor; + vec3 diffuseColor = vec3(0.0); + + // Compute reflectance - for purely metallic materials this is used as the diffuse color + vec3 f0 = vec3(0.0); + + float NdotV = 0.0; + float NdotL = 0.0; + float NdotH = 0.0; + float LdotH = 0.0; + + BRDF_Base( + baseColor, + baseReflectance, + roughness, + metallic, + diffuseDivisor, + specularMultiplier, + remappedRoughness, + diffuseColor, + f0 + ); + + BRDF_DotProducts( + viewDir, + specularLightDir, + normal, + NdotV, + NdotL, + NdotH, + LdotH + ); + + // Specular + vec3 Fr = singleScatteringBRDF_Specular(NdotV, NdotL, NdotH, LdotH, remappedRoughness, f0) * NdotL; + + BRDF_DotProducts( + viewDir, + diffuseLightDir, + normal, + NdotV, + NdotL, + NdotH, + LdotH + ); + + // Diffuse + vec3 Fd = singleScatteringBRDF_Diffuse_Lambert(NdotV, NdotL, NdotH, LdotH, remappedRoughness, diffuseColor) * NdotL; + + // Does not account for light color/intensity (functions below do that) + specular = Fr; + diffuse = Fd; +} + vec3 calculateLighting_Burley( vec3 lightColor, vec3 lightDir, @@ -350,6 +503,76 @@ vec3 calculateLighting_Lambert( return attenuationFactor * (ambient + shadowFactor * applyFog(finalBrightness, viewDist, fogIntensity)); } +vec3 calculateLighting_Burley_SeparateDiffuseSpecular( + vec3 lightColor, + vec3 specularLightDir, + vec3 diffuseLightDir, + vec3 viewDir, + vec3 normal, + vec3 baseColor, + float viewDist, + float fogIntensity, + float roughness, + float metallic, + float ambientOcclusion, + float shadowFactor, + vec3 baseReflectance, + float specularAttenuationFactor, + float diffuseAttenuationFactor, + float ambientIntensity, + vec3 diffuseDivisor, + vec3 specularMultiplier) { + + vec3 brdfSpecular = vec3(0.0); + vec3 brdfDiffuse = vec3(0.0); + + BRDF_Burley_SeparateDiffuseSpecular(specularLightDir, diffuseLightDir, viewDir, normal, baseColor, baseReflectance, roughness, metallic, diffuseDivisor, specularMultiplier, brdfSpecular, brdfDiffuse); + + brdfSpecular = specularAttenuationFactor * brdfSpecular; + brdfDiffuse = diffuseAttenuationFactor * brdfDiffuse; + vec3 brdf = brdfSpecular + brdfDiffuse; + + vec3 ambient = brdf * ambientOcclusion * lightColor * ambientIntensity; + vec3 finalBrightness = brdf * lightColor; + + return ambient + shadowFactor * applyFog(finalBrightness, viewDist, fogIntensity); +} + +vec3 calculateLighting_Lambert_SeparateDiffuseSpecular( + vec3 lightColor, + vec3 specularLightDir, + vec3 diffuseLightDir, + vec3 viewDir, + vec3 normal, + vec3 baseColor, + float viewDist, + float fogIntensity, + float roughness, + float metallic, + float ambientOcclusion, + float shadowFactor, + vec3 baseReflectance, + float specularAttenuationFactor, + float diffuseAttenuationFactor, + float ambientIntensity, + vec3 diffuseDivisor, + vec3 specularMultiplier) { + + vec3 brdfSpecular = vec3(0.0); + vec3 brdfDiffuse = vec3(0.0); + + BRDF_Lambert_SeparateDiffuseSpecular(specularLightDir, diffuseLightDir, viewDir, normal, baseColor, baseReflectance, roughness, metallic, diffuseDivisor, specularMultiplier, brdfSpecular, brdfDiffuse); + + brdfSpecular = specularAttenuationFactor * brdfSpecular; + brdfDiffuse = diffuseAttenuationFactor * brdfDiffuse; + vec3 brdf = brdfSpecular + brdfDiffuse; + + vec3 ambient = brdf * ambientOcclusion * lightColor * ambientIntensity; + vec3 finalBrightness = brdf * lightColor; + + return ambient + shadowFactor * applyFog(finalBrightness, viewDist, fogIntensity); +} + vec3 calculateDirectionalLighting( vec3 lightColor, vec3 lightDir, @@ -392,7 +615,8 @@ vec3 calculateVirtualPointLighting2( vec3 baseColor, vec3 normal, vec3 viewDir, - vec3 lightPos, + vec3 specularLightPos, + vec3 diffuseLightPos, vec3 lightColor, float viewDist, float lightRadius, @@ -402,10 +626,32 @@ vec3 calculateVirtualPointLighting2( float shadowFactor, vec3 baseReflectance) { - vec3 lightDir = lightPos - fragPosition; + vec3 specularLightDir = specularLightPos - fragPosition; + vec3 diffuseLightDir = diffuseLightPos - fragPosition; + float adjustedShadowFactor = 1.0 - shadowFactor; //adjustedShadowFactor = max(adjustedShadowFactor, 1.0); - return calculateLighting_Lambert(lightColor, lightDir, viewDir, normal, baseColor, viewDist, 0.0, roughness, metallic, ambientOcclusion, adjustedShadowFactor, baseReflectance, vplAttenuation(lightDir, lightRadius), 0.0, baseColor, 1.0 / (baseColor + PREVENT_DIV_BY_ZERO)); + return calculateLighting_Lambert_SeparateDiffuseSpecular( + lightColor, + specularLightDir, + diffuseLightDir, + viewDir, + normal, + baseColor, + viewDist, + 0.0, + roughness, + metallic, + ambientOcclusion, + adjustedShadowFactor, + baseReflectance, + vplSpecularAttenuation(specularLightDir, lightRadius), + vplDiffuseAttenuation(diffuseLightDir, lightRadius), + 0.0, + baseColor, + 1.0 / (baseColor + PREVENT_DIV_BY_ZERO) + ); + //return calculateLighting_Lambert(lightColor, lightDir, viewDir, normal, baseColor, viewDist, 0.0, roughness, metallic, ambientOcclusion, adjustedShadowFactor, baseReflectance, vplAttenuation(lightDir, lightRadius), 0.0, vec3(1.0), vec3(1.0)); } \ No newline at end of file diff --git a/Source/Shaders/pbr_geometry_pass.fs b/Source/Shaders/pbr_geometry_pass.fs index 82431438..a1cb546f 100644 --- a/Source/Shaders/pbr_geometry_pass.fs +++ b/Source/Shaders/pbr_geometry_pass.fs @@ -107,10 +107,10 @@ void main() { vec3 normal = bool(fsNormalMapped) ? calculateNormal(material, texCoords) : (fsNormal + 1.0) * 0.5; // [-1, 1] -> [0, 1] - //float roughness = bool(fsRoughnessMapped) ? texture(material.roughnessMap, texCoords).r : material.metallicRoughness[1]; - //float metallic = bool(fsMetallicMapped) ? texture(material.metallicMap, texCoords).r : material.metallicRoughness[0]; - float roughness = material.metallicRoughness[1]; - float metallic = material.metallicRoughness[0]; + float roughness = bool(fsRoughnessMapped) ? texture(material.roughnessMap, texCoords).r : material.metallicRoughness[1]; + float metallic = bool(fsMetallicMapped) ? texture(material.metallicMap, texCoords).r : material.metallicRoughness[0]; + //float roughness = material.metallicRoughness[1]; + //float metallic = material.metallicRoughness[0]; // float roughness = material.metallicRoughness[1]; // float metallic = material.metallicRoughness[0]; // See https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/main/source/Renderer/shaders/material_info.glsl diff --git a/Source/Shaders/shadowVpl.fs b/Source/Shaders/shadowVpl.fs index df312fa3..a1dab88f 100644 --- a/Source/Shaders/shadowVpl.fs +++ b/Source/Shaders/shadowVpl.fs @@ -20,6 +20,8 @@ void main() { runAlphaTest(baseColor.a); + //vec3 emissive = bool(fsEmissiveMapped) ? emissiveTextureMultiplier * texture(material.emissiveMap, texCoords).rgb : FLOAT3_TO_VEC3(material.emissiveColor); + // get distance between fragment and light source float lightDistance = length(fsPosition.xyz - lightPos); diff --git a/Source/Shaders/visibility_culling.cs b/Source/Shaders/visibility_culling.cs index 7f4424a4..3e547b0c 100644 --- a/Source/Shaders/visibility_culling.cs +++ b/Source/Shaders/visibility_culling.cs @@ -30,6 +30,10 @@ DrawElementsIndirectCommand selectedLods[]; }; +layout (std430, binding = 15) buffer outputBlock3 { + DrawElementsIndirectCommand lowestLodOutDrawCalls[]; +}; + #ifdef SELECT_LOD layout (std430, binding = 5) readonly buffer lod0 { DrawElementsIndirectCommand drawCallsLod0[]; @@ -83,6 +87,7 @@ void main() { //center = center - viewPosition; //(view * vec4(center, 1.0)).xyz; //float dist = length((view * vec4(center, 1.0)).xyz);//abs(center.z); DrawElementsIndirectCommand draw = inDrawCalls[i]; + DrawElementsIndirectCommand lowestLodDraw = draw; #ifdef SELECT_LOD DrawElementsIndirectCommand lod; @@ -90,6 +95,8 @@ void main() { const float maxDist = max(zfar, 1000.0) - firstLodDist; const float restLodDist = maxDist / 7; + lowestLodDraw = drawCallsLod7[i]; + if (dist < firstLodDist) { draw = drawCallsLod0[i]; } @@ -124,12 +131,15 @@ void main() { if (!isAabbVisible(frustumPlanes, aabb)) { draw.instanceCount = 0; + lowestLodDraw.instanceCount = 0; } else { draw.instanceCount = 1; + lowestLodDraw.instanceCount = 1; } outDrawCalls[i] = draw; + lowestLodOutDrawCalls[i] = lowestLodDraw; #ifdef SELECT_LOD selectedLods[i] = lod; diff --git a/Source/Shaders/vpl_common.glsl b/Source/Shaders/vpl_common.glsl index fe38621f..2d179f84 100644 --- a/Source/Shaders/vpl_common.glsl +++ b/Source/Shaders/vpl_common.glsl @@ -4,7 +4,7 @@ STRATUS_GLSL_VERSION // These needs to match what is in the renderer backend! // TODO: Find a better way to sync these values with renderer -#define MAX_TOTAL_VPLS_BEFORE_CULLING (8192) +#define MAX_TOTAL_VPLS_BEFORE_CULLING (10000) #define MAX_TOTAL_VPLS_PER_FRAME (MAX_TOTAL_SHADOW_MAPS) #define MAX_VPLS_PER_TILE (12) @@ -48,7 +48,7 @@ struct VplStage2PerTileOutputs { struct VplData { vec4 position; vec4 color; - vec4 _3; + vec4 specularPosition; float radius; float farPlane; float intensity; diff --git a/Source/Shaders/vpl_light_color.cs b/Source/Shaders/vpl_light_color.cs index ddb121da..5c6ac9d7 100644 --- a/Source/Shaders/vpl_light_color.cs +++ b/Source/Shaders/vpl_light_color.cs @@ -32,6 +32,7 @@ }; uniform samplerCubeArray diffuseCubeMaps[MAX_TOTAL_SHADOW_ATLASES]; +uniform samplerCubeArray shadowCubeMaps[MAX_TOTAL_SHADOW_ATLASES]; layout (std430, binding = 4) readonly buffer inputBlock3 { AtlasEntry diffuseIndices[]; @@ -48,8 +49,10 @@ void main() { int index = i; VplData data = lightData[index]; AtlasEntry entry = diffuseIndices[index]; + // First two samples from the exact direction vector for a total of 10 samples after loop vec3 color = textureLod(diffuseCubeMaps[entry.index], vec4(-infiniteLightDirection, float(entry.layer)), 0).rgb * infiniteLightColor; + float magnitude = data.radius * textureLod(shadowCubeMaps[entry.index], vec4(-infiniteLightDirection, float(entry.layer)), 0).r; float offset = 0.5; float offsets[2] = float[](-offset, offset); float totalColors = 1.0; @@ -64,6 +67,10 @@ void main() { // } // } + //vec4 specularPos = data.position; + vec4 specularPos = vec4(data.position.xyz - 1.1 * magnitude * infiniteLightDirection, 1.0); + lightData[index].color = vec4(color / totalColors * data.intensity * colorMultiplier, 1.0); + lightData[index].specularPosition = specularPos; } } \ No newline at end of file diff --git a/Source/Shaders/vpl_pbr_gi.fs b/Source/Shaders/vpl_pbr_gi.fs index 624db780..4d2085ed 100644 --- a/Source/Shaders/vpl_pbr_gi.fs +++ b/Source/Shaders/vpl_pbr_gi.fs @@ -14,7 +14,7 @@ out vec3 color; out vec4 reservoir; #define STANDARD_MAX_SAMPLES_PER_PIXEL 5 -#define ABSOLUTE_MAX_SAMPLES_PER_PIXEL 5 +#define ABSOLUTE_MAX_SAMPLES_PER_PIXEL 10 #define MAX_RESAMPLES_PER_PIXEL STANDARD_MAX_SAMPLES_PER_PIXEL //#define MAX_SHADOW_SAMPLES_PER_PIXEL 25 @@ -113,6 +113,8 @@ void performLightingCalculations(vec3 screenColor, vec2 pixelCoords, vec2 texCoo float ambient = textureLod(gRoughnessMetallicAmbient, texCoords, 0).b;// * ambientOcclusion; vec3 baseReflectivity = vec3(textureLod(gBaseReflectivity, texCoords, 0).r); + float roughnessWeight = 1.0 - roughness; + float history = textureLod(historyDepth, texCoords, 0).r; vec3 vplColor = vec3(0.0); //screenColor; @@ -122,136 +124,76 @@ void performLightingCalculations(vec3 screenColor, vec2 pixelCoords, vec2 texCoo // Used to seed the pseudo-random number generator // See https://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl - vec3 seed = vec3(0.0, 0.0, time); - int maxRandomIndex = numVisible[0] - 1; - // float shadowFactor = 0.0; - // for (int baseLightIndex = 0; baseLightIndex < maxShadowLights; ++baseLightIndex) { - // //seed.z += 1000.0; - // //float rand = random(seed); - // //int lightIndex = vplVisibleIndex[int(maxRandomIndex * rand)]; - // int lightIndex = vplVisibleIndex[baseLightIndex]; - // vec3 lightPosition = lightData[lightIndex].position.xyz; - // AtlasEntry entry = shadowIndices[lightIndex]; - - // shadowFactor += calculateShadowValue1Sample(shadowCubeMaps[entry.index], entry.layer, lightData[lightIndex].farPlane, fragPos, lightPosition, dot(lightPosition - fragPos, normal)); - // } - - // shadowFactor /= float(maxShadowLights); - const float seedZMultiplier = 10000.0; const float seedZOffset = 10000.0; - //float seedZ = float(frameCount % 20) * seedZMultiplier; + float seedZ = time; - seed = vec3(gl_FragCoord.xy, time); - //seed = vec3(gl_FragCoord.xy, time + float(frameCount)); - //seed = vec3(gl_FragCoord.xy, 0.0); - //seed = vec3(gl_FragCoord.xy, seedZ); - //seed = vec3(0.0, 0.0, time); - //seed = vec3(0.0, gl_FragCoord.y, 0.0); - //seed = vec3(distToCamera * 10.0, 0.0, time); - //seed = vec3(distToCamera, 0.0, time); - //seed = vec3(fragPos.x, fragPos.y, fragPos.z + time); - //seed = vec3(0.0, gl_FragCoord.y, time); - //int haltonIndex = int(ceil(haltonSize * random(seed))); + vec3 seed = vec3(gl_FragCoord.xy, time); float validSamples = 0.0; - bool useBase2 = false; - //float rand = random(seed); - //int offset = frameCount % numVisible; + vec3 colorNoShadow = vec3(0.0); - //int startIndex = int(gl_FragCoord.x) + int(gl_FragCoord.y) * haltonSize; - //int startIndex = int(random(seed) * haltonSize); - //int startIndex = 0; - //int baseHaltonIndex = int((float(gl_FragCoord.x) / float(haltonSize)) * float(haltonSize)) % haltonSize; - // float normalizedHistory = 1.0 - history / float(MAX_SAMPLES_PER_PIXEL); - // //int sampleCount = history < float(MAX_SAMPLES_PER_PIXEL) ? int(normalizedHistory * MAX_SAMPLES_PER_PIXEL) : 1; - // int sampleCount = int(normalizedHistory * MAX_SAMPLES_PER_PIXEL); - // sampleCount = max(sampleCount, 1); - //int sampleCount = history < 2.0 ? MAX_SAMPLES_PER_PIXEL : 1; - //int sampleCount = history < float(MAX_SAMPLES_PER_PIXEL) ? MAX_SAMPLES_PER_PIXEL : 1; - //int sampleCount = history < float(MAX_SAMPLES_PER_PIXEL) ? MAX_SAMPLES_PER_PIXEL : HALF_MAX_SAMPLES_PER_PIXEL; + float distRatioToCamera = min(1.0 - distToCamera / 1000.0, 1.0); - int samplesMax = history < ABSOLUTE_MAX_SAMPLES_PER_PIXEL ? ABSOLUTE_MAX_SAMPLES_PER_PIXEL : STANDARD_MAX_SAMPLES_PER_PIXEL; - int sampleCount = max(1, int(samplesMax * distRatioToCamera)); + int maxSamplesPerPixel = int(mix(STANDARD_MAX_SAMPLES_PER_PIXEL, ABSOLUTE_MAX_SAMPLES_PER_PIXEL, roughnessWeight)); + //int maxSamplesPerPixel = STANDARD_MAX_SAMPLES_PER_PIXEL; + int samplesMax = history < ABSOLUTE_MAX_SAMPLES_PER_PIXEL ? ABSOLUTE_MAX_SAMPLES_PER_PIXEL : maxSamplesPerPixel; + samplesMax = max(1, int(samplesMax * distRatioToCamera)); + int sampleCount = samplesMax;//max(1, int(samplesMax * 0.5)); + + int maxRandomIndex = numVisible[0] - 1; //min(numVisible[0] - 1, int((numVisible[0] - 1) * (1.0 / 3.0))); + //maxRandomIndex = int(maxRandomIndex * mix(1.0, 0.5, distRatioToCamera)); + for (int i = 0, resamples = 0, count = 0; i < sampleCount; i += 1, count += 1) { - //seed.z += 1000.0; - float rand = random(seed); - seed.z += seedZOffset; - //seed.z += 1000.0; - // float rand = haltonSequence[haltonIndex].base3; - // if (useBase2) { - // rand = haltonSequence[haltonIndex].base2; - // ++haltonIndex; - // if (haltonIndex > haltonSize) { - // haltonIndex = 0; - // } - // // seed.z += 1000.0; - // // haltonIndex = int(ceil(haltonSize * random(seed))); - // } - // useBase2 = !useBase2; - - // Calculate true light index via lookup into active light table - //int lightIndex = tileData[baseTileIndex].indices[baseLightIndex]; - //int lightIndex = vplVisibleIndex[baseLightIndex]; - int lightIndex = int(maxRandomIndex * rand); - //int lightIndex = int(int(gl_FragCoord.x) + int(gl_FragCoord.y * numVisible) * rand) % numVisible; - //int lightIndex = int((fsTexCoords.x + rand) * maxRandomIndex) % numVisible; - // HaltonEntry baseHEntry = haltonSequence[baseHaltonIndex]; - // HaltonEntry offsetHEntry = haltonSequence[int(rand * (haltonSize - 1))]; - // rand = baseHEntry.base2 + offsetHEntry.base3; - // if ((startIndex % (2 * haltonSize)) % 2 == 0) { - // rand = hentry.base3; - // } - //int lightIndex = int(numVisible * rand) % numVisible; - //int lightIndex = (int(maxRandomIndex * rand) + int(gl_FragCoord.x) * numVisible + int(gl_FragCoord.y)) % numVisible; - //int lightIndex = (int(maxRandomIndex * rand) + i + resamples) % numVisible; - //int lightIndex = (int(maxRandomIndex * rand) + offset + count) % numVisible; - AtlasEntry entry = shadowIndices[lightIndex]; - //if (lightIndex > MAX_TOTAL_VPLS_PER_FRAME) continue; - - vec3 lightPosition = lightData[lightIndex].position.xyz; - - // Make sure the light is in the direction of the plane+normal. If n*(a-p) < 0, the point is on the other side of the plane. - // If 0 the point is on the plane. If > 0 then the point is on the side of the plane visible along the normal's direction. - // See https://math.stackexchange.com/questions/1330210/how-to-check-if-a-point-is-in-the-direction-of-the-normal-of-a-plane - vec3 lightMinusFrag = lightPosition - fragPos; - float lightRadius = lightData[lightIndex].radius; - float distance = length(lightMinusFrag); - - //validSamples += 1.0; - - if (resamples < MAX_RESAMPLES_PER_PIXEL) { - float sideCheck = dot(normal, normalize(lightMinusFrag)); - if (sideCheck < 0.0 || distance > lightRadius) { - ++resamples; - --i; - continue; - } - } - - float distanceRatio = clamp(distance / lightRadius, 0.0, 1.0); - //float distanceSquaredRatio = clamp((distance * distance) / lightRadius, 0.0, 1.0); - float distAttenuation = distanceRatio; - - vec3 lightColor = lightData[lightIndex].color.xyz; - //float lightIntensity = length(lightColor); - - //validSamples += 1.0; - //float ratio = distance / lightRadius; - //if (distance > lightRadii[lightIndex]) continue; - - float shadowFactor = distToCamera < 700 ? calculateShadowValue1Sample(shadowCubeMaps[entry.index], entry.layer, lightData[lightIndex].farPlane, fragPos, lightPosition, dot(lightPosition - fragPos, normal), 0.05) : 0.0; - shadowFactor = min(shadowFactor, mix(minGiOcclusionFactor, 1.0, distanceRatio)); - - float reweightingFactor = 1.0; - - if (shadowFactor > 0.0) { - reweightingFactor = (1.0 - distAttenuation) * minGiOcclusionFactor + distAttenuation; - } - - validSamples += reweightingFactor; - - vec3 tmpColor = ambientOcclusion * calculateVirtualPointLighting2(fragPos, baseColor, normal, viewDir, lightPosition, lightColor, distToCamera, lightRadius, roughness, metallic, ambient, 0.0, baseReflectivity); - //colorNoShadow += tmpColor; + float rand = random(seed); + seed.z += seedZOffset; + int lightIndex = int(maxRandomIndex * rand); + AtlasEntry entry = shadowIndices[lightIndex]; + \ + vec3 lightPosition = lightData[lightIndex].position.xyz; + vec3 specularLightPosition = lightData[lightIndex].specularPosition.xyz; + + /* Make sure the light is in the direction of the plane+normal. If n*(a-p) < 0, the point is on the other side of the plane. */ + /* If 0 the point is on the plane. If > 0 then the point is on the side of the plane visible along the normal's direction. */ + /* See https://math.stackexchange.com/questions/1330210/how-to-check-if-a-point-is-in-the-direction-of-the-normal-of-a-plane */ + vec3 lightMinusFrag = lightPosition - fragPos; + float lightRadius = lightData[lightIndex].radius; + float distance = length(lightMinusFrag); + + if (resamples < MAX_RESAMPLES_PER_PIXEL) { + float sideCheck = dot(normal, normalize(lightMinusFrag)); + if (sideCheck < 0.0 || distance > lightRadius) { + ++resamples; + --i; + continue; + } + } + + float distanceRatio = clamp((2.0 * distance) / lightRadius, 0.0, 1.0); + float distAttenuation = distanceRatio; + + vec3 lightColor = lightData[lightIndex].color.xyz; + + float shadowFactor = + distToCamera < 700 ? calculateShadowValue1Sample(shadowCubeMaps[entry.index], + entry.layer, + lightData[lightIndex].farPlane, + fragPos, + lightPosition, + dot(lightPosition - fragPos, normal), 0.05) + : 0.0; + shadowFactor = min(shadowFactor, mix(minGiOcclusionFactor, 1.0, distanceRatio)); + + float reweightingFactor = 1.0; + + if (shadowFactor > 0.0) { + reweightingFactor = (1.0 - distAttenuation) * minGiOcclusionFactor + distAttenuation; + } + + validSamples += reweightingFactor; + + vec3 tmpColor = ambientOcclusion * calculateVirtualPointLighting2(fragPos, baseColor, normal, viewDir, specularLightPosition, + lightPosition, lightColor, distToCamera, lightRadius, roughness, metallic, ambient, 0.0, baseReflectivity + ); vplColor = vplColor + (1.0 - shadowFactor) * tmpColor; } diff --git a/Source/Shaders/vpl_pbr_gi_denoise.fs b/Source/Shaders/vpl_pbr_gi_denoise.fs index 3472cfe9..18ed6cbf 100644 --- a/Source/Shaders/vpl_pbr_gi_denoise.fs +++ b/Source/Shaders/vpl_pbr_gi_denoise.fs @@ -59,6 +59,9 @@ uniform int numReservoirNeighbors = 10; uniform float time; uniform float framesPerSecond; +uniform mat4 invProjectionView; +uniform mat4 prevInvProjectionView; + #define COMPONENT_WISE_MIN_VALUE 0.001 // const float waveletFactors[5] = float[]( @@ -245,24 +248,18 @@ vec4 computeMergedReservoir(vec3 centerNormal, float centerDepth) { const int halfNearestNeighborhood = nearestNeighborhood / 2; const int halfNumReservoirNeighbors = numReservoirNeighbors / 2; - int minmaxNearest = 1; + int minmaxNearest = 0; for (int dx = -minmaxNearest; dx <= minmaxNearest; ++dx) { for (int dy = -minmaxNearest; dy <= minmaxNearest; ++dy) { ACCEPT_OR_REJECT_RESERVOIR_DETERMINISTIC(0) } } - // for (int count = 0; count < halfNumReservoirNeighbors; ++count) { - // ACCEPT_OR_REJECT_RESERVOIR_RANDOM(nearestNeighborhood, halfNearestNeighborhood, 0) + // int minmaxNearest = 0; + // for (int count = 0; count < numReservoirNeighbors; ++count) { + // ACCEPT_OR_REJECT_RESERVOIR_RANDOM(neighborhood, halfNeighborhood, minmaxNearest) // } - for (int count = 0; count < numReservoirNeighbors; ++count) { - - ACCEPT_OR_REJECT_RESERVOIR_RANDOM(neighborhood, halfNeighborhood, minmaxNearest) - - //++count; - } - centerReservoir.a = runningSum; return centerReservoir; } @@ -278,7 +275,7 @@ void main() { //vec3 baseColor = texture(albedo, fsTexCoords).rgb; vec3 centerIllum = texture(indirectIllumination, fsTexCoords).rgb; - float centerLum = linearColorToLuminance(centerIllum); + float centerLum = 1.0;//linearColorToLuminance(centerIllum); vec3 centerShadow = texture(indirectShadows, fsTexCoords).rgb; vec3 centerNormal = sampleNormal(normal, fsTexCoords); @@ -295,6 +292,7 @@ void main() { //int filterSizeXY = 2 * dminmax + 1; int count = 0; if (mergeReservoirs) { + //if (true) { reservoirFiltered = computeMergedReservoir(centerNormal, centerDepth); } else { @@ -342,7 +340,10 @@ void main() { // accumMultiplier = 0.0; // } - float prevCenterDepth = texture(depth, prevTexCoords).r; + float prevCenterDepth = texture(prevDepth, prevTexCoords).r; + //vec3 currWorldPos = worldPositionFromDepth(fsTexCoords, centerDepth, invProjectionView); + //vec3 prevWorldPos = worldPositionFromDepth(prevTexCoords, prevCenterDepth, prevInvProjectionView); + prevCenterNormal = sampleNormalWithOffset(prevNormal, prevTexCoords, ivec2(0, 0)); vec3 prevGi = textureOffset(prevIndirectIllumination, prevTexCoords, ivec2(0, 0)).rgb; @@ -350,6 +351,11 @@ void main() { float prevId = texture(prevIds, prevTexCoords).r; float wn = max(0.0, dot(centerNormal, prevCenterNormal)); + /* If it is less than 0.906 it means the angle exceeded 25 degrees (positive or negative angle) */ + // if (wn < 0.95) { + // wn = 0.0; + // } + //wn = pow(wn, 8.0); //float similarity = 1.0; // float wn = 1.0; @@ -366,7 +372,13 @@ void main() { // //continue; // wz = 0.0; // } - float wz = exp(-10.0 * abs(centerDepth - prevCenterDepth)); + + float wz1 = exp(-abs(centerDepth - prevCenterDepth)); + //float wz2 = 1.0; + //if (length(currWorldPos - prevWorldPos) > 0.01) { + //wz2 = 0.0; + //} + float wz = wz1; //wz1 * wz2; //float wz = exp(-abs(centerDepth - prevCenterDepth) / (sigmaZ * abs(dot(currGradient, fsTexCoords - prevTexCoords)) + 0.0001)); // float wz = exp(-50.0 * abs(centerDepth - prevCenterDepth)); @@ -390,7 +402,7 @@ void main() { float similarity = wn * wz * wid; - if (similarity < 0.95) { + if (similarity < 0.99) { similarity = 0.0; accumMultiplier = 0.0; //complete = true; @@ -402,7 +414,9 @@ void main() { float maxAccumulationFactor = 1.0 / historyAccum; illumAvg = mix(prevGi, currGi, maxAccumulationFactor); - //illumAvg = shadowFactor; + //illumAvg = currGi; + //illumAvg = vec3(abs(centerDepth - prevCenterDepth)); + //illumAvg = vec3(length(currWorldPos - prevWorldPos)); } combinedColor = screenColor + gi * illumAvg;